Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickpath.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickpath_p.h"
5#include "qquickpath_p_p.h"
6#include "qquicksvgparser_p.h"
7
8#include <QSet>
9#include <QTime>
10
11#include <private/qbezier_p.h>
12#include <QtCore/qmath.h>
13#include <QtCore/private/qnumeric_p.h>
14
16
125 : QObject(*(new QQuickPathPrivate), parent)
126{
127}
128
130 : QObject(dd, parent)
131{
132}
133
137
144{
145 Q_D(const QQuickPath);
146 return d->startX.isValid() ? d->startX.value() : 0;
147}
148
150{
151 Q_D(QQuickPath);
152 if (d->startX.isValid() && qFuzzyCompare(x, d->startX))
153 return;
154 d->startX = x;
156 processPath();
157}
158
160{
161 Q_D(const QQuickPath);
162 return d->startX.isValid();
163}
164
166{
167 Q_D(const QQuickPath);
168 return d->startY.isValid() ? d->startY.value() : 0;
169}
170
172{
173 Q_D(QQuickPath);
174 if (d->startY.isValid() && qFuzzyCompare(y, d->startY))
175 return;
176 d->startY = y;
178 processPath();
179}
180
182{
183 Q_D(const QQuickPath);
184 return d->startY.isValid();
185}
186
192{
193 Q_D(const QQuickPath);
194 return d->closed;
195}
196
221QQmlListProperty<QQuickPathElement> QQuickPath::pathElements()
222{
223 return QQmlListProperty<QQuickPathElement>(this,
224 nullptr,
229}
230
232{
233 QQuickPath *path = static_cast<QQuickPath*>(object);
234
236}
237
239{
241
242 return d->_pathElements.at(index);
243}
244
245void QQuickPath::pathElements_append(QQmlListProperty<QQuickPathElement> *property, QQuickPathElement *pathElement)
246{
248 QQuickPath *path = static_cast<QQuickPath*>(property->object);
249
250 d->_pathElements.append(pathElement);
251
252 if (d->componentComplete) {
253 QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement);
254 if (curve)
255 d->_pathCurves.append(curve);
256 else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
257 d->_pathTexts.append(text);
258 else {
259 QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement);
260 if (attribute && !d->_attributes.contains(attribute->name()))
261 d->_attributes.append(attribute->name());
262 }
263
264 path->processPath();
265
266 connect(pathElement, SIGNAL(changed()), path, SLOT(processPath()));
267 }
268}
269
270qsizetype QQuickPath::pathElements_count(QQmlListProperty<QQuickPathElement> *property)
271{
273
274 return d->_pathElements.size();
275}
276
277void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *property)
278{
280 QQuickPath *path = static_cast<QQuickPath*>(property->object);
281
283 d->_pathElements.clear();
284 d->_pathCurves.clear();
285 d->_pointCache.clear();
286 d->_pathTexts.clear();
287}
288
289void QQuickPath::interpolate(int idx, const QString &name, qreal value)
290{
291 Q_D(QQuickPath);
292 interpolate(d->_attributePoints, idx, name, value);
293}
294
295void QQuickPath::interpolate(QList<AttributePoint> &attributePoints, int idx, const QString &name, qreal value)
296{
297 if (!idx)
298 return;
299
300 qreal lastValue = 0;
301 qreal lastPercent = 0;
302 int search = idx - 1;
303 while(search >= 0) {
304 const AttributePoint &point = attributePoints.at(search);
305 if (point.values.contains(name)) {
306 lastValue = point.values.value(name);
307 lastPercent = point.origpercent;
308 break;
309 }
310 --search;
311 }
312
313 ++search;
314
315 const AttributePoint &curPoint = attributePoints.at(idx);
316
317 for (int ii = search; ii < idx; ++ii) {
318 AttributePoint &point = attributePoints[ii];
319
320 qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
321 point.values.insert(name, val);
322 }
323}
324
325void QQuickPath::endpoint(const QString &name)
326{
327 Q_D(QQuickPath);
328 const AttributePoint &first = d->_attributePoints.first();
329 qreal val = first.values.value(name);
330 for (int ii = d->_attributePoints.size() - 1; ii >= 0; ii--) {
331 const AttributePoint &point = d->_attributePoints.at(ii);
332 if (point.values.contains(name)) {
333 for (int jj = ii + 1; jj < d->_attributePoints.size(); ++jj) {
334 AttributePoint &setPoint = d->_attributePoints[jj];
335 setPoint.values.insert(name, val);
336 }
337 return;
338 }
339 }
340}
341
342void QQuickPath::endpoint(QList<AttributePoint> &attributePoints, const QString &name)
343{
344 const AttributePoint &first = attributePoints.first();
345 qreal val = first.values.value(name);
346 for (int ii = attributePoints.size() - 1; ii >= 0; ii--) {
347 const AttributePoint &point = attributePoints.at(ii);
348 if (point.values.contains(name)) {
349 for (int jj = ii + 1; jj < attributePoints.size(); ++jj) {
350 AttributePoint &setPoint = attributePoints[jj];
351 setPoint.values.insert(name, val);
352 }
353 return;
354 }
355 }
356}
357
358void QQuickPath::processPath()
359{
360 Q_D(QQuickPath);
361
362 if (!d->componentComplete)
363 return;
364
365 d->_pointCache.clear();
366 d->prevBez.isValid = false;
367
368 if (d->isShapePath) {
369 // This path is a ShapePath, so avoid extra overhead
370 d->_path = createShapePath(QPointF(), QPointF(), d->pathLength, &d->closed);
371 } else {
372 d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
373 }
374
375 if (d->simplify)
376 d->_path = d->_path.simplified();
377
378 emit changed();
379}
380
381inline static void scalePath(QPainterPath &path, const QSizeF &scale)
382{
383 const qreal xscale = scale.width();
384 const qreal yscale = scale.height();
385 if (xscale == 1 && yscale == 1)
386 return;
387
388 for (int i = 0; i < path.elementCount(); ++i) {
389 const QPainterPath::Element &element = path.elementAt(i);
390 path.setElementPositionAt(i, element.x * xscale, element.y * yscale);
391 }
392}
393
394QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed)
395{
396 Q_D(QQuickPath);
397
398 pathLength = 0;
399 attributePoints.clear();
400
401 if (!d->componentComplete)
402 return QPainterPath();
403
405
406 AttributePoint first;
407 for (int ii = 0; ii < attributes.size(); ++ii)
408 first.values[attributes.at(ii)] = 0;
409 attributePoints << first;
410
411 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
412 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
413 path.moveTo(startX, startY);
414
415 const QString percentString = QStringLiteral("_qfx_percent");
416
417 bool usesPercent = false;
418 int index = 0;
419 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
420 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement)) {
422 data.index = index;
423 data.endPoint = endPoint;
424 data.curves = d->_pathCurves;
425 curve->addToPath(path, data);
426 AttributePoint p;
427 p.origpercent = path.length();
428 attributePoints << p;
429 ++index;
430 } else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement)) {
431 AttributePoint &point = attributePoints.last();
432 point.values[attribute->name()] = attribute->value();
433 interpolate(attributePoints, attributePoints.size() - 1, attribute->name(), attribute->value());
434 } else if (QQuickPathPercent *percent = qobject_cast<QQuickPathPercent *>(pathElement)) {
435 AttributePoint &point = attributePoints.last();
436 point.values[percentString] = percent->value();
437 interpolate(attributePoints, attributePoints.size() - 1, percentString, percent->value());
438 usesPercent = true;
439 } else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
440 text->addToPath(path);
441 }
442 }
443
444 // Fixup end points
445 const AttributePoint &last = attributePoints.constLast();
446 for (int ii = 0; ii < attributes.size(); ++ii) {
447 if (!last.values.contains(attributes.at(ii)))
448 endpoint(attributePoints, attributes.at(ii));
449 }
450 if (usesPercent && !last.values.contains(percentString)) {
451 d->_attributePoints.last().values[percentString] = 1;
452 interpolate(d->_attributePoints.size() - 1, percentString, 1);
453 }
454 scalePath(path, d->scale);
455
456 // Adjust percent
457 qreal length = path.length();
458 qreal prevpercent = 0;
459 qreal prevorigpercent = 0;
460 for (int ii = 0; ii < attributePoints.size(); ++ii) {
461 const AttributePoint &point = attributePoints.at(ii);
462 if (point.values.contains(percentString)) { //special string for QQuickPathPercent
463 if ( ii > 0) {
464 qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
465 (point.values.value(percentString)-prevpercent);
466 attributePoints[ii].scale = scale;
467 }
468 attributePoints[ii].origpercent /= length;
469 attributePoints[ii].percent = point.values.value(percentString);
470 prevorigpercent = attributePoints.at(ii).origpercent;
471 prevpercent = attributePoints.at(ii).percent;
472 } else {
473 attributePoints[ii].origpercent /= length;
474 attributePoints[ii].percent = attributePoints.at(ii).origpercent;
475 }
476 }
477
478 if (closed) {
479 QPointF end = path.currentPosition();
480 *closed = length > 0 && startX * d->scale.width() == end.x() && startY * d->scale.height() == end.y();
481 }
482 pathLength = length;
483
484 return path;
485}
486
487QPainterPath QQuickPath::createShapePath(const QPointF &startPoint, const QPointF &endPoint, qreal &pathLength, bool *closed)
488{
489 Q_D(QQuickPath);
490
491 if (!d->componentComplete)
492 return QPainterPath();
493
495
496 qreal startX = d->startX.isValid() ? d->startX.value() : startPoint.x();
497 qreal startY = d->startY.isValid() ? d->startY.value() : startPoint.y();
498 path.moveTo(startX, startY);
499
500 int index = 0;
501 for (QQuickCurve *curve : std::as_const(d->_pathCurves)) {
503 data.index = index;
504 data.endPoint = endPoint;
505 data.curves = d->_pathCurves;
506 curve->addToPath(path, data);
507 ++index;
508 }
509
510 for (QQuickPathText *text : std::as_const(d->_pathTexts))
511 text->addToPath(path);
512
513 if (closed) {
514 QPointF end = path.currentPosition();
515 *closed = startX == end.x() && startY == end.y();
516 }
517 scalePath(path, d->scale);
518
519 // Note: Length of paths inside ShapePath is not used, so currently
520 // length is always 0. This avoids potentially heavy path.length()
521 //pathLength = path.length();
522 pathLength = 0;
523
524 return path;
525}
526
528{
529 Q_D(QQuickPath);
530 d->componentComplete = false;
531}
532
534{
535 Q_D(const QQuickPath);
536
537 for (QQuickPathElement *pathElement : d->_pathElements)
538 disconnect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
539}
540
542{
543 Q_D(const QQuickPath);
544
545 for (QQuickPathElement *pathElement : d->_pathElements)
546 connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
547}
548
550{
551 Q_D(QQuickPath);
552
553 QSet<QString> attributes;
554
555 // First gather up all the attributes
556 for (QQuickPathElement *pathElement : std::as_const(d->_pathElements)) {
557 if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
558 d->_pathCurves.append(curve);
559 else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
560 d->_pathTexts.append(text);
561 else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
562 attributes.insert(attribute->name());
563 }
564
565 d->_attributes = attributes.values();
566}
567
569{
570 Q_D(QQuickPath);
571 d->componentComplete = true;
572
574
575 processPath();
576
578}
579
581{
582 Q_D(const QQuickPath);
583 return d->_path;
584}
585
587{
588 Q_D(const QQuickPath);
589 if (!d->componentComplete) {
590 QSet<QString> attrs;
591
592 // First gather up all the attributes
593 for (QQuickPathElement *pathElement : d->_pathElements) {
595 qobject_cast<QQuickPathAttribute *>(pathElement))
596 attrs.insert(attribute->name());
597 }
598 return attrs.values();
599 }
600 return d->_attributes;
601}
602
603static inline QBezier nextBezier(const QPainterPath &path, int *current, qreal *bezLength, bool reverse = false)
604{
605 const int lastElement = reverse ? 0 : path.elementCount() - 1;
606 const int start = reverse ? *current - 1 : *current + 1;
607 for (int i=start; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
608 const QPainterPath::Element &e = path.elementAt(i);
609
610 switch (e.type) {
612 break;
614 {
615 QLineF line(path.elementAt(i-1), e);
616 *bezLength = line.length();
617 QPointF a = path.elementAt(i-1);
618 QPointF delta = e - a;
619 *current = i;
620 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
621 }
623 {
624 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
625 e,
626 path.elementAt(i+1),
627 path.elementAt(i+2));
628 *bezLength = b.length();
629 *current = i;
630 return b;
631 }
632 default:
633 break;
634 }
635 }
636 *current = lastElement;
637 *bezLength = 0;
638 return QBezier();
639}
640
641static inline int segmentCount(const QPainterPath &path, qreal pathLength)
642{
643 // In the really simple case of a single straight line we can interpolate without jitter
644 // between just two points.
645 if (path.elementCount() == 2
646 && path.elementAt(0).type == QPainterPath::MoveToElement
647 && path.elementAt(1).type == QPainterPath::LineToElement) {
648 return 1;
649 }
650 // more points means less jitter between items as they move along the
651 // path, but takes longer to generate
652 return qCeil(pathLength*5);
653}
654
655//derivative of the equation
657{
658 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
659}
660
661void QQuickPath::createPointCache() const
662{
663 Q_D(const QQuickPath);
664 qreal pathLength = d->pathLength;
665 if (pathLength <= 0 || qt_is_nan(pathLength))
666 return;
667
668 const int segments = segmentCount(d->_path, pathLength);
669 const int lastElement = d->_path.elementCount() - 1;
670 d->_pointCache.resize(segments+1);
671
672 int currElement = -1;
673 qreal bezLength = 0;
674 QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
675 qreal currLength = bezLength;
676 qreal epc = currLength / pathLength;
677
678 for (int i = 0; i < d->_pointCache.size(); i++) {
679 //find which set we are in
680 qreal prevPercent = 0;
681 qreal prevOrigPercent = 0;
682 for (int ii = 0; ii < d->_attributePoints.size(); ++ii) {
683 qreal percent = qreal(i)/segments;
684 const AttributePoint &point = d->_attributePoints.at(ii);
685 if (percent < point.percent || ii == d->_attributePoints.size() - 1) { //### || is special case for very last item
686 qreal elementPercent = (percent - prevPercent);
687
688 qreal spc = prevOrigPercent + elementPercent * point.scale;
689
690 while (spc > epc) {
691 if (currElement > lastElement)
692 break;
693 currBez = nextBezier(d->_path, &currElement, &bezLength);
694 if (bezLength == 0.0) {
695 currLength = pathLength;
696 epc = 1.0;
697 break;
698 }
699 currLength += bezLength;
700 epc = currLength / pathLength;
701 }
702 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
703 d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
704 break;
705 }
706 prevOrigPercent = point.origpercent;
707 prevPercent = point.percent;
708 }
709 }
710}
711
713{
714 Q_D(const QQuickPath);
715 d->prevBez.isValid = false;
716}
717
727{
728 Q_D(QQuickPath);
729 if (d->simplify == s)
730 return;
731
732 d->simplify = s;
733 processPath();
734
735 emit simplifyChanged();
736}
737
739{
740 Q_D(const QQuickPath);
741 return d->simplify;
742}
743
756{
757 Q_D(const QQuickPath);
758 return d->scale;
759}
760
762{
763 Q_D(QQuickPath);
764 if (scale == d->scale)
765 return;
766 d->scale = scale;
767 emit scaleChanged();
768 processPath();
769}
770
772{
773 Q_D(const QQuickPath);
774 return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
775}
776
777QPointF QQuickPath::sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
778{
779 Q_ASSERT(p >= 0.0 && p <= 1.0);
780
781 if (!prevBez.isValid)
782 return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
783 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
784
785 return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
786 forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
787}
788
789QPointF QQuickPath::forwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
790{
791 if (pathLength <= 0 || qt_is_nan(pathLength))
792 return path.pointAtPercent(0); //expensive?
793
794 const int lastElement = path.elementCount() - 1;
795 bool haveCachedBez = prevBez.isValid;
796 int currElement = haveCachedBez ? prevBez.element : -1;
797 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
798 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
799 qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
800 qreal epc = currLength / pathLength;
801
802 //find which set we are in
803 qreal prevPercent = 0;
804 qreal prevOrigPercent = 0;
805 for (int ii = 0; ii < attributePoints.size(); ++ii) {
806 qreal percent = p;
807 const AttributePoint &point = attributePoints.at(ii);
808 if (percent < point.percent || ii == attributePoints.size() - 1) {
809 qreal elementPercent = (percent - prevPercent);
810
811 qreal spc = prevOrigPercent + elementPercent * point.scale;
812
813 while (spc > epc) {
814 Q_ASSERT(!(currElement > lastElement));
815 Q_UNUSED(lastElement);
816 currBez = nextBezier(path, &currElement, &bezLength);
817 currLength += bezLength;
818 epc = currLength / pathLength;
819 }
820 prevBez.element = currElement;
821 prevBez.bezLength = bezLength;
822 prevBez.currLength = currLength;
823 prevBez.bezier = currBez;
824 prevBez.p = p;
825 prevBez.isValid = true;
826
827 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
828
829 if (angle) {
830 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
831 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
832 *angle = QLineF(0, 0, m1, m2).angle();
833 }
834
835 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
836 }
837 prevOrigPercent = point.origpercent;
838 prevPercent = point.percent;
839 }
840
841 return QPointF(0,0);
842}
843
844//ideally this should be merged with forwardsPointAt
845QPointF QQuickPath::backwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle)
846{
847 if (pathLength <= 0 || qt_is_nan(pathLength))
848 return path.pointAtPercent(0);
849
850 const int firstElement = 1; //element 0 is always a MoveTo, which we ignore
851 bool haveCachedBez = prevBez.isValid;
852 int currElement = haveCachedBez ? prevBez.element : path.elementCount();
853 qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
854 QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength, true /*reverse*/);
855 qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
856 qreal prevLength = currLength - bezLength;
857 qreal epc = prevLength / pathLength;
858
859 for (int ii = attributePoints.size() - 1; ii > 0; --ii) {
860 qreal percent = p;
861 const AttributePoint &point = attributePoints.at(ii);
862 const AttributePoint &prevPoint = attributePoints.at(ii-1);
863 if (percent > prevPoint.percent || ii == 1) {
864 qreal elementPercent = (percent - prevPoint.percent);
865
866 qreal spc = prevPoint.origpercent + elementPercent * point.scale;
867
868 while (spc < epc) {
869 Q_ASSERT(!(currElement < firstElement));
870 Q_UNUSED(firstElement);
871 currBez = nextBezier(path, &currElement, &bezLength, true /*reverse*/);
872 //special case for first element is to avoid floating point math
873 //causing an epc that never hits 0.
874 currLength = (currElement == firstElement) ? bezLength : prevLength;
875 prevLength = currLength - bezLength;
876 epc = prevLength / pathLength;
877 }
878 prevBez.element = currElement;
879 prevBez.bezLength = bezLength;
880 prevBez.currLength = currLength;
881 prevBez.bezier = currBez;
882 prevBez.p = p;
883 prevBez.isValid = true;
884
885 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
886
887 if (angle) {
888 qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
889 qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
890 *angle = QLineF(0, 0, m1, m2).angle();
891 }
892
893 return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
894 }
895 }
896
897 return QPointF(0,0);
898}
899
916QPointF QQuickPath::pointAtPercent(qreal t) const
917{
918 Q_D(const QQuickPath);
919 if (d->isShapePath) // this since ShapePath does not calculate the length at all,
920 return d->_path.pointAtPercent(t); // in order to be faster.
921
922 if (d->_pointCache.isEmpty()) {
923 createPointCache();
924 if (d->_pointCache.isEmpty())
925 return QPointF();
926 }
927
928 const int segmentCount = d->_pointCache.size() - 1;
929 qreal idxf = t*segmentCount;
930 int idx1 = qFloor(idxf);
931 qreal delta = idxf - idx1;
932 if (idx1 > segmentCount)
933 idx1 = segmentCount;
934 else if (idx1 < 0)
935 idx1 = 0;
936
937 if (delta == 0.0)
938 return d->_pointCache.at(idx1);
939
940 // interpolate between the two points.
941 int idx2 = qCeil(idxf);
942 if (idx2 > segmentCount)
943 idx2 = segmentCount;
944 else if (idx2 < 0)
945 idx2 = 0;
946
947 QPointF p1 = d->_pointCache.at(idx1);
948 QPointF p2 = d->_pointCache.at(idx2);
949 QPointF pos = p1 * (1.0-delta) + p2 * delta;
950
951 return pos;
952}
953
955{
956 Q_D(const QQuickPath);
957 if (percent < 0 || percent > 1)
958 return 0;
959
960 for (int ii = 0; ii < d->_attributePoints.size(); ++ii) {
961 const AttributePoint &point = d->_attributePoints.at(ii);
962
963 if (point.percent == percent) {
964 return point.values.value(name);
965 } else if (point.percent > percent) {
966 qreal lastValue =
967 ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
968 qreal lastPercent =
969 ii?(d->_attributePoints.at(ii - 1).percent):0;
970 qreal curValue = point.values.value(name);
971 qreal curPercent = point.percent;
972
973 return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
974 }
975 }
976
977 return 0;
978}
979
980/****************************************************************************/
981
983{
984 return _x.isValid() ? _x.value() : 0;
985}
986
988{
989 if (!_x.isValid() || _x != x) {
990 _x = x;
991 emit xChanged();
992 emit changed();
993 }
994}
995
997{
998 return _x.isValid();
999}
1000
1002{
1003 return _y.isValid() ? _y.value() : 0;
1004}
1005
1007{
1008 if (!_y.isValid() || _y != y) {
1009 _y = y;
1010 emit yChanged();
1011 emit changed();
1012 }
1013}
1014
1016{
1017 return _y.isValid();
1018}
1019
1021{
1022 return _relativeX;
1023}
1024
1026{
1027 if (!_relativeX.isValid() || _relativeX != x) {
1028 _relativeX = x;
1030 emit changed();
1031 }
1032}
1033
1035{
1036 return _relativeX.isValid();
1037}
1038
1040{
1041 return _relativeY;
1042}
1043
1045{
1046 if (!_relativeY.isValid() || _relativeY != y) {
1047 _relativeY = y;
1049 emit changed();
1050 }
1051}
1052
1054{
1055 return _relativeY.isValid();
1056}
1057
1058/****************************************************************************/
1059
1110{
1111 return _name;
1112}
1113
1115{
1116 if (_name == name)
1117 return;
1118 _name = name;
1119 emit nameChanged();
1120}
1121
1162{
1163 return _value;
1164}
1165
1167{
1168 if (_value != value) {
1169 _value = value;
1171 emit changed();
1172 }
1173}
1174
1175/****************************************************************************/
1176
1221inline QPointF positionForCurve(const QQuickPathData &data, const QPointF &prevPoint)
1222{
1223 QQuickCurve *curve = data.curves.at(data.index);
1224 bool isEnd = data.index == data.curves.size() - 1;
1225 return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
1226 curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
1227}
1228
1230{
1231 path.lineTo(positionForCurve(data, path.currentPosition()));
1232}
1233
1234/****************************************************************************/
1235
1288{
1289 path.moveTo(positionForCurve(data, path.currentPosition()));
1290}
1291
1292/****************************************************************************/
1293
1352{
1353 return _controlX;
1354}
1355
1357{
1358 if (_controlX != x) {
1359 _controlX = x;
1361 emit changed();
1362 }
1363}
1364
1365
1370{
1371 return _controlY;
1372}
1373
1375{
1376 if (_controlY != y) {
1377 _controlY = y;
1379 emit changed();
1380 }
1381}
1382
1399{
1400 return _relativeControlX;
1401}
1402
1404{
1405 if (!_relativeControlX.isValid() || _relativeControlX != x) {
1406 _relativeControlX = x;
1408 emit changed();
1409 }
1410}
1411
1413{
1414 return _relativeControlX.isValid();
1415}
1416
1418{
1419 return _relativeControlY;
1420}
1421
1423{
1424 if (!_relativeControlY.isValid() || _relativeControlY != y) {
1425 _relativeControlY = y;
1427 emit changed();
1428 }
1429}
1430
1432{
1433 return _relativeControlY.isValid();
1434}
1435
1437{
1438 const QPointF &prevPoint = path.currentPosition();
1439 QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
1440 hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
1441 path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
1442}
1443
1444/****************************************************************************/
1445
1504{
1505 return _control1X;
1506}
1507
1509{
1510 if (_control1X != x) {
1511 _control1X = x;
1513 emit changed();
1514 }
1515}
1516
1518{
1519 return _control1Y;
1520}
1521
1523{
1524 if (_control1Y != y) {
1525 _control1Y = y;
1527 emit changed();
1528 }
1529}
1530
1538{
1539 return _control2X;
1540}
1541
1543{
1544 if (_control2X != x) {
1545 _control2X = x;
1547 emit changed();
1548 }
1549}
1550
1552{
1553 return _control2Y;
1554}
1555
1557{
1558 if (_control2Y != y) {
1559 _control2Y = y;
1561 emit changed();
1562 }
1563}
1564
1583{
1584 return _relativeControl1X;
1585}
1586
1588{
1589 if (!_relativeControl1X.isValid() || _relativeControl1X != x) {
1590 _relativeControl1X = x;
1592 emit changed();
1593 }
1594}
1595
1597{
1598 return _relativeControl1X.isValid();
1599}
1600
1602{
1603 return _relativeControl1Y;
1604}
1605
1607{
1608 if (!_relativeControl1Y.isValid() || _relativeControl1Y != y) {
1609 _relativeControl1Y = y;
1611 emit changed();
1612 }
1613}
1614
1616{
1617 return _relativeControl1Y.isValid();
1618}
1619
1621{
1622 return _relativeControl2X;
1623}
1624
1626{
1627 if (!_relativeControl2X.isValid() || _relativeControl2X != x) {
1628 _relativeControl2X = x;
1630 emit changed();
1631 }
1632}
1633
1635{
1636 return _relativeControl2X.isValid();
1637}
1638
1640{
1641 return _relativeControl2Y;
1642}
1643
1645{
1646 if (!_relativeControl2Y.isValid() || _relativeControl2Y != y) {
1647 _relativeControl2Y = y;
1649 emit changed();
1650 }
1651}
1652
1654{
1655 return _relativeControl2Y.isValid();
1656}
1657
1659{
1660 const QPointF &prevPoint = path.currentPosition();
1661 QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
1662 hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
1663 QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
1664 hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
1665 path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
1666}
1667
1668/****************************************************************************/
1669
1715{
1716 int count = path.elementCount();
1717 if (count < 1)
1718 return QPointF();
1719
1720 int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
1721 return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
1722}
1723
1725{
1726 //here we convert catmull-rom spline to bezier for use in QPainterPath.
1727 //basic conversion algorithm:
1728 // catmull-rom points * inverse bezier matrix * catmull-rom matrix = bezier points
1729 //each point in the catmull-rom spline produces a bezier endpoint + 2 control points
1730 //calculations for each point use a moving window of 4 points
1731 // (previous 2 points + current point + next point)
1732 QPointF prevFar, prev, point, next;
1733
1734 //get previous points
1735 int index = data.index - 1;
1736 QQuickCurve *curve = index == -1 ? 0 : data.curves.at(index);
1737 if (qobject_cast<QQuickPathCatmullRomCurve*>(curve)) {
1738 prev = path.currentPosition();
1739 prevFar = previousPathPosition(path);
1740 } else {
1741 prev = path.currentPosition();
1742 bool prevFarSet = false;
1743 if (index == -1 && data.curves.size() > 1) {
1744 if (qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(data.curves.size()-1))) {
1745 //TODO: profile and optimize
1746 QPointF pos = prev;
1747 QQuickPathData loopData;
1748 loopData.endPoint = data.endPoint;
1749 loopData.curves = data.curves;
1750 for (int i = data.index; i < data.curves.size(); ++i) {
1751 loopData.index = i;
1752 pos = positionForCurve(loopData, pos);
1753 if (i == data.curves.size()-2)
1754 prevFar = pos;
1755 }
1756 if (pos == QPointF(path.elementAt(0))) {
1757 //this is a closed path starting and ending with catmull-rom segments.
1758 //we try to smooth the join point
1759 prevFarSet = true;
1760 }
1761 }
1762 }
1763 if (!prevFarSet)
1764 prevFar = prev;
1765 }
1766
1767 //get current point
1768 point = positionForCurve(data, path.currentPosition());
1769
1770 //get next point
1771 index = data.index + 1;
1772 if (index < data.curves.size() && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(index))) {
1773 QQuickPathData nextData;
1774 nextData.index = index;
1775 nextData.endPoint = data.endPoint;
1776 nextData.curves = data.curves;
1777 next = positionForCurve(nextData, point);
1778 } else {
1779 if (point == QPointF(path.elementAt(0)) && qobject_cast<QQuickPathCatmullRomCurve*>(data.curves.at(0)) && path.elementCount() >= 3) {
1780 //this is a closed path starting and ending with catmull-rom segments.
1781 //we try to smooth the join point
1782 next = QPointF(path.elementAt(3)); //the first catmull-rom point
1783 } else
1784 next = point;
1785 }
1786
1787 /*
1788 full conversion matrix (inverse bezier * catmull-rom):
1789 0.000, 1.000, 0.000, 0.000,
1790 -0.167, 1.000, 0.167, 0.000,
1791 0.000, 0.167, 1.000, -0.167,
1792 0.000, 0.000, 1.000, 0.000
1793
1794 conversion doesn't require full matrix multiplication,
1795 so below we simplify
1796 */
1797 QPointF control1(prevFar.x() * qreal(-0.167) +
1798 prev.x() +
1799 point.x() * qreal(0.167),
1800 prevFar.y() * qreal(-0.167) +
1801 prev.y() +
1802 point.y() * qreal(0.167));
1803
1804 QPointF control2(prev.x() * qreal(0.167) +
1805 point.x() +
1806 next.x() * qreal(-0.167),
1807 prev.y() * qreal(0.167) +
1808 point.y() +
1809 next.y() * qreal(-0.167));
1810
1811 path.cubicTo(control1, control2, point);
1812}
1813
1814/****************************************************************************/
1815
1879{
1880 return _radiusX;
1881}
1882
1884{
1885 if (_radiusX == radius)
1886 return;
1887
1888 _radiusX = radius;
1890 emit changed();
1891}
1892
1894{
1895 return _radiusY;
1896}
1897
1899{
1900 if (_radiusY == radius)
1901 return;
1902
1903 _radiusY = radius;
1905 emit changed();
1906}
1907
1928{
1929 return _useLargeArc;
1930}
1931
1933{
1934 if (_useLargeArc == largeArc)
1935 return;
1936
1937 _useLargeArc = largeArc;
1939 emit changed();
1940}
1941
1960{
1961 return _direction;
1962}
1963
1965{
1966 if (_direction == direction)
1967 return;
1968
1969 _direction = direction;
1971 emit changed();
1972}
1973
1996{
1997 return _xAxisRotation;
1998}
1999
2001{
2002 if (_xAxisRotation == rotation)
2003 return;
2004
2005 _xAxisRotation = rotation;
2006 emit xAxisRotationChanged();
2007 emit changed();
2008}
2009
2011{
2012 const QPointF &startPoint = path.currentPosition();
2013 const QPointF &endPoint = positionForCurve(data, startPoint);
2015 _radiusX,
2016 _radiusY,
2017 _xAxisRotation,
2018 _useLargeArc,
2019 _direction == Clockwise ? 1 : 0,
2020 endPoint.x(),
2021 endPoint.y(),
2022 startPoint.x(), startPoint.y());
2023}
2024
2025/****************************************************************************/
2026
2049{
2050 return _centerX;
2051}
2052
2054{
2055 if (_centerX == centerX)
2056 return;
2057
2058 _centerX = centerX;
2060 emit changed();
2061}
2062
2064{
2065 return _centerY;
2066}
2067
2069{
2070 if (_centerY == centerY)
2071 return;
2072
2073 _centerY = centerY;
2075 emit changed();
2076}
2077
2086{
2087 return _radiusX;
2088}
2089
2091{
2092 if (_radiusX == radius)
2093 return;
2094
2095 _radiusX = radius;
2097 emit changed();
2098}
2099
2101{
2102 return _radiusY;
2103}
2104
2106{
2107 if (_radiusY == radius)
2108 return;
2109
2110 _radiusY = radius;
2112 emit changed();
2113}
2114
2124{
2125 return _startAngle;
2126}
2127
2129{
2130 if (_startAngle == angle)
2131 return;
2132
2133 _startAngle = angle;
2135 emit changed();
2136}
2137
2148{
2149 return _sweepAngle;
2150}
2151
2153{
2154 if (_sweepAngle == angle)
2155 return;
2156
2157 _sweepAngle = angle;
2159 emit changed();
2160}
2161
2173{
2174 return _moveToStart;
2175}
2176
2178{
2179 if (_moveToStart == move)
2180 return;
2181
2182 _moveToStart = move;
2184 emit changed();
2185}
2186
2188{
2189 qreal x = _centerX - _radiusX;
2190 qreal y = _centerY - _radiusY;
2191 qreal width = _radiusX * 2;
2192 qreal height = _radiusY * 2;
2193 if (_moveToStart)
2194 path.arcMoveTo(x, y, width, height, -_startAngle);
2195 path.arcTo(x, y, width, height, -_startAngle, -_sweepAngle);
2196}
2197
2198/****************************************************************************/
2199
2233{
2234 return _path;
2235}
2236
2238{
2239 if (_path == path)
2240 return;
2241
2242 _path = path;
2243 emit pathChanged();
2244 emit changed();
2245}
2246
2251
2252/****************************************************************************/
2253
2336{
2337 return _value;
2338}
2339
2341{
2342 if (_value != value) {
2343 _value = value;
2345 emit changed();
2346 }
2347}
2348
2396
2398{
2399 return QVariant::fromValue(m_path);
2400}
2401
2403{
2404 if (path.userType() == QMetaType::QPolygonF) {
2405 setPath(path.value<QPolygonF>());
2406 } else if (path.canConvert<QVector<QPointF>>()) {
2407 setPath(path.value<QVector<QPointF>>());
2408 } else if (path.canConvert<QVariantList>()) {
2409 // This handles cases other than QPolygonF or QVector<QPointF>, such as
2410 // QList<QPointF>, QVector<QPoint>, QVariantList of QPointF, QVariantList of QPoint.
2411 QVector<QPointF> pathList;
2413 // If path is a QJSValue, e.g. coming from a JS array of Qt.point() in QML,
2414 // then path.value<QVariantList>() is inefficient.
2415 // TODO We should be able to iterate over path.value<QSequentialIterable>() eventually
2416 for (const QVariant &v : vl)
2417 pathList.append(v.toPointF());
2418 setPath(pathList);
2419 } else {
2420 qWarning() << "PathPolyline: path of type" << path.userType() << "not supported";
2421 }
2422}
2423
2424void QQuickPathPolyline::setPath(const QVector<QPointF> &path)
2425{
2426 if (m_path != path) {
2427 const QPointF &oldStart = start();
2428 m_path = path;
2429 const QPointF &newStart = start();
2430 emit pathChanged();
2431 if (oldStart != newStart)
2433 emit changed();
2434 }
2435}
2436
2438{
2439 if (m_path.size()) {
2440 const QPointF &p = m_path.first();
2441 return p;
2442 }
2443 return QPointF();
2444}
2445
2447{
2448 if (m_path.size() < 2)
2449 return;
2450
2451 path.moveTo(m_path.first());
2452 for (int i = 1; i < m_path.size(); ++i)
2453 path.lineTo(m_path.at(i));
2454}
2455
2456
2532
2534{
2535 return QVariant::fromValue(m_paths);
2536}
2537
2539{
2540 if (paths.canConvert<QVector<QPolygonF>>()) {
2541 const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>();
2542 QVector<QVector<QPointF>> pathVectors;
2543 for (const QPolygonF &p : pathPolygons)
2544 pathVectors << p;
2545 setPaths(pathVectors);
2546 } else if (paths.canConvert<QVector<QVector<QPointF>>>()) {
2547 setPaths(paths.value<QVector<QVector<QPointF>>>());
2548 } else if (paths.canConvert<QVariantList>()) {
2549 // This handles cases other than QVector<QPolygonF> or QVector<QVector<QPointF>>, such as
2550 // QList<QVector<QPointF>>, QList<QList<QPointF>>, QVariantList of QVector<QPointF>,
2551 // QVariantList of QVariantList of QPointF, QVector<QList<QPoint>> etc.
2552 QVector<QVector<QPointF>> pathsList;
2554 for (const QVariant &v : vll) {
2555 // If we bind a QVector<QPolygonF> property directly, rather than via QVariant,
2556 // it will come through as QJSValue that can be converted to QVariantList of QPolygonF.
2557 if (v.canConvert<QPolygonF>()) {
2558 pathsList.append(v.value<QPolygonF>());
2559 } else {
2561 QVector<QPointF> l;
2562 for (const QVariant &point : vl) {
2563 if (point.canConvert<QPointF>())
2564 l.append(point.toPointF());
2565 }
2566 if (l.size() >= 2)
2567 pathsList.append(l);
2568 }
2569 }
2570 setPaths(pathsList);
2571 } else {
2572 qWarning() << "PathMultiline: paths of type" << paths.userType() << "not supported";
2573 setPaths(QVector<QVector<QPointF>>());
2574 }
2575}
2576
2577void QQuickPathMultiline::setPaths(const QVector<QVector<QPointF>> &paths)
2578{
2579 if (m_paths != paths) {
2580 const QPointF &oldStart = start();
2581 m_paths = paths;
2582 const QPointF &newStart = start();
2584 if (oldStart != newStart)
2586 emit changed();
2587 }
2588}
2589
2591{
2592 if (m_paths.size())
2593 return m_paths.first().first();
2594 return QPointF();
2595}
2596
2598{
2599 if (!m_paths.size())
2600 return;
2601 for (const QVector<QPointF> &p: m_paths) {
2602 path.moveTo(p.first());
2603 for (int i = 1; i < p.size(); ++i)
2604 path.lineTo(p.at(i));
2605 }
2606}
2607
2819void QQuickPathText::updatePath() const
2820{
2821 if (!_path.isEmpty())
2822 return;
2823
2824 _path.addText(0.0, 0.0, _font, _text);
2825
2826 // Account for distance from baseline to top, since addText() takes baseline position
2827 QRectF brect = _path.boundingRect();
2828 _path.translate(_x, _y - brect.y());
2829}
2830
2832{
2833 if (_text.isEmpty())
2834 return;
2835 updatePath();
2836 path.addPath(_path);
2837}
2838
2840
2841#include "moc_qquickpath_p.cpp"
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:33
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
qreal angle() const
Definition qline.cpp:564
T value(qsizetype i) const
Definition qlist.h:664
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtGui
\inmodule QtGui
void translate(qreal dx, qreal dy)
Translates all elements in the path by ({dx}, {dy}).
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision.
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
void addText(const QPointF &point, const QFont &f, const QString &text)
Adds the given text to this path as a set of closed subpaths created from the font supplied.
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
void relativeXChanged()
qreal relativeY
void setX(qreal x)
void xChanged()
void yChanged()
void setY(qreal y)
qreal relativeX
void relativeYChanged()
bool hasRelativeY()
void setRelativeY(qreal y)
bool hasRelativeX()
void setRelativeX(qreal x)
void setCenterY(qreal)
void setMoveToStart(bool)
void setStartAngle(qreal)
void addToPath(QPainterPath &path, const QQuickPathData &) override
void setRadiusY(qreal)
void setRadiusX(qreal)
void setCenterX(qreal)
void setSweepAngle(qreal)
void directionChanged()
void setRadiusY(qreal)
void radiusXChanged()
void setUseLargeArc(bool)
ArcDirection direction
void setXAxisRotation(qreal rotation)
void radiusYChanged()
void addToPath(QPainterPath &path, const QQuickPathData &) override
void setDirection(ArcDirection direction)
void useLargeArcChanged()
void setRadiusX(qreal)
void setValue(qreal value)
void setName(const QString &name)
void addToPath(QPainterPath &path, const QQuickPathData &) override
void control1YChanged()
void relativeControl1XChanged()
void control2XChanged()
void setControl2X(qreal x)
bool hasRelativeControl1X()
bool hasRelativeControl2X()
void setControl2Y(qreal y)
bool hasRelativeControl1Y()
void addToPath(QPainterPath &path, const QQuickPathData &) override
void setRelativeControl1X(qreal x)
bool hasRelativeControl2Y()
void control2YChanged()
void control1XChanged()
void setRelativeControl1Y(qreal y)
void relativeControl2YChanged()
void relativeControl1YChanged()
void setControl1Y(qreal y)
void setControl1X(qreal x)
void setRelativeControl2X(qreal x)
void relativeControl2XChanged()
void setRelativeControl2Y(qreal y)
void addToPath(QPainterPath &path, const QQuickPathData &) override
void addToPath(QPainterPath &path, const QQuickPathData &) override
\qmltype PathMove \instantiates QQuickPathMove \inqmlmodule QtQuick
void addToPath(QPainterPath &path, const QQuickPathData &) override
void setPaths(const QVariant &paths)
QQuickPathMultiline(QObject *parent=nullptr)
\qmltype PathMultiline \instantiates QQuickPathMultiline \inqmlmodule QtQuick
void setValue(qreal value)
QQuickPathPolyline(QObject *parent=nullptr)
\qmltype PathPolyline \instantiates QQuickPathPolyline \inqmlmodule QtQuick
void addToPath(QPainterPath &path, const QQuickPathData &data) override
void setPath(const QVariant &path)
static QQuickPathPrivate * get(QQuickPath *path)
void setRelativeControlY(qreal y)
void controlXChanged()
void addToPath(QPainterPath &path, const QQuickPathData &) override
void setControlX(qreal x)
void setRelativeControlX(qreal x)
bool hasRelativeControlY()
void relativeControlYChanged()
bool hasRelativeControlX()
void controlYChanged()
void relativeControlXChanged()
void setControlY(qreal y)
void setPath(const QString &path)
void addToPath(QPainterPath &path, const QQuickPathData &) override
void pathChanged()
void addToPath(QPainterPath &path)
void setStartX(qreal x)
qreal attributeAt(const QString &, qreal) const
bool hasStartX() const
void classBegin() override
Invoked after class creation, but before any properties have been set.
QPainterPath createShapePath(const QPointF &startPoint, const QPointF &endPoint, qreal &pathLength, bool *closed=nullptr)
void connectPathElements()
void startYChanged()
void setScale(const QSizeF &scale)
static QQuickPathElement * pathElements_at(QQmlListProperty< QQuickPathElement > *, qsizetype)
FINALQSizeF scale
void setSimplify(bool s)
\qmlproperty bool QtQuick::Path::simplify
bool hasStartY() const
static qsizetype pathElements_count(QQmlListProperty< QQuickPathElement > *)
~QQuickPath() override
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
QPointF sequentialPointAt(qreal p, qreal *angle=nullptr) const
QQmlListProperty< QQuickPathElement > pathElements
\qmlproperty list<PathElement> QtQuick::Path::pathElements This property holds the objects composing ...
QPainterPath createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList< AttributePoint > &attributePoints, bool *closed=nullptr)
void setStartY(qreal y)
void gatherAttributes()
void invalidateSequentialHistory() const
QQuickPath(QObject *parent=nullptr)
\qmltype PathElement \instantiates QQuickPathElement \inqmlmodule QtQuick
void startXChanged()
void changed()
void disconnectPathElements()
static void pathElements_append(QQmlListProperty< QQuickPathElement > *, QQuickPathElement *)
QStringList attributes() const
QPainterPath path() const
bool isClosed() const
\qmlproperty bool QtQuick::Path::closed This property holds whether the start and end of the path are...
static void pathElements_clear(QQmlListProperty< QQuickPathElement > *)
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QPixmap p2
QPixmap p1
[0]
QString text
direction
short next
Definition keywords.cpp:445
Q_QUICK_EXPORT void pathArc(QPainterPath &path, qreal rx, qreal ry, qreal x_axis_rotation, int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx, qreal cury)
bool parsePathDataFast(const QString &dataStr, QPainterPath &path)
Combined button and popup list for selecting options.
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT EGLint attribute
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
#define qWarning
Definition qlogging.h:166
int qFloor(T v)
Definition qmath.h:42
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:112
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum GLenum GLuint GLint GLint GLint yscale
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLsizei const GLuint * paths
GLenum GLenum GLuint GLint GLint xscale
GLfloat angle
GLuint start
GLuint name
GLint first
GLint y
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint GLfloat * val
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint segments
GLfloat GLfloat p
[1]
GLenum GLenum GLenum GLenum GLenum scale
static qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
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 \instantiates QQuickPathLine \inqmlmodule QtQuick
QPointF previousPathPosition(const QPainterPath &path)
\qmltype PathCurve \instantiates QQuickPathCatmullRomCurve \inqmlmodule QtQuick
static QBezier nextBezier(const QPainterPath &path, int *current, qreal *bezLength, bool reverse=false)
static void scalePath(QPainterPath &path, const QSizeF &scale)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
const char property[13]
Definition qwizard.cpp:101
myObject disconnect()
[26]
const T & value() const