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);
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
279QQmlListProperty<QQuickPathElement> QQuickPath::pathElements()
281 return QQmlListProperty<QQuickPathElement>(
this,
287 pathElements_replace,
288 pathElements_removeLast);
293 QQuickPath *path =
static_cast<QQuickPath*>(object);
295 return QQuickPathPrivate::get(path);
298QQuickPathElement *QQuickPath::pathElements_at(QQmlListProperty<QQuickPathElement> *property, qsizetype index)
300 QQuickPathPrivate *d = privatePath(property->object);
302 return d->_pathElements.at(index);
305void QQuickPath::pathElements_append(QQmlListProperty<QQuickPathElement> *property, QQuickPathElement *pathElement)
307 QQuickPathPrivate *d = privatePath(property->object);
308 d->appendPathElement(pathElement);
311qsizetype QQuickPath::pathElements_count(QQmlListProperty<QQuickPathElement> *property)
313 QQuickPathPrivate *d = privatePath(property->object);
315 return d->_pathElements.size();
318void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *property)
320 QQuickPathPrivate *d = privatePath(property->object);
321 d->clearPathElements();
324void QQuickPath::pathElements_replace(
325 QQmlListProperty<QQuickPathElement> *property, qsizetype position,
326 QQuickPathElement *pathElement)
328 privatePath(property->object)->replacePathElement(position, pathElement);
331void QQuickPath::pathElements_removeLast(QQmlListProperty<QQuickPathElement> *property)
333 privatePath(property->object)->removeLastPathElement();
336void QQuickPath::interpolate(
int idx,
const QString &name, qreal value)
339 interpolate(d->_attributePoints, idx, name, value);
342void QQuickPath::interpolate(QList<AttributePoint> &attributePoints,
int idx,
const QString &name, qreal value)
348 qreal lastPercent = 0;
349 int search = idx - 1;
351 const AttributePoint &point = attributePoints.at(search);
352 if (point.values.contains(name)) {
353 lastValue = point.values.value(name);
354 lastPercent = point.origpercent;
362 const AttributePoint &curPoint = attributePoints.at(idx);
364 for (
int ii = search; ii < idx; ++ii) {
365 AttributePoint &point = attributePoints[ii];
367 qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
368 point.values.insert(name, val);
372void QQuickPath::endpoint(
const QString &name)
375 const AttributePoint &first = d->_attributePoints.first();
376 qreal val = first.values.value(name);
377 for (
int ii = d->_attributePoints.size() - 1; ii >= 0; ii--) {
378 const AttributePoint &point = d->_attributePoints.at(ii);
379 if (point.values.contains(name)) {
380 for (
int jj = ii + 1; jj < d->_attributePoints.size(); ++jj) {
381 AttributePoint &setPoint = d->_attributePoints[jj];
382 setPoint.values.insert(name, val);
389void QQuickPath::endpoint(QList<AttributePoint> &attributePoints,
const QString &name)
391 const AttributePoint &first = attributePoints.first();
392 qreal val = first.values.value(name);
393 for (
int ii = attributePoints.size() - 1; ii >= 0; ii--) {
394 const AttributePoint &point = attributePoints.at(ii);
395 if (point.values.contains(name)) {
396 for (
int jj = ii + 1; jj < attributePoints.size(); ++jj) {
397 AttributePoint &setPoint = attributePoints[jj];
398 setPoint.values.insert(name, val);
405void QQuickPath::processPath()
409 if (!d->componentComplete)
412 if (!d->asynchronous) {
414 }
else if (!d->processPending) {
415 d->processPending =
true;
416 QMetaObject::invokeMethod(
this, &QQuickPath::doProcessPath, Qt::QueuedConnection);
420void QQuickPath::doProcessPath()
424 d->processPending =
false;
426 if (!d->componentComplete)
429 if (d->useCustomPath)
432 d->_pointCache.clear();
433 d->prevBez.isValid =
false;
435 if (d->isShapePath) {
437 d->_path = createShapePath(QPointF(), QPointF(), d->pathLength, &d->closed);
439 d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
443 d->_path = d->_path.simplified();
448inline static void scalePath(QPainterPath &path,
const QSizeF &scale)
450 const qreal xscale = scale.width();
451 const qreal yscale = scale.height();
452 if (xscale == 1 && yscale == 1)
455 for (
int i = 0; i < path.elementCount(); ++i) {
456 const QPainterPath::Element &element = path.elementAt(i);
457 path.setElementPositionAt(i, element.x * xscale, element.y * yscale);
461QPainterPath QQuickPath::createPath(
const QPointF &startPoint,
const QPointF &endPoint,
const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints,
bool *closed)
466 attributePoints.clear();
468 if (!d->componentComplete)
469 return QPainterPath();
473 AttributePoint first;
474 for (
int ii = 0; ii < attributes.size(); ++ii)
475 first.values[attributes.at(ii)] = 0;
476 attributePoints << first;
478 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
479 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
480 path.moveTo(startX, startY);
482 const QString percentString = QStringLiteral(
"_qfx_percent");
484 bool usesPercent =
false;
486 qCDebug(lcPath).nospace() <<
this <<
" is creating path starting at " << startPoint
487 <<
" and ending at " << endPoint <<
" with " << pathLength <<
" element(s):";
488 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
489 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
492 data.endPoint = endPoint;
493 data.curves = d->_pathCurves;
494 curve->addToPath(path, data);
496 p.origpercent = path.length();
497 attributePoints << p;
499 qCDebug(lcPath) <<
"- index" << index <<
"curve:" << data.curves.at(data.index);
500 }
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
501 AttributePoint &point = attributePoints.last();
502 point.values[attribute->name()] = attribute->value();
503 interpolate(attributePoints, attributePoints.size() - 1, attribute->name(), attribute->value());
504 qCDebug(lcPath) <<
"- index" << index <<
"attribute:" << attribute->value();
505 }
else if (QQuickPathPercent *percent = qobject_cast<QQuickPathPercent *>(pathElement)) {
506 AttributePoint &point = attributePoints.last();
507 point.values[percentString] = percent->value();
508 interpolate(attributePoints, attributePoints.size() - 1, percentString, percent->value());
509 qCDebug(lcPath) <<
"- index" << index <<
"percent:" << percent->value();
511 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
512 text->addToPath(path);
513 qCDebug(lcPath) <<
"- index" << index <<
"text:" << text->text();
518 const AttributePoint &last = attributePoints.constLast();
519 for (
int ii = 0; ii < attributes.size(); ++ii) {
520 if (!last.values.contains(attributes.at(ii)))
521 endpoint(attributePoints, attributes.at(ii));
523 if (usesPercent && !last.values.contains(percentString)) {
524 d->_attributePoints.last().values[percentString] = 1;
525 interpolate(d->_attributePoints.size() - 1, percentString, 1);
527 scalePath(path, d->scale);
530 qreal length = path.length();
531 qreal prevpercent = 0;
532 qreal prevorigpercent = 0;
533 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
534 const AttributePoint &point = attributePoints.at(ii);
535 if (point.values.contains(percentString)) {
537 qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
538 (point.values.value(percentString)-prevpercent);
539 attributePoints[ii].scale = scale;
541 attributePoints[ii].origpercent /= length;
542 attributePoints[ii].percent = point.values.value(percentString);
543 prevorigpercent = attributePoints.at(ii).origpercent;
544 prevpercent = attributePoints.at(ii).percent;
546 attributePoints[ii].origpercent /= length;
547 attributePoints[ii].percent = attributePoints.at(ii).origpercent;
552 QPointF end = path.currentPosition();
553 *closed = length > 0 && startX * d->scale.width() == end.x() && startY * d->scale.height() == end.y();
560QPainterPath QQuickPath::createShapePath(
const QPointF &startPoint,
const QPointF &endPoint, qreal &pathLength,
bool *closed)
564 if (!d->componentComplete)
565 return QPainterPath();
569 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
570 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
571 path.moveTo(startX, startY);
574 qCDebug(lcPath).nospace() <<
this <<
" is creating shape path from " << d->_pathCurves.size()
575 <<
" curve(s) with endPoint " << endPoint <<
":";
576 for (QQuickCurve *curve : std::as_const(d->_pathCurves)) {
579 data.endPoint = endPoint;
580 data.curves = d->_pathCurves;
581 curve->addToPath(path, data);
582 qCDebug(lcPath) <<
"- index" << data.index << data.curves.at(data.index);
586 for (QQuickPathText *text : std::as_const(d->_pathTexts))
587 text->addToPath(path);
590 QPointF end = path.currentPosition();
591 *closed = startX == end.x() && startY == end.y();
593 scalePath(path, d->scale);
598 path.setCachingEnabled(
true);
603void QQuickPath::classBegin()
606 d->componentComplete =
false;
609void QQuickPath::disconnectPathElements()
611 Q_D(
const QQuickPath);
613 for (QQuickPathElement *pathElement : d->_pathElements) {
615 disconnect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
619void QQuickPath::connectPathElements()
621 Q_D(
const QQuickPath);
623 for (QQuickPathElement *pathElement : d->_pathElements) {
625 connect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
629void QQuickPath::gatherAttributes()
633 QSet<QString> attributes;
635 Q_ASSERT(d->_pathCurves.isEmpty());
638 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
639 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
640 d->_pathCurves.append(curve);
641 else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
642 d->_pathTexts.append(text);
643 else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
644 attributes.insert(attribute->name());
647 d->_attributes = attributes.values();
650void QQuickPath::componentComplete()
653 d->componentComplete =
true;
660 connectPathElements();
663QPainterPath QQuickPath::path()
const
665 Q_D(
const QQuickPath);
669void QQuickPath::setPath(
const QPainterPath &path)
672 d->useCustomPath = !path.isEmpty();
673 d->_pointCache.clear();
674 d->prevBez.isValid =
false;
679QStringList QQuickPath::attributes()
const
681 Q_D(
const QQuickPath);
682 if (!d->componentComplete) {
686 for (QQuickPathElement *pathElement : d->_pathElements) {
687 if (QQuickPathAttribute *attribute =
688 qobject_cast<QQuickPathAttribute *>(pathElement))
689 attrs.insert(attribute->name());
691 return attrs.values();
693 return d->_attributes;
696static inline QBezier nextBezier(
const QPainterPath &path,
int *current, qreal *bezLength,
bool reverse =
false)
698 const int lastElement = reverse ? 0 : path.elementCount() - 1;
699 const int start = reverse ? *current - 1 : *current + 1;
700 for (
int i=start; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
701 const QPainterPath::Element &e = path.elementAt(i);
704 case QPainterPath::MoveToElement:
706 case QPainterPath::LineToElement:
708 QLineF line(path.elementAt(i-1), e);
709 *bezLength = line.length();
710 QPointF a = path.elementAt(i-1);
711 QPointF delta = e - a;
713 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
715 case QPainterPath::CurveToElement:
717 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
720 path.elementAt(i+2));
721 *bezLength = b.length();
729 *current = lastElement;
734static inline int segmentCount(
const QPainterPath &path, qreal pathLength)
738 if (path.elementCount() == 2
739 && path.elementAt(0).type == QPainterPath::MoveToElement
740 && path.elementAt(1).type == QPainterPath::LineToElement) {
745 return qCeil(pathLength*5);
749static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
751 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
754void QQuickPath::createPointCache()
const
756 Q_D(
const QQuickPath);
757 qreal pathLength = d->pathLength;
758 if (pathLength <= 0 || qt_is_nan(pathLength))
761 const int segments = segmentCount(d->_path, pathLength);
762 const int lastElement = d->_path.elementCount() - 1;
763 d->_pointCache.resize(segments+1);
765 int currElement = -1;
767 QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
768 qreal currLength = bezLength;
769 qreal epc = currLength / pathLength;
771 for (
int i = 0; i < d->_pointCache.size(); i++) {
773 qreal prevPercent = 0;
774 qreal prevOrigPercent = 0;
775 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
776 qreal percent = qreal(i)/segments;
777 const AttributePoint &point = d->_attributePoints.at(ii);
778 if (percent < point.percent || ii == d->_attributePoints.size() - 1) {
779 qreal elementPercent = (percent - prevPercent);
781 qreal spc = prevOrigPercent + elementPercent * point.scale;
784 if (currElement > lastElement)
786 currBez = nextBezier(d->_path, &currElement, &bezLength);
787 if (bezLength == 0.0) {
788 currLength = pathLength;
792 currLength += bezLength;
793 epc = currLength / pathLength;
795 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
796 d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
799 prevOrigPercent = point.origpercent;
800 prevPercent = point.percent;
805void QQuickPath::invalidateSequentialHistory()
const
807 Q_D(
const QQuickPath);
808 d->prevBez.isValid =
false;
812
813
814
815
816
817
818
819void QQuickPath::setSimplify(
bool s)
822 if (d->simplify == s)
828 emit simplifyChanged();
831bool QQuickPath::simplify()
const
833 Q_D(
const QQuickPath);
838
839
840
841
842
843
844
845
846bool QQuickPath::isAsynchronous()
const
848 Q_D(
const QQuickPath);
849 return d->asynchronous;
852void QQuickPath::setAsynchronous(
bool a)
855 if (d->asynchronous == a)
859 emit asynchronousChanged();
863
864
865
866
867
868
869
870
871
872
873QSizeF QQuickPath::scale()
const
875 Q_D(
const QQuickPath);
879void QQuickPath::setScale(
const QSizeF &scale)
882 if (scale == d->scale)
889QPointF QQuickPath::sequentialPointAt(qreal p, qreal *angle)
const
891 Q_D(
const QQuickPath);
892 return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
895QPointF QQuickPath::sequentialPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
897 Q_ASSERT(p >= 0.0 && p <= 1.0);
899 if (!prevBez.isValid)
900 return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
901 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
903 return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
904 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
907QPointF QQuickPath::forwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
909 if (pathLength <= 0 || qt_is_nan(pathLength))
910 return path.pointAtPercent(0);
912 const int lastElement = path.elementCount() - 1;
913 bool haveCachedBez = prevBez.isValid;
914 int currElement = haveCachedBez ? prevBez.element : -1;
915 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
916 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
917 qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
918 qreal epc = currLength / pathLength;
921 qreal prevPercent = 0;
922 qreal prevOrigPercent = 0;
923 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
925 const AttributePoint &point = attributePoints.at(ii);
926 if (percent < point.percent || ii == attributePoints.size() - 1) {
927 qreal elementPercent = (percent - prevPercent);
929 qreal spc = prevOrigPercent + elementPercent * point.scale;
932 Q_ASSERT(!(currElement > lastElement));
933 Q_UNUSED(lastElement);
934 currBez = nextBezier(path, &currElement, &bezLength);
935 currLength += bezLength;
936 epc = currLength / pathLength;
938 prevBez.element = currElement;
939 prevBez.bezLength = bezLength;
940 prevBez.currLength = currLength;
941 prevBez.bezier = currBez;
943 prevBez.isValid =
true;
945 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
948 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
949 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
950 *angle = QLineF(0, 0, m1, m2).angle();
953 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
955 prevOrigPercent = point.origpercent;
956 prevPercent = point.percent;
963QPointF QQuickPath::backwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
965 if (pathLength <= 0 || qt_is_nan(pathLength))
966 return path.pointAtPercent(0);
968 const int firstElement = 1;
969 bool haveCachedBez = prevBez.isValid;
970 int currElement = haveCachedBez ? prevBez.element : path.elementCount();
971 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
972 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength,
true );
973 qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
974 qreal prevLength = currLength - bezLength;
975 qreal epc = prevLength / pathLength;
977 for (
int ii = attributePoints.size() - 1; ii > 0; --ii) {
979 const AttributePoint &point = attributePoints.at(ii);
980 const AttributePoint &prevPoint = attributePoints.at(ii-1);
981 if (percent > prevPoint.percent || ii == 1) {
982 qreal elementPercent = (percent - prevPoint.percent);
984 qreal spc = prevPoint.origpercent + elementPercent * point.scale;
987 Q_ASSERT(!(currElement < firstElement));
988 Q_UNUSED(firstElement);
989 currBez = nextBezier(path, &currElement, &bezLength,
true );
992 currLength = (currElement == firstElement) ? bezLength : prevLength;
993 prevLength = currLength - bezLength;
994 epc = prevLength / pathLength;
996 prevBez.element = currElement;
997 prevBez.bezLength = bezLength;
998 prevBez.currLength = currLength;
999 prevBez.bezier = currBez;
1001 prevBez.isValid =
true;
1003 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
1006 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
1007 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
1008 *angle = QLineF(0, 0, m1, m2).angle();
1011 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
1015 return QPointF(0,0);
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034QPointF QQuickPath::pointAtPercent(qreal t)
const
1036 Q_D(
const QQuickPath);
1038 return d->_path.pointAtPercent(t);
1040 if (d->_pointCache.isEmpty()) {
1042 if (d->_pointCache.isEmpty())
1046 const int segmentCount = d->_pointCache.size() - 1;
1047 qreal idxf = t*segmentCount;
1048 int idx1 = qFloor(idxf);
1049 qreal delta = idxf - idx1;
1050 if (idx1 > segmentCount)
1051 idx1 = segmentCount;
1056 return d->_pointCache.at(idx1);
1059 int idx2 = qCeil(idxf);
1060 if (idx2 > segmentCount)
1061 idx2 = segmentCount;
1065 QPointF p1 = d->_pointCache.at(idx1);
1066 QPointF p2 = d->_pointCache.at(idx2);
1067 QPointF pos = p1 * (1.0-delta) + p2 * delta;
1072qreal QQuickPath::attributeAt(
const QString &name, qreal percent)
const
1074 Q_D(
const QQuickPath);
1075 if (percent < 0 || percent > 1)
1078 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
1079 const AttributePoint &point = d->_attributePoints.at(ii);
1081 if (point.percent == percent) {
1082 return point.values.value(name);
1083 }
else if (point.percent > percent) {
1085 ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
1087 ii?(d->_attributePoints.at(ii - 1).percent):0;
1088 qreal curValue = point.values.value(name);
1089 qreal curPercent = point.percent;
1091 return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
1100qreal QQuickCurve::x()
const
1102 return _x.isValid() ? _x.value() : 0;
1105void QQuickCurve::setX(qreal x)
1107 if (!_x.isValid() || _x != x) {
1114bool QQuickCurve::hasX()
1116 return _x.isValid();
1119qreal QQuickCurve::y()
const
1121 return _y.isValid() ? _y.value() : 0;
1124void QQuickCurve::setY(qreal y)
1126 if (!_y.isValid() || _y != y) {
1133bool QQuickCurve::hasY()
1135 return _y.isValid();
1138qreal QQuickCurve::relativeX()
const
1143void QQuickCurve::setRelativeX(qreal x)
1145 if (!_relativeX.isValid() || _relativeX != x) {
1147 emit relativeXChanged();
1152bool QQuickCurve::hasRelativeX()
1154 return _relativeX.isValid();
1157qreal QQuickCurve::relativeY()
const
1162void QQuickCurve::setRelativeY(qreal y)
1164 if (!_relativeY.isValid() || _relativeY != y) {
1166 emit relativeYChanged();
1171bool QQuickCurve::hasRelativeY()
1173 return _relativeY.isValid();
1176#ifndef QT_NO_DEBUG_STREAM
1179 QDebugStateSaver saver(debug);
1180 debug.nospace() << curve->metaObject()->className() <<
'(' << (
const void *)curve;
1181 if (!curve->objectName().isEmpty())
1182 debug <<
" name=" << curve->objectName();
1183 debug <<
" x=" << curve->x();
1184 debug <<
" y=" << curve->y();
1185 debug <<
" relativeX=" << curve->relativeX();
1186 debug <<
" relativeY=" << curve->relativeY();
1195
1196
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
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1240
1241
1243QString QQuickPathAttribute::name()
const
1248void QQuickPathAttribute::setName(
const QString &name)
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1293
1294
1295qreal QQuickPathAttribute::value()
const
1300void QQuickPathAttribute::setValue(qreal value)
1302 if (_value != value) {
1304 emit valueChanged();
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1332
1333
1334
1335
1336
1337
1338
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1357 QQuickCurve *curve = data.curves.at(data
.index);
1358 bool isEnd = data
.index == data.curves.size() - 1;
1359 return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
1360 curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
1363void QQuickPathLine::addToPath(QPainterPath &path,
const QQuickPathData &data)
1365 path.lineTo(positionForCurve(data, path.currentPosition()));
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1398
1399
1400
1401
1402
1403
1404
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1421void QQuickPathMove::addToPath(QPainterPath &path,
const QQuickPathData &data)
1423 path.moveTo(positionForCurve(data, path.currentPosition()));
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1452
1453
1454
1455
1456
1457
1458
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1476
1477
1478
1479
1480
1483
1484
1485qreal QQuickPathQuad::controlX()
const
1490void QQuickPathQuad::setControlX(qreal x)
1492 if (_controlX != x) {
1494 emit controlXChanged();
1501
1502
1503qreal QQuickPathQuad::controlY()
const
1508void QQuickPathQuad::setControlY(qreal y)
1510 if (_controlY != y) {
1512 emit controlYChanged();
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1532qreal QQuickPathQuad::relativeControlX()
const
1534 return _relativeControlX;
1537void QQuickPathQuad::setRelativeControlX(qreal x)
1539 if (!_relativeControlX.isValid() || _relativeControlX != x) {
1540 _relativeControlX = x;
1541 emit relativeControlXChanged();
1546bool QQuickPathQuad::hasRelativeControlX()
1548 return _relativeControlX.isValid();
1551qreal QQuickPathQuad::relativeControlY()
const
1553 return _relativeControlY;
1556void QQuickPathQuad::setRelativeControlY(qreal y)
1558 if (!_relativeControlY.isValid() || _relativeControlY != y) {
1559 _relativeControlY = y;
1560 emit relativeControlYChanged();
1565bool QQuickPathQuad::hasRelativeControlY()
1567 return _relativeControlY.isValid();
1570void QQuickPathQuad::addToPath(QPainterPath &path,
const QQuickPathData &data)
1572 const QPointF &prevPoint = path.currentPosition();
1573 QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
1574 hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
1575 path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1608
1609
1610
1611
1612
1613
1614
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1632
1633
1634
1635
1636
1637qreal QQuickPathCubic::control1X()
const
1642void QQuickPathCubic::setControl1X(qreal x)
1644 if (_control1X != x) {
1646 emit control1XChanged();
1651qreal QQuickPathCubic::control1Y()
const
1656void QQuickPathCubic::setControl1Y(qreal y)
1658 if (_control1Y != y) {
1660 emit control1YChanged();
1666
1667
1668
1669
1670
1671qreal QQuickPathCubic::control2X()
const
1676void QQuickPathCubic::setControl2X(qreal x)
1678 if (_control2X != x) {
1680 emit control2XChanged();
1685qreal QQuickPathCubic::control2Y()
const
1690void QQuickPathCubic::setControl2Y(qreal y)
1692 if (_control2Y != y) {
1694 emit control2YChanged();
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1716qreal QQuickPathCubic::relativeControl1X()
const
1718 return _relativeControl1X;
1721void QQuickPathCubic::setRelativeControl1X(qreal x)
1723 if (!_relativeControl1X.isValid() || _relativeControl1X != x) {
1724 _relativeControl1X = x;
1725 emit relativeControl1XChanged();
1730bool QQuickPathCubic::hasRelativeControl1X()
1732 return _relativeControl1X.isValid();
1735qreal QQuickPathCubic::relativeControl1Y()
const
1737 return _relativeControl1Y;
1740void QQuickPathCubic::setRelativeControl1Y(qreal y)
1742 if (!_relativeControl1Y.isValid() || _relativeControl1Y != y) {
1743 _relativeControl1Y = y;
1744 emit relativeControl1YChanged();
1749bool QQuickPathCubic::hasRelativeControl1Y()
1751 return _relativeControl1Y.isValid();
1754qreal QQuickPathCubic::relativeControl2X()
const
1756 return _relativeControl2X;
1759void QQuickPathCubic::setRelativeControl2X(qreal x)
1761 if (!_relativeControl2X.isValid() || _relativeControl2X != x) {
1762 _relativeControl2X = x;
1763 emit relativeControl2XChanged();
1768bool QQuickPathCubic::hasRelativeControl2X()
1770 return _relativeControl2X.isValid();
1773qreal QQuickPathCubic::relativeControl2Y()
const
1775 return _relativeControl2Y;
1778void QQuickPathCubic::setRelativeControl2Y(qreal y)
1780 if (!_relativeControl2Y.isValid() || _relativeControl2Y != y) {
1781 _relativeControl2Y = y;
1782 emit relativeControl2YChanged();
1787bool QQuickPathCubic::hasRelativeControl2Y()
1789 return _relativeControl2Y.isValid();
1792void QQuickPathCubic::addToPath(QPainterPath &path,
const QQuickPathData &data)
1794 const QPointF &prevPoint = path.currentPosition();
1795 QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
1796 hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
1797 QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
1798 hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
1799 path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1825
1826
1827
1828
1829
1830
1831
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1850 int count = path.elementCount();
1854 int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
1855 return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
1858void QQuickPathCatmullRomCurve::addToPath(QPainterPath &path,
const QQuickPathData &data)
1866 QPointF prevFar, prev, point, next;
1869 int index = data.index - 1;
1870 QQuickCurve *curve = index == -1 ? 0 : data.curves.at(index);
1871 if (qobject_cast<QQuickPathCatmullRomCurve*>(curve)) {
1872 prev = path.currentPosition();
1873 prevFar = previousPathPosition(path);
1875 prev = path.currentPosition();
1876 bool prevFarSet =
false;
1877 if (index == -1 && data.curves.size() > 1) {
1878 if (qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(data.curves.size()-1))) {
1881 QQuickPathData loopData;
1882 loopData.endPoint = data.endPoint;
1883 loopData.curves = data.curves;
1884 for (
int i = data.index; i < data.curves.size(); ++i) {
1886 pos = positionForCurve(loopData, pos);
1887 if (i == data.curves.size()-2)
1890 if (pos == QPointF(path.elementAt(0))) {
1902 point = positionForCurve(data, path.currentPosition());
1905 index = data.index + 1;
1906 if (index < data.curves.size() && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(index))) {
1907 QQuickPathData nextData;
1908 nextData.index = index;
1909 nextData.endPoint = data.endPoint;
1910 nextData.curves = data.curves;
1911 next = positionForCurve(nextData, point);
1913 if (point == QPointF(path.elementAt(0)) && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(0)) && path.elementCount() >= 3) {
1916 next = QPointF(path.elementAt(3));
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931 QPointF control1(prevFar.x() * qreal(-0.167) +
1933 point.x() * qreal(0.167),
1934 prevFar.y() * qreal(-0.167) +
1936 point.y() * qreal(0.167));
1938 QPointF control2(prev.x() * qreal(0.167) +
1940 next.x() * qreal(-0.167),
1941 prev.y() * qreal(0.167) +
1943 next.y() * qreal(-0.167));
1945 path.cubicTo(control1, control2, point);
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1974
1975
1976
1977
1978
1979
1980
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2012qreal QQuickPathArc::radiusX()
const
2017void QQuickPathArc::setRadiusX(qreal radius)
2019 if (_radiusX == radius)
2023 emit radiusXChanged();
2027qreal QQuickPathArc::radiusY()
const
2032void QQuickPathArc::setRadiusY(qreal radius)
2034 if (_radiusY == radius)
2038 emit radiusYChanged();
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2061bool QQuickPathArc::useLargeArc()
const
2063 return _useLargeArc;
2066void QQuickPathArc::setUseLargeArc(
bool largeArc)
2068 if (_useLargeArc == largeArc)
2071 _useLargeArc = largeArc;
2072 emit useLargeArcChanged();
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2093QQuickPathArc::ArcDirection QQuickPathArc::direction()
const
2098void QQuickPathArc::setDirection(ArcDirection direction)
2100 if (_direction == direction)
2103 _direction = direction;
2104 emit directionChanged();
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2129qreal QQuickPathArc::xAxisRotation()
const
2131 return _xAxisRotation;
2134void QQuickPathArc::setXAxisRotation(qreal rotation)
2136 if (_xAxisRotation == rotation)
2139 _xAxisRotation = rotation;
2140 emit xAxisRotationChanged();
2144void QQuickPathArc::addToPath(QPainterPath &path,
const QQuickPathData &data)
2146 const QPointF &startPoint = path.currentPosition();
2147 const QPointF &endPoint = positionForCurve(data, startPoint);
2148 QQuickSvgParser::pathArc(path,
2153 _direction == Clockwise ? 1 : 0,
2156 startPoint.x(), startPoint.y());
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2176
2177
2178
2179
2180
2182qreal QQuickPathAngleArc::centerX()
const
2187void QQuickPathAngleArc::setCenterX(qreal centerX)
2189 if (_centerX == centerX)
2193 emit centerXChanged();
2197qreal QQuickPathAngleArc::centerY()
const
2202void QQuickPathAngleArc::setCenterY(qreal centerY)
2204 if (_centerY == centerY)
2208 emit centerYChanged();
2213
2214
2215
2216
2217
2219qreal QQuickPathAngleArc::radiusX()
const
2224void QQuickPathAngleArc::setRadiusX(qreal radius)
2226 if (_radiusX == radius)
2230 emit radiusXChanged();
2234qreal QQuickPathAngleArc::radiusY()
const
2239void QQuickPathAngleArc::setRadiusY(qreal radius)
2241 if (_radiusY == radius)
2245 emit radiusYChanged();
2250
2251
2252
2253
2254
2255
2257qreal QQuickPathAngleArc::startAngle()
const
2262void QQuickPathAngleArc::setStartAngle(qreal angle)
2264 if (_startAngle == angle)
2267 _startAngle = angle;
2268 emit startAngleChanged();
2273
2274
2275
2276
2277
2278
2279
2281qreal QQuickPathAngleArc::sweepAngle()
const
2286void QQuickPathAngleArc::setSweepAngle(qreal angle)
2288 if (_sweepAngle == angle)
2291 _sweepAngle = angle;
2292 emit sweepAngleChanged();
2297
2298
2299
2300
2301
2302
2303
2304
2306bool QQuickPathAngleArc::moveToStart()
const
2308 return _moveToStart;
2311void QQuickPathAngleArc::setMoveToStart(
bool move)
2313 if (_moveToStart == move)
2316 _moveToStart = move;
2317 emit moveToStartChanged();
2321void QQuickPathAngleArc::addToPath(QPainterPath &path,
const QQuickPathData &)
2323 qreal x = _centerX - _radiusX;
2324 qreal y = _centerY - _radiusY;
2325 qreal width = _radiusX * 2;
2326 qreal height = _radiusY * 2;
2328 path.arcMoveTo(x, y, width, height, -_startAngle);
2329 path.arcTo(x, y, width, height, -_startAngle, -_sweepAngle);
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2358
2359
2360
2361
2362
2363
2364
2366QString QQuickPathSvg::path()
const
2371void QQuickPathSvg::setPath(
const QString &path)
2381void QQuickPathSvg::addToPath(QPainterPath &path,
const QQuickPathData &)
2383 QQuickSvgParser::parsePathDataFast(_path, path);
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2408
2409
2410
2411
2412
2413
2414
2415
2416
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2434
2435
2436
2437
2438
2439
2440
2442qreal QQuickPathRectangle::width()
const
2447void QQuickPathRectangle::setWidth(qreal width)
2449 if (_width == width)
2453 emit widthChanged();
2457qreal QQuickPathRectangle::height()
const
2462void QQuickPathRectangle::setHeight(qreal height)
2464 if (_height == height)
2468 emit heightChanged();
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2499qreal QQuickPathRectangle::strokeAdjustment()
const
2501 return _strokeAdjustment;
2504void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
2506 if (_strokeAdjustment == newStrokeAdjustment)
2508 _strokeAdjustment = newStrokeAdjustment;
2509 emit strokeAdjustmentChanged();
2514
2515
2516
2517
2519qreal QQuickPathRectangle::radius()
const
2521 return _extra.isAllocated() ? _extra->radius : 0;
2524void QQuickPathRectangle::setRadius(qreal newRadius)
2526 if (_extra.value().radius == newRadius)
2528 _extra->radius = newRadius;
2529 emit radiusChanged();
2530 if (!(_extra->isRadiusSet(Qt::TopLeftCorner)))
2531 emit topLeftRadiusChanged();
2532 if (!(_extra->isRadiusSet(Qt::TopRightCorner)))
2533 emit topRightRadiusChanged();
2534 if (!(_extra->isRadiusSet(Qt::BottomLeftCorner)))
2535 emit bottomLeftRadiusChanged();
2536 if (!(_extra->isRadiusSet(Qt::BottomRightCorner)))
2537 emit bottomRightRadiusChanged();
2542
2543
2545qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner)
const
2547 if (_extra.isAllocated())
2548 return (_extra->isRadiusSet(corner)) ? _extra->cornerRadii[corner] : _extra->radius;
2553void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
2555 if (_extra.value().cornerRadii[corner] == newCornerRadius
2556 && (_extra->isRadiusSet(corner)))
2558 _extra->cornerRadii[corner] = newCornerRadius;
2559 _extra->cornerProperties |= (1 << corner);
2561 emitCornerRadiusChanged(corner);
2564void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
2566 if (!_extra.isAllocated() || !(_extra->isRadiusSet(corner)))
2568 _extra->cornerProperties &= ~(1 << corner);
2569 emitCornerRadiusChanged(corner);
2572void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
2575 case Qt::TopLeftCorner:
2576 emit topLeftRadiusChanged();
2578 case Qt::TopRightCorner:
2579 emit topRightRadiusChanged();
2581 case Qt::BottomLeftCorner:
2582 emit bottomLeftRadiusChanged();
2584 case Qt::BottomRightCorner:
2585 emit bottomRightRadiusChanged();
2592
2593
2594
2595
2596
2598bool QQuickPathRectangle::hasBevel()
const
2600 return _extra.isAllocated() ? (_extra->cornerProperties & (1 << 8)) != 0 :
false;
2603void QQuickPathRectangle::setBevel(
bool bevel)
2605 if (((_extra.value().cornerProperties & (1 << 8)) != 0) == bevel)
2608 _extra->cornerProperties |= (1 << 8);
2610 _extra->cornerProperties &= ~(1 << 8);
2612 emit bevelChanged();
2613 if (!(_extra->isBevelSet(Qt::TopLeftCorner)))
2614 emit topLeftBevelChanged();
2615 if (!(_extra->isBevelSet(Qt::TopRightCorner)))
2616 emit topRightBevelChanged();
2617 if (!(_extra->isBevelSet(Qt::BottomLeftCorner)))
2618 emit bottomLeftBevelChanged();
2619 if (!(_extra->isBevelSet(Qt::BottomRightCorner)))
2620 emit bottomRightBevelChanged();
2624
2625
2626
2628bool QQuickPathRectangle::cornerBevel(Qt::Corner corner)
const
2630 if (_extra.isAllocated())
2631 return _extra->isBevelSet(corner);
2636void QQuickPathRectangle::setCornerBevel(Qt::Corner corner,
bool newCornerBevel)
2638 if ((_extra.value().isBevelSet(corner)) == newCornerBevel)
2640 if (!newCornerBevel) {
2641 resetCornerBevel(corner);
2644 _extra->cornerProperties |= (1 << (corner + 4));
2645 emitCornerBevelChanged(corner);
2648void QQuickPathRectangle::resetCornerBevel(Qt::Corner corner)
2650 if (!_extra.isAllocated() || !(_extra->isBevelSet(corner)))
2652 _extra->cornerProperties &= ~(1 << (corner + 4));
2653 emitCornerBevelChanged(corner);
2656void QQuickPathRectangle::emitCornerBevelChanged(Qt::Corner corner)
2659 case Qt::TopLeftCorner:
2660 emit topLeftBevelChanged();
2662 case Qt::TopRightCorner:
2663 emit topRightBevelChanged();
2665 case Qt::BottomLeftCorner:
2666 emit bottomLeftBevelChanged();
2668 case Qt::BottomRightCorner:
2669 emit bottomRightBevelChanged();
2675void QQuickPathRectangle::addToPath(QPainterPath &path,
const QQuickPathData &data)
2677 QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
2679 qreal halfStroke = _strokeAdjustment * 0.5;
2680 rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
2684 if (!_extra.isAllocated()) {
2689 const qreal maxDiameter = qMin(rect.width(), rect.height());
2690 const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
2691 auto effectiveDiameter = [&](Qt::Corner corner) {
2692 qreal radius = _extra->cornerRadii[corner];
2693 return (_extra->isRadiusSet(corner)) ? qMin(maxDiameter, 2 * radius) : generalDiameter;
2695 const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
2696 const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
2697 const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
2698 const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
2700 path.moveTo(rect.left() + diamTL * 0.5, rect.top());
2702 if (!cornerBevel(Qt::TopRightCorner)) {
2704 path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
2707 path.lineTo(QPointF(rect.right() - diamTR * 0.5, rect.top()));
2708 path.lineTo(QPointF(rect.right(), rect.top() + diamTR * 0.5));
2712 path.lineTo(rect.topRight());
2716 if (!cornerBevel(Qt::BottomRightCorner)) {
2717 path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
2719 path.lineTo(QPointF(rect.right(), rect.bottom() - diamBR * 0.5));
2720 path.lineTo(QPointF(rect.right() - diamBR * 0.5, rect.bottom()));
2723 path.lineTo(rect.bottomRight());
2727 if (!cornerBevel(Qt::BottomLeftCorner)) {
2728 path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
2730 path.lineTo(QPointF(rect.left() + diamBL * 0.5, rect.bottom()));
2731 path.lineTo(QPointF(rect.left(), rect.bottom() - diamBL * 0.5));
2734 path.lineTo(rect.bottomLeft());
2738 if (!cornerBevel(Qt::TopLeftCorner))
2739 path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
2741 path.lineTo(QPointF(rect.left(), rect.top() + diamTL * 0.5));
2743 path.lineTo(rect.topLeft());
2745 path.closeSubpath();
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
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
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2832qreal QQuickPathPercent::value()
const
2837void QQuickPathPercent::setValue(qreal value)
2839 if (_value != value) {
2841 emit valueChanged();
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2874
2875
2876
2877
2880
2881
2882
2883
2884
2885
2886
2887
2888
2890QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
2894QVariant QQuickPathPolyline::path()
const
2896 return QVariant::fromValue(m_path);
2899void QQuickPathPolyline::setPath(
const QVariant &path)
2901 if (path.userType() == QMetaType::QPolygonF) {
2902 setPath(path.value<QPolygonF>());
2903 }
else if (path.canConvert<QVector<QPointF>>()) {
2904 setPath(path.value<QVector<QPointF>>());
2905 }
else if (path.canConvert<QVariantList>()) {
2908 QVector<QPointF> pathList;
2909 QVariantList vl = path.value<QVariantList>();
2913 for (
const QVariant &v : vl)
2914 pathList.append(v.toPointF());
2917 qWarning() <<
"PathPolyline: path of type" << path.userType() <<
"not supported";
2921void QQuickPathPolyline::setPath(
const QVector<QPointF> &path)
2923 if (m_path != path) {
2924 const QPointF &oldStart = start();
2926 const QPointF &newStart = start();
2928 if (oldStart != newStart)
2929 emit startChanged();
2934QPointF QQuickPathPolyline::start()
const
2936 if (m_path.size()) {
2937 const QPointF &p = m_path.first();
2943void QQuickPathPolyline::addToPath(QPainterPath &path,
const QQuickPathData &)
2945 if (m_path.size() < 2)
2948 path.moveTo(m_path.first());
2949 for (
int i = 1; i < m_path.size(); ++i)
2950 path.lineTo(m_path.at(i));
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
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
3009
3010
3011
3012
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3026QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
3030QVariant QQuickPathMultiline::paths()
const
3032 return QVariant::fromValue(m_paths);
3035void QQuickPathMultiline::setPaths(
const QVariant &paths)
3037 if (paths.canConvert<QVector<QPolygonF>>()) {
3038 const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>();
3039 QVector<QVector<QPointF>> pathVectors;
3040 for (
const QPolygonF &p : pathPolygons)
3042 setPaths(pathVectors);
3043 }
else if (paths.canConvert<QVector<QVector<QPointF>>>()) {
3044 setPaths(paths.value<QVector<QVector<QPointF>>>());
3045 }
else if (paths.canConvert<QVariantList>()) {
3049 QVector<QVector<QPointF>> pathsList;
3050 QVariantList vll = paths.value<QVariantList>();
3051 for (
const QVariant &v : vll) {
3054 if (v.canConvert<QPolygonF>()) {
3055 pathsList.append(v.value<QPolygonF>());
3057 QVariantList vl = v.value<QVariantList>();
3059 for (
const QVariant &point : vl) {
3060 if (point.canConvert<QPointF>())
3061 l.append(point.toPointF());
3064 pathsList.append(l);
3067 setPaths(pathsList);
3069 qWarning() <<
"PathMultiline: paths of type" << paths.userType() <<
"not supported";
3070 setPaths(QVector<QVector<QPointF>>());
3074void QQuickPathMultiline::setPaths(
const QVector<QVector<QPointF>> &paths)
3076 if (m_paths != paths) {
3077 const QPointF &oldStart = start();
3079 const QPointF &newStart = start();
3080 emit pathsChanged();
3081 if (oldStart != newStart)
3082 emit startChanged();
3087QPointF QQuickPathMultiline::start()
const
3090 return m_paths.first().first();
3094void QQuickPathMultiline::addToPath(QPainterPath &path,
const QQuickPathData &)
3096 if (!m_paths.size())
3098 for (
const QVector<QPointF> &p: m_paths) {
3099 path.moveTo(p.first());
3100 for (
int i = 1; i < p.size(); ++i)
3101 path.lineTo(p.at(i));
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3138
3139
3140
3141
3144
3145
3146
3147
3148
3149
3150
3151
3154
3155
3156
3157
3160
3161
3162
3163
3164
3165
3166
3167
3170
3171
3172
3173
3174
3175
3176
3179
3180
3181
3182
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3207
3208
3209
3210
3213
3214
3215
3216
3219
3220
3221
3222
3225
3226
3227
3228
3231
3232
3233
3234
3235
3236
3237
3240
3241
3242
3243
3244
3245
3246
3249
3250
3251
3252
3253
3254
3255
3256
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3304
3305
3306
3307
3308
3311
3312
3313
3314
3315
3318
3319
3320
3321
3322
3325
3326
3327
3328
3329
3330void QQuickPathText::updatePath()
const
3332 if (!_path.isEmpty())
3335 _path.addText(0.0, 0.0, _font, _text);
3338 QRectF brect = _path.boundingRect();
3339 _path.translate(_x, _y - brect.y());
3342void QQuickPathText::addToPath(QPainterPath &path)
3344 if (_text.isEmpty())
3347 path.addPath(_path);
3352#include "moc_qquickpath_p.cpp"
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)