Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / graphicsitems / qdeclarativepath.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativepath_p.h"
43 #include "private/qdeclarativepath_p_p.h"
44
45 #include <QSet>
46 #include <QTime>
47
48 #include <private/qbezier_p.h>
49 #include <QtCore/qmath.h>
50 #include <QtCore/qnumeric.h>
51
52 QT_BEGIN_NAMESPACE
53
54 /*!
55     \qmlclass PathElement QDeclarativePathElement
56     \ingroup qml-view-elements
57     \since 4.7
58     \brief PathElement is the base path type.
59
60     This type is the base for all path types.  It cannot
61     be instantiated.
62
63     \sa Path, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
64 */
65
66 /*!
67     \qmlclass Path QDeclarativePath
68     \ingroup qml-view-elements
69     \since 4.7
70     \brief A Path object defines a path for use by \l PathView.
71
72     A Path is composed of one or more path segments - PathLine, PathQuad,
73     PathCubic.
74
75     The spacing of the items along the Path can be adjusted via a
76     PathPercent object.
77
78     PathAttribute allows named attributes with values to be defined
79     along the path.
80
81     \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
82 */
83 QDeclarativePath::QDeclarativePath(QObject *parent)
84  : QObject(*(new QDeclarativePathPrivate), parent)
85 {
86 }
87
88 QDeclarativePath::~QDeclarativePath()
89 {
90 }
91
92 /*!
93     \qmlproperty real Path::startX
94     \qmlproperty real Path::startY
95     These properties hold the starting position of the path.
96 */
97 qreal QDeclarativePath::startX() const
98 {
99     Q_D(const QDeclarativePath);
100     return d->startX;
101 }
102
103 void QDeclarativePath::setStartX(qreal x)
104 {
105     Q_D(QDeclarativePath);
106     if (qFuzzyCompare(x, d->startX))
107         return;
108     d->startX = x;
109     emit startXChanged();
110     processPath();
111 }
112
113 qreal QDeclarativePath::startY() const
114 {
115     Q_D(const QDeclarativePath);
116     return d->startY;
117 }
118
119 void QDeclarativePath::setStartY(qreal y)
120 {
121     Q_D(QDeclarativePath);
122     if (qFuzzyCompare(y, d->startY))
123         return;
124     d->startY = y;
125     emit startYChanged();
126     processPath();
127 }
128
129 /*!
130     \qmlproperty bool Path::closed
131     This property holds whether the start and end of the path are identical.
132 */
133 bool QDeclarativePath::isClosed() const
134 {
135     Q_D(const QDeclarativePath);
136     return d->closed;
137 }
138
139 /*!
140     \qmlproperty list<PathElement> Path::pathElements
141     This property holds the objects composing the path.
142
143     \default
144
145     A path can contain the following path objects:
146     \list
147         \i \l PathLine - a straight line to a given position.
148         \i \l PathQuad - a quadratic Bezier curve to a given position with a control point.
149         \i \l PathCubic - a cubic Bezier curve to a given position with two control points.
150         \i \l PathAttribute - an attribute at a given position in the path.
151         \i \l PathPercent - a way to spread out items along various segments of the path.
152     \endlist
153
154     \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 2
155 */
156
157 QDeclarativeListProperty<QDeclarativePathElement> QDeclarativePath::pathElements()
158 {
159     Q_D(QDeclarativePath);
160     return QDeclarativeListProperty<QDeclarativePathElement>(this, d->_pathElements);
161 }
162
163 void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
164 {
165     Q_D(QDeclarativePath);
166     if (!idx)
167         return;
168
169     qreal lastValue = 0;
170     qreal lastPercent = 0;
171     int search = idx - 1;
172     while(search >= 0) {
173         const AttributePoint &point = d->_attributePoints.at(search);
174         if (point.values.contains(name)) {
175             lastValue = point.values.value(name);
176             lastPercent = point.origpercent;
177             break;
178         }
179         --search;
180     }
181
182     ++search;
183
184     const AttributePoint &curPoint = d->_attributePoints.at(idx);
185
186     for (int ii = search; ii < idx; ++ii) {
187         AttributePoint &point = d->_attributePoints[ii];
188
189         qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
190         point.values.insert(name, val);
191     }
192 }
193
194 void QDeclarativePath::endpoint(const QString &name)
195 {
196     Q_D(QDeclarativePath);
197     const AttributePoint &first = d->_attributePoints.first();
198     qreal val = first.values.value(name);
199     for (int ii = d->_attributePoints.count() - 1; ii >= 0; ii--) {
200         const AttributePoint &point = d->_attributePoints.at(ii);
201         if (point.values.contains(name)) {
202             for (int jj = ii + 1; jj < d->_attributePoints.count(); ++jj) {
203                 AttributePoint &setPoint = d->_attributePoints[jj];
204                 setPoint.values.insert(name, val);
205             }
206             return;
207         }
208     }
209 }
210
211 void QDeclarativePath::processPath()
212 {
213     Q_D(QDeclarativePath);
214
215     if (!d->componentComplete)
216         return;
217
218     d->_pointCache.clear();
219     d->_attributePoints.clear();
220     d->_path = QPainterPath();
221
222     AttributePoint first;
223     for (int ii = 0; ii < d->_attributes.count(); ++ii)
224         first.values[d->_attributes.at(ii)] = 0;
225     d->_attributePoints << first;
226
227     d->_path.moveTo(d->startX, d->startY);
228
229     QDeclarativeCurve *lastCurve = 0;
230     foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
231         if (QDeclarativeCurve *curve = qobject_cast<QDeclarativeCurve *>(pathElement)) {
232             curve->addToPath(d->_path);
233             AttributePoint p;
234             p.origpercent = d->_path.length();
235             d->_attributePoints << p;
236             lastCurve = curve;
237         } else if (QDeclarativePathAttribute *attribute = qobject_cast<QDeclarativePathAttribute *>(pathElement)) {
238             AttributePoint &point = d->_attributePoints.last();
239             point.values[attribute->name()] = attribute->value();
240             interpolate(d->_attributePoints.count() - 1, attribute->name(), attribute->value());
241         } else if (QDeclarativePathPercent *percent = qobject_cast<QDeclarativePathPercent *>(pathElement)) {
242             AttributePoint &point = d->_attributePoints.last();
243             point.values[QLatin1String("_qfx_percent")] = percent->value();
244             interpolate(d->_attributePoints.count() - 1, QLatin1String("_qfx_percent"), percent->value());
245         }
246     }
247
248     // Fixup end points
249     const AttributePoint &last = d->_attributePoints.last();
250     for (int ii = 0; ii < d->_attributes.count(); ++ii) {
251         if (!last.values.contains(d->_attributes.at(ii)))
252             endpoint(d->_attributes.at(ii));
253     }
254
255     // Adjust percent
256     qreal length = d->_path.length();
257     qreal prevpercent = 0;
258     qreal prevorigpercent = 0;
259     for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
260         const AttributePoint &point = d->_attributePoints.at(ii);
261         if (point.values.contains(QLatin1String("_qfx_percent"))) { //special string for QDeclarativePathPercent
262             if ( ii > 0) {
263                 qreal scale = (d->_attributePoints[ii].origpercent/length - prevorigpercent) /
264                             (point.values.value(QLatin1String("_qfx_percent"))-prevpercent);
265                 d->_attributePoints[ii].scale = scale;
266             }
267             d->_attributePoints[ii].origpercent /= length;
268             d->_attributePoints[ii].percent = point.values.value(QLatin1String("_qfx_percent"));
269             prevorigpercent = d->_attributePoints[ii].origpercent;
270             prevpercent = d->_attributePoints[ii].percent;
271         } else {
272             d->_attributePoints[ii].origpercent /= length;
273             d->_attributePoints[ii].percent = d->_attributePoints[ii].origpercent;
274         }
275     }
276
277     d->closed = lastCurve && d->startX == lastCurve->x() && d->startY == lastCurve->y();
278
279     emit changed();
280 }
281
282 void QDeclarativePath::classBegin()
283 {
284     Q_D(QDeclarativePath);
285     d->componentComplete = false;
286 }
287
288 void QDeclarativePath::componentComplete()
289 {
290     Q_D(QDeclarativePath);
291     QSet<QString> attrs;
292     d->componentComplete = true;
293
294     // First gather up all the attributes
295     foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
296         if (QDeclarativePathAttribute *attribute =
297             qobject_cast<QDeclarativePathAttribute *>(pathElement))
298             attrs.insert(attribute->name());
299     }
300     d->_attributes = attrs.toList();
301
302     processPath();
303
304     foreach (QDeclarativePathElement *pathElement, d->_pathElements)
305         connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
306 }
307
308 QPainterPath QDeclarativePath::path() const
309 {
310     Q_D(const QDeclarativePath);
311     return d->_path;
312 }
313
314 QStringList QDeclarativePath::attributes() const
315 {
316     Q_D(const QDeclarativePath);
317     if (!d->componentComplete) {
318         QSet<QString> attrs;
319
320         // First gather up all the attributes
321         foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
322             if (QDeclarativePathAttribute *attribute =
323                 qobject_cast<QDeclarativePathAttribute *>(pathElement))
324                 attrs.insert(attribute->name());
325         }
326         return attrs.toList();
327     }
328     return d->_attributes;
329 }
330
331 static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bezLength)
332 {
333     const int lastElement = path.elementCount() - 1;
334     for (int i=*from; i <= lastElement; ++i) {
335         const QPainterPath::Element &e = path.elementAt(i);
336
337         switch (e.type) {
338         case QPainterPath::MoveToElement:
339             break;
340         case QPainterPath::LineToElement:
341         {
342             QLineF line(path.elementAt(i-1), e);
343             *bezLength = line.length();
344             QPointF a = path.elementAt(i-1);
345             QPointF delta = e - a;
346             *from = i+1;
347             return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
348         }
349         case QPainterPath::CurveToElement:
350         {
351             QBezier b = QBezier::fromPoints(path.elementAt(i-1),
352                                             e,
353                                             path.elementAt(i+1),
354                                             path.elementAt(i+2));
355             *bezLength = b.length();
356             *from = i+3;
357             return b;
358         }
359         default:
360             break;
361         }
362     }
363     *from = lastElement;
364     *bezLength = 0;
365     return QBezier();
366 }
367
368 void QDeclarativePath::createPointCache() const
369 {
370     Q_D(const QDeclarativePath);
371     qreal pathLength = d->_path.length();
372     if (pathLength <= 0 || qIsNaN(pathLength))
373         return;
374     // more points means less jitter between items as they move along the
375     // path, but takes longer to generate
376     const int points = qCeil(pathLength*5);
377     const int lastElement = d->_path.elementCount() - 1;
378     d->_pointCache.resize(points+1);
379
380     int currElement = 0;
381     qreal bezLength = 0;
382     QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
383     qreal currLength = bezLength;
384     qreal epc = currLength / pathLength;
385
386     for (int i = 0; i < d->_pointCache.size(); i++) {
387         //find which set we are in
388         qreal prevPercent = 0;
389         qreal prevOrigPercent = 0;
390         for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
391             qreal percent = qreal(i)/points;
392             const AttributePoint &point = d->_attributePoints.at(ii);
393             if (percent < point.percent || ii == d->_attributePoints.count() - 1) { //### || is special case for very last item
394                 qreal elementPercent = (percent - prevPercent);
395
396                 qreal spc = prevOrigPercent + elementPercent * point.scale;
397
398                 while (spc > epc) {
399                     if (currElement > lastElement)
400                         break;
401                     currBez = nextBezier(d->_path, &currElement, &bezLength);
402                     if (bezLength == 0.0) {
403                         currLength = pathLength;
404                         epc = 1.0;
405                         break;
406                     }
407                     currLength += bezLength;
408                     epc = currLength / pathLength;
409                 }
410                 qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
411                 d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
412                 break;
413             }
414             prevOrigPercent = point.origpercent;
415             prevPercent = point.percent;
416         }
417     }
418 }
419
420 QPointF QDeclarativePath::pointAt(qreal p) const
421 {
422     Q_D(const QDeclarativePath);
423     if (d->_pointCache.isEmpty()) {
424         createPointCache();
425         if (d->_pointCache.isEmpty())
426             return QPointF();
427     }
428     int idx = qRound(p*d->_pointCache.size());
429     if (idx >= d->_pointCache.size())
430         idx = d->_pointCache.size() - 1;
431     else if (idx < 0)
432         idx = 0;
433     return d->_pointCache.at(idx);
434 }
435
436 qreal QDeclarativePath::attributeAt(const QString &name, qreal percent) const
437 {
438     Q_D(const QDeclarativePath);
439     if (percent < 0 || percent > 1)
440         return 0;
441
442     for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
443         const AttributePoint &point = d->_attributePoints.at(ii);
444
445         if (point.percent == percent) {
446             return point.values.value(name);
447         } else if (point.percent > percent) {
448             qreal lastValue =
449                 ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
450             qreal lastPercent =
451                 ii?(d->_attributePoints.at(ii - 1).percent):0;
452             qreal curValue = point.values.value(name);
453             qreal curPercent = point.percent;
454
455             return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
456         }
457     }
458
459     return 0;
460 }
461
462 /****************************************************************************/
463
464 qreal QDeclarativeCurve::x() const
465 {
466     return _x;
467 }
468
469 void QDeclarativeCurve::setX(qreal x)
470 {
471     if (_x != x) {
472         _x = x;
473         emit xChanged();
474         emit changed();
475     }
476 }
477
478 qreal QDeclarativeCurve::y() const
479 {
480     return _y;
481 }
482
483 void QDeclarativeCurve::setY(qreal y)
484 {
485     if (_y != y) {
486         _y = y;
487         emit yChanged();
488         emit changed();
489     }
490 }
491
492 /****************************************************************************/
493
494 /*!
495     \qmlclass PathAttribute QDeclarativePathAttribute
496     \ingroup qml-view-elements
497     \since 4.7
498     \brief The PathAttribute allows setting an attribute at a given position in a Path.
499
500     The PathAttribute object allows attributes consisting of a name and
501     a value to be specified for various points along a path.  The
502     attributes are exposed to the delegate as
503     \l{qdeclarativeintroduction.html#attached-properties} {Attached Properties}.
504     The value of an attribute at any particular point along the path is interpolated
505     from the PathAttributes bounding that point.
506
507     The example below shows a path with the items scaled to 30% with
508     opacity 50% at the top of the path and scaled 100% with opacity
509     100% at the bottom.  Note the use of the PathView.iconScale and
510     PathView.iconOpacity attached properties to set the scale and opacity
511     of the delegate.
512
513     \table
514     \row
515     \o \image declarative-pathattribute.png
516     \o
517     \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 0
518     (see the PathView documentation for the specification of ContactModel.qml
519      used for ContactModel above.)
520     \endtable
521
522
523     \sa Path
524 */
525
526 /*!
527     \qmlproperty string PathAttribute::name
528     This property holds the name of the attribute to change.
529
530     This attribute will be available to the delegate as PathView.<name>
531
532     Note that using an existing Item property name such as "opacity" as an
533     attribute is allowed.  This is because path attributes add a new
534     \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
535     which in no way clashes with existing properties.
536 */
537
538 /*!
539     the name of the attribute to change.
540 */
541
542 QString QDeclarativePathAttribute::name() const
543 {
544     return _name;
545 }
546
547 void QDeclarativePathAttribute::setName(const QString &name)
548 {
549     if (_name == name)
550         return;
551      _name = name;
552     emit nameChanged();
553 }
554
555 /*!
556    \qmlproperty real PathAttribute::value
557    This property holds the value for the attribute.
558
559    The value specified can be used to influence the visual appearance
560    of an item along the path. For example, the following Path specifies
561    an attribute named \e itemRotation, which has the value \e 0 at the
562    beginning of the path, and the value 90 at the end of the path.
563
564    \qml
565    Path {
566        startX: 0
567        startY: 0
568        PathAttribute { name: "itemRotation"; value: 0 }
569        PathLine { x: 100; y: 100 }
570        PathAttribute { name: "itemRotation"; value: 90 }
571    }
572    \endqml
573
574    In our delegate, we can then bind the \e rotation property to the
575    \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
576    \e PathView.itemRotation created for this attribute.
577
578    \qml
579    Rectangle {
580        width: 10; height: 10
581        rotation: PathView.itemRotation
582    }
583    \endqml
584
585    As each item is positioned along the path, it will be rotated accordingly:
586    an item at the beginning of the path with be not be rotated, an item at
587    the end of the path will be rotated 90 degrees, and an item mid-way along
588    the path will be rotated 45 degrees.
589 */
590
591 /*!
592     the new value of the attribute.
593 */
594 qreal QDeclarativePathAttribute::value() const
595 {
596     return _value;
597 }
598
599 void QDeclarativePathAttribute::setValue(qreal value)
600 {
601     if (_value != value) {
602         _value = value;
603         emit valueChanged();
604         emit changed();
605     }
606 }
607
608 /****************************************************************************/
609
610 /*!
611     \qmlclass PathLine QDeclarativePathLine
612     \ingroup qml-view-elements
613     \since 4.7
614     \brief The PathLine defines a straight line.
615
616     The example below creates a path consisting of a straight line from
617     0,100 to 200,100:
618
619     \qml
620     Path {
621         startX: 0; startY: 100
622         PathLine { x: 200; y: 100 }
623     }
624     \endqml
625
626     \sa Path, PathQuad, PathCubic
627 */
628
629 /*!
630     \qmlproperty real PathLine::x
631     \qmlproperty real PathLine::y
632
633     Defines the end point of the line.
634 */
635
636 void QDeclarativePathLine::addToPath(QPainterPath &path)
637 {
638     path.lineTo(x(), y());
639 }
640
641 /****************************************************************************/
642
643 /*!
644     \qmlclass PathQuad QDeclarativePathQuad
645     \ingroup qml-view-elements
646     \since 4.7
647     \brief The PathQuad defines a quadratic Bezier curve with a control point.
648
649     The following QML produces the path shown below:
650     \table
651     \row
652     \o \image declarative-pathquad.png
653     \o
654     \qml
655     Path {
656         startX: 0; startY: 0
657         PathQuad { x: 200; y: 0; controlX: 100; controlY: 150 }
658     }
659     \endqml
660     \endtable
661
662     \sa Path, PathCubic, PathLine
663 */
664
665 /*!
666     \qmlproperty real PathQuad::x
667     \qmlproperty real PathQuad::y
668
669     Defines the end point of the curve.
670 */
671
672 /*!
673    \qmlproperty real PathQuad::controlX
674    \qmlproperty real PathQuad::controlY
675
676    Defines the position of the control point.
677 */
678
679 /*!
680     the x position of the control point.
681 */
682 qreal QDeclarativePathQuad::controlX() const
683 {
684     return _controlX;
685 }
686
687 void QDeclarativePathQuad::setControlX(qreal x)
688 {
689     if (_controlX != x) {
690         _controlX = x;
691         emit controlXChanged();
692         emit changed();
693     }
694 }
695
696
697 /*!
698     the y position of the control point.
699 */
700 qreal QDeclarativePathQuad::controlY() const
701 {
702     return _controlY;
703 }
704
705 void QDeclarativePathQuad::setControlY(qreal y)
706 {
707     if (_controlY != y) {
708         _controlY = y;
709         emit controlYChanged();
710         emit changed();
711     }
712 }
713
714 void QDeclarativePathQuad::addToPath(QPainterPath &path)
715 {
716     path.quadTo(controlX(), controlY(), x(), y());
717 }
718
719 /****************************************************************************/
720
721 /*!
722    \qmlclass PathCubic QDeclarativePathCubic
723     \ingroup qml-view-elements
724     \since 4.7
725    \brief The PathCubic defines a cubic Bezier curve with two control points.
726
727     The following QML produces the path shown below:
728     \table
729     \row
730     \o \image declarative-pathcubic.png
731     \o
732     \qml
733     Path {
734         startX: 20; startY: 0
735         PathCubic {
736             x: 180; y: 0
737             control1X: -10; control1Y: 90
738             control2X: 210; control2Y: 90
739         }
740     }
741     \endqml
742     \endtable
743
744     \sa Path, PathQuad, PathLine
745 */
746
747 /*!
748     \qmlproperty real PathCubic::x
749     \qmlproperty real PathCubic::y
750
751     Defines the end point of the curve.
752 */
753
754 /*!
755    \qmlproperty real PathCubic::control1X
756    \qmlproperty real PathCubic::control1Y
757
758     Defines the position of the first control point.
759 */
760 qreal QDeclarativePathCubic::control1X() const
761 {
762     return _control1X;
763 }
764
765 void QDeclarativePathCubic::setControl1X(qreal x)
766 {
767     if (_control1X != x) {
768         _control1X = x;
769         emit control1XChanged();
770         emit changed();
771     }
772 }
773
774 qreal QDeclarativePathCubic::control1Y() const
775 {
776     return _control1Y;
777 }
778
779 void QDeclarativePathCubic::setControl1Y(qreal y)
780 {
781     if (_control1Y != y) {
782         _control1Y = y;
783         emit control1YChanged();
784         emit changed();
785     }
786 }
787
788 /*!
789    \qmlproperty real PathCubic::control2X
790    \qmlproperty real PathCubic::control2Y
791
792     Defines the position of the second control point.
793 */
794 qreal QDeclarativePathCubic::control2X() const
795 {
796     return _control2X;
797 }
798
799 void QDeclarativePathCubic::setControl2X(qreal x)
800 {
801     if (_control2X != x) {
802         _control2X = x;
803         emit control2XChanged();
804         emit changed();
805     }
806 }
807
808 qreal QDeclarativePathCubic::control2Y() const
809 {
810     return _control2Y;
811 }
812
813 void QDeclarativePathCubic::setControl2Y(qreal y)
814 {
815     if (_control2Y != y) {
816         _control2Y = y;
817         emit control2YChanged();
818         emit changed();
819     }
820 }
821
822 void QDeclarativePathCubic::addToPath(QPainterPath &path)
823 {
824     path.cubicTo(control1X(), control1Y(), control2X(), control2Y(), x(), y());
825 }
826
827 /****************************************************************************/
828
829 /*!
830     \qmlclass PathPercent QDeclarativePathPercent
831     \ingroup qml-view-elements
832     \since 4.7
833     \brief The PathPercent manipulates the way a path is interpreted.
834
835     PathPercent allows you to manipulate the spacing between items on a
836     PathView's path. You can use it to bunch together items on part of
837     the path, and spread them out on other parts of the path.
838
839     The examples below show the normal distrubution of items along a path
840     compared to a distribution which places 50% of the items along the
841     PathLine section of the path.
842     \table
843     \row
844     \o \image declarative-nopercent.png
845     \o
846     \qml
847     PathView {
848         // ...
849         Path {
850             startX: 20; startY: 0
851             PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
852             PathLine { x: 150; y: 80 }
853             PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
854         }
855     }
856     \endqml
857     \row
858     \o \image declarative-percent.png
859     \o
860     \qml
861     PathView {
862         // ...
863         Path {
864             startX: 20; startY: 0
865             PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
866             PathPercent { value: 0.25 }
867             PathLine { x: 150; y: 80 }
868             PathPercent { value: 0.75 }
869             PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
870             PathPercent { value: 1 }
871         }
872     }
873     \endqml
874     \endtable
875
876     \sa Path
877 */
878
879 /*!
880     \qmlproperty real PathPercent::value
881     The proporation of items that should be laid out up to this point.
882
883     This value should always be higher than the last value specified
884     by a PathPercent at a previous position in the Path.
885
886     In the following example we have a Path made up of three PathLines.
887     Normally, the items of the PathView would be laid out equally along
888     this path, with an equal number of items per line segment. PathPercent
889     allows us to specify that the first and third lines should each hold
890     10% of the laid out items, while the second line should hold the remaining
891     80%.
892
893     \qml
894     PathView {
895         // ...
896         Path {
897             startX: 0; startY: 0
898             PathLine { x:100; y: 0; }
899             PathPercent { value: 0.1 }
900             PathLine { x: 100; y: 100 }
901             PathPercent { value: 0.9 }
902             PathLine { x: 100; y: 0 }
903             PathPercent { value: 1 }
904         }
905     }
906     \endqml
907 */
908
909 qreal QDeclarativePathPercent::value() const
910 {
911     return _value;
912 }
913
914 void QDeclarativePathPercent::setValue(qreal value)
915 {
916     if (_value != value) {
917         _value = value;
918         emit valueChanged();
919         emit changed();
920     }
921 }
922 QT_END_NAMESPACE