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