Skip to content

Latest commit

 

History

History
1800 lines (1492 loc) · 51.7 KB

qquickpath.cpp

File metadata and controls

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