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 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
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 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at qt-info@nokia.com.
|
---|
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
|
---|