12#include <private/qbezier_p.h>
13#include <QtCore/qmath.h>
14#include <QtCore/private/qnumeric_p.h>
18Q_STATIC_LOGGING_CATEGORY(lcPath,
"qt.quick.shapes.path")
20void QQuickPathPrivate::enablePathElement(QQuickPathElement *pathElement)
24 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
25 _pathCurves.append(curve);
26 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
27 _pathTexts.append(text);
29 QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement);
30 if (attribute && !_attributes.contains(attribute->name()))
31 _attributes.append(attribute->name());
35 if (!_pathElements.contains(pathElement))
36 q->connect(pathElement, SIGNAL(changed()), q, SLOT(processPath()));
39void QQuickPathPrivate::disablePathElement(QQuickPathElement *pathElement)
43 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
44 _pathCurves.removeOne(curve);
45 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
46 _pathTexts.removeOne(text);
47 }
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
48 const QString name = attribute->name();
52 for (QQuickPathElement *other : std::as_const(_pathElements)) {
53 QQuickPathAttribute *otherAttribute = qobject_cast<QQuickPathAttribute *>(other);
54 if (otherAttribute && otherAttribute->name() == name) {
61 _attributes.removeOne(name);
65 if (!_pathElements.contains(pathElement))
66 q->disconnect(pathElement, SIGNAL(changed()), q, SLOT(processPath()));
70
71
72
73
74
75
76
77
78
79
80
81
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181QQuickPath::QQuickPath(QObject *parent)
182 : QObject(*(
new QQuickPathPrivate), parent)
186QQuickPath::QQuickPath(QQuickPathPrivate &dd, QObject *parent)
187 : QObject(dd, parent)
191QQuickPath::~QQuickPath()
196
197
198
199
200qreal QQuickPath::startX()
const
202 Q_D(
const QQuickPath);
203 return d->startX.isValid() ? d->startX.value() : 0;
206void QQuickPath::setStartX(qreal x)
209 if (d->startX.isValid() && qFuzzyCompare(x, d->startX))
212 emit startXChanged();
216bool QQuickPath::hasStartX()
const
218 Q_D(
const QQuickPath);
219 return d->startX.isValid();
222qreal QQuickPath::startY()
const
224 Q_D(
const QQuickPath);
225 return d->startY.isValid() ? d->startY.value() : 0;
228void QQuickPath::setStartY(qreal y)
231 if (d->startY.isValid() && qFuzzyCompare(y, d->startY))
234 emit startYChanged();
238bool QQuickPath::hasStartY()
const
240 Q_D(
const QQuickPath);
241 return d->startY.isValid();
245
246
247
248bool QQuickPath::isClosed()
const
250 Q_D(
const QQuickPath);
251 if (d->_pathElements.isEmpty())
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
281QQmlListProperty<QQuickPathElement> QQuickPath::pathElements()
283 return QQmlListProperty<QQuickPathElement>(
this,
289 pathElements_replace,
290 pathElements_removeLast);
295 QQuickPath *path =
static_cast<QQuickPath*>(object);
297 return QQuickPathPrivate::get(path);
300QQuickPathElement *QQuickPath::pathElements_at(QQmlListProperty<QQuickPathElement> *property, qsizetype index)
302 QQuickPathPrivate *d = privatePath(property->object);
304 return d->_pathElements.at(index);
307void QQuickPath::pathElements_append(QQmlListProperty<QQuickPathElement> *property, QQuickPathElement *pathElement)
309 QQuickPathPrivate *d = privatePath(property->object);
310 d->appendPathElement(pathElement);
313qsizetype QQuickPath::pathElements_count(QQmlListProperty<QQuickPathElement> *property)
315 QQuickPathPrivate *d = privatePath(property->object);
317 return d->_pathElements.size();
320void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *property)
322 QQuickPathPrivate *d = privatePath(property->object);
323 d->clearPathElements();
326void QQuickPath::pathElements_replace(
327 QQmlListProperty<QQuickPathElement> *property, qsizetype position,
328 QQuickPathElement *pathElement)
330 privatePath(property->object)->replacePathElement(position, pathElement);
333void QQuickPath::pathElements_removeLast(QQmlListProperty<QQuickPathElement> *property)
335 privatePath(property->object)->removeLastPathElement();
338void QQuickPath::interpolate(
int idx,
const QString &name, qreal value)
341 interpolate(d->_attributePoints, idx, name, value);
344void QQuickPath::interpolate(QList<AttributePoint> &attributePoints,
int idx,
const QString &name, qreal value)
350 qreal lastPercent = 0;
351 int search = idx - 1;
353 const AttributePoint &point = attributePoints.at(search);
354 if (point.values.contains(name)) {
355 lastValue = point.values.value(name);
356 lastPercent = point.origpercent;
364 const AttributePoint &curPoint = attributePoints.at(idx);
366 for (
int ii = search; ii < idx; ++ii) {
367 AttributePoint &point = attributePoints[ii];
369 qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
370 point.values.insert(name, val);
374void QQuickPath::endpoint(
const QString &name)
377 const AttributePoint &first = d->_attributePoints.first();
378 qreal val = first.values.value(name);
379 for (
int ii = d->_attributePoints.size() - 1; ii >= 0; ii--) {
380 const AttributePoint &point = d->_attributePoints.at(ii);
381 if (point.values.contains(name)) {
382 for (
int jj = ii + 1; jj < d->_attributePoints.size(); ++jj) {
383 AttributePoint &setPoint = d->_attributePoints[jj];
384 setPoint.values.insert(name, val);
391void QQuickPath::endpoint(QList<AttributePoint> &attributePoints,
const QString &name)
393 const AttributePoint &first = attributePoints.first();
394 qreal val = first.values.value(name);
395 for (
int ii = attributePoints.size() - 1; ii >= 0; ii--) {
396 const AttributePoint &point = attributePoints.at(ii);
397 if (point.values.contains(name)) {
398 for (
int jj = ii + 1; jj < attributePoints.size(); ++jj) {
399 AttributePoint &setPoint = attributePoints[jj];
400 setPoint.values.insert(name, val);
407void QQuickPath::processPath()
411 if (!d->componentComplete)
414 if (!d->asynchronous) {
416 }
else if (!d->processPending) {
417 d->processPending =
true;
418 QMetaObject::invokeMethod(
this, &QQuickPath::doProcessPath, Qt::QueuedConnection);
422void QQuickPath::doProcessPath()
426 d->processPending =
false;
428 if (!d->componentComplete)
431 if (d->useCustomPath)
434 d->_pointCache.clear();
435 d->prevBez.isValid =
false;
437 if (d->isShapePath) {
439 d->_path = createShapePath(QPointF(), QPointF(), d->pathLength, &d->closed);
441 d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
445 d->_path = d->_path.simplified();
450inline static void scalePath(QPainterPath &path,
const QSizeF &scale)
452 const qreal xscale = scale.width();
453 const qreal yscale = scale.height();
454 if (xscale == 1 && yscale == 1)
457 for (
int i = 0; i < path.elementCount(); ++i) {
458 const QPainterPath::Element &element = path.elementAt(i);
459 path.setElementPositionAt(i, element.x * xscale, element.y * yscale);
463QPainterPath QQuickPath::createPath(
const QPointF &startPoint,
const QPointF &endPoint,
const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints,
bool *closed)
468 attributePoints.clear();
470 if (!d->componentComplete)
471 return QPainterPath();
475 AttributePoint first;
476 for (
int ii = 0; ii < attributes.size(); ++ii)
477 first.values[attributes.at(ii)] = 0;
478 attributePoints << first;
480 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
481 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
482 path.moveTo(startX, startY);
484 const QString percentString = QStringLiteral(
"_qfx_percent");
486 bool usesPercent =
false;
488 qCDebug(lcPath).nospace() <<
this <<
" is creating path starting at " << startPoint
489 <<
" and ending at " << endPoint <<
" with " << pathLength <<
" element(s):";
490 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
491 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
494 data.endPoint = endPoint;
495 data.curves = d->_pathCurves;
496 curve->addToPath(path, data);
498 p.origpercent = path.length();
499 attributePoints << p;
501 qCDebug(lcPath) <<
"- index" << index <<
"curve:" << data.curves.at(data.index);
502 }
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
503 AttributePoint &point = attributePoints.last();
504 point.values[attribute->name()] = attribute->value();
505 interpolate(attributePoints, attributePoints.size() - 1, attribute->name(), attribute->value());
506 qCDebug(lcPath) <<
"- index" << index <<
"attribute:" << attribute->value();
507 }
else if (QQuickPathPercent *percent = qobject_cast<QQuickPathPercent *>(pathElement)) {
508 AttributePoint &point = attributePoints.last();
509 point.values[percentString] = percent->value();
510 interpolate(attributePoints, attributePoints.size() - 1, percentString, percent->value());
511 qCDebug(lcPath) <<
"- index" << index <<
"percent:" << percent->value();
513 }
else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
514 text->addToPath(path);
515 qCDebug(lcPath) <<
"- index" << index <<
"text:" << text->text();
520 const AttributePoint &last = attributePoints.constLast();
521 for (
int ii = 0; ii < attributes.size(); ++ii) {
522 if (!last.values.contains(attributes.at(ii)))
523 endpoint(attributePoints, attributes.at(ii));
525 if (usesPercent && !last.values.contains(percentString)) {
526 d->_attributePoints.last().values[percentString] = 1;
527 interpolate(d->_attributePoints.size() - 1, percentString, 1);
529 scalePath(path, d->scale);
532 qreal length = path.length();
533 qreal prevpercent = 0;
534 qreal prevorigpercent = 0;
535 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
536 const AttributePoint &point = attributePoints.at(ii);
537 if (point.values.contains(percentString)) {
539 qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
540 (point.values.value(percentString)-prevpercent);
541 attributePoints[ii].scale = scale;
543 attributePoints[ii].origpercent /= length;
544 attributePoints[ii].percent = point.values.value(percentString);
545 prevorigpercent = attributePoints.at(ii).origpercent;
546 prevpercent = attributePoints.at(ii).percent;
548 attributePoints[ii].origpercent /= length;
549 attributePoints[ii].percent = attributePoints.at(ii).origpercent;
554 QPointF end = path.currentPosition();
555 *closed = length > 0 && startX * d->scale.width() == end.x() && startY * d->scale.height() == end.y();
562QPainterPath QQuickPath::createShapePath(
const QPointF &startPoint,
const QPointF &endPoint, qreal &pathLength,
bool *closed)
566 if (!d->componentComplete)
567 return QPainterPath();
571 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
572 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
573 path.moveTo(startX, startY);
576 qCDebug(lcPath).nospace() <<
this <<
" is creating shape path from " << d->_pathCurves.size()
577 <<
" curve(s) with endPoint " << endPoint <<
":";
578 for (QQuickCurve *curve : std::as_const(d->_pathCurves)) {
581 data.endPoint = endPoint;
582 data.curves = d->_pathCurves;
583 curve->addToPath(path, data);
584 qCDebug(lcPath) <<
"- index" << data.index << data.curves.at(data.index);
588 for (QQuickPathText *text : std::as_const(d->_pathTexts))
589 text->addToPath(path);
592 QPointF end = path.currentPosition();
593 *closed = startX == end.x() && startY == end.y();
595 scalePath(path, d->scale);
600 path.setCachingEnabled(
true);
605void QQuickPath::classBegin()
608 d->componentComplete =
false;
611void QQuickPath::disconnectPathElements()
613 Q_D(
const QQuickPath);
615 for (QQuickPathElement *pathElement : d->_pathElements) {
617 disconnect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
621void QQuickPath::connectPathElements()
623 Q_D(
const QQuickPath);
625 for (QQuickPathElement *pathElement : d->_pathElements) {
627 connect(pathElement, SIGNAL(changed()),
this, SLOT(processPath()));
631void QQuickPath::gatherAttributes()
635 QSet<QString> attributes;
637 Q_ASSERT(d->_pathCurves.isEmpty());
640 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
641 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
642 d->_pathCurves.append(curve);
643 else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
644 d->_pathTexts.append(text);
645 else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
646 attributes.insert(attribute->name());
649 d->_attributes = attributes.values();
652void QQuickPath::componentComplete()
655 d->componentComplete =
true;
662 connectPathElements();
665QPainterPath QQuickPath::path()
const
667 Q_D(
const QQuickPath);
671void QQuickPath::setPath(
const QPainterPath &path)
674 d->useCustomPath = !path.isEmpty();
675 d->_pointCache.clear();
676 d->prevBez.isValid =
false;
681QStringList QQuickPath::attributes()
const
683 Q_D(
const QQuickPath);
684 if (!d->componentComplete) {
688 for (QQuickPathElement *pathElement : d->_pathElements) {
689 if (QQuickPathAttribute *attribute =
690 qobject_cast<QQuickPathAttribute *>(pathElement))
691 attrs.insert(attribute->name());
693 return attrs.values();
695 return d->_attributes;
698static inline QBezier nextBezier(
const QPainterPath &path,
int *current, qreal *bezLength,
bool reverse =
false)
700 const int lastElement = reverse ? 0 : path.elementCount() - 1;
701 const int start = reverse ? *current - 1 : *current + 1;
702 for (
int i=start; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
703 const QPainterPath::Element &e = path.elementAt(i);
706 case QPainterPath::MoveToElement:
708 case QPainterPath::LineToElement:
710 QLineF line(path.elementAt(i-1), e);
711 *bezLength = line.length();
712 QPointF a = path.elementAt(i-1);
713 QPointF delta = e - a;
715 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
717 case QPainterPath::CurveToElement:
719 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
722 path.elementAt(i+2));
723 *bezLength = b.length();
731 *current = lastElement;
736static inline int segmentCount(
const QPainterPath &path, qreal pathLength)
740 if (path.elementCount() == 2
741 && path.elementAt(0).type == QPainterPath::MoveToElement
742 && path.elementAt(1).type == QPainterPath::LineToElement) {
747 return qCeil(pathLength*5);
751static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
753 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
756void QQuickPath::createPointCache()
const
758 Q_D(
const QQuickPath);
759 qreal pathLength = d->pathLength;
760 if (pathLength <= 0 || qt_is_nan(pathLength))
763 const int segments = segmentCount(d->_path, pathLength);
764 const int lastElement = d->_path.elementCount() - 1;
765 d->_pointCache.resize(segments+1);
767 int currElement = -1;
769 QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
770 qreal currLength = bezLength;
771 qreal epc = currLength / pathLength;
773 for (
int i = 0; i < d->_pointCache.size(); i++) {
775 qreal prevPercent = 0;
776 qreal prevOrigPercent = 0;
777 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
778 qreal percent = qreal(i)/segments;
779 const AttributePoint &point = d->_attributePoints.at(ii);
780 if (percent < point.percent || ii == d->_attributePoints.size() - 1) {
781 qreal elementPercent = (percent - prevPercent);
783 qreal spc = prevOrigPercent + elementPercent * point.scale;
786 if (currElement > lastElement)
788 currBez = nextBezier(d->_path, &currElement, &bezLength);
789 if (bezLength == 0.0) {
790 currLength = pathLength;
794 currLength += bezLength;
795 epc = currLength / pathLength;
797 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
798 d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
801 prevOrigPercent = point.origpercent;
802 prevPercent = point.percent;
807void QQuickPath::invalidateSequentialHistory()
const
809 Q_D(
const QQuickPath);
810 d->prevBez.isValid =
false;
814
815
816
817
818
819
820
821void QQuickPath::setSimplify(
bool s)
824 if (d->simplify == s)
830 emit simplifyChanged();
833bool QQuickPath::simplify()
const
835 Q_D(
const QQuickPath);
840
841
842
843
844
845
846
847
848bool QQuickPath::isAsynchronous()
const
850 Q_D(
const QQuickPath);
851 return d->asynchronous;
854void QQuickPath::setAsynchronous(
bool a)
857 if (d->asynchronous == a)
861 emit asynchronousChanged();
865
866
867
868
869
870
871
872
873
874
875QSizeF QQuickPath::scale()
const
877 Q_D(
const QQuickPath);
881void QQuickPath::setScale(
const QSizeF &scale)
884 if (scale == d->scale)
891QPointF QQuickPath::sequentialPointAt(qreal p, qreal *angle)
const
893 Q_D(
const QQuickPath);
894 return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
897QPointF QQuickPath::sequentialPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
899 Q_ASSERT(p >= 0.0 && p <= 1.0);
901 if (!prevBez.isValid)
902 return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
903 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
905 return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
906 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
909QPointF QQuickPath::forwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
911 if (pathLength <= 0 || qt_is_nan(pathLength))
912 return path.pointAtPercent(0);
914 const int lastElement = path.elementCount() - 1;
915 bool haveCachedBez = prevBez.isValid;
916 int currElement = haveCachedBez ? prevBez.element : -1;
917 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
918 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
919 qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
920 qreal epc = currLength / pathLength;
923 qreal prevPercent = 0;
924 qreal prevOrigPercent = 0;
925 for (
int ii = 0; ii < attributePoints.size(); ++ii) {
927 const AttributePoint &point = attributePoints.at(ii);
928 if (percent < point.percent || ii == attributePoints.size() - 1) {
929 qreal elementPercent = (percent - prevPercent);
931 qreal spc = prevOrigPercent + elementPercent * point.scale;
934 Q_ASSERT(!(currElement > lastElement));
935 Q_UNUSED(lastElement);
936 currBez = nextBezier(path, &currElement, &bezLength);
937 currLength += bezLength;
938 epc = currLength / pathLength;
940 prevBez.element = currElement;
941 prevBez.bezLength = bezLength;
942 prevBez.currLength = currLength;
943 prevBez.bezier = currBez;
945 prevBez.isValid =
true;
947 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
950 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
951 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
952 *angle = QLineF(0, 0, m1, m2).angle();
955 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
957 prevOrigPercent = point.origpercent;
958 prevPercent = point.percent;
965QPointF QQuickPath::backwardsPointAt(
const QPainterPath &path,
const qreal &pathLength,
const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
967 if (pathLength <= 0 || qt_is_nan(pathLength))
968 return path.pointAtPercent(0);
970 const int firstElement = 1;
971 bool haveCachedBez = prevBez.isValid;
972 int currElement = haveCachedBez ? prevBez.element : path.elementCount();
973 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
974 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength,
true );
975 qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
976 qreal prevLength = currLength - bezLength;
977 qreal epc = prevLength / pathLength;
979 for (
int ii = attributePoints.size() - 1; ii > 0; --ii) {
981 const AttributePoint &point = attributePoints.at(ii);
982 const AttributePoint &prevPoint = attributePoints.at(ii-1);
983 if (percent > prevPoint.percent || ii == 1) {
984 qreal elementPercent = (percent - prevPoint.percent);
986 qreal spc = prevPoint.origpercent + elementPercent * point.scale;
989 Q_ASSERT(!(currElement < firstElement));
990 Q_UNUSED(firstElement);
991 currBez = nextBezier(path, &currElement, &bezLength,
true );
994 currLength = (currElement == firstElement) ? bezLength : prevLength;
995 prevLength = currLength - bezLength;
996 epc = prevLength / pathLength;
998 prevBez.element = currElement;
999 prevBez.bezLength = bezLength;
1000 prevBez.currLength = currLength;
1001 prevBez.bezier = currBez;
1003 prevBez.isValid =
true;
1005 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
1008 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
1009 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
1010 *angle = QLineF(0, 0, m1, m2).angle();
1013 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
1017 return QPointF(0,0);
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036QPointF QQuickPath::pointAtPercent(qreal t)
const
1038 Q_D(
const QQuickPath);
1040 return d->_path.pointAtPercent(t);
1042 if (d->_pointCache.isEmpty()) {
1044 if (d->_pointCache.isEmpty())
1048 const int segmentCount = d->_pointCache.size() - 1;
1049 qreal idxf = t*segmentCount;
1050 int idx1 = qFloor(idxf);
1051 qreal delta = idxf - idx1;
1052 if (idx1 > segmentCount)
1053 idx1 = segmentCount;
1058 return d->_pointCache.at(idx1);
1061 int idx2 = qCeil(idxf);
1062 if (idx2 > segmentCount)
1063 idx2 = segmentCount;
1067 QPointF p1 = d->_pointCache.at(idx1);
1068 QPointF p2 = d->_pointCache.at(idx2);
1069 QPointF pos = p1 * (1.0-delta) + p2 * delta;
1074qreal QQuickPath::attributeAt(
const QString &name, qreal percent)
const
1076 Q_D(
const QQuickPath);
1077 if (percent < 0 || percent > 1)
1080 for (
int ii = 0; ii < d->_attributePoints.size(); ++ii) {
1081 const AttributePoint &point = d->_attributePoints.at(ii);
1083 if (point.percent == percent) {
1084 return point.values.value(name);
1085 }
else if (point.percent > percent) {
1087 ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
1089 ii?(d->_attributePoints.at(ii - 1).percent):0;
1090 qreal curValue = point.values.value(name);
1091 qreal curPercent = point.percent;
1093 return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
1102qreal QQuickCurve::x()
const
1104 return _x.isValid() ? _x.value() : 0;
1107void QQuickCurve::setX(qreal x)
1109 if (!_x.isValid() || _x != x) {
1116bool QQuickCurve::hasX()
1118 return _x.isValid();
1121qreal QQuickCurve::y()
const
1123 return _y.isValid() ? _y.value() : 0;
1126void QQuickCurve::setY(qreal y)
1128 if (!_y.isValid() || _y != y) {
1135bool QQuickCurve::hasY()
1137 return _y.isValid();
1140qreal QQuickCurve::relativeX()
const
1145void QQuickCurve::setRelativeX(qreal x)
1147 if (!_relativeX.isValid() || _relativeX != x) {
1149 emit relativeXChanged();
1154bool QQuickCurve::hasRelativeX()
1156 return _relativeX.isValid();
1159qreal QQuickCurve::relativeY()
const
1164void QQuickCurve::setRelativeY(qreal y)
1166 if (!_relativeY.isValid() || _relativeY != y) {
1168 emit relativeYChanged();
1173bool QQuickCurve::hasRelativeY()
1175 return _relativeY.isValid();
1178#ifndef QT_NO_DEBUG_STREAM
1181 QDebugStateSaver saver(debug);
1182 debug.nospace() << curve->metaObject()->className() <<
'(' << (
const void *)curve;
1183 if (!curve->objectName().isEmpty())
1184 debug <<
" name=" << curve->objectName();
1185 debug <<
" x=" << curve->x();
1186 debug <<
" y=" << curve->y();
1187 debug <<
" relativeX=" << curve->relativeX();
1188 debug <<
" relativeY=" << curve->relativeY();
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1230
1231
1232
1233
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1248
1249
1251QString QQuickPathAttribute::name()
const
1256void QQuickPathAttribute::setName(
const QString &name)
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
1297
1298
1301
1302
1303qreal QQuickPathAttribute::value()
const
1308void QQuickPathAttribute::setValue(qreal value)
1310 if (_value != value) {
1312 emit valueChanged();
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1340
1341
1342
1343
1344
1345
1346
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1365 QQuickCurve *curve = data.curves.at(data
.index);
1366 bool isEnd = data
.index == data.curves.size() - 1;
1367 return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
1368 curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
1371void QQuickPathLine::addToPath(QPainterPath &path,
const QQuickPathData &data)
1373 path.lineTo(positionForCurve(data, path.currentPosition()));
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1406
1407
1408
1409
1410
1411
1412
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1429void QQuickPathMove::addToPath(QPainterPath &path,
const QQuickPathData &data)
1431 path.moveTo(positionForCurve(data, path.currentPosition()));
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1460
1461
1462
1463
1466
1467
1468
1469
1470
1471
1472
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1490
1491
1492
1493
1494
1497
1498
1499qreal QQuickPathQuad::controlX()
const
1504void QQuickPathQuad::setControlX(qreal x)
1506 if (_controlX != x) {
1508 emit controlXChanged();
1515
1516
1517qreal QQuickPathQuad::controlY()
const
1522void QQuickPathQuad::setControlY(qreal y)
1524 if (_controlY != y) {
1526 emit controlYChanged();
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1546qreal QQuickPathQuad::relativeControlX()
const
1548 return _relativeControlX;
1551void QQuickPathQuad::setRelativeControlX(qreal x)
1553 if (!_relativeControlX.isValid() || _relativeControlX != x) {
1554 _relativeControlX = x;
1555 emit relativeControlXChanged();
1560bool QQuickPathQuad::hasRelativeControlX()
1562 return _relativeControlX.isValid();
1565qreal QQuickPathQuad::relativeControlY()
const
1567 return _relativeControlY;
1570void QQuickPathQuad::setRelativeControlY(qreal y)
1572 if (!_relativeControlY.isValid() || _relativeControlY != y) {
1573 _relativeControlY = y;
1574 emit relativeControlYChanged();
1579bool QQuickPathQuad::hasRelativeControlY()
1581 return _relativeControlY.isValid();
1584void QQuickPathQuad::addToPath(QPainterPath &path,
const QQuickPathData &data)
1586 const QPointF &prevPoint = path.currentPosition();
1587 QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
1588 hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
1589 path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1622
1623
1624
1625
1626
1627
1628
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1646
1647
1648
1649
1650
1651qreal QQuickPathCubic::control1X()
const
1656void QQuickPathCubic::setControl1X(qreal x)
1658 if (_control1X != x) {
1660 emit control1XChanged();
1665qreal QQuickPathCubic::control1Y()
const
1670void QQuickPathCubic::setControl1Y(qreal y)
1672 if (_control1Y != y) {
1674 emit control1YChanged();
1680
1681
1682
1683
1684
1685qreal QQuickPathCubic::control2X()
const
1690void QQuickPathCubic::setControl2X(qreal x)
1692 if (_control2X != x) {
1694 emit control2XChanged();
1699qreal QQuickPathCubic::control2Y()
const
1704void QQuickPathCubic::setControl2Y(qreal y)
1706 if (_control2Y != y) {
1708 emit control2YChanged();
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1730qreal QQuickPathCubic::relativeControl1X()
const
1732 return _relativeControl1X;
1735void QQuickPathCubic::setRelativeControl1X(qreal x)
1737 if (!_relativeControl1X.isValid() || _relativeControl1X != x) {
1738 _relativeControl1X = x;
1739 emit relativeControl1XChanged();
1744bool QQuickPathCubic::hasRelativeControl1X()
1746 return _relativeControl1X.isValid();
1749qreal QQuickPathCubic::relativeControl1Y()
const
1751 return _relativeControl1Y;
1754void QQuickPathCubic::setRelativeControl1Y(qreal y)
1756 if (!_relativeControl1Y.isValid() || _relativeControl1Y != y) {
1757 _relativeControl1Y = y;
1758 emit relativeControl1YChanged();
1763bool QQuickPathCubic::hasRelativeControl1Y()
1765 return _relativeControl1Y.isValid();
1768qreal QQuickPathCubic::relativeControl2X()
const
1770 return _relativeControl2X;
1773void QQuickPathCubic::setRelativeControl2X(qreal x)
1775 if (!_relativeControl2X.isValid() || _relativeControl2X != x) {
1776 _relativeControl2X = x;
1777 emit relativeControl2XChanged();
1782bool QQuickPathCubic::hasRelativeControl2X()
1784 return _relativeControl2X.isValid();
1787qreal QQuickPathCubic::relativeControl2Y()
const
1789 return _relativeControl2Y;
1792void QQuickPathCubic::setRelativeControl2Y(qreal y)
1794 if (!_relativeControl2Y.isValid() || _relativeControl2Y != y) {
1795 _relativeControl2Y = y;
1796 emit relativeControl2YChanged();
1801bool QQuickPathCubic::hasRelativeControl2Y()
1803 return _relativeControl2Y.isValid();
1806void QQuickPathCubic::addToPath(QPainterPath &path,
const QQuickPathData &data)
1808 const QPointF &prevPoint = path.currentPosition();
1809 QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
1810 hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
1811 QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
1812 hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
1813 path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1839
1840
1841
1842
1843
1844
1845
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1864 int count = path.elementCount();
1868 int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
1869 return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
1872void QQuickPathCatmullRomCurve::addToPath(QPainterPath &path,
const QQuickPathData &data)
1880 QPointF prevFar, prev, point, next;
1883 int index = data.index - 1;
1884 QQuickCurve *curve = index == -1 ? 0 : data.curves.at(index);
1885 if (qobject_cast<QQuickPathCatmullRomCurve*>(curve)) {
1886 prev = path.currentPosition();
1887 prevFar = previousPathPosition(path);
1889 prev = path.currentPosition();
1890 bool prevFarSet =
false;
1891 if (index == -1 && data.curves.size() > 1) {
1892 if (qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(data.curves.size()-1))) {
1895 QQuickPathData loopData;
1896 loopData.endPoint = data.endPoint;
1897 loopData.curves = data.curves;
1898 for (
int i = data.index; i < data.curves.size(); ++i) {
1900 pos = positionForCurve(loopData, pos);
1901 if (i == data.curves.size()-2)
1904 if (pos == QPointF(path.elementAt(0))) {
1916 point = positionForCurve(data, path.currentPosition());
1919 index = data.index + 1;
1920 if (index < data.curves.size() && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(index))) {
1921 QQuickPathData nextData;
1922 nextData.index = index;
1923 nextData.endPoint = data.endPoint;
1924 nextData.curves = data.curves;
1925 next = positionForCurve(nextData, point);
1927 if (point == QPointF(path.elementAt(0)) && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(0)) && path.elementCount() >= 3) {
1930 next = QPointF(path.elementAt(3));
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945 QPointF control1(prevFar.x() * qreal(-0.167) +
1947 point.x() * qreal(0.167),
1948 prevFar.y() * qreal(-0.167) +
1950 point.y() * qreal(0.167));
1952 QPointF control2(prev.x() * qreal(0.167) +
1954 next.x() * qreal(-0.167),
1955 prev.y() * qreal(0.167) +
1957 next.y() * qreal(-0.167));
1959 path.cubicTo(control1, control2, point);
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1988
1989
1990
1991
1992
1993
1994
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2026qreal QQuickPathArc::radiusX()
const
2031void QQuickPathArc::setRadiusX(qreal radius)
2033 if (_radiusX == radius)
2037 emit radiusXChanged();
2041qreal QQuickPathArc::radiusY()
const
2046void QQuickPathArc::setRadiusY(qreal radius)
2048 if (_radiusY == radius)
2052 emit radiusYChanged();
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2075bool QQuickPathArc::useLargeArc()
const
2077 return _useLargeArc;
2080void QQuickPathArc::setUseLargeArc(
bool largeArc)
2082 if (_useLargeArc == largeArc)
2085 _useLargeArc = largeArc;
2086 emit useLargeArcChanged();
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2107QQuickPathArc::ArcDirection QQuickPathArc::direction()
const
2112void QQuickPathArc::setDirection(ArcDirection direction)
2114 if (_direction == direction)
2117 _direction = direction;
2118 emit directionChanged();
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2143qreal QQuickPathArc::xAxisRotation()
const
2145 return _xAxisRotation;
2148void QQuickPathArc::setXAxisRotation(qreal rotation)
2150 if (_xAxisRotation == rotation)
2153 _xAxisRotation = rotation;
2154 emit xAxisRotationChanged();
2158void QQuickPathArc::addToPath(QPainterPath &path,
const QQuickPathData &data)
2160 const QPointF &startPoint = path.currentPosition();
2161 const QPointF &endPoint = positionForCurve(data, startPoint);
2162 QQuickSvgParser::pathArc(path,
2167 _direction == Clockwise ? 1 : 0,
2170 startPoint.x(), startPoint.y());
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2190
2191
2192
2193
2194
2196qreal QQuickPathAngleArc::centerX()
const
2201void QQuickPathAngleArc::setCenterX(qreal centerX)
2203 if (_centerX == centerX)
2207 emit centerXChanged();
2211qreal QQuickPathAngleArc::centerY()
const
2216void QQuickPathAngleArc::setCenterY(qreal centerY)
2218 if (_centerY == centerY)
2222 emit centerYChanged();
2227
2228
2229
2230
2231
2233qreal QQuickPathAngleArc::radiusX()
const
2238void QQuickPathAngleArc::setRadiusX(qreal radius)
2240 if (_radiusX == radius)
2244 emit radiusXChanged();
2248qreal QQuickPathAngleArc::radiusY()
const
2253void QQuickPathAngleArc::setRadiusY(qreal radius)
2255 if (_radiusY == radius)
2259 emit radiusYChanged();
2264
2265
2266
2267
2268
2269
2271qreal QQuickPathAngleArc::startAngle()
const
2276void QQuickPathAngleArc::setStartAngle(qreal angle)
2278 if (_startAngle == angle)
2281 _startAngle = angle;
2282 emit startAngleChanged();
2287
2288
2289
2290
2291
2292
2293
2295qreal QQuickPathAngleArc::sweepAngle()
const
2300void QQuickPathAngleArc::setSweepAngle(qreal angle)
2302 if (_sweepAngle == angle)
2305 _sweepAngle = angle;
2306 emit sweepAngleChanged();
2311
2312
2313
2314
2315
2316
2317
2318
2320bool QQuickPathAngleArc::moveToStart()
const
2322 return _moveToStart;
2325void QQuickPathAngleArc::setMoveToStart(
bool move)
2327 if (_moveToStart == move)
2330 _moveToStart = move;
2331 emit moveToStartChanged();
2335void QQuickPathAngleArc::addToPath(QPainterPath &path,
const QQuickPathData &)
2337 qreal x = _centerX - _radiusX;
2338 qreal y = _centerY - _radiusY;
2339 qreal width = _radiusX * 2;
2340 qreal height = _radiusY * 2;
2342 path.arcMoveTo(x, y, width, height, -_startAngle);
2343 path.arcTo(x, y, width, height, -_startAngle, -_sweepAngle);
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2372
2373
2374
2375
2376
2377
2378
2380QString QQuickPathSvg::path()
const
2385void QQuickPathSvg::setPath(
const QString &path)
2395void QQuickPathSvg::addToPath(QPainterPath &path,
const QQuickPathData &)
2397 QQuickSvgParser::parsePathDataFast(_path, path);
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2422
2423
2424
2425
2426
2427
2428
2429
2430
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2448
2449
2450
2451
2452
2453
2454
2456qreal QQuickPathRectangle::width()
const
2461void QQuickPathRectangle::setWidth(qreal width)
2463 if (_width == width)
2467 emit widthChanged();
2471qreal QQuickPathRectangle::height()
const
2476void QQuickPathRectangle::setHeight(qreal height)
2478 if (_height == height)
2482 emit heightChanged();
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2513qreal QQuickPathRectangle::strokeAdjustment()
const
2515 return _strokeAdjustment;
2518void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
2520 if (_strokeAdjustment == newStrokeAdjustment)
2522 _strokeAdjustment = newStrokeAdjustment;
2523 emit strokeAdjustmentChanged();
2528
2529
2530
2531
2533qreal QQuickPathRectangle::radius()
const
2535 return _extra.isAllocated() ? _extra->radius : 0;
2538void QQuickPathRectangle::setRadius(qreal newRadius)
2540 if (_extra.value().radius == newRadius)
2542 _extra->radius = newRadius;
2543 emit radiusChanged();
2544 if (!(_extra->isRadiusSet(Qt::TopLeftCorner)))
2545 emit topLeftRadiusChanged();
2546 if (!(_extra->isRadiusSet(Qt::TopRightCorner)))
2547 emit topRightRadiusChanged();
2548 if (!(_extra->isRadiusSet(Qt::BottomLeftCorner)))
2549 emit bottomLeftRadiusChanged();
2550 if (!(_extra->isRadiusSet(Qt::BottomRightCorner)))
2551 emit bottomRightRadiusChanged();
2556
2557
2559qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner)
const
2561 if (_extra.isAllocated())
2562 return (_extra->isRadiusSet(corner)) ? _extra->cornerRadii[corner] : _extra->radius;
2567void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
2569 if (_extra.value().cornerRadii[corner] == newCornerRadius
2570 && (_extra->isRadiusSet(corner)))
2572 _extra->cornerRadii[corner] = newCornerRadius;
2573 _extra->cornerProperties |= (1 << corner);
2575 emitCornerRadiusChanged(corner);
2578void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
2580 if (!_extra.isAllocated() || !(_extra->isRadiusSet(corner)))
2582 _extra->cornerProperties &= ~(1 << corner);
2583 emitCornerRadiusChanged(corner);
2586void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
2589 case Qt::TopLeftCorner:
2590 emit topLeftRadiusChanged();
2592 case Qt::TopRightCorner:
2593 emit topRightRadiusChanged();
2595 case Qt::BottomLeftCorner:
2596 emit bottomLeftRadiusChanged();
2598 case Qt::BottomRightCorner:
2599 emit bottomRightRadiusChanged();
2606
2607
2608
2609
2610
2612bool QQuickPathRectangle::hasBevel()
const
2614 return _extra.isAllocated() ? (_extra->cornerProperties & (1 << 8)) != 0 :
false;
2617void QQuickPathRectangle::setBevel(
bool bevel)
2619 if (((_extra.value().cornerProperties & (1 << 8)) != 0) == bevel)
2622 _extra->cornerProperties |= (1 << 8);
2624 _extra->cornerProperties &= ~(1 << 8);
2626 emit bevelChanged();
2627 if (!(_extra->isBevelSet(Qt::TopLeftCorner)))
2628 emit topLeftBevelChanged();
2629 if (!(_extra->isBevelSet(Qt::TopRightCorner)))
2630 emit topRightBevelChanged();
2631 if (!(_extra->isBevelSet(Qt::BottomLeftCorner)))
2632 emit bottomLeftBevelChanged();
2633 if (!(_extra->isBevelSet(Qt::BottomRightCorner)))
2634 emit bottomRightBevelChanged();
2638
2639
2640
2642bool QQuickPathRectangle::cornerBevel(Qt::Corner corner)
const
2644 if (_extra.isAllocated())
2645 return _extra->isBevelSet(corner);
2650void QQuickPathRectangle::setCornerBevel(Qt::Corner corner,
bool newCornerBevel)
2652 if ((_extra.value().isBevelSet(corner)) == newCornerBevel)
2654 if (!newCornerBevel) {
2655 resetCornerBevel(corner);
2658 _extra->cornerProperties |= (1 << (corner + 4));
2659 emitCornerBevelChanged(corner);
2662void QQuickPathRectangle::resetCornerBevel(Qt::Corner corner)
2664 if (!_extra.isAllocated() || !(_extra->isBevelSet(corner)))
2666 _extra->cornerProperties &= ~(1 << (corner + 4));
2667 emitCornerBevelChanged(corner);
2670void QQuickPathRectangle::emitCornerBevelChanged(Qt::Corner corner)
2673 case Qt::TopLeftCorner:
2674 emit topLeftBevelChanged();
2676 case Qt::TopRightCorner:
2677 emit topRightBevelChanged();
2679 case Qt::BottomLeftCorner:
2680 emit bottomLeftBevelChanged();
2682 case Qt::BottomRightCorner:
2683 emit bottomRightBevelChanged();
2689void QQuickPathRectangle::addToPath(QPainterPath &path,
const QQuickPathData &data)
2691 QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
2693 qreal halfStroke = _strokeAdjustment * 0.5;
2694 rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
2698 if (!_extra.isAllocated()) {
2703 const qreal maxDiameter = qMin(rect.width(), rect.height());
2704 const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
2705 auto effectiveDiameter = [&](Qt::Corner corner) {
2706 qreal radius = _extra->cornerRadii[corner];
2707 return (_extra->isRadiusSet(corner)) ? qMin(maxDiameter, 2 * radius) : generalDiameter;
2709 const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
2710 const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
2711 const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
2712 const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
2714 path.moveTo(rect.left() + diamTL * 0.5, rect.top());
2716 if (!cornerBevel(Qt::TopRightCorner)) {
2718 path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
2721 path.lineTo(QPointF(rect.right() - diamTR * 0.5, rect.top()));
2722 path.lineTo(QPointF(rect.right(), rect.top() + diamTR * 0.5));
2726 path.lineTo(rect.topRight());
2730 if (!cornerBevel(Qt::BottomRightCorner)) {
2731 path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
2733 path.lineTo(QPointF(rect.right(), rect.bottom() - diamBR * 0.5));
2734 path.lineTo(QPointF(rect.right() - diamBR * 0.5, rect.bottom()));
2737 path.lineTo(rect.bottomRight());
2741 if (!cornerBevel(Qt::BottomLeftCorner)) {
2742 path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
2744 path.lineTo(QPointF(rect.left() + diamBL * 0.5, rect.bottom()));
2745 path.lineTo(QPointF(rect.left(), rect.bottom() - diamBL * 0.5));
2748 path.lineTo(rect.bottomLeft());
2752 if (!cornerBevel(Qt::TopLeftCorner))
2753 path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
2755 path.lineTo(QPointF(rect.left(), rect.top() + diamTL * 0.5));
2757 path.lineTo(rect.topLeft());
2759 path.closeSubpath();
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
2813
2814
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
2843
2844
2846qreal QQuickPathPercent::value()
const
2851void QQuickPathPercent::setValue(qreal value)
2853 if (_value != value) {
2855 emit valueChanged();
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2888
2889
2890
2891
2894
2895
2896
2897
2898
2899
2900
2901
2902
2904QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
2908QVariant QQuickPathPolyline::path()
const
2910 return QVariant::fromValue(m_path);
2913void QQuickPathPolyline::setPath(
const QVariant &path)
2915 if (path.userType() == QMetaType::QPolygonF) {
2916 setPath(path.value<QPolygonF>());
2917 }
else if (path.canConvert<QList<QPointF>>()) {
2918 setPath(path.value<QList<QPointF>>());
2919 }
else if (path.canConvert<QVariantList>()) {
2922 QList<QPointF> pathList;
2923 QVariantList vl = path.value<QVariantList>();
2927 for (
const QVariant &v : vl)
2928 pathList.append(v.toPointF());
2931 qWarning() <<
"PathPolyline: path of type" << path.userType() <<
"not supported";
2935void QQuickPathPolyline::setPath(
const QList<QPointF> &path)
2937 if (m_path != path) {
2938 const QPointF &oldStart = start();
2940 const QPointF &newStart = start();
2942 if (oldStart != newStart)
2943 emit startChanged();
2948QPointF QQuickPathPolyline::start()
const
2950 if (m_path.size()) {
2951 const QPointF &p = m_path.first();
2957void QQuickPathPolyline::addToPath(QPainterPath &path,
const QQuickPathData &)
2959 if (m_path.size() < 2)
2962 path.moveTo(m_path.first());
2963 for (
int i = 1; i < m_path.size(); ++i)
2964 path.lineTo(m_path.at(i));
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
3019
3020
3023
3024
3025
3026
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3040QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
3044QVariant QQuickPathMultiline::paths()
const
3046 return QVariant::fromValue(m_paths);
3049void QQuickPathMultiline::setPaths(
const QVariant &paths)
3051 if (paths.canConvert<QList<QPolygonF>>()) {
3052 const QList<QPolygonF> pathPolygons = paths.value<QList<QPolygonF>>();
3053 QList<QList<QPointF>> pathVectors;
3054 for (
const QPolygonF &p : pathPolygons)
3056 setPaths(pathVectors);
3057 }
else if (paths.canConvert<QList<QList<QPointF>>>()) {
3058 setPaths(paths.value<QList<QList<QPointF>>>());
3059 }
else if (paths.canConvert<QVariantList>()) {
3063 QList<QList<QPointF>> pathsList;
3064 QVariantList vll = paths.value<QVariantList>();
3065 for (
const QVariant &v : vll) {
3068 if (v.canConvert<QPolygonF>()) {
3069 pathsList.append(v.value<QPolygonF>());
3071 QVariantList vl = v.value<QVariantList>();
3073 for (
const QVariant &point : vl) {
3074 if (point.canConvert<QPointF>())
3075 l.append(point.toPointF());
3078 pathsList.append(l);
3081 setPaths(pathsList);
3083 qWarning() <<
"PathMultiline: paths of type" << paths.userType() <<
"not supported";
3084 setPaths(QList<QList<QPointF>>());
3088void QQuickPathMultiline::setPaths(
const QList<QList<QPointF>> &paths)
3090 if (m_paths != paths) {
3091 const QPointF &oldStart = start();
3093 const QPointF &newStart = start();
3094 emit pathsChanged();
3095 if (oldStart != newStart)
3096 emit startChanged();
3101QPointF QQuickPathMultiline::start()
const
3104 return m_paths.first().first();
3108void QQuickPathMultiline::addToPath(QPainterPath &path,
const QQuickPathData &)
3110 if (!m_paths.size())
3112 for (
const QList<QPointF> &p: m_paths) {
3113 path.moveTo(p.first());
3114 for (
int i = 1; i < p.size(); ++i)
3115 path.lineTo(p.at(i));
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
3148
3149
3152
3153
3154
3155
3158
3159
3160
3161
3162
3163
3164
3165
3168
3169
3170
3171
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
3260
3261
3262
3263
3264
3265
3268
3269
3270
3271
3272
3273
3276
3277
3278
3279
3282
3283
3284
3285
3288
3289
3290
3291
3292
3295
3296
3297
3298
3299
3302
3303
3304
3305
3306
3309
3310
3311
3312
3313
3314void QQuickPathText::updatePath()
const
3316 if (!_path.isEmpty())
3319 _path.addText(0.0, 0.0, _font, _text);
3322 QRectF brect = _path.boundingRect();
3323 _path.translate(_x, _y - brect.y());
3326void QQuickPathText::addToPath(QPainterPath &path)
3328 if (_text.isEmpty())
3331 path.addPath(_path);
3336#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)