Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickrectangleshape.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
8
9Q_STATIC_LOGGING_CATEGORY(lcCalculateIndependentRadii, "qt.quick.shapes.designhelpers.rectangleshape.calculateindependentradii")
10Q_STATIC_LOGGING_CATEGORY(lcUpdatePolish, "qt.quick.shapes.designhelpers.rectangleshape.updatepolish")
11Q_STATIC_LOGGING_CATEGORY(lcMaybeUpdateElements, "qt.quick.shapes.designhelpers.rectangleshape.maybeupdateelements")
12
13void QQuickRectangleShapePrivate::setTopLeftRadius(int topLeftRadius,
14 QQml::PropertyUtils::State propertyState)
15{
16 Q_Q(QQuickRectangleShape);
17 const int oldEffectiveTopLeftRadius = q->topLeftRadius();
18 explicitTopLeftRadius = isExplicitlySet(propertyState);
19 this->topLeftRadius = topLeftRadius;
20
21 if (q->topLeftRadius() == oldEffectiveTopLeftRadius)
22 return;
23
24 q->polish();
25 emit q->topLeftRadiusChanged();
26}
27
28void QQuickRectangleShapePrivate::setTopRightRadius(int topRightRadius,
29 QQml::PropertyUtils::State propertyState)
30{
31 Q_Q(QQuickRectangleShape);
32 const int oldEffectiveTopRightRadius = q->topRightRadius();
33 explicitTopRightRadius = isExplicitlySet(propertyState);
34 this->topRightRadius = topRightRadius;
35
36 if (q->topRightRadius() == oldEffectiveTopRightRadius)
37 return;
38
39 q->polish();
40 emit q->topRightRadiusChanged();
41}
42
43void QQuickRectangleShapePrivate::setBottomLeftRadius(int bottomLeftRadius,
44 QQml::PropertyUtils::State propertyState)
45{
46 Q_Q(QQuickRectangleShape);
47 const int oldEffectiveBottomLeftRadius = q->bottomLeftRadius();
48 explicitBottomLeftRadius = isExplicitlySet(propertyState);
49 this->bottomLeftRadius = bottomLeftRadius;
50
51 if (q->bottomLeftRadius() == oldEffectiveBottomLeftRadius)
52 return;
53
54 q->polish();
55 emit q->bottomLeftRadiusChanged();
56}
57
58void QQuickRectangleShapePrivate::setBottomRightRadius(int bottomRightRadius,
59 QQml::PropertyUtils::State propertyState)
60{
61 Q_Q(QQuickRectangleShape);
62 const int oldEffectiveBottomRightRadius = q->bottomRightRadius();
63 explicitBottomRightRadius = isExplicitlySet(propertyState);
64 this->bottomRightRadius = bottomRightRadius;
65
66 if (q->bottomRightRadius() == oldEffectiveBottomRightRadius)
67 return;
68
69 q->polish();
70 emit q->bottomRightRadiusChanged();
71}
72
73void QQuickRectangleShapePrivate::setTopLeftBevel(bool topLeftBevel,
74 QQml::PropertyUtils::State propertyState)
75{
76 Q_Q(QQuickRectangleShape);
77 const bool oldTopLeftBevel = q->hasTopLeftBevel();
78 explicitTopLeftBevel = isExplicitlySet(propertyState);
79 this->topLeftBevel = topLeftBevel;
80
81 if (q->hasTopLeftBevel() == oldTopLeftBevel)
82 return;
83
84 q->polish();
85 emit q->topLeftBevelChanged();
86}
87
88void QQuickRectangleShapePrivate::setTopRightBevel(bool topRightBevel,
89 QQml::PropertyUtils::State propertyState)
90{
91 Q_Q(QQuickRectangleShape);
92 const bool oldTopRightBevel = q->hasTopRightBevel();
93 explicitTopRightBevel = isExplicitlySet(propertyState);
94 this->topRightBevel = topRightBevel;
95
96 if (q->hasTopRightBevel() == oldTopRightBevel)
97 return;
98
99 q->polish();
100 emit q->topRightBevelChanged();
101}
102
103void QQuickRectangleShapePrivate::setBottomLeftBevel(bool bottomLeftBevel,
104 QQml::PropertyUtils::State propertyState)
105{
106 Q_Q(QQuickRectangleShape);
107 const bool oldBottomLeftBevel = q->hasBottomLeftBevel();
108 explicitBottomLeftBevel = isExplicitlySet(propertyState);
109 this->bottomLeftBevel = bottomLeftBevel;
110
111 if (q->hasBottomLeftBevel() == oldBottomLeftBevel)
112 return;
113
114 q->polish();
115 emit q->bottomLeftBevelChanged();
116}
117
118void QQuickRectangleShapePrivate::setBottomRightBevel(bool bottomRightBevel,
119 QQml::PropertyUtils::State propertyState)
120{
121 Q_Q(QQuickRectangleShape);
122 const bool oldBottomRightBevel = q->hasBottomRightBevel();
123 explicitBottomRightBevel = isExplicitlySet(propertyState);
124 this->bottomRightBevel = bottomRightBevel;
125
126 if (q->hasBottomRightBevel() == oldBottomRightBevel)
127 return;
128
129 q->polish();
130 emit q->bottomRightBevelChanged();
131}
132
133template <typename T>
134T *createElement(QQuickShapePath *shapePath, const char *objectName)
135{
136 auto *element = new T(shapePath);
137 element->setObjectName(objectName);
138 return element;
139}
140
141/*!
142 \internal
143
144 Constructs and append the individual path elements to the ShapePath.
145*/
146void QQuickRectangleShapePrivate::maybeUpdateElements()
147{
148 if (!componentComplete)
149 return;
150
151 auto *shapePathPrivate = QQuickShapePathPrivate::get(shapePath);
152
153 // We need to delete the elements since we create them ourselves.
154 qCDebug(lcMaybeUpdateElements).nospace() << "maybeUpdateElements called on "
155 // Avoid printing the QQuickItem as it results in assertion failure in QQuickItemLayer::componentComplete.
156 << static_cast<void *>(q_func()) << "; deleting and clearing path elements";
157 shapePathPrivate->clearPathElements(QQuickPathPrivate::DeleteElementPolicy::Delete);
158
159 static const QQuickPathPrivate::ProcessPathPolicy DontProcessPath
160 = QQuickPathPrivate::ProcessPathPolicy::DontProcess;
161
162 // We avoid rendering issues (QDS-14861) by rotating the start position
163 // clockwise until the first visible edge after a hidden edge was found.
164 // Set the start position (startIndex) to that edge and continue the construction of
165 // the border item from there.
166 const std::array visibleEdges = {drawTop, drawRight, drawBottom, drawLeft };
167 int startIndex = 0;
168 for (int currentEdge = static_cast<int>(Edge::Top); currentEdge < static_cast<int>(Edge::NEdges); ++currentEdge) {
169 const int previousEdge = (currentEdge + 3) % 4;
170 if (!visibleEdges[previousEdge] && visibleEdges[currentEdge]) {
171 startIndex = currentEdge;
172 break;
173 }
174 }
175
176 firstVisibleEdge = static_cast<Edge>(startIndex);
177 qCDebug(lcMaybeUpdateElements) << "firstVisibleEdge:" << startIndex; // (Can't print the enum itself)
178
179 for (int i = 0; i < 4; i++) {
180 const int currentEdge = (startIndex + i) % 4;
181 const int nextEdge = (startIndex + i + 1) % 4;
182
183 switch (static_cast<Edge>(currentEdge)) {
184 case Edge::Top:
185 if (visibleEdges[currentEdge]) {
186 topPathLine = createElement<QQuickPathLine>(shapePath, "topPathLine");
187 shapePathPrivate->appendPathElement(topPathLine, DontProcessPath);
188 topPathMove = nullptr;
189 } else {
190 topPathLine = nullptr;
191 topPathMove = createElement<QQuickPathMove>(shapePath, "topPathMove");
192 shapePathPrivate->appendPathElement(topPathMove, DontProcessPath);
193 }
194
195 // Top right corner
196 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
197 topRightPathArc = createElement<QQuickPathArc>(shapePath, "topRightPathArc");
198 shapePathPrivate->appendPathElement(topRightPathArc, DontProcessPath);
199 } else {
200 topRightPathArc = nullptr;
201 }
202 break;
203 case Edge::Right:
204 if (visibleEdges[currentEdge]) {
205 rightPathLine = createElement<QQuickPathLine>(shapePath, "rightPathLine");
206 shapePathPrivate->appendPathElement(rightPathLine, DontProcessPath);
207 rightPathMove = nullptr;
208 } else {
209 rightPathLine = nullptr;
210 rightPathMove = createElement<QQuickPathMove>(shapePath, "rightPathMove");
211 shapePathPrivate->appendPathElement(rightPathMove, DontProcessPath);
212 }
213
214 // Bottom right corner
215 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
216 bottomRightPathArc = createElement<QQuickPathArc>(shapePath, "bottomRightPathArc");
217 shapePathPrivate->appendPathElement(bottomRightPathArc, DontProcessPath);
218 } else {
219 bottomRightPathArc = nullptr;
220 }
221 break;
222 case Edge::Bottom:
223 if (visibleEdges[currentEdge]) {
224 bottomPathLine = createElement<QQuickPathLine>(shapePath, "bottomPathLine");
225 shapePathPrivate->appendPathElement(bottomPathLine, DontProcessPath);
226 bottomPathMove = nullptr;
227 } else {
228 bottomPathLine = nullptr;
229 bottomPathMove = createElement<QQuickPathMove>(shapePath, "bottomPathMove");
230 shapePathPrivate->appendPathElement(bottomPathMove, DontProcessPath);
231 }
232
233 // Bottom left corner
234 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
235 bottomLeftPathArc = createElement<QQuickPathArc>(shapePath, "bottomLeftPathArc");
236 shapePathPrivate->appendPathElement(bottomLeftPathArc, DontProcessPath);
237 } else {
238 bottomLeftPathArc = nullptr;
239 }
240 break;
241 case Edge::Left:
242 if (visibleEdges[currentEdge]) {
243 leftPathLine = createElement<QQuickPathLine>(shapePath, "leftPathLine");
244 shapePathPrivate->appendPathElement(leftPathLine, DontProcessPath);
245 } else {
246 leftPathLine = nullptr;
247 // There isn't a leftPathMove because it will only be applicable for the case where
248 // there is only a top and bottom edge (the only configuration where a
249 // left-path-move could be needed), and if that is the case, it must start with the
250 // top edge, and must end at the left edge, so there is never need to move the path
251 // at the last (left in this case) edge.
252 }
253
254 // Top left corner
255 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
256 topLeftPathArc = createElement<QQuickPathArc>(shapePath, "topLeftPathArc");
257 shapePathPrivate->appendPathElement(topLeftPathArc, DontProcessPath);
258 } else {
259 topLeftPathArc = nullptr;
260 }
261 break;
262 case Edge::NEdges:
263 Q_UNREACHABLE();
264 }
265 }
266
267 qCDebug(lcMaybeUpdateElements) << "about to process path";
268 shapePath->processPath();
269 qCDebug(lcMaybeUpdateElements) << "about to call _q_shapePathChanged (i.e. polish and update implicit size)";
270 _q_shapePathChanged();
271}
272
273void QQuickRectangleShapePrivate::calculateIndependentRadii()
274{
275 Q_Q(const QQuickRectangleShape);
276 const qreal rectWidth = width.valueBypassingBindings();
277 const qreal rectHeight = height.valueBypassingBindings();
278 const int minDimension = qMin(rectWidth, rectHeight);
279 const int maxRadius = minDimension / 2;
280 const int topLeftRadius = q->topLeftRadius();
281 const int topRightRadius = q->topRightRadius();
282 const int bottomRightRadius = q->bottomRightRadius();
283 const int bottomLeftRadius = q->bottomLeftRadius();
284 const bool mixed = !(radius == topLeftRadius
285 && radius == topRightRadius
286 && radius == bottomLeftRadius
287 && radius == bottomRightRadius);
288
289 // Uniform radii
290 if (!mixed) {
291 effectiveTopLeftRadius = qMin(topLeftRadius, maxRadius);
292 effectiveTopRightRadius = qMin(topRightRadius, maxRadius);
293 effectiveBottomRightRadius = qMin(bottomRightRadius, maxRadius);
294 effectiveBottomLeftRadius = qMin(bottomLeftRadius, maxRadius);
295 qCDebug(lcCalculateIndependentRadii) << "calculateIndependentRadii: using uniform radii of" << radius
296 << "width" << rectWidth
297 << "height" << rectHeight
298 << "minDimension" << minDimension
299 << "tlr" << topLeftRadius
300 << "etlr" << effectiveTopLeftRadius
301 << "trr" << topRightRadius
302 << "etrr" << effectiveTopRightRadius
303 << "blr" << bottomLeftRadius
304 << "eblr" << effectiveBottomLeftRadius
305 << "brr" << bottomRightRadius
306 << "ebrr" << effectiveBottomRightRadius;
307 return;
308 }
309
310 // Mixed radii
311 qreal topLeftRadiusMin = qMin(minDimension, topLeftRadius);
312 qreal topRightRadiusMin = qMin(minDimension, topRightRadius);
313 qreal bottomLeftRadiusMin = qMin(minDimension, bottomLeftRadius);
314 qreal bottomRightRadiusMin = qMin(minDimension, bottomRightRadius);
315
316 // Top radii
317 const qreal topRadii = topLeftRadius + topRightRadius;
318
319 if (topRadii > rectWidth) {
320 const qreal topLeftRadiusFactor = topLeftRadius / topRadii;
321 const qreal tlr = qRound(rectWidth * topLeftRadiusFactor);
322
323 topLeftRadiusMin = qMin(topLeftRadiusMin, tlr);
324 topRightRadiusMin = qMin(topRightRadiusMin, rectWidth - tlr);
325 }
326
327 // Right radii
328 const qreal rightRadii = topRightRadius + bottomRightRadius;
329
330 if (rightRadii > rectHeight) {
331 const qreal topRightRadiusFactor = topRightRadius / rightRadii;
332 const qreal trr = qRound(rectHeight * topRightRadiusFactor);
333
334 topRightRadiusMin = qMin(topRightRadiusMin, trr);
335 bottomRightRadiusMin = qMin(bottomRightRadiusMin, rectHeight - trr);
336 }
337
338 // Bottom radii
339 const qreal bottomRadii = bottomRightRadius + bottomLeftRadius;
340
341 if (bottomRadii > rectWidth) {
342 const qreal bottomRightRadiusFactor = bottomRightRadius / bottomRadii;
343 const qreal brr = qRound(rectWidth * bottomRightRadiusFactor);
344
345 bottomRightRadiusMin = qMin(bottomRightRadiusMin, brr);
346 bottomLeftRadiusMin = qMin(bottomLeftRadiusMin, rectWidth - brr);
347 }
348
349 // Left radii
350 const qreal leftRadii = bottomLeftRadius + topLeftRadius;
351
352 if (leftRadii > rectHeight) {
353 const qreal bottomLeftRadiusFactor = bottomLeftRadius / leftRadii;
354 const qreal blr = qRound(rectHeight * bottomLeftRadiusFactor);
355
356 bottomLeftRadiusMin = qMin(bottomLeftRadiusMin, blr);
357 topLeftRadiusMin = qMin(topLeftRadiusMin, rectHeight - blr);
358 }
359
360 effectiveTopLeftRadius = topLeftRadiusMin;
361 effectiveTopRightRadius = topRightRadiusMin;
362 effectiveBottomLeftRadius = bottomLeftRadiusMin;
363 effectiveBottomRightRadius = bottomRightRadiusMin;
364
365 qCDebug(lcCalculateIndependentRadii) << "calculateIndependentRadii:"
366 << "width" << rectWidth
367 << "height" << rectHeight
368 << "borderMode" << borderMode
369 << "strokeWidth" << shapePath->strokeWidth()
370 << "minDimension" << minDimension
371 << "tlr" << topLeftRadius
372 << "etlr" << effectiveTopLeftRadius
373 << "trr" << topRightRadius
374 << "etrr" << effectiveTopRightRadius
375 << "blr" << bottomLeftRadius
376 << "eblr" << effectiveBottomLeftRadius
377 << "brr" << bottomRightRadius
378 << "ebrr" << effectiveBottomRightRadius
379 << "borderOffset" << borderOffset
380 << "startX" << shapePath->startX()
381 << "startY" << shapePath->startY();
382}
383
384/*!
385 \qmltype RectangleShape
386 \inqmlmodule QtQuick.Shapes.DesignHelpers
387 \brief A filled rectangle with an optional border.
388 \since QtQuick 6.10
389
390 RectangleShape is used to fill areas with solid color or gradients and to
391 provide a rectangular border.
392
393 Each Rectangle item is painted using either a solid fill color, specified
394 using the \l fillColor property, or a gradient, defined using one of the \l
395 ShapeGradient subtypes and set using the \l gradient property. If both a
396 color and a gradient are specified, the gradient is used.
397
398 An optional border can be added to a rectangle with its own color and
399 thickness by setting the \l strokeColor and \l strokeWidth properties.
400 Setting the color to \c transparent creates a border without a fill color.
401
402 Rounded rectangles can be drawn using the \l radius property. The radius
403 can also be specified separately for each corner. Additionally, \l bevel
404 can be applied on any corner to cut it off sharply.
405
406 RectangleShape's default value for \l {QtQuick.Shapes::Shape::preferredRendererType} is
407 \c Shape.CurveRenderer.
408
409 \section1 Example Usage
410
411 \snippet rectangleshape-bevel.qml rectangleShape
412
413 \image pathrectangle-bevel.png
414*/
415
416QQuickRectangleShape::QQuickRectangleShape(QQuickItem *parent)
417 : QQuickShape(*(new QQuickRectangleShapePrivate), parent)
418{
419 Q_D(QQuickRectangleShape);
420
421 setWidth(200);
422 setHeight(150);
423 setPreferredRendererType(CurveRenderer);
424
425 // Create the ShapePath.
426 d->shapePath = new QQuickShapePath(this);
427 d->shapePath->setObjectName("rectangleShapeShapePath");
428 d->shapePath->setStrokeWidth(4);
429 d->shapePath->setStrokeColor(QColorConstants::Black);
430 d->shapePath->setFillColor(QColorConstants::Transparent);
431 d->shapePath->setJoinStyle(QQuickShapePath::BevelJoin);
432 // Don't make it asynchronous, as it results in brief periods of incorrect rendering.
433
434 connect(d->shapePath, &QQuickShapePath::strokeColorChanged, this, &QQuickRectangleShape::strokeColorChanged);
435 connect(d->shapePath, &QQuickShapePath::strokeWidthChanged, this, &QQuickRectangleShape::strokeWidthChanged);
436 connect(d->shapePath, &QQuickShapePath::fillColorChanged, this, &QQuickRectangleShape::fillColorChanged);
437 connect(d->shapePath, &QQuickShapePath::joinStyleChanged, this, &QQuickRectangleShape::joinStyleChanged);
438 connect(d->shapePath, &QQuickShapePath::capStyleChanged, this, &QQuickRectangleShape::capStyleChanged);
439 connect(d->shapePath, &QQuickShapePath::strokeStyleChanged, this, &QQuickRectangleShape::strokeStyleChanged);
440 connect(d->shapePath, &QQuickShapePath::dashOffsetChanged, this, &QQuickRectangleShape::dashOffsetChanged);
441 connect(d->shapePath, &QQuickShapePath::dashPatternChanged, this, &QQuickRectangleShape::dashPatternChanged);
442 // QQuickShapePath has no change signal for fillGradient.
443
444 // Add the path as a child of us.
445 // The individual path elements will be added to the shape path in maybeUpdateElements().
446 // Do what vpe_append in qquickshape.cpp does except without the overhead of the QQmlListProperty stuff.
447 d->sp.append(d->shapePath);
448 // Similar, but for QQuickItemPrivate::data_append...
449 d->shapePath->setParent(this);
450 // ... which calls QQuickItemPrivate::resources_append.
451 d->extra.value().resourcesList.append(d->shapePath);
452
453 // QQuickShape::componentComplete sets up the connections to each path.
454 // It also calls _q_shapePathChanged, which will call polish (for our updatePolish).
455}
456
457QQuickRectangleShape::~QQuickRectangleShape()
458{
459}
460
461/*!
462 \since 6.11
463
464 This property holds whether the top border is drawn.
465
466 The default value is \c true.
467*/
468bool QQuickRectangleShape::drawTop() const
469{
470 Q_D(const QQuickRectangleShape);
471 return d->drawTop;
472}
473
474void QQuickRectangleShape::setDrawTop(bool drawTop)
475{
476 Q_D(QQuickRectangleShape);
477 if (drawTop == d->drawTop)
478 return;
479
480 d->drawTop = drawTop;
481 d->maybeUpdateElements();
482 emit drawTopChanged();
483}
484
485void QQuickRectangleShape::resetDrawTop()
486{
487 setDrawTop(QQuickRectangleShapePrivate::defaultDrawEdge);
488}
489
490/*!
491 \since 6.11
492
493 This property holds whether the right border is drawn.
494
495 The default value is \c true.
496*/
497bool QQuickRectangleShape::drawRight() const
498{
499 Q_D(const QQuickRectangleShape);
500 return d->drawRight;
501}
502
503void QQuickRectangleShape::setDrawRight(bool drawRight)
504{
505 Q_D(QQuickRectangleShape);
506 if (drawRight == d->drawRight)
507 return;
508
509 d->drawRight = drawRight;
510 d->maybeUpdateElements();
511 emit drawRightChanged();
512}
513
514void QQuickRectangleShape::resetDrawRight()
515{
516 setDrawRight(QQuickRectangleShapePrivate::defaultDrawEdge);
517}
518
519/*!
520 \since 6.11
521
522 This property holds whether the bottom border is drawn.
523
524 The default value is \c true.
525*/
526bool QQuickRectangleShape::drawBottom() const
527{
528 Q_D(const QQuickRectangleShape);
529 return d->drawBottom;
530}
531
532void QQuickRectangleShape::setDrawBottom(bool drawBottom)
533{
534 Q_D(QQuickRectangleShape);
535 if (drawBottom == d->drawBottom)
536 return;
537
538 d->drawBottom = drawBottom;
539 d->maybeUpdateElements();
540 emit drawBottomChanged();
541}
542
543void QQuickRectangleShape::resetDrawBottom()
544{
545 setDrawBottom(QQuickRectangleShapePrivate::defaultDrawEdge);
546}
547
548/*!
549 \since 6.11
550
551 This property holds whether the left border is drawn.
552
553 The default value is \c true.
554*/
555bool QQuickRectangleShape::drawLeft() const
556{
557 Q_D(const QQuickRectangleShape);
558 return d->drawLeft;
559}
560
561void QQuickRectangleShape::setDrawLeft(bool drawLeft)
562{
563 Q_D(QQuickRectangleShape);
564 if (drawLeft == d->drawLeft)
565 return;
566
567 d->drawLeft = drawLeft;
568 d->maybeUpdateElements();
569 emit drawLeftChanged();
570}
571
572void QQuickRectangleShape::resetDrawLeft()
573{
574 setDrawLeft(QQuickRectangleShapePrivate::defaultDrawEdge);
575}
576
577/*!
578 \include pathrectangle.qdocinc {radius-property}
579 {QtQuick.Shapes.DesignHelpers::RectangleShape}
580
581 The default value is \c 10.
582*/
583
584int QQuickRectangleShape::radius() const
585{
586 Q_D(const QQuickRectangleShape);
587 return d->radius;
588}
589
590void QQuickRectangleShape::setRadius(int radius)
591{
592 Q_D(QQuickRectangleShape);
593 if (radius == d->radius)
594 return;
595
596 const int oldTopLeftRadius = topLeftRadius();
597 const int oldTopRightRadius = topRightRadius();
598 const int oldBottomRightRadius = bottomRightRadius();
599 const int oldBottomLeftRadius = bottomLeftRadius();
600
601 d->radius = radius;
602 polish();
603 emit radiusChanged();
604 if (topLeftRadius() != oldTopLeftRadius)
605 emit topLeftRadiusChanged();
606 if (topRightRadius() != oldTopRightRadius)
607 emit topRightRadiusChanged();
608 if (bottomRightRadius() != oldBottomRightRadius)
609 emit bottomRightRadiusChanged();
610 if (bottomLeftRadius() != oldBottomLeftRadius)
611 emit bottomLeftRadiusChanged();
612}
613
614void QQuickRectangleShape::resetRadius()
615{
616 setRadius(QQuickRectangleShapePrivate::defaultRadius);
617}
618
619/*!
620 \include pathrectangle.qdocinc {radius-properties}
621 {QtQuick.Shapes.DesignHelpers::RectangleShape} {rectangleshape.qml} {rectangleShape}
622*/
623
624int QQuickRectangleShape::topLeftRadius() const
625{
626 Q_D(const QQuickRectangleShape);
627 return d->explicitTopLeftRadius ? d->topLeftRadius : d->radius;
628}
629
630void QQuickRectangleShape::setTopLeftRadius(int topLeftRadius)
631{
632 Q_D(QQuickRectangleShape);
633 d->setTopLeftRadius(topLeftRadius, QQml::PropertyUtils::State::ExplicitlySet);
634}
635
636void QQuickRectangleShape::resetTopLeftRadius()
637{
638 Q_D(QQuickRectangleShape);
639 d->setTopLeftRadius(QQuickRectangleShapePrivate::defaultRadius,
640 QQml::PropertyUtils::State::ImplicitlySet);
641}
642
643int QQuickRectangleShape::topRightRadius() const
644{
645 Q_D(const QQuickRectangleShape);
646 return d->explicitTopRightRadius ? d->topRightRadius : d->radius;
647}
648
649void QQuickRectangleShape::setTopRightRadius(int topRightRadius)
650{
651 Q_D(QQuickRectangleShape);
652 d->setTopRightRadius(topRightRadius, QQml::PropertyUtils::State::ExplicitlySet);
653}
654
655void QQuickRectangleShape::resetTopRightRadius()
656{
657 Q_D(QQuickRectangleShape);
658 d->setTopRightRadius(QQuickRectangleShapePrivate::defaultRadius,
659 QQml::PropertyUtils::State::ImplicitlySet);
660}
661
662int QQuickRectangleShape::bottomLeftRadius() const
663{
664 Q_D(const QQuickRectangleShape);
665 return d->explicitBottomLeftRadius ? d->bottomLeftRadius : d->radius;
666}
667
668void QQuickRectangleShape::setBottomLeftRadius(int bottomLeftRadius)
669{
670 Q_D(QQuickRectangleShape);
671 d->setBottomLeftRadius(bottomLeftRadius, QQml::PropertyUtils::State::ExplicitlySet);
672}
673
674void QQuickRectangleShape::resetBottomLeftRadius()
675{
676 Q_D(QQuickRectangleShape);
677 d->setBottomLeftRadius(QQuickRectangleShapePrivate::defaultRadius,
678 QQml::PropertyUtils::State::ImplicitlySet);
679}
680
681int QQuickRectangleShape::bottomRightRadius() const
682{
683 Q_D(const QQuickRectangleShape);
684 return d->explicitBottomRightRadius ? d->bottomRightRadius : d->radius;
685}
686
687void QQuickRectangleShape::setBottomRightRadius(int bottomRightRadius)
688{
689 Q_D(QQuickRectangleShape);
690 d->setBottomRightRadius(bottomRightRadius, QQml::PropertyUtils::State::ExplicitlySet);
691}
692
693void QQuickRectangleShape::resetBottomRightRadius()
694{
695 Q_D(QQuickRectangleShape);
696 d->setBottomRightRadius(QQuickRectangleShapePrivate::defaultRadius,
697 QQml::PropertyUtils::State::ImplicitlySet);
698}
699
700/*!
701 \include pathrectangle.qdocinc {bevel-property}
702 {QtQuick.Shapes.DesignHelpers::RectangleShape}
703 {rectangleshape-bevel.qml}{rectangleShape}
704*/
705
706bool QQuickRectangleShape::hasBevel() const
707{
708 Q_D(const QQuickRectangleShape);
709 return d->bevel;
710}
711
712void QQuickRectangleShape::setBevel(bool bevel)
713{
714 Q_D(QQuickRectangleShape);
715 if (bevel == d->bevel)
716 return;
717
718 const bool oldTopLeftBevel = hasTopLeftBevel();
719 const bool oldTopRightBevel = hasTopRightBevel();
720 const bool oldBottomRightBevel = hasBottomRightBevel();
721 const bool oldBottomLeftBevel = hasBottomLeftBevel();
722
723 d->bevel = bevel;
724 polish();
725 emit bevelChanged();
726 if (hasTopLeftBevel() != oldTopLeftBevel)
727 emit topLeftBevelChanged();
728 if (hasTopRightBevel() != oldTopRightBevel)
729 emit topRightBevelChanged();
730 if (hasBottomRightBevel() != oldBottomRightBevel)
731 emit bottomRightBevelChanged();
732 if (hasBottomLeftBevel() != oldBottomLeftBevel)
733 emit bottomLeftBevelChanged();
734}
735
736void QQuickRectangleShape::resetBevel()
737{
738 setBevel(false);
739}
740
741/*!
742 \include pathrectangle.qdocinc {bevel-properties}
743 {QtQuick.Shapes.DesignHelpers::RectangleShape}
744 {rectangleshape.qml} {rectangleShape}
745*/
746
747bool QQuickRectangleShape::hasTopLeftBevel() const
748{
749 Q_D(const QQuickRectangleShape);
750 return d->explicitTopLeftBevel ? d->topLeftBevel : d->bevel;
751}
752
753void QQuickRectangleShape::setTopLeftBevel(bool topLeftBevel)
754{
755 Q_D(QQuickRectangleShape);
756 d->setTopLeftBevel(topLeftBevel, QQml::PropertyUtils::State::ExplicitlySet);
757}
758
759void QQuickRectangleShape::resetTopLeftBevel()
760{
761 Q_D(QQuickRectangleShape);
762 d->setTopLeftBevel(QQuickRectangleShapePrivate::defaultBevel,
763 QQml::PropertyUtils::State::ImplicitlySet);
764}
765
766bool QQuickRectangleShape::hasTopRightBevel() const
767{
768 Q_D(const QQuickRectangleShape);
769 return d->explicitTopRightBevel ? d->topRightBevel : d->bevel;
770}
771
772void QQuickRectangleShape::setTopRightBevel(bool topRightBevel)
773{
774 Q_D(QQuickRectangleShape);
775 d->setTopRightBevel(topRightBevel, QQml::PropertyUtils::State::ExplicitlySet);
776}
777
778void QQuickRectangleShape::resetTopRightBevel()
779{
780 Q_D(QQuickRectangleShape);
781 d->setTopRightBevel(QQuickRectangleShapePrivate::defaultBevel,
782 QQml::PropertyUtils::State::ImplicitlySet);
783}
784
785bool QQuickRectangleShape::hasBottomLeftBevel() const
786{
787 Q_D(const QQuickRectangleShape);
788 return d->explicitBottomLeftBevel ? d->bottomLeftBevel : d->bevel;
789}
790
791void QQuickRectangleShape::setBottomLeftBevel(bool bottomLeftBevel)
792{
793 Q_D(QQuickRectangleShape);
794 d->setBottomLeftBevel(bottomLeftBevel, QQml::PropertyUtils::State::ExplicitlySet);
795}
796
797void QQuickRectangleShape::resetBottomLeftBevel()
798{
799 Q_D(QQuickRectangleShape);
800 d->setBottomLeftBevel(QQuickRectangleShapePrivate::defaultBevel,
801 QQml::PropertyUtils::State::ImplicitlySet);
802}
803
804bool QQuickRectangleShape::hasBottomRightBevel() const
805{
806 Q_D(const QQuickRectangleShape);
807 return d->explicitBottomRightBevel ? d->bottomRightBevel : d->bevel;
808}
809
810void QQuickRectangleShape::setBottomRightBevel(bool bottomRightBevel)
811{
812 Q_D(QQuickRectangleShape);
813 d->setBottomRightBevel(bottomRightBevel, QQml::PropertyUtils::State::ExplicitlySet);
814}
815
816void QQuickRectangleShape::resetBottomRightBevel()
817{
818 Q_D(QQuickRectangleShape);
819 d->setBottomRightBevel(QQuickRectangleShapePrivate::defaultBevel,
820 QQml::PropertyUtils::State::ImplicitlySet);
821}
822
823/*!
824 \qmlproperty color QtQuick.Shapes.DesignHelpers::RectangleShape::strokeColor
825
826 This property holds the stroking color.
827
828 When set to \c transparent, no stroking occurs.
829
830 The default value is \c "black".
831*/
832
833QColor QQuickRectangleShape::strokeColor() const
834{
835 Q_D(const QQuickRectangleShape);
836 return d->shapePath->strokeColor();
837}
838
839void QQuickRectangleShape::setStrokeColor(const QColor &color)
840{
841 Q_D(QQuickRectangleShape);
842 d->shapePath->setStrokeColor(color);
843}
844
845/*!
846 \qmlproperty real QtQuick.Shapes.DesignHelpers::RectangleShape::strokeWidth
847
848 This property holds the stroke width.
849
850 When set to a negative value, no stroking occurs.
851
852 The default value is \c 1.
853*/
854
855qreal QQuickRectangleShape::strokeWidth() const
856{
857 Q_D(const QQuickRectangleShape);
858 return d->shapePath->strokeWidth();
859}
860
861void QQuickRectangleShape::setStrokeWidth(qreal width)
862{
863 Q_D(QQuickRectangleShape);
864 d->shapePath->setStrokeWidth(width);
865}
866
867/*!
868 \qmlproperty color QtQuick.Shapes.DesignHelpers::RectangleShape::fillColor
869
870 This property holds the fill color.
871
872 When set to \c transparent, no filling occurs.
873
874 The default value is \c "white".
875
876 \note If either \l fillGradient is set to something other than \c null, it
877 will be used instead of \c fillColor.
878*/
879
880QColor QQuickRectangleShape::fillColor() const
881{
882 Q_D(const QQuickRectangleShape);
883 return d->shapePath->fillColor();
884}
885
886void QQuickRectangleShape::setFillColor(const QColor &color)
887{
888 Q_D(QQuickRectangleShape);
889 d->shapePath->setFillColor(color);
890}
891
892/*!
893 \include shapepath.qdocinc {fillRule-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
894*/
895
896QQuickShapePath::FillRule QQuickRectangleShape::fillRule() const
897{
898 Q_D(const QQuickRectangleShape);
899 return d->shapePath->fillRule();
900}
901
902void QQuickRectangleShape::setFillRule(QQuickShapePath::FillRule fillRule)
903{
904 Q_D(QQuickRectangleShape);
905 d->shapePath->setFillRule(fillRule);
906}
907
908/*!
909 \include shapepath.qdocinc {joinStyle-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
910*/
911
912QQuickShapePath::JoinStyle QQuickRectangleShape::joinStyle() const
913{
914 Q_D(const QQuickRectangleShape);
915 return d->shapePath->joinStyle();
916}
917
918void QQuickRectangleShape::setJoinStyle(QQuickShapePath::JoinStyle style)
919{
920 Q_D(QQuickRectangleShape);
921 d->shapePath->setJoinStyle(style);
922}
923
924int QQuickRectangleShape::miterLimit() const
925{
926 Q_D(const QQuickRectangleShape);
927 return d->shapePath->miterLimit();
928}
929
930void QQuickRectangleShape::setMiterLimit(int limit)
931{
932 Q_D(QQuickRectangleShape);
933 d->shapePath->setMiterLimit(limit);
934}
935
936/*!
937 \include shapepath.qdocinc {capStyle-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
938*/
939
940QQuickShapePath::CapStyle QQuickRectangleShape::capStyle() const
941{
942 Q_D(const QQuickRectangleShape);
943 return d->shapePath->capStyle();
944}
945
946void QQuickRectangleShape::setCapStyle(QQuickShapePath::CapStyle style)
947{
948 Q_D(QQuickRectangleShape);
949 d->shapePath->setCapStyle(style);
950}
951
952/*!
953 \include shapepath.qdocinc {strokeStyle-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
954*/
955
956QQuickShapePath::StrokeStyle QQuickRectangleShape::strokeStyle() const
957{
958 Q_D(const QQuickRectangleShape);
959 return d->shapePath->strokeStyle();
960}
961
962void QQuickRectangleShape::setStrokeStyle(QQuickShapePath::StrokeStyle style)
963{
964 Q_D(QQuickRectangleShape);
965 d->shapePath->setStrokeStyle(style);
966}
967
968/*!
969 \include shapepath.qdocinc {dashOffset-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
970*/
971
972qreal QQuickRectangleShape::dashOffset() const
973{
974 Q_D(const QQuickRectangleShape);
975 return d->shapePath->dashOffset();
976}
977
978void QQuickRectangleShape::setDashOffset(qreal offset)
979{
980 Q_D(QQuickRectangleShape);
981 d->shapePath->setDashOffset(offset);
982}
983
984/*!
985 \include shapepath.qdocinc {dashPattern-property} {QtQuick.Shapes.DesignHelpers::RectangleShape}
986*/
987
988QVector<qreal> QQuickRectangleShape::dashPattern() const
989{
990 Q_D(const QQuickRectangleShape);
991 return d->shapePath->dashPattern();
992}
993
994void QQuickRectangleShape::setDashPattern(const QVector<qreal> &array)
995{
996 Q_D(QQuickRectangleShape);
997 d->shapePath->setDashPattern(array);
998}
999
1000/*!
1001 \qmlproperty ShapeGradient QtQuick.Shapes.DesignHelpers::RectangleShape::fillGradient
1002
1003 The fillGradient of the rectangle fill color.
1004
1005 By default, no fillGradient is enabled and the value is null. In this case, the
1006 fill uses a solid color based on the value of \l fillColor.
1007
1008 When set, \l fillColor is ignored and filling is done using one of the
1009 \l ShapeGradient subtypes.
1010
1011 \note The \l Gradient type cannot be used here. Rather, prefer using one of
1012 the advanced subtypes, like \l LinearGradient.
1013*/
1014QQuickShapeGradient *QQuickRectangleShape::fillGradient() const
1015{
1016 Q_D(const QQuickRectangleShape);
1017 return d->shapePath->fillGradient();
1018}
1019
1020void QQuickRectangleShape::setFillGradient(QQuickShapeGradient *fillGradient)
1021{
1022 Q_D(QQuickRectangleShape);
1023 d->shapePath->setFillGradient(fillGradient);
1024}
1025
1026void QQuickRectangleShape::resetFillGradient()
1027{
1028 setFillGradient(nullptr);
1029}
1030
1031/*!
1032 \qmlproperty enumeration QtQuick.Shapes.DesignHelpers::RectangleShape::borderMode
1033
1034 The \l borderMode property determines where the border is drawn along the
1035 edge of the rectangle.
1036
1037 \value RectangleShape.Inside
1038 The border is drawn along the inside edge of the item and does not
1039 affect the item width.
1040
1041 This is the default value.
1042 \value RectangleShape.Middle
1043 The border is drawn over the edge of the item and does not
1044 affect the item width.
1045 \value RectangleShape.Outside
1046 The border is drawn along the outside edge of the item and increases
1047 the item width by the value of \l strokeWidth.
1048
1049 \sa strokeWidth
1050*/
1051QQuickRectangleShape::BorderMode QQuickRectangleShape::borderMode() const
1052{
1053 Q_D(const QQuickRectangleShape);
1054 return d->borderMode;
1055}
1056
1057void QQuickRectangleShape::setBorderMode(BorderMode borderMode)
1058{
1059 Q_D(QQuickRectangleShape);
1060 if (borderMode == d->borderMode)
1061 return;
1062
1063 d->borderMode = borderMode;
1064 polish();
1065 emit borderModeChanged();
1066}
1067
1068void QQuickRectangleShape::resetBorderMode()
1069{
1070 setBorderMode(BorderMode::Inside);
1071}
1072
1073void QQuickRectangleShape::componentComplete()
1074{
1075 Q_D(QQuickRectangleShape);
1076 d->componentComplete = true;
1077 // Do this before componentComplete(), because we need the elements to be
1078 // present in order for the connections to them to be made.
1079 d->maybeUpdateElements();
1080 QQuickShape::componentComplete();
1081}
1082
1083void QQuickRectangleShape::updatePolish()
1084{
1085 Q_D(QQuickRectangleShape);
1086 const qreal rectWidth = d->width.valueBypassingBindings();
1087 const qreal rectHeight = d->height.valueBypassingBindings();
1088
1089 d->calculateIndependentRadii();
1090
1091 switch (d->borderMode) {
1092 case QQuickRectangleShape::BorderMode::Inside:
1093 d->borderOffset = d->shapePath->strokeWidth() * 0.5;
1094 break;
1095 case QQuickRectangleShape::BorderMode::Middle:
1096 d->borderOffset = 0;
1097 break;
1098 case QQuickRectangleShape::BorderMode::Outside:
1099 d->borderOffset = -d->shapePath->strokeWidth() * 0.5;
1100 break;
1101 }
1102
1103 switch (d->borderMode) {
1104 case QQuickRectangleShape::BorderMode::Outside:
1105 d->borderRadiusAdjustment = d->shapePath->strokeWidth() * 0.5;
1106 break;
1107 case QQuickRectangleShape::BorderMode::Middle:
1108 d->borderRadiusAdjustment = d->shapePath->strokeWidth();
1109 break;
1110 default:
1111 d->borderRadiusAdjustment = 0;
1112 break;
1113 }
1114
1115 switch (d->firstVisibleEdge) {
1116 case QQuickRectangleShapePrivate::Edge::Top:
1117 d->shapePath->setStartX(d->effectiveTopLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
1118 d->shapePath->setStartY(d->borderOffset);
1119 break;
1120 case QQuickRectangleShapePrivate::Edge::Right:
1121 d->shapePath->setStartX(rectWidth - d->borderOffset);
1122 d->shapePath->setStartY(d->effectiveTopRightRadius + d->borderOffset + d->borderRadiusAdjustment);
1123 break;
1124 case QQuickRectangleShapePrivate::Edge::Bottom:
1125 d->shapePath->setStartX(rectWidth - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1126 d->shapePath->setStartY(rectHeight - d->borderOffset);
1127 break;
1128 case QQuickRectangleShapePrivate::Edge::Left:
1129 d->shapePath->setStartX(d->borderOffset);
1130 d->shapePath->setStartY(rectHeight - d->effectiveBottomLeftRadius - d->borderOffset - d->borderRadiusAdjustment);
1131 break;
1132 default:
1133 Q_UNREACHABLE();
1134 }
1135
1136 if (d->topPathLine) {
1137 d->topPathLine->setX(rectWidth - d->effectiveTopRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1138 d->topPathLine->setY(d->borderOffset);
1139 } else {
1140 d->topPathMove->setX(rectWidth - d->borderOffset);
1141 d->topPathMove->setY(d->effectiveTopRightRadius + d->borderOffset + d->borderRadiusAdjustment);
1142 }
1143
1144 if (d->topRightPathArc) {
1145 d->topRightPathArc->setX(rectWidth - d->borderOffset);
1146 d->topRightPathArc->setY(d->effectiveTopRightRadius + d->borderOffset + d->borderRadiusAdjustment);
1147 d->topRightPathArc->setRadiusX(d->topRightBevel ? 50000 : d->effectiveTopRightRadius + d->borderRadiusAdjustment);
1148 d->topRightPathArc->setRadiusY(d->topRightBevel ? 50000 : d->effectiveTopRightRadius + d->borderRadiusAdjustment);
1149 }
1150
1151 if (d->rightPathLine) {
1152 d->rightPathLine->setX(rectWidth - d->borderOffset);
1153 d->rightPathLine->setY(rectHeight - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1154 } else {
1155 d->rightPathMove->setX(rectWidth - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1156 d->rightPathMove->setY(rectHeight - d->borderOffset);
1157 }
1158
1159 if (d->bottomRightPathArc) {
1160 d->bottomRightPathArc->setX(rectWidth - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1161 d->bottomRightPathArc->setY(rectHeight - d->borderOffset);
1162 d->bottomRightPathArc->setRadiusX(d->bottomRightBevel ? 50000 : d->effectiveBottomRightRadius + d->borderRadiusAdjustment);
1163 d->bottomRightPathArc->setRadiusY(d->bottomRightBevel ? 50000 : d->effectiveBottomRightRadius + d->borderRadiusAdjustment);
1164 }
1165
1166 if (d->bottomPathLine) {
1167 d->bottomPathLine->setX(d->effectiveBottomLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
1168 d->bottomPathLine->setY(rectHeight - d->borderOffset);
1169 } else {
1170 d->bottomPathMove->setX(d->borderOffset);
1171 d->bottomPathMove->setY(rectHeight - d->effectiveBottomLeftRadius - d->borderOffset - d->borderRadiusAdjustment);
1172 }
1173
1174 if (d->bottomLeftPathArc) {
1175 d->bottomLeftPathArc->setX(d->borderOffset);
1176 d->bottomLeftPathArc->setY(rectHeight - d->effectiveBottomLeftRadius - d->borderOffset - d->borderRadiusAdjustment);
1177 d->bottomLeftPathArc->setRadiusX(d->bottomLeftBevel ? 50000 : d->effectiveBottomLeftRadius + d->borderRadiusAdjustment);
1178 d->bottomLeftPathArc->setRadiusY(d->bottomLeftBevel ? 50000 : d->effectiveBottomLeftRadius + d->borderRadiusAdjustment);
1179 }
1180
1181 if (d->leftPathLine) {
1182 d->leftPathLine->setX(d->borderOffset);
1183 d->leftPathLine->setY(d->effectiveTopLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
1184 }
1185
1186 if (d->topLeftPathArc) {
1187 d->topLeftPathArc->setX(d->effectiveTopLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
1188 d->topLeftPathArc->setY(d->borderOffset);
1189 d->topLeftPathArc->setRadiusX(d->topLeftBevel ? 50000 : d->effectiveTopLeftRadius + d->borderRadiusAdjustment);
1190 d->topLeftPathArc->setRadiusY(d->topLeftBevel ? 50000 : d->effectiveTopLeftRadius + d->borderRadiusAdjustment);
1191 }
1192
1193 // This does stuff with each path, so we want to call it after we've made our own changes.
1194 QQuickShape::updatePolish();
1195
1196 qCDebug(lcUpdatePolish) << "updatePolish:"
1197 << "width" << rectWidth
1198 << "height" << rectHeight
1199 << "borderMode" << d->borderMode
1200 << "strokeWidth" << d->shapePath->strokeWidth()
1201 << "etlr" << d->effectiveTopLeftRadius
1202 << "etrr" << d->effectiveTopRightRadius
1203 << "eblr" << d->effectiveBottomLeftRadius
1204 << "ebrr" << d->effectiveBottomRightRadius
1205 << "borderOffset" << d->borderOffset
1206 << "startX" << d->shapePath->startX()
1207 << "startY" << d->shapePath->startY();
1208}
1209
1210QT_END_NAMESPACE
1211
1212#include "moc_qquickrectangleshape_p.cpp"
T * createElement(QQuickShapePath *shapePath, const char *objectName)