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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quick/items/qquickrectangle.cpp