12#include <private/qbezier_p.h>
13#include <QtCore/qmath.h>
14#include <QtCore/private/qnumeric_p.h>
18Q_STATIC_LOGGING_CATEGORY(lcPath,
"qt.quick.shapes.path")
20void QQuickPathPrivate::enablePathElement(QQuickPathElement *pathElement)
24 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
25 _pathCurves.append(curve);
26 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
27 _pathTexts.append(text);
29 QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement);
30 if (attribute && !_attributes.contains(attribute->name()))
31 _attributes.append(attribute->name());
35 if (!_pathElements.contains(pathElement))
36 q->connect(pathElement, SIGNAL(changed()), q, SLOT(processPath()));
39void QQuickPathPrivate::disablePathElement(QQuickPathElement *pathElement)
43 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
44 _pathCurves.removeOne(curve);
45 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
46 _pathTexts.removeOne(text);
47 }
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
48 const QString name = attribute->name();
52 for (QQuickPathElement *other : std::as_const(_pathElements)) {
53 QQuickPathAttribute *otherAttribute = qobject_cast<QQuickPathAttribute *>(other);
54 if (otherAttribute && otherAttribute->name() == name) {
61 _attributes.removeOne(name);
65 if (!_pathElements.contains(pathElement))
66 q->disconnect(pathElement, SIGNAL(changed()), q, SLOT(processPath()));
70
71
72
73
74
75
76
77
78
79
80
81
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181QQuickPath::QQuickPath(QObject *parent)
182 : QObject(*(
new QQuickPathPrivate), parent)
186QQuickPath::QQuickPath(QQuickPathPrivate &dd, QObject *parent)
187 : QObject(dd, parent)
191QQuickPath::~QQuickPath()
196
197
198
199
200qreal QQuickPath::startX()
const
202 Q_D(
const QQuickPath);
203 return d->startX.isValid() ? d->startX.value() : 0;
206void QQuickPath::setStartX(qreal x)
209 if (d->startX.isValid() && qFuzzyCompare(x, d->startX))
212 emit startXChanged();
216bool QQuickPath::hasStartX()
const
218 Q_D(
const QQuickPath);
219 return d->startX.isValid();
222qreal QQuickPath::startY()
const
224 Q_D(
const QQuickPath);
225 return d->startY.isValid() ? d->startY.value() : 0;
228void QQuickPath::setStartY(qreal y)
231 if (d->startY.isValid() && qFuzzyCompare(y, d->startY))
234 emit startYChanged();
238bool QQuickPath::hasStartY()
const
240 Q_D(
const QQuickPath);
241 return d->startY.isValid();
245
246
247
248bool QQuickPath::isClosed()
const
250 Q_D(
const QQuickPath);
251 if (d->_pathElements.isEmpty())
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
281QQmlListProperty<QQuickPathElement> QQuickPath::pathElements()
283 return QQmlListProperty<QQuickPathElement>(
this,
289 pathElements_replace,
290 pathElements_removeLast);
295 QQuickPath *path =
static_cast<QQuickPath*>(object);
297 return QQuickPathPrivate::get(path);
300QQuickPathElement *QQuickPath::pathElements_at(QQmlListProperty<QQuickPathElement> *property, qsizetype index)
302 QQuickPathPrivate *d = privatePath(property->object);
304 return d->_pathElements.at(index);
307void QQuickPath::pathElements_append(QQmlListProperty<QQuickPathElement> *property, QQuickPathElement *pathElement)
309 QQuickPathPrivate *d = privatePath(property->object);
310 d->appendPathElement(pathElement);
313qsizetype QQuickPath::pathElements_count(QQmlListProperty<QQuickPathElement> *property)
315 QQuickPathPrivate *d = privatePath(property->object);
317 return d->_pathElements.size();
320void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *property)
322 QQuickPathPrivate *d = privatePath(property->object);
323 d->clearPathElements();
326void QQuickPath::pathElements_replace(
327 QQmlListProperty<QQuickPathElement> *property, qsizetype position,
328 QQuickPathElement *pathElement)
330 privatePath(property->object)->replacePathElement(position, pathElement);
333void QQuickPath::pathElements_removeLast(QQmlListProperty<QQuickPathElement> *property)
335 privatePath(property->object)->removeLastPathElement();
338void QQuickPath::interpolate(
int idx,
const QString &name, qreal value)
341 interpolate(d->_attributePoints, idx, name, value);
344void QQuickPath::interpolate(QList<AttributePoint> &attributePoints,
int idx,
const QString &name, qreal value)
350 qreal lastPercent = 0;
351 int search = idx - 1;
353 const AttributePoint &point = attributePoints.at(search);
354 if (point.values.contains(name)) {
355 lastValue = point.values.value(name);
356 lastPercent = point.origpercent;
364 const AttributePoint &curPoint = attributePoints.at(idx);
366 for (
int ii = search; ii < idx; ++ii) {
367 AttributePoint &point = attributePoints[ii];
369 qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
370 point.values.insert(name, val);
374void QQuickPath::endpoint(
const QString &name)
377 const AttributePoint &first = d->_attributePoints.first();
378 qreal val = first.values.value(name);
379 for (
int ii = d->_attributePoints.size() - 1; ii >= 0; ii--) {
380 const AttributePoint &point = d->_attributePoints.at(ii);
381 if (point.values.contains(name)) {
382 for (
int jj = ii + 1; jj < d->_attributePoints.size(); ++jj) {
383 AttributePoint &setPoint = d->_attributePoints[jj];
384 setPoint.values.insert(name, val);
391void QQuickPath::endpoint(QList<AttributePoint> &attributePoints,
const QString &name)
393 const AttributePoint &first = attributePoints.first();
394 qreal val = first.values.value(name);
395 for (
int ii = attributePoints.size() - 1; ii >= 0; ii--) {
396 const AttributePoint &point = attributePoints.at(ii);
397 if (point.values.contains(name)) {
398 for (
int jj = ii + 1; jj < attributePoints.size(); ++jj) {
399 AttributePoint &setPoint = attributePoints[jj];
400 setPoint.values.insert(name, val);
407void QQuickPath::processPath()
411 if (!d->componentComplete)
414 if (!d->asynchronous) {
416 }
else if (!d->processPending) {
417 d->processPending =
true;
418 QMetaObject::invokeMethod(
this, &QQuickPath::doProcessPath, Qt::QueuedConnection);
422void QQuickPath::doProcessPath()
426 d->processPending =
false;
428 if (!d->componentComplete)
431 if (d->useCustomPath)
434 d->_pointCache.clear();
435 d->prevBez.isValid =
false;
437 if (d->isShapePath) {
439 d->_path = createShapePath(QPointF(), QPointF(), d->pathLength, &d->closed);
441 d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
445 d->_path = d->_path.simplified();
450inline static void scalePath(QPainterPath &path,
const QSizeF &scale)
452 const qreal xscale = scale.width();
453 const qreal yscale = scale.height();
454 if (xscale == 1 && yscale == 1)
457 for (
int i = 0; i < path.elementCount(); ++i) {
458 const QPainterPath::Element &element = path.elementAt(i);
459 path.setElementPositionAt(i, element.x * xscale, element.y * yscale);
463QPainterPath QQuickPath::createPath(
const QPointF &startPoint,
const QPointF &endPoint,
const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints,
bool *closed)
468 attributePoints.clear();
470 if (!d->componentComplete)
471 return QPainterPath();
475 AttributePoint first;
476 for (
int ii = 0; ii < attributes.size(); ++ii)
477 first.values[attributes.at(ii)] = 0;
478 attributePoints << first;
480 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
481 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
482 path.moveTo(startX, startY);
484 const QString percentString = QStringLiteral(
"_qfx_percent");
486 bool usesPercent =
false;
488 qCDebug(lcPath).nospace() <<
this <<
" is creating path starting at " << startPoint
489 <<
" and ending at " << endPoint <<
" with " << pathLength <<
" element(s):";
490 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
491 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
494 data.endPoint = endPoint;
495 data.curves = d->_pathCurves;
496 curve->addToPath(path, data);
498 p.origpercent = path.length();
499 attributePoints << p;
501 qCDebug(lcPath) <<
"- index" << index <<
"curve:" << data.curves.at(data.index);
502 }
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
503 AttributePoint &point = attributePoints.last();
504 point.values[attribute->name()] = attribute->value();
505 interpolate(attributePoints, attributePoints.size() - 1, attribute->name(), attribute->value());
506 qCDebug(lcPath) <<
"- index" << index <<
"attribute:" << attribute->value();
507 }
else if (QQuickPathPercent *percent = qobject_cast<QQuickPathPercent *>(pathElement)) {
508 AttributePoint &point = attributePoints.last();
509 point.values[percentString] = percent->value();
510 interpolate(attributePoints, attributePoints.size() - 1, percentString, percent->value());
511 qCDebug(lcPath) <<
"- index" << index <<
"percent:" << percent->value();
513 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
514 text->addToPath(path);
515 qCDebug(lcPath) <<
"- index" << index <<
"text:" << text->text();
520 const AttributePoint &last = attributePoints.constLast();
521 for (
int ii = 0; ii < attributes.size(); ++ii) {
522 if (!last.values.contains(attributes.at(ii)))
523 endpoint(attributePoints, attributes.at(ii));
525 if (usesPercent && !last.values.contains(percentString)) {
526 d->_attributePoints.last().values[percentString] = 1;
527 interpolate(d->_attributePoints.size() - 1, percentString, 1);
529 scalePath(path, d->scale);
532 qreal length = path.length();
533 qreal prevpercent = 0;
534 qreal prevorigpercent = 0;
535 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
536 const AttributePoint &point = attributePoints.at(ii);
537 if (point.values.contains(percentString)) {
539 qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
540 (point.values.value(percentString)-prevpercent);
541 attributePoints[ii].scale = scale;
543 attributePoints[ii].origpercent /= length;
544 attributePoints[ii].percent = point.values.value(percentString);
545 prevorigpercent = attributePoints.at(ii).origpercent;
546 prevpercent = attributePoints.at(ii).percent;
548 attributePoints[ii].origpercent /= length;
549 attributePoints[ii].percent = attributePoints.at(ii).origpercent;
554 QPointF end = path.currentPosition();
555 *closed = length > 0 && startX * d->scale.width() == end.x() && startY * d->scale.height() == end.y();
562QPainterPath QQuickPath::createShapePath(
const QPointF &startPoint,
const QPointF &endPoint, qreal &pathLength,
bool *closed)
566 if (!d->componentComplete)
567 return QPainterPath();
571 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
572 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
573 path.moveTo(startX, startY);
576 qCDebug(lcPath).nospace() <<
this <<
" is creating shape path from " << d->_pathCurves.size()
577 <<
" curve(s) with endPoint " << endPoint <<
":";
578 for (QQuickCurve *curve : std::as_const(d->_pathCurves)) {
581 data.endPoint = endPoint;
582 data.curves = d->_pathCurves;
583 curve->addToPath(path, data);
584 qCDebug(lcPath) <<
"- index" << data.index << data.curves.at(data.index);
588 for (QQuickPathText *text : std::as_const(d->_pathTexts))
589 text->addToPath(path);
592 QPointF end = path.currentPosition();
593 *closed = startX == end.x() && startY == end.y();
595 scalePath(path, d->scale);
600 path.setCachingEnabled(
true);
605void QQuickPath::classBegin()
608 d->componentComplete =
false;
611void QQuickPath::disconnectPathElements()
613 Q_D(
const QQuickPath);
615 for (QQuickPathElement *pathElement : d->_pathElements) {
617 disconnect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
621void QQuickPath::connectPathElements()
623 Q_D(
const QQuickPath);
625 for (QQuickPathElement *pathElement : d->_pathElements) {
627 connect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
631void QQuickPath::gatherAttributes()
635 QSet<QString> attributes;
637 Q_ASSERT(d->_pathCurves.isEmpty());
640 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
641 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
642 d->_pathCurves.append(curve);
643 else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
644 d->_pathTexts.append(text);
645 else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
646 attributes.insert(attribute->name());
649 d->_attributes = attributes.values();
652void QQuickPath::componentComplete()
655 d->componentComplete =
true;
662 connectPathElements();
665QPainterPath QQuickPath::path()
const
667 Q_D(
const QQuickPath);
671void QQuickPath::setPath(
const QPainterPath &path)
674 d->useCustomPath = !path.isEmpty();
675 d->_pointCache.clear();
676 d->prevBez.isValid =
false;
681QStringList QQuickPath::attributes()
const
683 Q_D(
const QQuickPath);
684 if (!d->componentComplete) {
688 for (QQuickPathElement *pathElement : d->_pathElements) {
689 if (QQuickPathAttribute *attribute =
690 qobject_cast<QQuickPathAttribute *>(pathElement))
691 attrs.insert(attribute->name());
693 return attrs.values();
695 return d->_attributes;
698static inline QBezier nextBezier(
const QPainterPath &path,
int *current, qreal *bezLength,
bool reverse =
false)
700 const int lastElement = reverse ? 0 : path.elementCount() - 1;
701 const int start = reverse ? *current - 1 : *current + 1;
702 for (
int i=start; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
703 const QPainterPath::Element &e = path.elementAt(i);
706 case QPainterPath::MoveToElement:
708 case QPainterPath::LineToElement:
710 QLineF line(path.elementAt(i-1), e);
711 *bezLength = line.length();
712 QPointF a = path.elementAt(i-1);
713 QPointF delta = e - a;
715 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
717 case QPainterPath::CurveToElement:
719 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
722 path.elementAt(i+2));
723 *bezLength = b.length();
731 *current = lastElement;
736static inline int segmentCount(
const QPainterPath &path, qreal pathLength)
740 if (path.elementCount() == 2
741 && path.elementAt(0).type == QPainterPath::MoveToElement
742 && path.elementAt(1).type == QPainterPath::LineToElement) {
747 return qCeil(pathLength*5);
751static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
753 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
756void QQuickPath::createPointCache()
const
758 Q_D(
const QQuickPath);
759 qreal pathLength = d->pathLength;
760 if (pathLength <= 0 || qt_is_nan(pathLength))
763 const int segments = segmentCount(d->_path, pathLength);
764 const int lastElement = d->_path.elementCount() - 1;
765 d->_pointCache.resize(segments+1);
767 int currElement = -1;
769 QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
770 qreal currLength = bezLength;
771 qreal epc = currLength / pathLength;
773 for (
int i = 0; i < d->_pointCache.size(); i++) {
775 qreal prevPercent = 0;
776 qreal prevOrigPercent = 0;
777 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
778 qreal percent = qreal(i)/segments;
779 const AttributePoint &point = d->_attributePoints.at(ii);
780 if (percent < point.percent || ii == d->_attributePoints.size() - 1) {
781 qreal elementPercent = (percent - prevPercent);
783 qreal spc = prevOrigPercent + elementPercent * point.scale;
786 if (currElement > lastElement)
788 currBez = nextBezier(d->_path, &currElement, &bezLength);
789 if (bezLength == 0.0) {
790 currLength = pathLength;
794 currLength += bezLength;
795 epc = currLength / pathLength;
797 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
798 d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
801 prevOrigPercent = point.origpercent;
802 prevPercent = point.percent;
807void QQuickPath::invalidateSequentialHistory()
const
809 Q_D(
const QQuickPath);
810 d->prevBez.isValid =
false;
814
815
816
817
818
819
820
821void QQuickPath::setSimplify(
bool s)
824 if (d->simplify == s)
830 emit simplifyChanged();
833bool QQuickPath::simplify()
const
835 Q_D(
const QQuickPath);
840
841
842
843
844
845
846
847
848bool QQuickPath::isAsynchronous()
const
850 Q_D(
const QQuickPath);
851 return d->asynchronous;
854void QQuickPath::setAsynchronous(
bool a)
857 if (d->asynchronous == a)
861 emit asynchronousChanged();
865
866
867
868
869
870
871
872
873
874
875QSizeF QQuickPath::scale()
const
877 Q_D(
const QQuickPath);
881void QQuickPath::setScale(
const QSizeF &scale)
884 if (scale == d->scale)
891QPointF QQuickPath::sequentialPointAt(qreal p, qreal *angle)
const
893 Q_D(
const QQuickPath);
894 return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
897QPointF QQuickPath::sequentialPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
899 Q_ASSERT(p >= 0.0 && p <= 1.0);
901 if (!prevBez.isValid)
902 return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
903 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
905 return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
906 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
909QPointF QQuickPath::forwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
911 if (pathLength <= 0 || qt_is_nan(pathLength))
912 return path.pointAtPercent(0);
914 const int lastElement = path.elementCount() - 1;
915 bool haveCachedBez = prevBez.isValid;
916 int currElement = haveCachedBez ? prevBez.element : -1;
917 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
918 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
919 qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
920 qreal epc = currLength / pathLength;
923 qreal prevPercent = 0;
924 qreal prevOrigPercent = 0;
925 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
927 const AttributePoint &point = attributePoints.at(ii);
928 if (percent < point.percent || ii == attributePoints.size() - 1) {
929 qreal elementPercent = (percent - prevPercent);
931 qreal spc = prevOrigPercent + elementPercent * point.scale;
934 Q_ASSERT(!(currElement > lastElement));
935 Q_UNUSED(lastElement);
936 currBez = nextBezier(path, &currElement, &bezLength);
937 currLength += bezLength;
938 epc = currLength / pathLength;
940 prevBez.element = currElement;
941 prevBez.bezLength = bezLength;
942 prevBez.currLength = currLength;
943 prevBez.bezier = currBez;
945 prevBez.isValid =
true;
947 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
950 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
951 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
952 *angle = QLineF(0, 0, m1, m2).angle();
955 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
957 prevOrigPercent = point.origpercent;
958 prevPercent = point.percent;
965QPointF QQuickPath::backwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
967 if (pathLength <= 0 || qt_is_nan(pathLength))
968 return path.pointAtPercent(0);
970 const int firstElement = 1;
971 bool haveCachedBez = prevBez.isValid;
972 int currElement = haveCachedBez ? prevBez.element : path.elementCount();
973 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
974 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength,
true );
975 qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
976 qreal prevLength = currLength - bezLength;
977 qreal epc = prevLength / pathLength;
979 for (
int ii = attributePoints.size() - 1; ii > 0; --ii) {
981 const AttributePoint &point = attributePoints.at(ii);
982 const AttributePoint &prevPoint = attributePoints.at(ii-1);
983 if (percent > prevPoint.percent || ii == 1) {
984 qreal elementPercent = (percent - prevPoint.percent);
986 qreal spc = prevPoint.origpercent + elementPercent * point.scale;
989 Q_ASSERT(!(currElement < firstElement));
990 Q_UNUSED(firstElement);
991 currBez = nextBezier(path, &currElement, &bezLength,
true );
994 currLength = (currElement == firstElement) ? bezLength : prevLength;
995 prevLength = currLength - bezLength;
996 epc = prevLength / pathLength;
998 prevBez.element = currElement;
999 prevBez.bezLength = bezLength;
1000 prevBez.currLength = currLength;
1001 prevBez.bezier = currBez;
1003 prevBez.isValid =
true;
1005 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
1008 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
1009 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
1010 *angle = QLineF(0, 0, m1, m2).angle();
1013 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
1017 return QPointF(0,0);
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036QPointF QQuickPath::pointAtPercent(qreal t)
const
1038 Q_D(
const QQuickPath);
1040 return d->_path.pointAtPercent(t);
1042 if (d->_pointCache.isEmpty()) {
1044 if (d->_pointCache.isEmpty())
1048 const int segmentCount = d->_pointCache.size() - 1;
1049 qreal idxf = t*segmentCount;
1050 int idx1 = qFloor(idxf);
1051 qreal delta = idxf - idx1;
1052 if (idx1 > segmentCount)
1053 idx1 = segmentCount;
1058 return d->_pointCache.at(idx1);
1061 int idx2 = qCeil(idxf);
1062 if (idx2 > segmentCount)
1063 idx2 = segmentCount;
1067 QPointF p1 = d->_pointCache.at(idx1);
1068 QPointF p2 = d->_pointCache.at(idx2);
1069 QPointF pos = p1 * (1.0-delta) + p2 * delta;
1074qreal QQuickPath::attributeAt(
const QString &name, qreal percent)
const
1076 Q_D(
const QQuickPath);
1077 if (percent < 0 || percent > 1)
1080 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
1081 const AttributePoint &point = d->_attributePoints.at(ii);
1083 if (point.percent == percent) {
1084 return point.values.value(name);
1085 }
else if (point.percent > percent) {
1087 ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
1089 ii?(d->_attributePoints.at(ii - 1).percent):0;
1090 qreal curValue = point.values.value(name);
1091 qreal curPercent = point.percent;
1093 return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
1102qreal QQuickCurve::x()
const
1104 return _x.isValid() ? _x.value() : 0;
1107void QQuickCurve::setX(qreal x)
1109 if (!_x.isValid() || _x != x) {
1116bool QQuickCurve::hasX()
1118 return _x.isValid();
1121qreal QQuickCurve::y()
const
1123 return _y.isValid() ? _y.value() : 0;
1126void QQuickCurve::setY(qreal y)
1128 if (!_y.isValid() || _y != y) {
1135bool QQuickCurve::hasY()
1137 return _y.isValid();
1140qreal QQuickCurve::relativeX()
const
1145void QQuickCurve::setRelativeX(qreal x)
1147 if (!_relativeX.isValid() || _relativeX != x) {
1149 emit relativeXChanged();
1154bool QQuickCurve::hasRelativeX()
1156 return _relativeX.isValid();
1159qreal QQuickCurve::relativeY()
const
1164void QQuickCurve::setRelativeY(qreal y)
1166 if (!_relativeY.isValid() || _relativeY != y) {
1168 emit relativeYChanged();
1173bool QQuickCurve::hasRelativeY()
1175 return _relativeY.isValid();
1178#ifndef QT_NO_DEBUG_STREAM
1181 QDebugStateSaver saver(debug);
1182 debug.nospace() << curve->metaObject()->className() <<
'(' << (
const void *)curve;
1183 if (!curve->objectName().isEmpty())
1184 debug <<
" name=" << curve->objectName();
1185 debug <<
" x=" << curve->x();
1186 debug <<
" y=" << curve->y();
1187 debug <<
" relativeX=" << curve->relativeX();
1188 debug <<
" relativeY=" << curve->relativeY();
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1232
1233
1234
1235
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1250
1251
1253QString QQuickPathAttribute::name()
const
1258void QQuickPathAttribute::setName(
const QString &name)
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1303
1304
1305qreal QQuickPathAttribute::value()
const
1310void QQuickPathAttribute::setValue(qreal value)
1312 if (_value != value) {
1314 emit valueChanged();
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1342
1343
1344
1345
1346
1347
1348
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1367 QQuickCurve *curve = data.curves.at(data
.index);
1368 bool isEnd = data
.index == data.curves.size() - 1;
1369 return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
1370 curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
1373void QQuickPathLine::addToPath(QPainterPath &path,
const QQuickPathData &data)
1375 path.lineTo(positionForCurve(data, path.currentPosition()));
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1408
1409
1410
1411
1412
1413
1414
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1431void QQuickPathMove::addToPath(QPainterPath &path,
const QQuickPathData &data)
1433 path.moveTo(positionForCurve(data, path.currentPosition()));
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1463
1464
1465
1466
1469
1470
1471
1472
1473
1474
1475
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1493
1494
1495
1496
1497
1500
1501
1502qreal QQuickPathQuad::controlX()
const
1507void QQuickPathQuad::setControlX(qreal x)
1509 if (_controlX != x) {
1511 emit controlXChanged();
1518
1519
1520qreal QQuickPathQuad::controlY()
const
1525void QQuickPathQuad::setControlY(qreal y)
1527 if (_controlY != y) {
1529 emit controlYChanged();
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1549qreal QQuickPathQuad::relativeControlX()
const
1551 return _relativeControlX;
1554void QQuickPathQuad::setRelativeControlX(qreal x)
1556 if (!_relativeControlX.isValid() || _relativeControlX != x) {
1557 _relativeControlX = x;
1558 emit relativeControlXChanged();
1563bool QQuickPathQuad::hasRelativeControlX()
1565 return _relativeControlX.isValid();
1568qreal QQuickPathQuad::relativeControlY()
const
1570 return _relativeControlY;
1573void QQuickPathQuad::setRelativeControlY(qreal y)
1575 if (!_relativeControlY.isValid() || _relativeControlY != y) {
1576 _relativeControlY = y;
1577 emit relativeControlYChanged();
1582bool QQuickPathQuad::hasRelativeControlY()
1584 return _relativeControlY.isValid();
1587void QQuickPathQuad::addToPath(QPainterPath &path,
const QQuickPathData &data)
1589 const QPointF &prevPoint = path.currentPosition();
1590 QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
1591 hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
1592 path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1625
1626
1627
1628
1629
1630
1631
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1649
1650
1651
1652
1653
1654qreal QQuickPathCubic::control1X()
const
1659void QQuickPathCubic::setControl1X(qreal x)
1661 if (_control1X != x) {
1663 emit control1XChanged();
1668qreal QQuickPathCubic::control1Y()
const
1673void QQuickPathCubic::setControl1Y(qreal y)
1675 if (_control1Y != y) {
1677 emit control1YChanged();
1683
1684
1685
1686
1687
1688qreal QQuickPathCubic::control2X()
const
1693void QQuickPathCubic::setControl2X(qreal x)
1695 if (_control2X != x) {
1697 emit control2XChanged();
1702qreal QQuickPathCubic::control2Y()
const
1707void QQuickPathCubic::setControl2Y(qreal y)
1709 if (_control2Y != y) {
1711 emit control2YChanged();
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1733qreal QQuickPathCubic::relativeControl1X()
const
1735 return _relativeControl1X;
1738void QQuickPathCubic::setRelativeControl1X(qreal x)
1740 if (!_relativeControl1X.isValid() || _relativeControl1X != x) {
1741 _relativeControl1X = x;
1742 emit relativeControl1XChanged();
1747bool QQuickPathCubic::hasRelativeControl1X()
1749 return _relativeControl1X.isValid();
1752qreal QQuickPathCubic::relativeControl1Y()
const
1754 return _relativeControl1Y;
1757void QQuickPathCubic::setRelativeControl1Y(qreal y)
1759 if (!_relativeControl1Y.isValid() || _relativeControl1Y != y) {
1760 _relativeControl1Y = y;
1761 emit relativeControl1YChanged();
1766bool QQuickPathCubic::hasRelativeControl1Y()
1768 return _relativeControl1Y.isValid();
1771qreal QQuickPathCubic::relativeControl2X()
const
1773 return _relativeControl2X;
1776void QQuickPathCubic::setRelativeControl2X(qreal x)
1778 if (!_relativeControl2X.isValid() || _relativeControl2X != x) {
1779 _relativeControl2X = x;
1780 emit relativeControl2XChanged();
1785bool QQuickPathCubic::hasRelativeControl2X()
1787 return _relativeControl2X.isValid();
1790qreal QQuickPathCubic::relativeControl2Y()
const
1792 return _relativeControl2Y;
1795void QQuickPathCubic::setRelativeControl2Y(qreal y)
1797 if (!_relativeControl2Y.isValid() || _relativeControl2Y != y) {
1798 _relativeControl2Y = y;
1799 emit relativeControl2YChanged();
1804bool QQuickPathCubic::hasRelativeControl2Y()
1806 return _relativeControl2Y.isValid();
1809void QQuickPathCubic::addToPath(QPainterPath &path,
const QQuickPathData &data)
1811 const QPointF &prevPoint = path.currentPosition();
1812 QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
1813 hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
1814 QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
1815 hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
1816 path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1843
1844
1845
1846
1847
1848
1849
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1868 int count = path.elementCount();
1872 int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
1873 return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
1876void QQuickPathCatmullRomCurve::addToPath(QPainterPath &path,
const QQuickPathData &data)
1884 QPointF prevFar, prev, point, next;
1887 int index = data.index - 1;
1888 QQuickCurve *curve = index == -1 ? 0 : data.curves.at(index);
1889 if (qobject_cast<QQuickPathCatmullRomCurve*>(curve)) {
1890 prev = path.currentPosition();
1891 prevFar = previousPathPosition(path);
1893 prev = path.currentPosition();
1894 bool prevFarSet =
false;
1895 if (index == -1 && data.curves.size() > 1) {
1896 if (qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(data.curves.size()-1))) {
1899 QQuickPathData loopData;
1900 loopData.endPoint = data.endPoint;
1901 loopData.curves = data.curves;
1902 for (
int i = data.index; i < data.curves.size(); ++i) {
1904 pos = positionForCurve(loopData, pos);
1905 if (i == data.curves.size()-2)
1908 if (pos == QPointF(path.elementAt(0))) {
1920 point = positionForCurve(data, path.currentPosition());
1923 index = data.index + 1;
1924 if (index < data.curves.size() && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(index))) {
1925 QQuickPathData nextData;
1926 nextData.index = index;
1927 nextData.endPoint = data.endPoint;
1928 nextData.curves = data.curves;
1929 next = positionForCurve(nextData, point);
1931 if (point == QPointF(path.elementAt(0)) && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(0)) && path.elementCount() >= 3) {
1934 next = QPointF(path.elementAt(3));
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949 QPointF control1(prevFar.x() * qreal(-0.167) +
1951 point.x() * qreal(0.167),
1952 prevFar.y() * qreal(-0.167) +
1954 point.y() * qreal(0.167));
1956 QPointF control2(prev.x() * qreal(0.167) +
1958 next.x() * qreal(-0.167),
1959 prev.y() * qreal(0.167) +
1961 next.y() * qreal(-0.167));
1963 path.cubicTo(control1, control2, point);
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1993
1994
1995
1996
1997
1998
1999
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2032qreal QQuickPathArc::radiusX()
const
2037void QQuickPathArc::setRadiusX(qreal radius)
2039 if (_radiusX == radius)
2043 emit radiusXChanged();
2047qreal QQuickPathArc::radiusY()
const
2052void QQuickPathArc::setRadiusY(qreal radius)
2054 if (_radiusY == radius)
2058 emit radiusYChanged();
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2082bool QQuickPathArc::useLargeArc()
const
2084 return _useLargeArc;
2087void QQuickPathArc::setUseLargeArc(
bool largeArc)
2089 if (_useLargeArc == largeArc)
2092 _useLargeArc = largeArc;
2093 emit useLargeArcChanged();
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2115QQuickPathArc::ArcDirection QQuickPathArc::direction()
const
2120void QQuickPathArc::setDirection(ArcDirection direction)
2122 if (_direction == direction)
2125 _direction = direction;
2126 emit directionChanged();
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2152qreal QQuickPathArc::xAxisRotation()
const
2154 return _xAxisRotation;
2157void QQuickPathArc::setXAxisRotation(qreal rotation)
2159 if (_xAxisRotation == rotation)
2162 _xAxisRotation = rotation;
2163 emit xAxisRotationChanged();
2167void QQuickPathArc::addToPath(QPainterPath &path,
const QQuickPathData &data)
2169 const QPointF &startPoint = path.currentPosition();
2170 const QPointF &endPoint = positionForCurve(data, startPoint);
2171 QQuickSvgParser::pathArc(path,
2176 _direction == Clockwise ? 1 : 0,
2179 startPoint.x(), startPoint.y());
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2199
2200
2201
2202
2203
2205qreal QQuickPathAngleArc::centerX()
const
2210void QQuickPathAngleArc::setCenterX(qreal centerX)
2212 if (_centerX == centerX)
2216 emit centerXChanged();
2220qreal QQuickPathAngleArc::centerY()
const
2225void QQuickPathAngleArc::setCenterY(qreal centerY)
2227 if (_centerY == centerY)
2231 emit centerYChanged();
2236
2237
2238
2239
2240
2242qreal QQuickPathAngleArc::radiusX()
const
2247void QQuickPathAngleArc::setRadiusX(qreal radius)
2249 if (_radiusX == radius)
2253 emit radiusXChanged();
2257qreal QQuickPathAngleArc::radiusY()
const
2262void QQuickPathAngleArc::setRadiusY(qreal radius)
2264 if (_radiusY == radius)
2268 emit radiusYChanged();
2273
2274
2275
2276
2277
2278
2280qreal QQuickPathAngleArc::startAngle()
const
2285void QQuickPathAngleArc::setStartAngle(qreal angle)
2287 if (_startAngle == angle)
2290 _startAngle = angle;
2291 emit startAngleChanged();
2296
2297
2298
2299
2300
2301
2302
2304qreal QQuickPathAngleArc::sweepAngle()
const
2309void QQuickPathAngleArc::setSweepAngle(qreal angle)
2311 if (_sweepAngle == angle)
2314 _sweepAngle = angle;
2315 emit sweepAngleChanged();
2320
2321
2322
2323
2324
2325
2326
2327
2329bool QQuickPathAngleArc::moveToStart()
const
2331 return _moveToStart;
2334void QQuickPathAngleArc::setMoveToStart(
bool move)
2336 if (_moveToStart == move)
2339 _moveToStart = move;
2340 emit moveToStartChanged();
2344void QQuickPathAngleArc::addToPath(QPainterPath &path,
const QQuickPathData &)
2346 qreal x = _centerX - _radiusX;
2347 qreal y = _centerY - _radiusY;
2348 qreal width = _radiusX * 2;
2349 qreal height = _radiusY * 2;
2351 path.arcMoveTo(x, y, width, height, -_startAngle);
2352 path.arcTo(x, y, width, height, -_startAngle, -_sweepAngle);
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2382
2383
2384
2385
2386
2387
2388
2390QString QQuickPathSvg::path()
const
2395void QQuickPathSvg::setPath(
const QString &path)
2405void QQuickPathSvg::addToPath(QPainterPath &path,
const QQuickPathData &)
2407 QQuickSvgParser::parsePathDataFast(_path, path);
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2432
2433
2434
2435
2436
2437
2438
2439
2440
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2458
2459
2460
2461
2462
2463
2464
2466qreal QQuickPathRectangle::width()
const
2471void QQuickPathRectangle::setWidth(qreal width)
2473 if (_width == width)
2477 emit widthChanged();
2481qreal QQuickPathRectangle::height()
const
2486void QQuickPathRectangle::setHeight(qreal height)
2488 if (_height == height)
2492 emit heightChanged();
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2523qreal QQuickPathRectangle::strokeAdjustment()
const
2525 return _strokeAdjustment;
2528void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
2530 if (_strokeAdjustment == newStrokeAdjustment)
2532 _strokeAdjustment = newStrokeAdjustment;
2533 emit strokeAdjustmentChanged();
2538
2539
2540
2541
2543qreal QQuickPathRectangle::radius()
const
2545 return _extra.isAllocated() ? _extra->radius : 0;
2548void QQuickPathRectangle::setRadius(qreal newRadius)
2550 if (_extra.value().radius == newRadius)
2552 _extra->radius = newRadius;
2553 emit radiusChanged();
2554 if (!(_extra->isRadiusSet(Qt::TopLeftCorner)))
2555 emit topLeftRadiusChanged();
2556 if (!(_extra->isRadiusSet(Qt::TopRightCorner)))
2557 emit topRightRadiusChanged();
2558 if (!(_extra->isRadiusSet(Qt::BottomLeftCorner)))
2559 emit bottomLeftRadiusChanged();
2560 if (!(_extra->isRadiusSet(Qt::BottomRightCorner)))
2561 emit bottomRightRadiusChanged();
2566
2567
2569qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner)
const
2571 if (_extra.isAllocated())
2572 return (_extra->isRadiusSet(corner)) ? _extra->cornerRadii[corner] : _extra->radius;
2577void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
2579 if (_extra.value().cornerRadii[corner] == newCornerRadius
2580 && (_extra->isRadiusSet(corner)))
2582 _extra->cornerRadii[corner] = newCornerRadius;
2583 _extra->cornerProperties |= (1 << corner);
2585 emitCornerRadiusChanged(corner);
2588void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
2590 if (!_extra.isAllocated() || !(_extra->isRadiusSet(corner)))
2592 _extra->cornerProperties &= ~(1 << corner);
2593 emitCornerRadiusChanged(corner);
2596void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
2599 case Qt::TopLeftCorner:
2600 emit topLeftRadiusChanged();
2602 case Qt::TopRightCorner:
2603 emit topRightRadiusChanged();
2605 case Qt::BottomLeftCorner:
2606 emit bottomLeftRadiusChanged();
2608 case Qt::BottomRightCorner:
2609 emit bottomRightRadiusChanged();
2616
2617
2618
2619
2620
2622bool QQuickPathRectangle::hasBevel()
const
2624 return _extra.isAllocated() ? (_extra->cornerProperties & (1 << 8)) != 0 :
false;
2627void QQuickPathRectangle::setBevel(
bool bevel)
2629 if (((_extra.value().cornerProperties & (1 << 8)) != 0) == bevel)
2632 _extra->cornerProperties |= (1 << 8);
2634 _extra->cornerProperties &= ~(1 << 8);
2636 emit bevelChanged();
2637 if (!(_extra->isBevelSet(Qt::TopLeftCorner)))
2638 emit topLeftBevelChanged();
2639 if (!(_extra->isBevelSet(Qt::TopRightCorner)))
2640 emit topRightBevelChanged();
2641 if (!(_extra->isBevelSet(Qt::BottomLeftCorner)))
2642 emit bottomLeftBevelChanged();
2643 if (!(_extra->isBevelSet(Qt::BottomRightCorner)))
2644 emit bottomRightBevelChanged();
2648
2649
2650
2652bool QQuickPathRectangle::cornerBevel(Qt::Corner corner)
const
2654 if (!_extra.isAllocated())
2656 return _extra->isBevelSet(corner) || (_extra->cornerProperties & (1 << 8));
2659void QQuickPathRectangle::setCornerBevel(Qt::Corner corner,
bool newCornerBevel)
2661 if ((_extra.value().isBevelSet(corner)) == newCornerBevel)
2663 if (!newCornerBevel) {
2664 resetCornerBevel(corner);
2667 _extra->cornerProperties |= (1 << (corner + 4));
2668 emitCornerBevelChanged(corner);
2671void QQuickPathRectangle::resetCornerBevel(Qt::Corner corner)
2673 if (!_extra.isAllocated() || !(_extra->isBevelSet(corner)))
2675 _extra->cornerProperties &= ~(1 << (corner + 4));
2676 emitCornerBevelChanged(corner);
2679void QQuickPathRectangle::emitCornerBevelChanged(Qt::Corner corner)
2682 case Qt::TopLeftCorner:
2683 emit topLeftBevelChanged();
2685 case Qt::TopRightCorner:
2686 emit topRightBevelChanged();
2688 case Qt::BottomLeftCorner:
2689 emit bottomLeftBevelChanged();
2691 case Qt::BottomRightCorner:
2692 emit bottomRightBevelChanged();
2698void QQuickPathRectangle::addToPath(QPainterPath &path,
const QQuickPathData &data)
2700 QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
2702 qreal halfStroke = _strokeAdjustment * 0.5;
2703 rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
2707 if (!_extra.isAllocated()) {
2712 const qreal maxDiameter = qMin(rect.width(), rect.height());
2713 const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
2714 auto effectiveDiameter = [&](Qt::Corner corner) {
2715 qreal radius = _extra->cornerRadii[corner];
2716 return (_extra->isRadiusSet(corner)) ? qMin(maxDiameter, 2 * radius) : generalDiameter;
2718 const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
2719 const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
2720 const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
2721 const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
2723 path.moveTo(rect.left() + diamTL * 0.5, rect.top());
2725 if (!cornerBevel(Qt::TopRightCorner)) {
2727 path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
2730 path.lineTo(QPointF(rect.right() - diamTR * 0.5, rect.top()));
2731 path.lineTo(QPointF(rect.right(), rect.top() + diamTR * 0.5));
2735 path.lineTo(rect.topRight());
2739 if (!cornerBevel(Qt::BottomRightCorner)) {
2740 path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
2742 path.lineTo(QPointF(rect.right(), rect.bottom() - diamBR * 0.5));
2743 path.lineTo(QPointF(rect.right() - diamBR * 0.5, rect.bottom()));
2746 path.lineTo(rect.bottomRight());
2750 if (!cornerBevel(Qt::BottomLeftCorner)) {
2751 path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
2753 path.lineTo(QPointF(rect.left() + diamBL * 0.5, rect.bottom()));
2754 path.lineTo(QPointF(rect.left(), rect.bottom() - diamBL * 0.5));
2757 path.lineTo(rect.bottomLeft());
2761 if (!cornerBevel(Qt::TopLeftCorner))
2762 path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
2764 path.lineTo(QPointF(rect.left(), rect.top() + diamTL * 0.5));
2766 path.lineTo(rect.topLeft());
2768 path.closeSubpath();
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2857qreal QQuickPathPercent::value()
const
2862void QQuickPathPercent::setValue(qreal value)
2864 if (_value != value) {
2866 emit valueChanged();
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2899
2900
2901
2902
2905
2906
2907
2908
2909
2910
2911
2912
2913
2915QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
2919QVariant QQuickPathPolyline::path()
const
2921 return QVariant::fromValue(m_path);
2924void QQuickPathPolyline::setPath(
const QVariant &path)
2926 if (path.userType() == QMetaType::QPolygonF) {
2927 setPath(path.value<QPolygonF>());
2928 }
else if (path.canConvert<QList<QPointF>>()) {
2929 setPath(path.value<QList<QPointF>>());
2930 }
else if (path.canConvert<QVariantList>()) {
2933 QList<QPointF> pathList;
2934 QVariantList vl = path.value<QVariantList>();
2938 for (
const QVariant &v : vl)
2939 pathList.append(v.toPointF());
2942 qWarning() <<
"PathPolyline: path of type" << path.userType() <<
"not supported";
2946void QQuickPathPolyline::setPath(
const QList<QPointF> &path)
2948 if (m_path != path) {
2949 const QPointF &oldStart = start();
2951 const QPointF &newStart = start();
2953 if (oldStart != newStart)
2954 emit startChanged();
2959QPointF QQuickPathPolyline::start()
const
2961 if (m_path.size()) {
2962 const QPointF &p = m_path.first();
2968void QQuickPathPolyline::addToPath(QPainterPath &path,
const QQuickPathData &)
2970 if (m_path.size() < 2)
2973 path.moveTo(m_path.first());
2974 for (
int i = 1; i < m_path.size(); ++i)
2975 path.lineTo(m_path.at(i));
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3034
3035
3036
3037
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3051QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
3055QVariant QQuickPathMultiline::paths()
const
3057 return QVariant::fromValue(m_paths);
3060void QQuickPathMultiline::setPaths(
const QVariant &paths)
3062 if (paths.canConvert<QList<QPolygonF>>()) {
3063 const QList<QPolygonF> pathPolygons = paths.value<QList<QPolygonF>>();
3064 QList<QList<QPointF>> pathVectors;
3065 for (
const QPolygonF &p : pathPolygons)
3067 setPaths(pathVectors);
3068 }
else if (paths.canConvert<QList<QList<QPointF>>>()) {
3069 setPaths(paths.value<QList<QList<QPointF>>>());
3070 }
else if (paths.canConvert<QVariantList>()) {
3074 QList<QList<QPointF>> pathsList;
3075 QVariantList vll = paths.value<QVariantList>();
3076 for (
const QVariant &v : vll) {
3079 if (v.canConvert<QPolygonF>()) {
3080 pathsList.append(v.value<QPolygonF>());
3082 QVariantList vl = v.value<QVariantList>();
3084 for (
const QVariant &point : vl) {
3085 if (point.canConvert<QPointF>())
3086 l.append(point.toPointF());
3089 pathsList.append(l);
3092 setPaths(pathsList);
3094 qWarning() <<
"PathMultiline: paths of type" << paths.userType() <<
"not supported";
3095 setPaths(QList<QList<QPointF>>());
3099void QQuickPathMultiline::setPaths(
const QList<QList<QPointF>> &paths)
3101 if (m_paths != paths) {
3102 const QPointF &oldStart = start();
3104 const QPointF &newStart = start();
3105 emit pathsChanged();
3106 if (oldStart != newStart)
3107 emit startChanged();
3112QPointF QQuickPathMultiline::start()
const
3115 return m_paths.first().first();
3119void QQuickPathMultiline::addToPath(QPainterPath &path,
const QQuickPathData &)
3121 if (!m_paths.size())
3123 for (
const QList<QPointF> &p: m_paths) {
3124 path.moveTo(p.first());
3125 for (
int i = 1; i < p.size(); ++i)
3126 path.lineTo(p.at(i));
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3163
3164
3165
3166
3169
3170
3171
3172
3173
3174
3175
3176
3179
3180
3181
3182
3185
3186
3187
3188
3189
3190
3193
3194
3195
3196
3197
3198
3199
3202
3203
3204
3205
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3230
3231
3232
3233
3236
3237
3238
3239
3242
3243
3244
3245
3248
3249
3250
3251
3254
3255
3256
3257
3258
3259
3260
3263
3264
3265
3266
3267
3268
3271
3272
3273
3274
3275
3276
3279
3280
3281
3282
3283
3284
3287
3288
3289
3290
3293
3294
3295
3296
3299
3300
3301
3302
3303
3306
3307
3308
3309
3310
3313
3314
3315
3316
3317
3320
3321
3322
3323
3324
3325void QQuickPathText::updatePath()
const
3327 if (!_path.isEmpty())
3330 _path.addText(0.0, 0.0, _font, _text);
3333 QRectF brect = _path.boundingRect();
3334 _path.translate(_x, _y - brect.y());
3337void QQuickPathText::addToPath(QPainterPath &path)
3339 if (_text.isEmpty())
3342 path.addPath(_path);
3347#include "moc_qquickpath_p.cpp"
Combined button and popup list for selecting options.
QDebug operator<<(QDebug debug, const QQuickCurve *curve)
static qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
static QQuickPathPrivate * privatePath(QObject *object)
static int segmentCount(const QPainterPath &path, qreal pathLength)
QPointF positionForCurve(const QQuickPathData &data, const QPointF &prevPoint)
\qmltype PathLine \nativetype QQuickPathLine \inqmlmodule QtQuick
QPointF previousPathPosition(const QPainterPath &path)
\qmltype PathCurve \nativetype QQuickPathCatmullRomCurve \inqmlmodule QtQuick
static QBezier nextBezier(const QPainterPath &path, int *current, qreal *bezLength, bool reverse=false)
static void scalePath(QPainterPath &path, const QSizeF &scale)