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