146void QQuickRectangleShapePrivate::maybeUpdateElements()
148 if (!componentComplete)
151 auto *shapePathPrivate = QQuickShapePathPrivate::get(shapePath);
154 qCDebug(lcMaybeUpdateElements).nospace() <<
"maybeUpdateElements called on "
156 <<
static_cast<
void *>(q_func()) <<
"; deleting and clearing path elements";
157 shapePathPrivate->clearPathElements(QQuickPathPrivate::DeleteElementPolicy::Delete);
159 static const QQuickPathPrivate::ProcessPathPolicy DontProcessPath
160 = QQuickPathPrivate::ProcessPathPolicy::DontProcess;
166 const std::array visibleEdges = {drawTop, drawRight, drawBottom, drawLeft };
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;
176 firstVisibleEdge =
static_cast<Edge>(startIndex);
177 qCDebug(lcMaybeUpdateElements) <<
"firstVisibleEdge:" << startIndex;
179 for (
int i = 0; i < 4; i++) {
180 const int currentEdge = (startIndex + i) % 4;
181 const int nextEdge = (startIndex + i + 1) % 4;
183 switch (
static_cast<Edge>(currentEdge)) {
185 if (visibleEdges[currentEdge]) {
186 topPathLine = createElement<QQuickPathLine>(shapePath,
"topPathLine");
187 shapePathPrivate->appendPathElement(topPathLine, DontProcessPath);
188 topPathMove =
nullptr;
190 topPathLine =
nullptr;
191 topPathMove = createElement<QQuickPathMove>(shapePath,
"topPathMove");
192 shapePathPrivate->appendPathElement(topPathMove, DontProcessPath);
196 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
197 topRightPathArc = createElement<QQuickPathArc>(shapePath,
"topRightPathArc");
198 shapePathPrivate->appendPathElement(topRightPathArc, DontProcessPath);
200 topRightPathArc =
nullptr;
204 if (visibleEdges[currentEdge]) {
205 rightPathLine = createElement<QQuickPathLine>(shapePath,
"rightPathLine");
206 shapePathPrivate->appendPathElement(rightPathLine, DontProcessPath);
207 rightPathMove =
nullptr;
209 rightPathLine =
nullptr;
210 rightPathMove = createElement<QQuickPathMove>(shapePath,
"rightPathMove");
211 shapePathPrivate->appendPathElement(rightPathMove, DontProcessPath);
215 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
216 bottomRightPathArc = createElement<QQuickPathArc>(shapePath,
"bottomRightPathArc");
217 shapePathPrivate->appendPathElement(bottomRightPathArc, DontProcessPath);
219 bottomRightPathArc =
nullptr;
223 if (visibleEdges[currentEdge]) {
224 bottomPathLine = createElement<QQuickPathLine>(shapePath,
"bottomPathLine");
225 shapePathPrivate->appendPathElement(bottomPathLine, DontProcessPath);
226 bottomPathMove =
nullptr;
228 bottomPathLine =
nullptr;
229 bottomPathMove = createElement<QQuickPathMove>(shapePath,
"bottomPathMove");
230 shapePathPrivate->appendPathElement(bottomPathMove, DontProcessPath);
234 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
235 bottomLeftPathArc = createElement<QQuickPathArc>(shapePath,
"bottomLeftPathArc");
236 shapePathPrivate->appendPathElement(bottomLeftPathArc, DontProcessPath);
238 bottomLeftPathArc =
nullptr;
242 if (visibleEdges[currentEdge]) {
243 leftPathLine = createElement<QQuickPathLine>(shapePath,
"leftPathLine");
244 shapePathPrivate->appendPathElement(leftPathLine, DontProcessPath);
246 leftPathLine =
nullptr;
255 if (visibleEdges[currentEdge] && visibleEdges[nextEdge]) {
256 topLeftPathArc = createElement<QQuickPathArc>(shapePath,
"topLeftPathArc");
257 shapePathPrivate->appendPathElement(topLeftPathArc, DontProcessPath);
259 topLeftPathArc =
nullptr;
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();
273void QQuickRectangleShapePrivate::calculateIndependentRadii()
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);
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;
311 qreal topLeftRadiusMin = qMin(minDimension, topLeftRadius);
312 qreal topRightRadiusMin = qMin(minDimension, topRightRadius);
313 qreal bottomLeftRadiusMin = qMin(minDimension, bottomLeftRadius);
314 qreal bottomRightRadiusMin = qMin(minDimension, bottomRightRadius);
317 const qreal topRadii = topLeftRadius + topRightRadius;
319 if (topRadii > rectWidth) {
320 const qreal topLeftRadiusFactor = topLeftRadius / topRadii;
321 const qreal tlr = qRound(rectWidth * topLeftRadiusFactor);
323 topLeftRadiusMin = qMin(topLeftRadiusMin, tlr);
324 topRightRadiusMin = qMin(topRightRadiusMin, rectWidth - tlr);
328 const qreal rightRadii = topRightRadius + bottomRightRadius;
330 if (rightRadii > rectHeight) {
331 const qreal topRightRadiusFactor = topRightRadius / rightRadii;
332 const qreal trr = qRound(rectHeight * topRightRadiusFactor);
334 topRightRadiusMin = qMin(topRightRadiusMin, trr);
335 bottomRightRadiusMin = qMin(bottomRightRadiusMin, rectHeight - trr);
339 const qreal bottomRadii = bottomRightRadius + bottomLeftRadius;
341 if (bottomRadii > rectWidth) {
342 const qreal bottomRightRadiusFactor = bottomRightRadius / bottomRadii;
343 const qreal brr = qRound(rectWidth * bottomRightRadiusFactor);
345 bottomRightRadiusMin = qMin(bottomRightRadiusMin, brr);
346 bottomLeftRadiusMin = qMin(bottomLeftRadiusMin, rectWidth - brr);
350 const qreal leftRadii = bottomLeftRadius + topLeftRadius;
352 if (leftRadii > rectHeight) {
353 const qreal bottomLeftRadiusFactor = bottomLeftRadius / leftRadii;
354 const qreal blr = qRound(rectHeight * bottomLeftRadiusFactor);
356 bottomLeftRadiusMin = qMin(bottomLeftRadiusMin, blr);
357 topLeftRadiusMin = qMin(topLeftRadiusMin, rectHeight - blr);
360 effectiveTopLeftRadius = topLeftRadiusMin;
361 effectiveTopRightRadius = topRightRadiusMin;
362 effectiveBottomLeftRadius = bottomLeftRadiusMin;
363 effectiveBottomRightRadius = bottomRightRadiusMin;
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();
416QQuickRectangleShape::QQuickRectangleShape(QQuickItem *parent)
417 : QQuickShape(*(
new QQuickRectangleShapePrivate), parent)
419 Q_D(QQuickRectangleShape);
423 setPreferredRendererType(CurveRenderer);
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);
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);
447 d->sp.append(d->shapePath);
449 d->shapePath->setParent(
this);
451 d->extra.value().resourcesList.append(d->shapePath);
590void QQuickRectangleShape::setRadius(
int radius)
592 Q_D(QQuickRectangleShape);
593 if (radius == d->radius)
596 const int oldTopLeftRadius = topLeftRadius();
597 const int oldTopRightRadius = topRightRadius();
598 const int oldBottomRightRadius = bottomRightRadius();
599 const int oldBottomLeftRadius = bottomLeftRadius();
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();
712void QQuickRectangleShape::setBevel(
bool bevel)
714 Q_D(QQuickRectangleShape);
715 if (bevel == d->bevel)
718 const bool oldTopLeftBevel = hasTopLeftBevel();
719 const bool oldTopRightBevel = hasTopRightBevel();
720 const bool oldBottomRightBevel = hasBottomRightBevel();
721 const bool oldBottomLeftBevel = hasBottomLeftBevel();
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();
1083void QQuickRectangleShape::updatePolish()
1085 Q_D(QQuickRectangleShape);
1086 const qreal rectWidth = d->width.valueBypassingBindings();
1087 const qreal rectHeight = d->height.valueBypassingBindings();
1089 d->calculateIndependentRadii();
1091 switch (d->borderMode) {
1092 case QQuickRectangleShape::BorderMode::Inside:
1093 d->borderOffset = d->shapePath->strokeWidth() * 0.5;
1095 case QQuickRectangleShape::BorderMode::Middle:
1096 d->borderOffset = 0;
1098 case QQuickRectangleShape::BorderMode::Outside:
1099 d->borderOffset = -d->shapePath->strokeWidth() * 0.5;
1103 switch (d->borderMode) {
1104 case QQuickRectangleShape::BorderMode::Outside:
1105 d->borderRadiusAdjustment = d->shapePath->strokeWidth() * 0.5;
1107 case QQuickRectangleShape::BorderMode::Middle:
1108 d->borderRadiusAdjustment = d->shapePath->strokeWidth();
1111 d->borderRadiusAdjustment = 0;
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);
1120 case QQuickRectangleShapePrivate::Edge::Right:
1121 d->shapePath->setStartX(rectWidth - d->borderOffset);
1122 d->shapePath->setStartY(d->effectiveTopRightRadius + d->borderOffset + d->borderRadiusAdjustment);
1124 case QQuickRectangleShapePrivate::Edge::Bottom:
1125 d->shapePath->setStartX(rectWidth - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1126 d->shapePath->setStartY(rectHeight - d->borderOffset);
1128 case QQuickRectangleShapePrivate::Edge::Left:
1129 d->shapePath->setStartX(d->borderOffset);
1130 d->shapePath->setStartY(rectHeight - d->effectiveBottomLeftRadius - d->borderOffset - d->borderRadiusAdjustment);
1136 if (d->topPathLine) {
1137 d->topPathLine->setX(rectWidth - d->effectiveTopRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1138 d->topPathLine->setY(d->borderOffset);
1140 d->topPathMove->setX(rectWidth - d->borderOffset);
1141 d->topPathMove->setY(d->effectiveTopRightRadius + d->borderOffset + d->borderRadiusAdjustment);
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);
1151 if (d->rightPathLine) {
1152 d->rightPathLine->setX(rectWidth - d->borderOffset);
1153 d->rightPathLine->setY(rectHeight - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1155 d->rightPathMove->setX(rectWidth - d->effectiveBottomRightRadius - d->borderOffset - d->borderRadiusAdjustment);
1156 d->rightPathMove->setY(rectHeight - d->borderOffset);
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);
1166 if (d->bottomPathLine) {
1167 d->bottomPathLine->setX(d->effectiveBottomLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
1168 d->bottomPathLine->setY(rectHeight - d->borderOffset);
1170 d->bottomPathMove->setX(d->borderOffset);
1171 d->bottomPathMove->setY(rectHeight - d->effectiveBottomLeftRadius - d->borderOffset - d->borderRadiusAdjustment);
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);
1181 if (d->leftPathLine) {
1182 d->leftPathLine->setX(d->borderOffset);
1183 d->leftPathLine->setY(d->effectiveTopLeftRadius + d->borderOffset + d->borderRadiusAdjustment);
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);
1194 QQuickShape::updatePolish();
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();