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
qquickrectangle.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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// Qt-Security score:significant reason:default
4
7
8#include <QtQml/qqmlinfo.h>
9
10#include <QtQuick/private/qsgcontext_p.h>
11#include <private/qsgadaptationlayer_p.h>
12
13#include <private/qqmlmetatype_p.h>
14
15#include <QtGui/qpixmapcache.h>
16#include <QtCore/qmath.h>
17#include <QtCore/qmetaobject.h>
18
20
21// XXX todo - should we change rectangle to draw entirely within its width/height?
22/*!
23 \internal
24 \class QQuickPen
25 \brief For specifying a pen used for drawing rectangle borders on a QQuickView
26
27 By default, the pen is invalid and nothing is drawn. You must either set a color (then the default
28 width is 1) or a width (then the default color is black).
29
30 A width of 1 indicates is a single-pixel line on the border of the item being painted.
31
32 Example:
33 \qml
34 Rectangle {
35 border.width: 2
36 border.color: "red"
37 }
38 \endqml
39*/
40
41QQuickPen::QQuickPen(QObject *parent)
42 : QObject(parent)
43 , m_width(1)
44 , m_color(Qt::black)
45 , m_aligned(true)
46 , m_valid(false)
47{
48}
49
50qreal QQuickPen::width() const
51{
52 return m_width;
53}
54
55void QQuickPen::setWidth(qreal w)
56{
57 if (m_width == w && m_valid)
58 return;
59
60 m_width = w;
61 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
62 static_cast<QQuickItem*>(parent())->update();
63 emit widthChanged();
64}
65
66QColor QQuickPen::color() const
67{
68 return m_color;
69}
70
71void QQuickPen::setColor(const QColor &c)
72{
73 m_color = c;
74 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
75 static_cast<QQuickItem*>(parent())->update();
76 emit colorChanged();
77}
78
79bool QQuickPen::pixelAligned() const
80{
81 return m_aligned;
82}
83
84void QQuickPen::setPixelAligned(bool aligned)
85{
86 if (aligned == m_aligned)
87 return;
88 m_aligned = aligned;
89 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
90 static_cast<QQuickItem*>(parent())->update();
91 emit pixelAlignedChanged();
92}
93
94bool QQuickPen::isValid() const
95{
96 return m_valid;
97}
98
99/*!
100 \qmltype GradientStop
101 \nativetype QQuickGradientStop
102 \inqmlmodule QtQuick
103 \ingroup qtquick-visual-utility
104 \brief Defines the color at a position in a Gradient.
105
106 \sa Gradient
107*/
108
109/*!
110 \qmlproperty real QtQuick::GradientStop::position
111 \qmlproperty color QtQuick::GradientStop::color
112
113 The position and color properties describe the color used at a given
114 position in a gradient, as represented by a gradient stop.
115
116 The default position is 0.0; the default color is black.
117
118 \sa Gradient
119*/
120QQuickGradientStop::QQuickGradientStop(QObject *parent)
121 : QObject(parent)
122{
123}
124
125qreal QQuickGradientStop::position() const
126{
127 return m_position;
128}
129
130void QQuickGradientStop::setPosition(qreal position)
131{
132 m_position = position; updateGradient();
133}
134
135QColor QQuickGradientStop::color() const
136{
137 return m_color;
138}
139
140void QQuickGradientStop::setColor(const QColor &color)
141{
142 m_color = color; updateGradient();
143}
144
145void QQuickGradientStop::updateGradient()
146{
147 if (QQuickGradient *grad = qobject_cast<QQuickGradient*>(parent()))
148 grad->doUpdate();
149}
150
151/*!
152 \qmltype Gradient
153 \nativetype QQuickGradient
154 \inqmlmodule QtQuick
155 \ingroup qtquick-visual-utility
156 \brief Defines a gradient fill.
157
158 A gradient is defined by two or more colors, which will be blended seamlessly.
159
160 The colors are specified as a set of GradientStop child items, each of
161 which defines a position on the gradient from 0.0 to 1.0 and a color.
162 The position of each GradientStop is defined by setting its
163 \l{GradientStop::}{position} property; its color is defined using its
164 \l{GradientStop::}{color} property.
165
166 A gradient without any gradient stops is rendered as a solid white fill.
167
168 Note that this item is not a visual representation of a gradient. To display a
169 gradient, use a visual item (like \l Rectangle) which supports the use
170 of gradients.
171
172 \section1 Example Usage
173
174 \div {class="float-right"}
175 \inlineimage qml-gradient.png
176 \enddiv
177
178 The following example declares a \l Rectangle item with a gradient starting
179 with red, blending to yellow at one third of the height of the rectangle,
180 and ending with green:
181
182 \snippet qml/gradient.qml code
183
184 \clearfloat
185 \section1 Performance and Limitations
186
187 Calculating gradients can be computationally expensive compared to the use
188 of solid color fills or images. Consider using gradients for static items
189 in a user interface.
190
191 Since Qt 5.12, vertical and horizontal linear gradients can be applied to items.
192 If you need to apply angled gradients, a combination of rotation and clipping
193 can be applied to the relevant items. Alternatively, consider using
194 QtQuick.Shapes::LinearGradient or QtGraphicalEffects::LinearGradient. These
195 approaches can all introduce additional performance requirements for your application.
196
197 The use of animations involving gradient stops may not give the desired
198 result. An alternative way to animate gradients is to use pre-generated
199 images or SVG drawings containing gradients.
200
201 \sa GradientStop
202*/
203
204/*!
205 \qmlproperty list<GradientStop> QtQuick::Gradient::stops
206 \qmldefault
207
208 This property holds the gradient stops describing the gradient.
209
210 By default, this property contains an empty list.
211
212 To set the gradient stops, define them as children of the Gradient.
213*/
214QQuickGradient::QQuickGradient(QObject *parent)
215: QObject(parent)
216{
217}
218
219QQuickGradient::~QQuickGradient()
220{
221}
222
223QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
224{
225 return QQmlListProperty<QQuickGradientStop>(this, &m_stops);
226}
227
228/*!
229 \qmlproperty enumeration QtQuick::Gradient::orientation
230 \since 5.12
231
232 Set this property to define the direction of the gradient.
233
234 \value Gradient.Vertical a vertical gradient
235 \value Gradient.Horizontal a horizontal gradient
236
237 The default is Gradient.Vertical.
238*/
239void QQuickGradient::setOrientation(Orientation orientation)
240{
241 if (m_orientation == orientation)
242 return;
243
244 m_orientation = orientation;
245 emit orientationChanged();
246 emit updated();
247}
248
249QGradientStops QQuickGradient::gradientStops() const
250{
251 QGradientStops stops;
252 for (int i = 0; i < m_stops.size(); ++i){
253 int j = 0;
254 while (j < stops.size() && stops.at(j).first < m_stops[i]->position())
255 j++;
256 stops.insert(j, QGradientStop(m_stops.at(i)->position(), m_stops.at(i)->color()));
257 }
258 return stops;
259}
260
261void QQuickGradient::doUpdate()
262{
263 emit updated();
264}
265
267
269{
270 bool implicitAA = (radius > 0);
271 if (extraRectangle.isAllocated() && !implicitAA) {
272 const auto &extra = extraRectangle.value();
273 implicitAA = (extra.isTopLeftRadiusSet && extra.topLeftRadius > 0)
274 || (extra.isTopRightRadiusSet && extra.topRightRadius > 0)
275 || (extra.isBottomLeftRadiusSet && extra.bottomLeftRadius > 0)
276 || (extra.isBottomRightRadiusSet && extra.bottomRightRadius > 0);
277 }
278 setImplicitAntialiasing(implicitAA);
279}
280/*!
281 \qmltype Rectangle
282 \nativetype QQuickRectangle
283 \inqmlmodule QtQuick
284 \inherits Item
285 \ingroup qtquick-visual
286 \brief Paints a filled rectangle with an optional border.
287
288 Rectangle items are used to fill areas with solid color or gradients, and/or
289 to provide a rectangular border.
290
291 \section1 Appearance
292
293 Each Rectangle item is painted using either a solid fill color, specified using
294 the \l color property, or a gradient, defined using a Gradient type and set
295 using the \l gradient property. If both a color and a gradient are specified,
296 the gradient is used.
297
298 You can add an optional border to a rectangle with its own color and thickness
299 by setting the \l border.color and \l border.width properties. Set the color
300 to "transparent" to paint a border without a fill color.
301
302 You can also create rounded rectangles using the \l radius property. Since this
303 introduces curved edges to the corners of a rectangle, it may be appropriate to
304 set the \l Item::antialiasing property to improve its appearance. To set the
305 radii individually for different corners, you can use the properties
306 \l topLeftRadius, \l topRightRadius, \l bottomLeftRadius and
307 \l bottomRightRadius.
308
309 \section1 Example Usage
310
311 \div {class="float-right"}
312 \inlineimage declarative-rect.png
313 \enddiv
314
315 The following example shows the effects of some of the common properties on a
316 Rectangle item, which in this case is used to create a square:
317
318 \snippet qml/rectangle/rectangle.qml document
319
320 \clearfloat
321 \section1 Performance
322
323 Using the \l Item::antialiasing property improves the appearance of a rounded rectangle at
324 the cost of rendering performance. You should consider unsetting this property
325 for rectangles in motion, and only set it when they are stationary.
326
327 \sa Image
328*/
329
330QQuickRectangle::QQuickRectangle(QQuickItem *parent)
331: QQuickItem(*(new QQuickRectanglePrivate), parent)
332{
333 setFlag(ItemHasContents);
334#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
335 setAcceptTouchEvents(false);
336#endif
337}
338
339void QQuickRectangle::doUpdate()
340{
341 update();
342}
343
344/*!
345 \qmlproperty bool QtQuick::Rectangle::antialiasing
346
347 Used to decide if the Rectangle should use antialiasing or not.
348 \l {Antialiasing} provides information on the performance implications
349 of this property.
350
351 The default is true for Rectangles with a radius, and false otherwise.
352*/
353
354/*!
355 \qmlpropertygroup QtQuick::Rectangle::border
356 \qmlproperty int QtQuick::Rectangle::border.width
357 \qmlproperty color QtQuick::Rectangle::border.color
358 \qmlproperty bool QtQuick::Rectangle::border.pixelAligned
359
360 The width and color used to draw the border of the rectangle.
361
362 A width of 1 creates a thin line. For no line, use a width of 0 or a transparent color.
363
364 \note The width of the rectangle's border does not affect the geometry of the
365 rectangle itself or its position relative to other items if anchors are used.
366
367 The border is rendered within the rectangle's boundaries.
368
369 If \c pixelAligned is \c true (the default), the rendered border width is rounded to a whole
370 number of pixels, after device pixel ratio scaling. Setting \c pixelAligned to \c false will
371 allow fractional border widths, which may be desirable when \c antialiasing is enabled.
372*/
373QQuickPen *QQuickRectangle::border()
374{
375 Q_D(QQuickRectangle);
376 if (!d->pen) {
377 d->pen = new QQuickPen;
378 QQml_setParent_noEvent(d->pen, this);
379 }
380 return d->pen;
381}
382
383/*!
384 \qmlproperty var QtQuick::Rectangle::gradient
385
386 The gradient to use to fill the rectangle.
387
388 This property allows for the construction of simple vertical or horizontal gradients.
389 Other gradients may be formed by adding rotation to the rectangle.
390
391 \div {class="float-left"}
392 \inlineimage declarative-rect_gradient.png
393 \enddiv
394
395 \snippet qml/rectangle/rectangle-gradient.qml rectangles
396 \clearfloat
397
398 The property also accepts gradient presets from QGradient::Preset. Note however
399 that due to Rectangle only supporting simple vertical or horizontal gradients,
400 any preset with an unsupported angle will revert to the closest representation.
401
402 \snippet qml/rectangle/rectangle-gradient.qml presets
403 \clearfloat
404
405 If both a gradient and a color are specified, the gradient will be used.
406
407 \sa Gradient, color
408*/
409QJSValue QQuickRectangle::gradient() const
410{
411 Q_D(const QQuickRectangle);
412 return d->gradient;
413}
414
415void QQuickRectangle::setGradient(const QJSValue &gradient)
416{
417 Q_D(QQuickRectangle);
418 if (d->gradient.equals(gradient))
419 return;
420
421 static int updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex();
422 if (d->doUpdateSlotIdx < 0)
423 d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()");
424
425 if (auto oldGradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject()))
426 QMetaObject::disconnect(oldGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
427
428 if (gradient.isQObject()) {
429 if (auto newGradient = qobject_cast<QQuickGradient*>(gradient.toQObject())) {
430 d->gradient = gradient;
431 QMetaObject::connect(newGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
432 } else {
433 qmlWarning(this) << "Can't assign "
434 << QQmlMetaType::prettyTypeName(gradient.toQObject()) << " to gradient property";
435 d->gradient = QJSValue();
436 }
437 } else if (gradient.isNumber() || gradient.isString()) {
438 static const QMetaEnum gradientPresetMetaEnum = QMetaEnum::fromType<QGradient::Preset>();
439 Q_ASSERT(gradientPresetMetaEnum.isValid());
440
441 QGradient result;
442
443 // This code could simply use gradient.toVariant().convert<QGradient::Preset>(),
444 // but QTBUG-76377 prevents us from doing error checks. So we need to
445 // do them manually. Also, NumPresets cannot be used.
446
447 if (gradient.isNumber()) {
448 const auto preset = QGradient::Preset(gradient.toInt());
449 if (preset != QGradient::NumPresets && gradientPresetMetaEnum.valueToKey(preset))
450 result = QGradient(preset);
451 } else if (gradient.isString()) {
452 const auto presetName = gradient.toString();
453 if (presetName != QLatin1String("NumPresets")) {
454 bool ok;
455 const auto presetInt = gradientPresetMetaEnum.keyToValue(qPrintable(presetName), &ok);
456 if (ok)
457 result = QGradient(QGradient::Preset(presetInt));
458 }
459 }
460
461 if (result.type() != QGradient::NoGradient) {
462 d->gradient = gradient;
463 } else {
464 qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'";
465 d->gradient = QJSValue();
466 }
467 } else if (gradient.isNull() || gradient.isUndefined()) {
468 d->gradient = gradient;
469 } else {
470 qmlWarning(this) << "Unknown gradient type. Expected int, string, or Gradient";
471 d->gradient = QJSValue();
472 }
473
474 update();
475}
476
477void QQuickRectangle::resetGradient()
478{
479 setGradient(QJSValue());
480}
481
482/*!
483 \qmlproperty real QtQuick::Rectangle::radius
484 This property holds the corner radius used to draw a rounded rectangle.
485
486 If radius is non-zero, the rectangle will be painted as a rounded rectangle,
487 otherwise it will be painted as a normal rectangle. Individual corner radii
488 can be set as well (see below). These values will override \l radius. If
489 they are unset (by setting them to \c undefined), \l radius will be used instead.
490
491 \sa topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius
492*/
493qreal QQuickRectangle::radius() const
494{
495 Q_D(const QQuickRectangle);
496 return d->radius;
497}
498
499void QQuickRectangle::setRadius(qreal radius)
500{
501 Q_D(QQuickRectangle);
502 if (d->radius == radius)
503 return;
504
505 d->radius = radius;
506 d->maybeSetImplicitAntialiasing();
507
508 update();
509 emit radiusChanged();
510
511 if (d->extraRectangle.isAllocated()) {
512 if (!d->extraRectangle->isTopLeftRadiusSet)
513 emit topLeftRadiusChanged();
514 if (!d->extraRectangle->isTopRightRadiusSet)
515 emit topRightRadiusChanged();
516 if (!d->extraRectangle->isBottomLeftRadiusSet)
517 emit bottomLeftRadiusChanged();
518 if (!d->extraRectangle->isBottomRightRadiusSet)
519 emit bottomRightRadiusChanged();
520 } else {
521 emit topLeftRadiusChanged();
522 emit topRightRadiusChanged();
523 emit bottomLeftRadiusChanged();
524 emit bottomRightRadiusChanged();
525 }
526}
527
528/*!
529 \since 6.7
530 \qmlproperty real QtQuick::Rectangle::topLeftRadius
531 This property holds the radius used to draw the top left corner.
532
533 If \l topLeftRadius is not set, \l radius will be used instead.
534 If \l topLeftRadius is zero, the corner will be sharp.
535
536 \sa radius, topRightRadius, bottomLeftRadius, bottomRightRadius
537*/
538qreal QQuickRectangle::topLeftRadius() const
539{
540 Q_D(const QQuickRectangle);
541 if (d->extraRectangle.isAllocated() && d->extraRectangle->isTopLeftRadiusSet)
542 return d->extraRectangle->topLeftRadius;
543 return d->radius;
544}
545
546void QQuickRectangle::setTopLeftRadius(qreal radius)
547{
548 Q_D(QQuickRectangle);
549 if (d->extraRectangle.isAllocated()
550 && d->extraRectangle->topLeftRadius == radius
551 && d->extraRectangle->isTopLeftRadiusSet) {
552 return;
553 }
554
555 d->extraRectangle.value().topLeftRadius = radius;
556 d->extraRectangle.value().isTopLeftRadiusSet = true;
557 d->maybeSetImplicitAntialiasing();
558
559 update();
560 emit topLeftRadiusChanged();
561}
562
563void QQuickRectangle::resetTopLeftRadius()
564{
565 Q_D(QQuickRectangle);
566 if (!d->extraRectangle.isAllocated())
567 return;
568 if (!d->extraRectangle->isTopLeftRadiusSet)
569 return;
570
571 d->extraRectangle->isTopLeftRadiusSet = false;
572 d->maybeSetImplicitAntialiasing();
573
574 update();
575 emit topLeftRadiusChanged();
576}
577
578/*!
579 \since 6.7
580 \qmlproperty real QtQuick::Rectangle::topRightRadius
581 This property holds the radius used to draw the top right corner.
582
583 If \l topRightRadius is not set, \l radius will be used instead.
584 If \l topRightRadius is zero, the corner will be sharp.
585
586 \sa radius, topLeftRadius, bottomLeftRadius, bottomRightRadius
587*/
588qreal QQuickRectangle::topRightRadius() const
589{
590 Q_D(const QQuickRectangle);
591 if (d->extraRectangle.isAllocated() && d->extraRectangle->isTopRightRadiusSet)
592 return d->extraRectangle->topRightRadius;
593 return d->radius;
594}
595
596void QQuickRectangle::setTopRightRadius(qreal radius)
597{
598 Q_D(QQuickRectangle);
599 if (d->extraRectangle.isAllocated()
600 && d->extraRectangle->topRightRadius == radius
601 && d->extraRectangle->isTopRightRadiusSet) {
602 return;
603 }
604
605 d->extraRectangle.value().topRightRadius = radius;
606 d->extraRectangle.value().isTopRightRadiusSet = true;
607 d->maybeSetImplicitAntialiasing();
608
609 update();
610 emit topRightRadiusChanged();
611}
612
613void QQuickRectangle::resetTopRightRadius()
614{
615 Q_D(QQuickRectangle);
616 if (!d->extraRectangle.isAllocated())
617 return;
618 if (!d->extraRectangle.value().isTopRightRadiusSet)
619 return;
620
621 d->extraRectangle->isTopRightRadiusSet = false;
622 d->maybeSetImplicitAntialiasing();
623
624 update();
625 emit topRightRadiusChanged();
626}
627
628/*!
629 \since 6.7
630 \qmlproperty real QtQuick::Rectangle::bottomLeftRadius
631 This property holds the radius used to draw the bottom left corner.
632
633 If \l bottomLeftRadius is not set, \l radius will be used instead.
634 If \l bottomLeftRadius is zero, the corner will be sharp.
635
636 \sa radius, topLeftRadius, topRightRadius, bottomRightRadius
637*/
638qreal QQuickRectangle::bottomLeftRadius() const
639{
640 Q_D(const QQuickRectangle);
641 if (d->extraRectangle.isAllocated() && d->extraRectangle->isBottomLeftRadiusSet)
642 return d->extraRectangle->bottomLeftRadius;
643 return d->radius;
644}
645
646void QQuickRectangle::setBottomLeftRadius(qreal radius)
647{
648 Q_D(QQuickRectangle);
649 if (d->extraRectangle.isAllocated()
650 && d->extraRectangle->bottomLeftRadius == radius
651 && d->extraRectangle->isBottomLeftRadiusSet) {
652 return;
653 }
654
655 d->extraRectangle.value().bottomLeftRadius = radius;
656 d->extraRectangle.value().isBottomLeftRadiusSet = true;
657 d->maybeSetImplicitAntialiasing();
658
659 update();
660 emit bottomLeftRadiusChanged();
661}
662
663void QQuickRectangle::resetBottomLeftRadius()
664{
665 Q_D(QQuickRectangle);
666 if (!d->extraRectangle.isAllocated())
667 return;
668 if (!d->extraRectangle.value().isBottomLeftRadiusSet)
669 return;
670
671 d->extraRectangle->isBottomLeftRadiusSet = false;
672 d->maybeSetImplicitAntialiasing();
673
674 update();
675 emit bottomLeftRadiusChanged();
676}
677
678/*!
679 \since 6.7
680 \qmlproperty real QtQuick::Rectangle::bottomRightRadius
681 This property holds the radius used to draw the bottom right corner.
682
683 If \l bottomRightRadius is not set, \l radius will be used instead.
684 If \l bottomRightRadius is zero, the corner will be sharp.
685
686 \sa radius, topLeftRadius, topRightRadius, bottomLeftRadius
687*/
688qreal QQuickRectangle::bottomRightRadius() const
689{
690 Q_D(const QQuickRectangle);
691 if (d->extraRectangle.isAllocated() && d->extraRectangle->isBottomRightRadiusSet)
692 return d->extraRectangle->bottomRightRadius;
693 return d->radius;
694}
695
696void QQuickRectangle::setBottomRightRadius(qreal radius)
697{
698 Q_D(QQuickRectangle);
699 if (d->extraRectangle.isAllocated()
700 && d->extraRectangle->bottomRightRadius == radius
701 && d->extraRectangle->isBottomRightRadiusSet) {
702 return;
703 }
704
705 d->extraRectangle.value().bottomRightRadius = radius;
706 d->extraRectangle.value().isBottomRightRadiusSet = true;
707 d->maybeSetImplicitAntialiasing();
708
709 update();
710 emit bottomRightRadiusChanged();
711}
712
713void QQuickRectangle::resetBottomRightRadius()
714{
715 Q_D(QQuickRectangle);
716 if (!d->extraRectangle.isAllocated())
717 return;
718 if (!d->extraRectangle.value().isBottomRightRadiusSet)
719 return;
720
721 d->extraRectangle->isBottomRightRadiusSet = false;
722 d->maybeSetImplicitAntialiasing();
723
724 update();
725 emit bottomRightRadiusChanged();
726}
727
728/*!
729 \qmlproperty color QtQuick::Rectangle::color
730 This property holds the color used to fill the rectangle.
731
732 The default color is white.
733
734 \div {class="float-right"}
735 \inlineimage rect-color.png
736 \enddiv
737
738 The following example shows rectangles with colors specified
739 using hexadecimal and named color notation:
740
741 \snippet qml/rectangle/rectangle-colors.qml rectangles
742
743 \clearfloat
744 If both a gradient and a color are specified, the gradient will be used.
745
746 \sa gradient
747*/
748QColor QQuickRectangle::color() const
749{
750 Q_D(const QQuickRectangle);
751 return d->color;
752}
753
754void QQuickRectangle::setColor(const QColor &c)
755{
756 Q_D(QQuickRectangle);
757 if (d->color == c)
758 return;
759
760 d->color = c;
761 update();
762 emit colorChanged();
763}
764
765QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
766{
767 Q_UNUSED(data);
768 Q_D(QQuickRectangle);
769
770 if (width() <= 0 || height() <= 0
771 || (d->gradient.isUndefined() && d->color.alpha() == 0 && (!d->pen || d->pen->width() == 0 || d->pen->color().alpha() == 0))) {
772 delete oldNode;
773 return nullptr;
774 }
775
776 QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
777 if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
778
779 rectangle->setRect(QRectF(0, 0, width(), height()));
780 rectangle->setColor(d->color);
781
782 if (d->pen && d->pen->isValid()) {
783 rectangle->setPenColor(d->pen->color());
784 qreal penWidth = d->pen->width();
785 if (d->pen->pixelAligned()) {
786 qreal dpr = d->effectiveDevicePixelRatio();
787 penWidth = qRound(penWidth * dpr) / dpr; // Ensures integer width after dpr scaling
788 }
789 rectangle->setPenWidth(penWidth);
790 rectangle->setAligned(false); // width rounding already done, so the Node should not do it
791 } else {
792 rectangle->setPenWidth(0);
793 }
794
795 rectangle->setRadius(d->radius);
796 if (d->extraRectangle.isAllocated()) {
797 const auto &extra = d->extraRectangle.value();
798 if (extra.isTopLeftRadiusSet)
799 rectangle->setTopLeftRadius(extra.topLeftRadius);
800 else
801 rectangle->resetTopLeftRadius();
802 if (extra.isTopRightRadiusSet)
803 rectangle->setTopRightRadius(extra.topRightRadius);
804 else
805 rectangle->resetTopRightRadius();
806 if (extra.isBottomLeftRadiusSet)
807 rectangle->setBottomLeftRadius(extra.bottomLeftRadius);
808 else
809 rectangle->resetBottomLeftRadius();
810 if (extra.isBottomRightRadiusSet)
811 rectangle->setBottomRightRadius(extra.bottomRightRadius);
812 else
813 rectangle->resetBottomRightRadius();
814 } else {
815 rectangle->resetTopLeftRadius();
816 rectangle->resetTopRightRadius();
817 rectangle->resetBottomLeftRadius();
818 rectangle->resetBottomRightRadius();
819 }
820 rectangle->setAntialiasing(antialiasing());
821
822 QGradientStops stops;
823 bool vertical = true;
824 if (d->gradient.isQObject()) {
825 auto gradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject());
826 Q_ASSERT(gradient);
827 stops = gradient->gradientStops();
828 vertical = gradient->orientation() == QQuickGradient::Vertical;
829 } else if (d->gradient.isNumber() || d->gradient.isString()) {
830 QGradient preset(d->gradient.toVariant().value<QGradient::Preset>());
831 if (preset.type() == QGradient::LinearGradient) {
832 auto linearGradient = static_cast<QLinearGradient&>(preset);
833 const QPointF start = linearGradient.start();
834 const QPointF end = linearGradient.finalStop();
835 vertical = qAbs(start.y() - end.y()) >= qAbs(start.x() - end.x());
836 stops = linearGradient.stops();
837 if ((vertical && start.y() > end.y()) || (!vertical && start.x() > end.x())) {
838 // QSGInternalRectangleNode doesn't support stops in the wrong order,
839 // so we need to manually reverse them here.
840 QGradientStops reverseStops;
841 for (auto it = stops.rbegin(); it != stops.rend(); ++it) {
842 auto stop = *it;
843 stop.first = 1 - stop.first;
844 reverseStops.append(stop);
845 }
846 stops = reverseStops;
847 }
848 }
849 }
850 rectangle->setGradientStops(stops);
851 rectangle->setGradientVertical(vertical);
852
853 rectangle->update();
854
855 return rectangle;
856}
857
858QT_END_NAMESPACE
859
860#include "moc_qquickrectangle_p.cpp"