Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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?
41 : QObject(parent)
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
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
214: QObject(parent)
215{
216}
217
221
222QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
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 (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}
329: QQuickItem(*(new QQuickRectanglePrivate), parent)
330{
332#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
334#endif
335}
336
337void QQuickRectangle::doUpdate()
338{
339 update();
340}
341
372{
373 Q_D(QQuickRectangle);
374 if (!d->pen) {
375 d->pen = new QQuickPen;
376 QQml_setParent_noEvent(d->pen, this);
377 }
378 return d->pen;
379}
380
408{
409 Q_D(const QQuickRectangle);
410 return d->gradient;
411}
412
414{
415 Q_D(QQuickRectangle);
416 if (d->gradient.equals(gradient))
417 return;
418
419 static int updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex();
420 if (d->doUpdateSlotIdx < 0)
421 d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()");
422
423 if (auto oldGradient = qobject_cast<QQuickGradient*>(d->gradient.toQObject()))
424 QMetaObject::disconnect(oldGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
425
426 if (gradient.isQObject()) {
427 if (auto newGradient = qobject_cast<QQuickGradient*>(gradient.toQObject())) {
428 d->gradient = gradient;
429 QMetaObject::connect(newGradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
430 } else {
431 qmlWarning(this) << "Can't assign "
432 << QQmlMetaType::prettyTypeName(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
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(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);
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(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(this) << "Unknown gradient type. Expected int, string, or Gradient";
469 d->gradient = QJSValue();
470 }
471
472 update();
473}
474
479
492{
493 Q_D(const QQuickRectangle);
494 return d->radius;
495}
496
498{
499 Q_D(QQuickRectangle);
500 if (d->radius == radius)
501 return;
502
503 d->radius = radius;
504 d->maybeSetImplicitAntialiasing();
505
506 update();
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
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
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(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
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
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
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(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
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
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
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(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
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
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
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(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
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
761{
762 Q_D(const QQuickRectangle);
763 return d->color;
764}
765
767{
768 Q_D(QQuickRectangle);
769 if (d->color == c)
770 return;
771
772 d->color = c;
773 update();
775}
776
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(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*>(d->gradient.toQObject());
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(start.y() - end.y()) >= qAbs(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(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
858
859#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
@ 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:566
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:304
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:351
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:321
bool isString() const
Returns true if this QJSValue is of the primitive type String; otherwise returns false.
Definition qjsvalue.cpp:332
QString toString() const
Returns the string value of this QJSValue, as defined in \l{ECMA-262} section 9.8,...
Definition qjsvalue.cpp:494
\inmodule QtGui
Definition qbrush.h:394
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
reverse_iterator rend()
Definition qlist.h:635
reverse_iterator rbegin()
Definition qlist.h:634
\inmodule QtCore
static QMetaMethod fromSignal(PointerToMemberFunction signal)
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
\inmodule QtCore\reentrant
Definition qpoint.h:217
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:63
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:75
bool antialiasing
\qmlproperty bool QtQuick::Item::antialiasing
Definition qquickitem.h:113
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
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 > extraRectangle
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:484
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.
Definition qcompare.h:63
QPair< qreal, QColor > QGradientStop
Definition qbrush.h:131
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
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 color
[2]
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:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
QGraphicsSvgItem * black
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3641
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3556