[844] | 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
|
---|