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
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1246
1247
1249QString QQuickPathAttribute::name()
const
1254void QQuickPathAttribute::setName(
const QString &name)
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
1291
1292
1293
1294
1295
1296
1299
1300
1301qreal QQuickPathAttribute::value()
const
1306void QQuickPathAttribute::setValue(qreal value)
1308 if (_value != value) {
1310 emit valueChanged();
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1338
1339
1340
1341
1342
1343
1344
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1363 QQuickCurve *curve = data.curves.at(data
.index);
1364 bool isEnd = data
.index == data.curves.size() - 1;
1365 return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
1366 curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
1369void QQuickPathLine::addToPath(QPainterPath &path,
const QQuickPathData &data)
1371 path.lineTo(positionForCurve(data, path.currentPosition()));
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1404
1405
1406
1407
1408
1409
1410
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1427void QQuickPathMove::addToPath(QPainterPath &path,
const QQuickPathData &data)
1429 path.moveTo(positionForCurve(data, path.currentPosition()));
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1458
1459
1460
1461
1464
1465
1466
1467
1468
1469
1470
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1488
1489
1490
1491
1492
1495
1496
1497qreal QQuickPathQuad::controlX()
const
1502void QQuickPathQuad::setControlX(qreal x)
1504 if (_controlX != x) {
1506 emit controlXChanged();
1513
1514
1515qreal QQuickPathQuad::controlY()
const
1520void QQuickPathQuad::setControlY(qreal y)
1522 if (_controlY != y) {
1524 emit controlYChanged();
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1544qreal QQuickPathQuad::relativeControlX()
const
1546 return _relativeControlX;
1549void QQuickPathQuad::setRelativeControlX(qreal x)
1551 if (!_relativeControlX.isValid() || _relativeControlX != x) {
1552 _relativeControlX = x;
1553 emit relativeControlXChanged();
1558bool QQuickPathQuad::hasRelativeControlX()
1560 return _relativeControlX.isValid();
1563qreal QQuickPathQuad::relativeControlY()
const
1565 return _relativeControlY;
1568void QQuickPathQuad::setRelativeControlY(qreal y)
1570 if (!_relativeControlY.isValid() || _relativeControlY != y) {
1571 _relativeControlY = y;
1572 emit relativeControlYChanged();
1577bool QQuickPathQuad::hasRelativeControlY()
1579 return _relativeControlY.isValid();
1582void QQuickPathQuad::addToPath(QPainterPath &path,
const QQuickPathData &data)
1584 const QPointF &prevPoint = path.currentPosition();
1585 QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
1586 hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
1587 path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1620
1621
1622
1623
1624
1625
1626
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1644
1645
1646
1647
1648
1649qreal QQuickPathCubic::control1X()
const
1654void QQuickPathCubic::setControl1X(qreal x)
1656 if (_control1X != x) {
1658 emit control1XChanged();
1663qreal QQuickPathCubic::control1Y()
const
1668void QQuickPathCubic::setControl1Y(qreal y)
1670 if (_control1Y != y) {
1672 emit control1YChanged();
1678
1679
1680
1681
1682
1683qreal QQuickPathCubic::control2X()
const
1688void QQuickPathCubic::setControl2X(qreal x)
1690 if (_control2X != x) {
1692 emit control2XChanged();
1697qreal QQuickPathCubic::control2Y()
const
1702void QQuickPathCubic::setControl2Y(qreal y)
1704 if (_control2Y != y) {
1706 emit control2YChanged();
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1728qreal QQuickPathCubic::relativeControl1X()
const
1730 return _relativeControl1X;
1733void QQuickPathCubic::setRelativeControl1X(qreal x)
1735 if (!_relativeControl1X.isValid() || _relativeControl1X != x) {
1736 _relativeControl1X = x;
1737 emit relativeControl1XChanged();
1742bool QQuickPathCubic::hasRelativeControl1X()
1744 return _relativeControl1X.isValid();
1747qreal QQuickPathCubic::relativeControl1Y()
const
1749 return _relativeControl1Y;
1752void QQuickPathCubic::setRelativeControl1Y(qreal y)
1754 if (!_relativeControl1Y.isValid() || _relativeControl1Y != y) {
1755 _relativeControl1Y = y;
1756 emit relativeControl1YChanged();
1761bool QQuickPathCubic::hasRelativeControl1Y()
1763 return _relativeControl1Y.isValid();
1766qreal QQuickPathCubic::relativeControl2X()
const
1768 return _relativeControl2X;
1771void QQuickPathCubic::setRelativeControl2X(qreal x)
1773 if (!_relativeControl2X.isValid() || _relativeControl2X != x) {
1774 _relativeControl2X = x;
1775 emit relativeControl2XChanged();
1780bool QQuickPathCubic::hasRelativeControl2X()
1782 return _relativeControl2X.isValid();
1785qreal QQuickPathCubic::relativeControl2Y()
const
1787 return _relativeControl2Y;
1790void QQuickPathCubic::setRelativeControl2Y(qreal y)
1792 if (!_relativeControl2Y.isValid() || _relativeControl2Y != y) {
1793 _relativeControl2Y = y;
1794 emit relativeControl2YChanged();
1799bool QQuickPathCubic::hasRelativeControl2Y()
1801 return _relativeControl2Y.isValid();
1804void QQuickPathCubic::addToPath(QPainterPath &path,
const QQuickPathData &data)
1806 const QPointF &prevPoint = path.currentPosition();
1807 QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
1808 hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
1809 QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
1810 hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
1811 path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1837
1838
1839
1840
1841
1842
1843
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1862 int count = path.elementCount();
1866 int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
1867 return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
1870void QQuickPathCatmullRomCurve::addToPath(QPainterPath &path,
const QQuickPathData &data)
1878 QPointF prevFar, prev, point, next;
1881 int index = data.index - 1;
1882 QQuickCurve *curve = index == -1 ? 0 : data.curves.at(index);
1883 if (qobject_cast<QQuickPathCatmullRomCurve*>(curve)) {
1884 prev = path.currentPosition();
1885 prevFar = previousPathPosition(path);
1887 prev = path.currentPosition();
1888 bool prevFarSet =
false;
1889 if (index == -1 && data.curves.size() > 1) {
1890 if (qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(data.curves.size()-1))) {
1893 QQuickPathData loopData;
1894 loopData.endPoint = data.endPoint;
1895 loopData.curves = data.curves;
1896 for (
int i = data.index; i < data.curves.size(); ++i) {
1898 pos = positionForCurve(loopData, pos);
1899 if (i == data.curves.size()-2)
1902 if (pos == QPointF(path.elementAt(0))) {
1914 point = positionForCurve(data, path.currentPosition());
1917 index = data.index + 1;
1918 if (index < data.curves.size() && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(index))) {
1919 QQuickPathData nextData;
1920 nextData.index = index;
1921 nextData.endPoint = data.endPoint;
1922 nextData.curves = data.curves;
1923 next = positionForCurve(nextData, point);
1925 if (point == QPointF(path.elementAt(0)) && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(0)) && path.elementCount() >= 3) {
1928 next = QPointF(path.elementAt(3));
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943 QPointF control1(prevFar.x() * qreal(-0.167) +
1945 point.x() * qreal(0.167),
1946 prevFar.y() * qreal(-0.167) +
1948 point.y() * qreal(0.167));
1950 QPointF control2(prev.x() * qreal(0.167) +
1952 next.x() * qreal(-0.167),
1953 prev.y() * qreal(0.167) +
1955 next.y() * qreal(-0.167));
1957 path.cubicTo(control1, control2, point);
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1986
1987
1988
1989
1990
1991
1992
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2024qreal QQuickPathArc::radiusX()
const
2029void QQuickPathArc::setRadiusX(qreal radius)
2031 if (_radiusX == radius)
2035 emit radiusXChanged();
2039qreal QQuickPathArc::radiusY()
const
2044void QQuickPathArc::setRadiusY(qreal radius)
2046 if (_radiusY == radius)
2050 emit radiusYChanged();
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2073bool QQuickPathArc::useLargeArc()
const
2075 return _useLargeArc;
2078void QQuickPathArc::setUseLargeArc(
bool largeArc)
2080 if (_useLargeArc == largeArc)
2083 _useLargeArc = largeArc;
2084 emit useLargeArcChanged();
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2105QQuickPathArc::ArcDirection QQuickPathArc::direction()
const
2110void QQuickPathArc::setDirection(ArcDirection direction)
2112 if (_direction == direction)
2115 _direction = direction;
2116 emit directionChanged();
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2141qreal QQuickPathArc::xAxisRotation()
const
2143 return _xAxisRotation;
2146void QQuickPathArc::setXAxisRotation(qreal rotation)
2148 if (_xAxisRotation == rotation)
2151 _xAxisRotation = rotation;
2152 emit xAxisRotationChanged();
2156void QQuickPathArc::addToPath(QPainterPath &path,
const QQuickPathData &data)
2158 const QPointF &startPoint = path.currentPosition();
2159 const QPointF &endPoint = positionForCurve(data, startPoint);
2160 QQuickSvgParser::pathArc(path,
2165 _direction == Clockwise ? 1 : 0,
2168 startPoint.x(), startPoint.y());
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2188
2189
2190
2191
2192
2194qreal QQuickPathAngleArc::centerX()
const
2199void QQuickPathAngleArc::setCenterX(qreal centerX)
2201 if (_centerX == centerX)
2205 emit centerXChanged();
2209qreal QQuickPathAngleArc::centerY()
const
2214void QQuickPathAngleArc::setCenterY(qreal centerY)
2216 if (_centerY == centerY)
2220 emit centerYChanged();
2225
2226
2227
2228
2229
2231qreal QQuickPathAngleArc::radiusX()
const
2236void QQuickPathAngleArc::setRadiusX(qreal radius)
2238 if (_radiusX == radius)
2242 emit radiusXChanged();
2246qreal QQuickPathAngleArc::radiusY()
const
2251void QQuickPathAngleArc::setRadiusY(qreal radius)
2253 if (_radiusY == radius)
2257 emit radiusYChanged();
2262
2263
2264
2265
2266
2267
2269qreal QQuickPathAngleArc::startAngle()
const
2274void QQuickPathAngleArc::setStartAngle(qreal angle)
2276 if (_startAngle == angle)
2279 _startAngle = angle;
2280 emit startAngleChanged();
2285
2286
2287
2288
2289
2290
2291
2293qreal QQuickPathAngleArc::sweepAngle()
const
2298void QQuickPathAngleArc::setSweepAngle(qreal angle)
2300 if (_sweepAngle == angle)
2303 _sweepAngle = angle;
2304 emit sweepAngleChanged();
2309
2310
2311
2312
2313
2314
2315
2316
2318bool QQuickPathAngleArc::moveToStart()
const
2320 return _moveToStart;
2323void QQuickPathAngleArc::setMoveToStart(
bool move)
2325 if (_moveToStart == move)
2328 _moveToStart = move;
2329 emit moveToStartChanged();
2333void QQuickPathAngleArc::addToPath(QPainterPath &path,
const QQuickPathData &)
2335 qreal x = _centerX - _radiusX;
2336 qreal y = _centerY - _radiusY;
2337 qreal width = _radiusX * 2;
2338 qreal height = _radiusY * 2;
2340 path.arcMoveTo(x, y, width, height, -_startAngle);
2341 path.arcTo(x, y, width, height, -_startAngle, -_sweepAngle);
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2370
2371
2372
2373
2374
2375
2376
2378QString QQuickPathSvg::path()
const
2383void QQuickPathSvg::setPath(
const QString &path)
2393void QQuickPathSvg::addToPath(QPainterPath &path,
const QQuickPathData &)
2395 QQuickSvgParser::parsePathDataFast(_path, path);
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2420
2421
2422
2423
2424
2425
2426
2427
2428
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2446
2447
2448
2449
2450
2451
2452
2454qreal QQuickPathRectangle::width()
const
2459void QQuickPathRectangle::setWidth(qreal width)
2461 if (_width == width)
2465 emit widthChanged();
2469qreal QQuickPathRectangle::height()
const
2474void QQuickPathRectangle::setHeight(qreal height)
2476 if (_height == height)
2480 emit heightChanged();
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2511qreal QQuickPathRectangle::strokeAdjustment()
const
2513 return _strokeAdjustment;
2516void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
2518 if (_strokeAdjustment == newStrokeAdjustment)
2520 _strokeAdjustment = newStrokeAdjustment;
2521 emit strokeAdjustmentChanged();
2526
2527
2528
2529
2531qreal QQuickPathRectangle::radius()
const
2533 return _extra.isAllocated() ? _extra->radius : 0;
2536void QQuickPathRectangle::setRadius(qreal newRadius)
2538 if (_extra.value().radius == newRadius)
2540 _extra->radius = newRadius;
2541 emit radiusChanged();
2542 if (!(_extra->isRadiusSet(Qt::TopLeftCorner)))
2543 emit topLeftRadiusChanged();
2544 if (!(_extra->isRadiusSet(Qt::TopRightCorner)))
2545 emit topRightRadiusChanged();
2546 if (!(_extra->isRadiusSet(Qt::BottomLeftCorner)))
2547 emit bottomLeftRadiusChanged();
2548 if (!(_extra->isRadiusSet(Qt::BottomRightCorner)))
2549 emit bottomRightRadiusChanged();
2554
2555
2557qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner)
const
2559 if (_extra.isAllocated())
2560 return (_extra->isRadiusSet(corner)) ? _extra->cornerRadii[corner] : _extra->radius;
2565void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
2567 if (_extra.value().cornerRadii[corner] == newCornerRadius
2568 && (_extra->isRadiusSet(corner)))
2570 _extra->cornerRadii[corner] = newCornerRadius;
2571 _extra->cornerProperties |= (1 << corner);
2573 emitCornerRadiusChanged(corner);
2576void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
2578 if (!_extra.isAllocated() || !(_extra->isRadiusSet(corner)))
2580 _extra->cornerProperties &= ~(1 << corner);
2581 emitCornerRadiusChanged(corner);
2584void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
2587 case Qt::TopLeftCorner:
2588 emit topLeftRadiusChanged();
2590 case Qt::TopRightCorner:
2591 emit topRightRadiusChanged();
2593 case Qt::BottomLeftCorner:
2594 emit bottomLeftRadiusChanged();
2596 case Qt::BottomRightCorner:
2597 emit bottomRightRadiusChanged();
2604
2605
2606
2607
2608
2610bool QQuickPathRectangle::hasBevel()
const
2612 return _extra.isAllocated() ? (_extra->cornerProperties & (1 << 8)) != 0 :
false;
2615void QQuickPathRectangle::setBevel(
bool bevel)
2617 if (((_extra.value().cornerProperties & (1 << 8)) != 0) == bevel)
2620 _extra->cornerProperties |= (1 << 8);
2622 _extra->cornerProperties &= ~(1 << 8);
2624 emit bevelChanged();
2625 if (!(_extra->isBevelSet(Qt::TopLeftCorner)))
2626 emit topLeftBevelChanged();
2627 if (!(_extra->isBevelSet(Qt::TopRightCorner)))
2628 emit topRightBevelChanged();
2629 if (!(_extra->isBevelSet(Qt::BottomLeftCorner)))
2630 emit bottomLeftBevelChanged();
2631 if (!(_extra->isBevelSet(Qt::BottomRightCorner)))
2632 emit bottomRightBevelChanged();
2636
2637
2638
2640bool QQuickPathRectangle::cornerBevel(Qt::Corner corner)
const
2642 if (_extra.isAllocated())
2643 return _extra->isBevelSet(corner);
2648void QQuickPathRectangle::setCornerBevel(Qt::Corner corner,
bool newCornerBevel)
2650 if ((_extra.value().isBevelSet(corner)) == newCornerBevel)
2652 if (!newCornerBevel) {
2653 resetCornerBevel(corner);
2656 _extra->cornerProperties |= (1 << (corner + 4));
2657 emitCornerBevelChanged(corner);
2660void QQuickPathRectangle::resetCornerBevel(Qt::Corner corner)
2662 if (!_extra.isAllocated() || !(_extra->isBevelSet(corner)))
2664 _extra->cornerProperties &= ~(1 << (corner + 4));
2665 emitCornerBevelChanged(corner);
2668void QQuickPathRectangle::emitCornerBevelChanged(Qt::Corner corner)
2671 case Qt::TopLeftCorner:
2672 emit topLeftBevelChanged();
2674 case Qt::TopRightCorner:
2675 emit topRightBevelChanged();
2677 case Qt::BottomLeftCorner:
2678 emit bottomLeftBevelChanged();
2680 case Qt::BottomRightCorner:
2681 emit bottomRightBevelChanged();
2687void QQuickPathRectangle::addToPath(QPainterPath &path,
const QQuickPathData &data)
2689 QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
2691 qreal halfStroke = _strokeAdjustment * 0.5;
2692 rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
2696 if (!_extra.isAllocated()) {
2701 const qreal maxDiameter = qMin(rect.width(), rect.height());
2702 const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
2703 auto effectiveDiameter = [&](Qt::Corner corner) {
2704 qreal radius = _extra->cornerRadii[corner];
2705 return (_extra->isRadiusSet(corner)) ? qMin(maxDiameter, 2 * radius) : generalDiameter;
2707 const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
2708 const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
2709 const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
2710 const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
2712 path.moveTo(rect.left() + diamTL * 0.5, rect.top());
2714 if (!cornerBevel(Qt::TopRightCorner)) {
2716 path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
2719 path.lineTo(QPointF(rect.right() - diamTR * 0.5, rect.top()));
2720 path.lineTo(QPointF(rect.right(), rect.top() + diamTR * 0.5));
2724 path.lineTo(rect.topRight());
2728 if (!cornerBevel(Qt::BottomRightCorner)) {
2729 path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
2731 path.lineTo(QPointF(rect.right(), rect.bottom() - diamBR * 0.5));
2732 path.lineTo(QPointF(rect.right() - diamBR * 0.5, rect.bottom()));
2735 path.lineTo(rect.bottomRight());
2739 if (!cornerBevel(Qt::BottomLeftCorner)) {
2740 path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
2742 path.lineTo(QPointF(rect.left() + diamBL * 0.5, rect.bottom()));
2743 path.lineTo(QPointF(rect.left(), rect.bottom() - diamBL * 0.5));
2746 path.lineTo(rect.bottomLeft());
2750 if (!cornerBevel(Qt::TopLeftCorner))
2751 path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
2753 path.lineTo(QPointF(rect.left(), rect.top() + diamTL * 0.5));
2755 path.lineTo(rect.topLeft());
2757 path.closeSubpath();
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
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2844qreal QQuickPathPercent::value()
const
2849void QQuickPathPercent::setValue(qreal value)
2851 if (_value != value) {
2853 emit valueChanged();
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2886
2887
2888
2889
2892
2893
2894
2895
2896
2897
2898
2899
2900
2902QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
2906QVariant QQuickPathPolyline::path()
const
2908 return QVariant::fromValue(m_path);
2911void QQuickPathPolyline::setPath(
const QVariant &path)
2913 if (path.userType() == QMetaType::QPolygonF) {
2914 setPath(path.value<QPolygonF>());
2915 }
else if (path.canConvert<QVector<QPointF>>()) {
2916 setPath(path.value<QVector<QPointF>>());
2917 }
else if (path.canConvert<QVariantList>()) {
2920 QVector<QPointF> pathList;
2921 QVariantList vl = path.value<QVariantList>();
2925 for (
const QVariant &v : vl)
2926 pathList.append(v.toPointF());
2929 qWarning() <<
"PathPolyline: path of type" << path.userType() <<
"not supported";
2933void QQuickPathPolyline::setPath(
const QVector<QPointF> &path)
2935 if (m_path != path) {
2936 const QPointF &oldStart = start();
2938 const QPointF &newStart = start();
2940 if (oldStart != newStart)
2941 emit startChanged();
2946QPointF QQuickPathPolyline::start()
const
2948 if (m_path.size()) {
2949 const QPointF &p = m_path.first();
2955void QQuickPathPolyline::addToPath(QPainterPath &path,
const QQuickPathData &)
2957 if (m_path.size() < 2)
2960 path.moveTo(m_path.first());
2961 for (
int i = 1; i < m_path.size(); ++i)
2962 path.lineTo(m_path.at(i));
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
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3021
3022
3023
3024
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3038QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
3042QVariant QQuickPathMultiline::paths()
const
3044 return QVariant::fromValue(m_paths);
3047void QQuickPathMultiline::setPaths(
const QVariant &paths)
3049 if (paths.canConvert<QVector<QPolygonF>>()) {
3050 const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>();
3051 QVector<QVector<QPointF>> pathVectors;
3052 for (
const QPolygonF &p : pathPolygons)
3054 setPaths(pathVectors);
3055 }
else if (paths.canConvert<QVector<QVector<QPointF>>>()) {
3056 setPaths(paths.value<QVector<QVector<QPointF>>>());
3057 }
else if (paths.canConvert<QVariantList>()) {
3061 QVector<QVector<QPointF>> pathsList;
3062 QVariantList vll = paths.value<QVariantList>();
3063 for (
const QVariant &v : vll) {
3066 if (v.canConvert<QPolygonF>()) {
3067 pathsList.append(v.value<QPolygonF>());
3069 QVariantList vl = v.value<QVariantList>();
3071 for (
const QVariant &point : vl) {
3072 if (point.canConvert<QPointF>())
3073 l.append(point.toPointF());
3076 pathsList.append(l);
3079 setPaths(pathsList);
3081 qWarning() <<
"PathMultiline: paths of type" << paths.userType() <<
"not supported";
3082 setPaths(QVector<QVector<QPointF>>());
3086void QQuickPathMultiline::setPaths(
const QVector<QVector<QPointF>> &paths)
3088 if (m_paths != paths) {
3089 const QPointF &oldStart = start();
3091 const QPointF &newStart = start();
3092 emit pathsChanged();
3093 if (oldStart != newStart)
3094 emit startChanged();
3099QPointF QQuickPathMultiline::start()
const
3102 return m_paths.first().first();
3106void QQuickPathMultiline::addToPath(QPainterPath &path,
const QQuickPathData &)
3108 if (!m_paths.size())
3110 for (
const QVector<QPointF> &p: m_paths) {
3111 path.moveTo(p.first());
3112 for (
int i = 1; i < p.size(); ++i)
3113 path.lineTo(p.at(i));
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3150
3151
3152
3153
3156
3157
3158
3159
3160
3161
3162
3163
3166
3167
3168
3169
3172
3173
3174
3175
3176
3177
3178
3179
3182
3183
3184
3185
3186
3187
3188
3191
3192
3193
3194
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3219
3220
3221
3222
3225
3226
3227
3228
3231
3232
3233
3234
3237
3238
3239
3240
3243
3244
3245
3246
3247
3248
3249
3252
3253
3254
3255
3256
3257
3258
3261
3262
3263
3264
3265
3266
3267
3268
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3316
3317
3318
3319
3320
3323
3324
3325
3326
3327
3330
3331
3332
3333
3334
3337
3338
3339
3340
3341
3342void QQuickPathText::updatePath()
const
3344 if (!_path.isEmpty())
3347 _path.addText(0.0, 0.0, _font, _text);
3350 QRectF brect = _path.boundingRect();
3351 _path.translate(_x, _y - brect.y());
3354void QQuickPathText::addToPath(QPainterPath &path)
3356 if (_text.isEmpty())
3359 path.addPath(_path);
3364#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)