Qt 6.x
The Qt SDK
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
4#include "qquickrectangle_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
19
20// XXX todo - should we change rectangle to draw entirely within its width/height?
42 , m_width(1)
43 , m_color(Qt::black)
44 , m_aligned(true)
45 , m_valid(false)
46{
47}
48
50{
51 return m_width;
52}
53
55{
56 if (m_width == w && m_valid)
57 return;
58
59 m_width = w;
60 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
61 static_cast<QQuickItem*>(parent())->update();
63}
64
66{
67 return m_color;
68}
69
71{
72 m_color = c;
73 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
74 static_cast<QQuickItem*>(parent())->update();
76}
77
79{
80 return m_aligned;
81}
82
84{
85 if (aligned == m_aligned)
86 return;
87 m_aligned = aligned;
88 m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
89 static_cast<QQuickItem*>(parent())->update();
91}
92
94{
95 return m_valid;
96}
97
120 : QObject(parent)
121{
122}
123
125{
126 return m_position;
127}
128
130{
131 m_position = position; updateGradient();
132}
133
135{
136 return m_color;
137}
138
140{
141 m_color = color; updateGradient();
142}
143
144void QQuickGradientStop::updateGradient()
145{
146 if (QQuickGradient *grad = qobject_cast<QQuickGradient*>(parent()))
147 grad->doUpdate();
148}
149
215{
216}
217
219{
220}
221
223{
224 return QQmlListProperty<QQuickGradientStop>(this, &m_stops);
225}
226
239{
240 if (m_orientation == orientation)
241 return;
242
243 m_orientation = orientation;
245 emit updated();
246}
247
249{
251 for (int i = 0; i < m_stops.size(); ++i){
252 int j = 0;
253 while (j < stops.size() && stops.at(j).first < m_stops[i]->position())
254 j++;
255 stops.insert(j, 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
266
268{
269 bool implicitAA = (radius != 0);
270 if (extra.isAllocated() && !implicitAA) {
271 implicitAA = extra.value().topLeftRadius > 0.0
272 || extra.value().topRightRadius > 0.0
273 || extra.value().bottomLeftRadius > 0.0
274 || extra.value().bottomRightRadius > 0.0;
275 }
276 setImplicitAntialiasing(implicitAA);
277}
330{
332#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
334#endif
335}
336
337void QQuickRectangle::doUpdate()
338{
339 update();
340}
341
367{
368 Q_D(QQuickRectangle);
369 if (!d->pen) {
370 d->pen = new QQuickPen;
371 QQml_setParent_noEvent(d->pen, this);
372 }
373 return d->pen;
374}
375
403{
404 Q_D(const QQuickRectangle);
405 return d->gradient;
406}
407
409{
410 Q_D(QQuickRectangle);
411 if (d->gradient.equals(gradient))
412 return;
413
414 static int updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex();
415 if (d->doUpdateSlotIdx < 0)
416 d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()");
417
418 if (auto oldGradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject()))
419 QMetaObject::disconnect(oldGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
420
421 if (gradient.isQObject()) {
422 if (auto newGradient = qobject_cast<QQuickGradient*>(gradient.toQObject())) {
423 d->gradient = gradient;
424 QMetaObject::connect(newGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
425 } else {
426 qmlWarning(this) << "Can't assign "
427 << QQmlMetaType::prettyTypeName(gradient.toQObject()) << " to gradient property";
428 d->gradient = QJSValue();
429 }
430 } else if (gradient.isNumber() || gradient.isString()) {
431 static const QMetaEnum gradientPresetMetaEnum = QMetaEnum::fromType<QGradient::Preset>();
432 Q_ASSERT(gradientPresetMetaEnum.isValid());
433
435
436 // This code could simply use gradient.toVariant().convert<QGradient::Preset>(),
437 // but QTBUG-76377 prevents us from doing error checks. So we need to
438 // do them manually. Also, NumPresets cannot be used.
439
440 if (gradient.isNumber()) {
441 const auto preset = QGradient::Preset(gradient.toInt());
442 if (preset != QGradient::NumPresets && gradientPresetMetaEnum.valueToKey(preset))
443 result = QGradient(preset);
444 } else if (gradient.isString()) {
445 const auto presetName = gradient.toString();
446 if (presetName != QLatin1String("NumPresets")) {
447 bool ok;
448 const auto presetInt = gradientPresetMetaEnum.keyToValue(qPrintable(presetName), &ok);
449 if (ok)
450 result = QGradient(QGradient::Preset(presetInt));
451 }
452 }
453
454 if (result.type() != QGradient::NoGradient) {
455 d->gradient = gradient;
456 } else {
457 qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'";
458 d->gradient = QJSValue();
459 }
460 } else if (gradient.isNull() || gradient.isUndefined()) {
461 d->gradient = gradient;
462 } else {
463 qmlWarning(this) << "Unknown gradient type. Expected int, string, or Gradient";
464 d->gradient = QJSValue();
465 }
466
467 update();
468}
469
471{
473}
474
487{
488 Q_D(const QQuickRectangle);
489 return d->radius;
490}
491
493{
494 Q_D(QQuickRectangle);
495 if (d->radius == radius)
496 return;
497
498 d->radius = radius;
499 d->maybeSetImplicitAntialiasing();
500
501 update();
503}
504
519{
520 Q_D(const QQuickRectangle);
521 if (d->extra.isAllocated())
522 return qMax(d->extra.value().topLeftRadius, 0.);
523 return 0;
524}
525
527{
528 Q_D(QQuickRectangle);
529 if (d->extra.value().topLeftRadius == radius)
530 return;
531
532 if (radius < 0) { // use the fact that radius < 0 resets the radius.
533 qmlWarning(this) << "topLeftRadius (" << radius << ") cannot be less than 0.";
534 return;
535 }
536 d->extra.value().topLeftRadius = radius;
537 d->maybeSetImplicitAntialiasing();
538
539 update();
540 emit topLeftRadiusChanged();
541}
542
544{
545 Q_D(QQuickRectangle);
546 if (!d->extra.isAllocated())
547 return;
548 if (d->extra.value().topLeftRadius < 0)
549 return;
550
551 d->extra.value().topLeftRadius = -1.;
552 d->maybeSetImplicitAntialiasing();
553
554 update();
555 emit topLeftRadiusChanged();
556}
557
572{
573 Q_D(const QQuickRectangle);
574 if (d->extra.isAllocated())
575 return qMax(d->extra.value().topRightRadius, 0.);
576 return 0;
577}
578
580{
581 Q_D(QQuickRectangle);
582 if (d->extra.value().topRightRadius == radius)
583 return;
584
585 if (radius < 0) { // use the fact that radius < 0 resets the radius.
586 qmlWarning(this) << "topRightRadius (" << radius << ") cannot be less than 0.";
587 return;
588 }
589 d->extra.value().topRightRadius = radius;
590 d->maybeSetImplicitAntialiasing();
591
592 update();
593 emit topRightRadiusChanged();
594}
595
597{
598 Q_D(QQuickRectangle);
599 if (!d->extra.isAllocated())
600 return;
601 if (d->extra.value().topRightRadius < 0)
602 return;
603
604 d->extra.value().topRightRadius = -1.;
605 d->maybeSetImplicitAntialiasing();
606
607 update();
608 emit topRightRadiusChanged();
609}
610
625{
626 Q_D(const QQuickRectangle);
627 if (d->extra.isAllocated())
628 return qMax(d->extra.value().bottomLeftRadius, 0.);
629 return 0;
630}
631
633{
634 Q_D(QQuickRectangle);
635 if (d->extra.value().bottomLeftRadius == radius)
636 return;
637
638 if (radius < 0) { // use the fact that radius < 0 resets the radius.
639 qmlWarning(this) << "bottomLeftRadius (" << radius << ") cannot be less than 0.";
640 return;
641 }
642
643 d->extra.value().bottomLeftRadius = radius;
644 d->maybeSetImplicitAntialiasing();
645
646 update();
647 emit bottomLeftRadiusChanged();
648}
649
651{
652 Q_D(QQuickRectangle);
653 if (!d->extra.isAllocated())
654 return;
655 if (d->extra.value().bottomLeftRadius < 0)
656 return;
657
658 d->extra.value().bottomLeftRadius = -1.;
659 d->maybeSetImplicitAntialiasing();
660
661 update();
662 emit bottomLeftRadiusChanged();
663}
664
679{
680 Q_D(const QQuickRectangle);
681 if (d->extra.isAllocated())
682 return qMax(d->extra.value().bottomRightRadius, 0.);
683 return 0;
684}
685
687{
688 Q_D(QQuickRectangle);
689 if (d->extra.value().bottomRightRadius == radius)
690 return;
691
692 if (radius < 0) { // use the fact that radius < 0 resets the radius.
693 qmlWarning(this) << "bottomRightRadius (" << radius << ") cannot be less than 0.";
694 return;
695 }
696
697 d->extra.value().bottomRightRadius = radius;
698 d->maybeSetImplicitAntialiasing();
699
700 update();
701 emit bottomRightRadiusChanged();
702}
703
705{
706 Q_D(QQuickRectangle);
707 if (!d->extra.isAllocated())
708 return;
709 if (d->extra.value().bottomRightRadius < 0)
710 return;
711
712 d->extra.value().bottomRightRadius = -1.;
713 d->maybeSetImplicitAntialiasing();
714
715 update();
716 emit bottomRightRadiusChanged();
717}
718
740{
741 Q_D(const QQuickRectangle);
742 return d->color;
743}
744
746{
747 Q_D(QQuickRectangle);
748 if (d->color == c)
749 return;
750
751 d->color = c;
752 update();
754}
755
757{
758 Q_UNUSED(data);
759 Q_D(QQuickRectangle);
760
761 if (width() <= 0 || height() <= 0
762 || (d->color.alpha() == 0 && (!d->pen || d->pen->width() == 0 || d->pen->color().alpha() == 0))) {
763 delete oldNode;
764 return nullptr;
765 }
766
767 QSGInternalRectangleNode *rectangle = static_cast<QSGInternalRectangleNode *>(oldNode);
768 if (!rectangle) rectangle = d->sceneGraphContext()->createInternalRectangleNode();
769
770 rectangle->setRect(QRectF(0, 0, width(), height()));
771 rectangle->setColor(d->color);
772
773 if (d->pen && d->pen->isValid()) {
774 rectangle->setPenColor(d->pen->color());
775 qreal penWidth = d->pen->width();
776 if (d->pen->pixelAligned()) {
777 qreal dpr = window() ? window()->effectiveDevicePixelRatio() : 1.0;
778 penWidth = qRound(penWidth * dpr) / dpr; // Ensures integer width after dpr scaling
779 }
780 rectangle->setPenWidth(penWidth);
781 rectangle->setAligned(false); // width rounding already done, so the Node should not do it
782 } else {
783 rectangle->setPenWidth(0);
784 }
785
786 rectangle->setRadius(d->radius);
787 if (d->extra.isAllocated()) {
788 rectangle->setTopLeftRadius(d->extra.value().topLeftRadius);
789 rectangle->setTopRightRadius(d->extra.value().topRightRadius);
790 rectangle->setBottomLeftRadius(d->extra.value().bottomLeftRadius);
791 rectangle->setBottomRightRadius(d->extra.value().bottomRightRadius);
792 } else {
793 rectangle->setTopLeftRadius(-1.);
794 rectangle->setTopRightRadius(-1.);
795 rectangle->setBottomLeftRadius(-1.);
796 rectangle->setBottomRightRadius(-1.);
797 }
798 rectangle->setAntialiasing(antialiasing());
799
800 QGradientStops stops;
801 bool vertical = true;
802 if (d->gradient.isQObject()) {
803 auto gradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject());
805 stops = gradient->gradientStops();
806 vertical = gradient->orientation() == QQuickGradient::Vertical;
807 } else if (d->gradient.isNumber() || d->gradient.isString()) {
808 QGradient preset(d->gradient.toVariant().value<QGradient::Preset>());
809 if (preset.type() == QGradient::LinearGradient) {
810 auto linearGradient = static_cast<QLinearGradient&>(preset);
811 const QPointF start = linearGradient.start();
812 const QPointF end = linearGradient.finalStop();
813 vertical = qAbs(start.y() - end.y()) >= qAbs(start.x() - end.x());
814 stops = linearGradient.stops();
815 if ((vertical && start.y() > end.y()) || (!vertical && start.x() > end.x())) {
816 // QSGInternalRectangleNode doesn't support stops in the wrong order,
817 // so we need to manually reverse them here.
818 QGradientStops reverseStops;
819 for (auto it = stops.rbegin(); it != stops.rend(); ++it) {
820 auto stop = *it;
821 stop.first = 1 - stop.first;
822 reverseStops.append(stop);
823 }
824 stops = reverseStops;
825 }
826 }
827 }
828 rectangle->setGradientStops(stops);
829 rectangle->setGradientVertical(vertical);
830
831 rectangle->update();
832
833 return rectangle;
834}
835
837
838#include "moc_qquickrectangle_p.cpp"
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
int alpha() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1466
\inmodule QtGui
Definition qbrush.h:135
@ NumPresets
Definition qbrush.h:336
Type type() const
Returns the type of gradient.
Definition qbrush.h:344
@ LinearGradient
Definition qbrush.h:139
@ NoGradient
Definition qbrush.h:142
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
qint32 toInt() const
Returns the signed 32-bit integer value of this QJSValue, using the conversion rules described in \l{...
Definition qjsvalue.cpp:545
bool isQObject() const
Returns true if this QJSValue is a QObject; otherwise returns false.
bool isNumber() const
Returns true if this QJSValue is of the primitive type Number; otherwise returns false.
Definition qjsvalue.cpp:302
bool isUndefined() const
Returns true if this QJSValue is of the primitive type Undefined or if the managed value has been cle...
Definition qjsvalue.cpp:349
QObject * toQObject() const
If this QJSValue is a QObject, returns the QObject pointer that the QJSValue represents; otherwise,...
bool isNull() const
Returns true if this QJSValue is of the primitive type Null; otherwise returns false.
Definition qjsvalue.cpp:319
bool isString() const
Returns true if this QJSValue is of the primitive type String; otherwise returns false.
Definition qjsvalue.cpp:330
QString toString() const
Returns the string value of this QJSValue, as defined in \l{ECMA-262} section 9.8,...
Definition qjsvalue.cpp:473
\inmodule QtGui
Definition qbrush.h:394
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
reverse_iterator rend()
Definition qlist.h:618
reverse_iterator rbegin()
Definition qlist.h:617
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
const char * valueToKey(int value) const
Returns the string that is used as the name of the given enumeration value, or \nullptr if value is n...
int keyToValue(const char *key, bool *ok=nullptr) const
Returns the integer value of the given enumeration key, or -1 if key is not defined.
bool isValid() const
Returns true if this enum is valid (has a name); otherwise returns false.
static QMetaMethod fromSignal(PointerToMemberFunction signal)
int methodIndex() const
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
\inmodule QtCore\reentrant
Definition qpoint.h:214
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
static QString prettyTypeName(const QObject *object)
Returns the pretty QML type name (e.g.
QQuickGradientStop(QObject *parent=nullptr)
\qmltype GradientStop \instantiates QQuickGradientStop \inqmlmodule QtQuick
void setColor(const QColor &color)
void setPosition(qreal position)
QQuickGradient(QObject *parent=nullptr)
\qmltype Gradient \instantiates QQuickGradient \inqmlmodule QtQuick
void setOrientation(Orientation orientation)
\qmlproperty enumeration QtQuick::Gradient::orientation
~QQuickGradient() override
QQmlListProperty< QQuickGradientStop > stops
QGradientStops gradientStops() const
Orientation orientation
void orientationChanged()
void setImplicitAntialiasing(bool antialiasing)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
void setAcceptTouchEvents(bool accept)
If enabled is true, this sets the item to accept touch events; otherwise, touch events are not accept...
QQuickWindow * window() const
Returns the window in which this item is rendered.
qreal width
This property holds the width of this item.
Definition qquickitem.h:76
bool antialiasing
\qmlproperty bool QtQuick::Item::antialiasing
Definition qquickitem.h:112
qreal height
This property holds the height of this item.
Definition qquickitem.h:77
void update()
Schedules a call to updatePaintNode() for this item.
For specifying a pen used for drawing rectangle borders on a QQuickView.
void colorChanged()
void widthChanged()
bool isValid() const
void pixelAlignedChanged()
void setWidth(qreal w)
void setPixelAligned(bool aligned)
QQuickPen(QObject *parent=nullptr)
void setColor(const QColor &c)
QLazilyAllocated< ExtraData > extra
void setBottomRightRadius(qreal radius)
QQuickRectangle(QQuickItem *parent=nullptr)
\qmltype Rectangle \instantiates QQuickRectangle \inqmlmodule QtQuick \inherits Item
void setTopRightRadius(qreal radius)
void setBottomLeftRadius(qreal radius)
void setTopLeftRadius(qreal radius)
void setColor(const QColor &)
FINALqreal topRightRadius
void setRadius(qreal radius)
void setGradient(const QJSValue &gradient)
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
QQuickPen * border
\qmlproperty bool QtQuick::Rectangle::antialiasing
void radiusChanged()
FINALqreal bottomRightRadius
FINALqreal bottomLeftRadius
\inmodule QtCore\reentrant
Definition qrect.h:483
virtual void setRadius(qreal radius)=0
virtual void setAntialiasing(bool antialiasing)
virtual void setGradientVertical(bool vertical)=0
virtual void setAligned(bool aligned)=0
virtual void setPenColor(const QColor &color)=0
virtual void setTopRightRadius(qreal radius)=0
virtual void setBottomRightRadius(qreal radius)=0
virtual void setBottomLeftRadius(qreal radius)=0
virtual void setPenWidth(qreal width)=0
virtual void setGradientStops(const QGradientStops &stops)=0
virtual void setRect(const QRectF &rect)=0
virtual void setTopLeftRadius(qreal radius)=0
virtual void update()=0
virtual void setColor(const QColor &color)=0
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QPair< qreal, QColor > QGradientStop
Definition qbrush.h:131
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLfloat GLfloat GLfloat w
[0]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
const GLubyte * c
GLuint64EXT * result
[6]
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Int aligned(Int v, Int byteAlign)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QGraphicsSvgItem * black
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3504
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3419
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent