1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativestateoperations_p.h"
43
44 #include <qdeclarative.h>
45 #include <qdeclarativecontext.h>
46 #include <qdeclarativeexpression.h>
47 #include <qdeclarativeinfo.h>
48 #include <qdeclarativeanchors_p_p.h>
49 #include <qdeclarativeitem_p.h>
50 #include <qdeclarativeguard_p.h>
51 #include <qdeclarativenullablevalue_p_p.h>
52 #include "private/qdeclarativecontext_p.h"
53 #include "private/qdeclarativeproperty_p.h"
54 #include "private/qdeclarativebinding_p.h"
55 #include "private/qdeclarativestate_p_p.h"
56
57 #include <QtCore/qdebug.h>
58 #include <QtGui/qgraphicsitem.h>
59 #ifdef Q_OS_WINCE
60 // qgraphicsitem.h includes qfunctions_wince.h.
61 // qfunctions_wince.h defines a missing posix rewind for WinCE,
62 // but this conflicts with rewind method defined in this class.
63 // As a workaround we undefine WinCE posix replacement for rewind here.
64 # undef rewind
65 #endif
66 #include <QtCore/qmath.h>
67
68 #include <private/qobject_p.h>
69
70 QT_BEGIN_NAMESPACE
71
72 class QDeclarativeParentChangePrivate : public QDeclarativeStateOperationPrivate
73 {
74 Q_DECLARE_PUBLIC(QDeclarativeParentChange)
75 public:
QDeclarativeParentChangePrivate()76 QDeclarativeParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
77 rewindParent(0), rewindStackBefore(0) {}
78
79 QDeclarativeItem *target;
80 QDeclarativeGuard<QDeclarativeItem> parent;
81 QDeclarativeGuard<QDeclarativeItem> origParent;
82 QDeclarativeGuard<QDeclarativeItem> origStackBefore;
83 QDeclarativeItem *rewindParent;
84 QDeclarativeItem *rewindStackBefore;
85
86 QDeclarativeNullableValue<QDeclarativeScriptString> xString;
87 QDeclarativeNullableValue<QDeclarativeScriptString> yString;
88 QDeclarativeNullableValue<QDeclarativeScriptString> widthString;
89 QDeclarativeNullableValue<QDeclarativeScriptString> heightString;
90 QDeclarativeNullableValue<QDeclarativeScriptString> scaleString;
91 QDeclarativeNullableValue<QDeclarativeScriptString> rotationString;
92
93 QDeclarativeNullableValue<qreal> x;
94 QDeclarativeNullableValue<qreal> y;
95 QDeclarativeNullableValue<qreal> width;
96 QDeclarativeNullableValue<qreal> height;
97 QDeclarativeNullableValue<qreal> scale;
98 QDeclarativeNullableValue<qreal> rotation;
99
100 void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0);
101 };
102
doChange(QDeclarativeItem * targetParent,QDeclarativeItem * stackBefore)103 void QDeclarativeParentChangePrivate::doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore)
104 {
105 if (targetParent && target && target->parentItem()) {
106 Q_Q(QDeclarativeParentChange);
107 bool ok;
108 const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
109 if (transform.type() >= QTransform::TxShear || !ok) {
110 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under complex transform");
111 ok = false;
112 }
113
114 qreal scale = 1;
115 qreal rotation = 0;
116 bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
117 if (ok && !isRotate) {
118 if (transform.m11() == transform.m22())
119 scale = transform.m11();
120 else {
121 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under non-uniform scale");
122 ok = false;
123 }
124 } else if (ok && isRotate) {
125 if (transform.m11() == transform.m22())
126 scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
127 else {
128 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under non-uniform scale");
129 ok = false;
130 }
131
132 if (scale != 0)
133 rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/qreal(M_PI);
134 else {
135 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under scale of 0");
136 ok = false;
137 }
138 }
139
140 const QPointF &point = transform.map(QPointF(target->x(),target->y()));
141 qreal x = point.x();
142 qreal y = point.y();
143
144 // setParentItem will update the transformOriginPoint if needed
145 target->setParentItem(targetParent);
146
147 if (ok && target->transformOrigin() != QDeclarativeItem::TopLeft) {
148 qreal tempxt = target->transformOriginPoint().x();
149 qreal tempyt = target->transformOriginPoint().y();
150 QTransform t;
151 t.translate(-tempxt, -tempyt);
152 t.rotate(rotation);
153 t.scale(scale, scale);
154 t.translate(tempxt, tempyt);
155 const QPointF &offset = t.map(QPointF(0,0));
156 x += offset.x();
157 y += offset.y();
158 }
159
160 if (ok) {
161 //qDebug() << x << y << rotation << scale;
162 target->setX(x);
163 target->setY(y);
164 target->setRotation(target->rotation() + rotation);
165 target->setScale(target->scale() * scale);
166 }
167 } else if (target) {
168 target->setParentItem(targetParent);
169 }
170
171 //restore the original stack position.
172 //### if stackBefore has also been reparented this won't work
173 if (stackBefore)
174 target->stackBefore(stackBefore);
175 }
176
177 /*!
178 \preliminary
179 \qmlclass ParentChange QDeclarativeParentChange
180 \ingroup qml-state-elements
181 \brief The ParentChange element allows you to reparent an Item in a state change.
182
183 ParentChange reparents an item while preserving its visual appearance (position, size,
184 rotation, and scale) on screen. You can then specify a transition to move/resize/rotate/scale
185 the item to its final intended appearance.
186
187 ParentChange can only preserve visual appearance if no complex transforms are involved.
188 More specifically, it will not work if the transform property has been set for any
189 items involved in the reparenting (i.e. items in the common ancestor tree
190 for the original and new parent).
191
192 The example below displays a large red rectangle and a small blue rectangle, side by side.
193 When the \c blueRect is clicked, it changes to the "reparented" state: its parent is changed to \c redRect and it is
194 positioned at (10, 10) within the red rectangle, as specified in the ParentChange.
195
196 \snippet doc/src/snippets/declarative/parentchange.qml 0
197
198 \image parentchange.png
199
200 You can specify at which point in a transition you want a ParentChange to occur by
201 using a ParentAnimation.
202 */
203
204
QDeclarativeParentChange(QObject * parent)205 QDeclarativeParentChange::QDeclarativeParentChange(QObject *parent)
206 : QDeclarativeStateOperation(*(new QDeclarativeParentChangePrivate), parent)
207 {
208 }
209
~QDeclarativeParentChange()210 QDeclarativeParentChange::~QDeclarativeParentChange()
211 {
212 }
213
214 /*!
215 \qmlproperty real ParentChange::x
216 \qmlproperty real ParentChange::y
217 \qmlproperty real ParentChange::width
218 \qmlproperty real ParentChange::height
219 \qmlproperty real ParentChange::scale
220 \qmlproperty real ParentChange::rotation
221 These properties hold the new position, size, scale, and rotation
222 for the item in this state.
223 */
x() const224 QDeclarativeScriptString QDeclarativeParentChange::x() const
225 {
226 Q_D(const QDeclarativeParentChange);
227 return d->xString.value;
228 }
229
tryReal(QDeclarativeNullableValue<qreal> & value,const QString & string)230 void tryReal(QDeclarativeNullableValue<qreal> &value, const QString &string)
231 {
232 bool ok = false;
233 qreal realValue = string.toFloat(&ok);
234 if (ok)
235 value = realValue;
236 else
237 value.invalidate();
238 }
239
setX(QDeclarativeScriptString x)240 void QDeclarativeParentChange::setX(QDeclarativeScriptString x)
241 {
242 Q_D(QDeclarativeParentChange);
243 d->xString = x;
244 tryReal(d->x, x.script());
245 }
246
xIsSet() const247 bool QDeclarativeParentChange::xIsSet() const
248 {
249 Q_D(const QDeclarativeParentChange);
250 return d->xString.isValid();
251 }
252
y() const253 QDeclarativeScriptString QDeclarativeParentChange::y() const
254 {
255 Q_D(const QDeclarativeParentChange);
256 return d->yString.value;
257 }
258
setY(QDeclarativeScriptString y)259 void QDeclarativeParentChange::setY(QDeclarativeScriptString y)
260 {
261 Q_D(QDeclarativeParentChange);
262 d->yString = y;
263 tryReal(d->y, y.script());
264 }
265
yIsSet() const266 bool QDeclarativeParentChange::yIsSet() const
267 {
268 Q_D(const QDeclarativeParentChange);
269 return d->yString.isValid();
270 }
271
width() const272 QDeclarativeScriptString QDeclarativeParentChange::width() const
273 {
274 Q_D(const QDeclarativeParentChange);
275 return d->widthString.value;
276 }
277
setWidth(QDeclarativeScriptString width)278 void QDeclarativeParentChange::setWidth(QDeclarativeScriptString width)
279 {
280 Q_D(QDeclarativeParentChange);
281 d->widthString = width;
282 tryReal(d->width, width.script());
283 }
284
widthIsSet() const285 bool QDeclarativeParentChange::widthIsSet() const
286 {
287 Q_D(const QDeclarativeParentChange);
288 return d->widthString.isValid();
289 }
290
height() const291 QDeclarativeScriptString QDeclarativeParentChange::height() const
292 {
293 Q_D(const QDeclarativeParentChange);
294 return d->heightString.value;
295 }
296
setHeight(QDeclarativeScriptString height)297 void QDeclarativeParentChange::setHeight(QDeclarativeScriptString height)
298 {
299 Q_D(QDeclarativeParentChange);
300 d->heightString = height;
301 tryReal(d->height, height.script());
302 }
303
heightIsSet() const304 bool QDeclarativeParentChange::heightIsSet() const
305 {
306 Q_D(const QDeclarativeParentChange);
307 return d->heightString.isValid();
308 }
309
scale() const310 QDeclarativeScriptString QDeclarativeParentChange::scale() const
311 {
312 Q_D(const QDeclarativeParentChange);
313 return d->scaleString.value;
314 }
315
setScale(QDeclarativeScriptString scale)316 void QDeclarativeParentChange::setScale(QDeclarativeScriptString scale)
317 {
318 Q_D(QDeclarativeParentChange);
319 d->scaleString = scale;
320 tryReal(d->scale, scale.script());
321 }
322
scaleIsSet() const323 bool QDeclarativeParentChange::scaleIsSet() const
324 {
325 Q_D(const QDeclarativeParentChange);
326 return d->scaleString.isValid();
327 }
328
rotation() const329 QDeclarativeScriptString QDeclarativeParentChange::rotation() const
330 {
331 Q_D(const QDeclarativeParentChange);
332 return d->rotationString.value;
333 }
334
setRotation(QDeclarativeScriptString rotation)335 void QDeclarativeParentChange::setRotation(QDeclarativeScriptString rotation)
336 {
337 Q_D(QDeclarativeParentChange);
338 d->rotationString = rotation;
339 tryReal(d->rotation, rotation.script());
340 }
341
rotationIsSet() const342 bool QDeclarativeParentChange::rotationIsSet() const
343 {
344 Q_D(const QDeclarativeParentChange);
345 return d->rotationString.isValid();
346 }
347
originalParent() const348 QDeclarativeItem *QDeclarativeParentChange::originalParent() const
349 {
350 Q_D(const QDeclarativeParentChange);
351 return d->origParent;
352 }
353
354 /*!
355 \qmlproperty Item ParentChange::target
356 This property holds the item to be reparented
357 */
358
object() const359 QDeclarativeItem *QDeclarativeParentChange::object() const
360 {
361 Q_D(const QDeclarativeParentChange);
362 return d->target;
363 }
364
setObject(QDeclarativeItem * target)365 void QDeclarativeParentChange::setObject(QDeclarativeItem *target)
366 {
367 Q_D(QDeclarativeParentChange);
368 d->target = target;
369 }
370
371 /*!
372 \qmlproperty Item ParentChange::parent
373 This property holds the new parent for the item in this state.
374 */
375
parent() const376 QDeclarativeItem *QDeclarativeParentChange::parent() const
377 {
378 Q_D(const QDeclarativeParentChange);
379 return d->parent;
380 }
381
setParent(QDeclarativeItem * parent)382 void QDeclarativeParentChange::setParent(QDeclarativeItem *parent)
383 {
384 Q_D(QDeclarativeParentChange);
385 d->parent = parent;
386 }
387
actions()388 QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions()
389 {
390 Q_D(QDeclarativeParentChange);
391 if (!d->target || !d->parent)
392 return ActionList();
393
394 ActionList actions;
395
396 QDeclarativeAction a;
397 a.event = this;
398 actions << a;
399
400 QDeclarativeContext *ctxt = qmlContext(this);
401
402 if (d->xString.isValid()) {
403 if (d->x.isValid()) {
404 QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, d->x.value);
405 actions << xa;
406 } else {
407 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->xString.value.script(), d->target, ctxt);
408 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"), ctxt));
409 QDeclarativeAction xa;
410 xa.property = newBinding->property();
411 xa.toBinding = newBinding;
412 xa.fromValue = xa.property.read();
413 xa.deletableToBinding = true;
414 actions << xa;
415 }
416 }
417
418 if (d->yString.isValid()) {
419 if (d->y.isValid()) {
420 QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, d->y.value);
421 actions << ya;
422 } else {
423 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->yString.value.script(), d->target, ctxt);
424 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"), ctxt));
425 QDeclarativeAction ya;
426 ya.property = newBinding->property();
427 ya.toBinding = newBinding;
428 ya.fromValue = ya.property.read();
429 ya.deletableToBinding = true;
430 actions << ya;
431 }
432 }
433
434 if (d->scaleString.isValid()) {
435 if (d->scale.isValid()) {
436 QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, d->scale.value);
437 actions << sa;
438 } else {
439 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->scaleString.value.script(), d->target, ctxt);
440 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"), ctxt));
441 QDeclarativeAction sa;
442 sa.property = newBinding->property();
443 sa.toBinding = newBinding;
444 sa.fromValue = sa.property.read();
445 sa.deletableToBinding = true;
446 actions << sa;
447 }
448 }
449
450 if (d->rotationString.isValid()) {
451 if (d->rotation.isValid()) {
452 QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, d->rotation.value);
453 actions << ra;
454 } else {
455 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->rotationString.value.script(), d->target, ctxt);
456 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"), ctxt));
457 QDeclarativeAction ra;
458 ra.property = newBinding->property();
459 ra.toBinding = newBinding;
460 ra.fromValue = ra.property.read();
461 ra.deletableToBinding = true;
462 actions << ra;
463 }
464 }
465
466 if (d->widthString.isValid()) {
467 if (d->width.isValid()) {
468 QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, d->width.value);
469 actions << wa;
470 } else {
471 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->widthString.value.script(), d->target, ctxt);
472 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"), ctxt));
473 QDeclarativeAction wa;
474 wa.property = newBinding->property();
475 wa.toBinding = newBinding;
476 wa.fromValue = wa.property.read();
477 wa.deletableToBinding = true;
478 actions << wa;
479 }
480 }
481
482 if (d->heightString.isValid()) {
483 if (d->height.isValid()) {
484 QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, d->height.value);
485 actions << ha;
486 } else {
487 QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->heightString.value.script(), d->target, ctxt);
488 newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"), ctxt));
489 QDeclarativeAction ha;
490 ha.property = newBinding->property();
491 ha.toBinding = newBinding;
492 ha.fromValue = ha.property.read();
493 ha.deletableToBinding = true;
494 actions << ha;
495 }
496 }
497
498 return actions;
499 }
500
501 class AccessibleFxItem : public QDeclarativeItem
502 {
503 Q_OBJECT
504 Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
505 public:
siblingIndex()506 int siblingIndex() {
507 Q_D(QDeclarativeItem);
508 return d->siblingIndex;
509 }
510 };
511
saveOriginals()512 void QDeclarativeParentChange::saveOriginals()
513 {
514 Q_D(QDeclarativeParentChange);
515 saveCurrentValues();
516 d->origParent = d->rewindParent;
517 d->origStackBefore = d->rewindStackBefore;
518 }
519
520 /*void QDeclarativeParentChange::copyOriginals(QDeclarativeActionEvent *other)
521 {
522 Q_D(QDeclarativeParentChange);
523 QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(other);
524
525 d->origParent = pc->d_func()->rewindParent;
526 d->origStackBefore = pc->d_func()->rewindStackBefore;
527
528 saveCurrentValues();
529 }*/
530
execute(Reason)531 void QDeclarativeParentChange::execute(Reason)
532 {
533 Q_D(QDeclarativeParentChange);
534 d->doChange(d->parent);
535 }
536
isReversable()537 bool QDeclarativeParentChange::isReversable()
538 {
539 return true;
540 }
541
reverse(Reason)542 void QDeclarativeParentChange::reverse(Reason)
543 {
544 Q_D(QDeclarativeParentChange);
545 d->doChange(d->origParent, d->origStackBefore);
546 }
547
typeName() const548 QString QDeclarativeParentChange::typeName() const
549 {
550 return QLatin1String("ParentChange");
551 }
552
override(QDeclarativeActionEvent * other)553 bool QDeclarativeParentChange::override(QDeclarativeActionEvent*other)
554 {
555 Q_D(QDeclarativeParentChange);
556 if (other->typeName() != QLatin1String("ParentChange"))
557 return false;
558 if (QDeclarativeParentChange *otherPC = static_cast<QDeclarativeParentChange*>(other))
559 return (d->target == otherPC->object());
560 return false;
561 }
562
saveCurrentValues()563 void QDeclarativeParentChange::saveCurrentValues()
564 {
565 Q_D(QDeclarativeParentChange);
566 if (!d->target) {
567 d->rewindParent = 0;
568 d->rewindStackBefore = 0;
569 return;
570 }
571
572 d->rewindParent = d->target->parentItem();
573 d->rewindStackBefore = 0;
574
575 if (!d->rewindParent)
576 return;
577
578 //try to determine the item's original stack position so we can restore it
579 int siblingIndex = ((AccessibleFxItem*)d->target)->siblingIndex() + 1;
580 QList<QGraphicsItem*> children = d->rewindParent->childItems();
581 for (int i = 0; i < children.count(); ++i) {
582 QDeclarativeItem *child = qobject_cast<QDeclarativeItem*>(children.at(i));
583 if (!child)
584 continue;
585 if (((AccessibleFxItem*)child)->siblingIndex() == siblingIndex) {
586 d->rewindStackBefore = child;
587 break;
588 }
589 }
590 }
591
rewind()592 void QDeclarativeParentChange::rewind()
593 {
594 Q_D(QDeclarativeParentChange);
595 d->doChange(d->rewindParent, d->rewindStackBefore);
596 }
597
598 class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate
599 {
600 public:
QDeclarativeStateChangeScriptPrivate()601 QDeclarativeStateChangeScriptPrivate() {}
602
603 QDeclarativeScriptString script;
604 QString name;
605 };
606
607 /*!
608 \qmlclass StateChangeScript QDeclarativeStateChangeScript
609 \ingroup qml-state-elements
610 \brief The StateChangeScript element allows you to run a script in a state.
611
612 A StateChangeScript is run upon entering a state. You can optionally use
613 ScriptAction to specify the point in the transition at which
614 the StateChangeScript should to be run.
615
616 \snippet snippets/declarative/states/statechangescript.qml state and transition
617
618 \sa ScriptAction
619 */
620
QDeclarativeStateChangeScript(QObject * parent)621 QDeclarativeStateChangeScript::QDeclarativeStateChangeScript(QObject *parent)
622 : QDeclarativeStateOperation(*(new QDeclarativeStateChangeScriptPrivate), parent)
623 {
624 }
625
~QDeclarativeStateChangeScript()626 QDeclarativeStateChangeScript::~QDeclarativeStateChangeScript()
627 {
628 }
629
630 /*!
631 \qmlproperty script StateChangeScript::script
632 This property holds the script to run when the state is current.
633 */
script() const634 QDeclarativeScriptString QDeclarativeStateChangeScript::script() const
635 {
636 Q_D(const QDeclarativeStateChangeScript);
637 return d->script;
638 }
639
setScript(const QDeclarativeScriptString & s)640 void QDeclarativeStateChangeScript::setScript(const QDeclarativeScriptString &s)
641 {
642 Q_D(QDeclarativeStateChangeScript);
643 d->script = s;
644 }
645
646 /*!
647 \qmlproperty string StateChangeScript::name
648 This property holds the name of the script. This name can be used by a
649 ScriptAction to target a specific script.
650
651 \sa ScriptAction::scriptName
652 */
name() const653 QString QDeclarativeStateChangeScript::name() const
654 {
655 Q_D(const QDeclarativeStateChangeScript);
656 return d->name;
657 }
658
setName(const QString & n)659 void QDeclarativeStateChangeScript::setName(const QString &n)
660 {
661 Q_D(QDeclarativeStateChangeScript);
662 d->name = n;
663 }
664
execute(Reason)665 void QDeclarativeStateChangeScript::execute(Reason)
666 {
667 Q_D(QDeclarativeStateChangeScript);
668 const QString &script = d->script.script();
669 if (!script.isEmpty()) {
670 QDeclarativeExpression expr(d->script.context(), d->script.scopeObject(), script);
671 QDeclarativeData *ddata = QDeclarativeData::get(this);
672 if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
673 expr.setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
674 expr.evaluate();
675 if (expr.hasError())
676 qmlInfo(this, expr.error());
677 }
678 }
679
actions()680 QDeclarativeStateChangeScript::ActionList QDeclarativeStateChangeScript::actions()
681 {
682 ActionList rv;
683 QDeclarativeAction a;
684 a.event = this;
685 rv << a;
686 return rv;
687 }
688
typeName() const689 QString QDeclarativeStateChangeScript::typeName() const
690 {
691 return QLatin1String("StateChangeScript");
692 }
693
694 /*!
695 \qmlclass AnchorChanges QDeclarativeAnchorChanges
696 \ingroup qml-state-elements
697 \brief The AnchorChanges element allows you to change the anchors of an item in a state.
698
699 The AnchorChanges element is used to modify the anchors of an item in a \l State.
700
701 AnchorChanges cannot be used to modify the margins on an item. For this, use
702 PropertyChanges intead.
703
704 In the following example we change the top and bottom anchors of an item
705 using AnchorChanges, and the top and bottom anchor margins using
706 PropertyChanges:
707
708 \snippet doc/src/snippets/declarative/anchorchanges.qml 0
709
710 \image anchorchanges.png
711
712 AnchorChanges can be animated using AnchorAnimation.
713 \qml
714 //animate our anchor changes
715 Transition {
716 AnchorAnimation {}
717 }
718 \endqml
719
720 Margin animations can be animated using NumberAnimation.
721
722 For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
723 */
724
725 class QDeclarativeAnchorSetPrivate : public QObjectPrivate
726 {
727 Q_DECLARE_PUBLIC(QDeclarativeAnchorSet)
728 public:
QDeclarativeAnchorSetPrivate()729 QDeclarativeAnchorSetPrivate()
730 : usedAnchors(0), resetAnchors(0), fill(0),
731 centerIn(0)/*, leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
732 margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)*/
733 {
734 }
735
736 QDeclarativeAnchors::Anchors usedAnchors;
737 QDeclarativeAnchors::Anchors resetAnchors;
738
739 QDeclarativeItem *fill;
740 QDeclarativeItem *centerIn;
741
742 QDeclarativeScriptString leftScript;
743 QDeclarativeScriptString rightScript;
744 QDeclarativeScriptString topScript;
745 QDeclarativeScriptString bottomScript;
746 QDeclarativeScriptString hCenterScript;
747 QDeclarativeScriptString vCenterScript;
748 QDeclarativeScriptString baselineScript;
749
750 /*qreal leftMargin;
751 qreal rightMargin;
752 qreal topMargin;
753 qreal bottomMargin;
754 qreal margins;
755 qreal vCenterOffset;
756 qreal hCenterOffset;
757 qreal baselineOffset;*/
758 };
759
QDeclarativeAnchorSet(QObject * parent)760 QDeclarativeAnchorSet::QDeclarativeAnchorSet(QObject *parent)
761 : QObject(*new QDeclarativeAnchorSetPrivate, parent)
762 {
763 }
764
~QDeclarativeAnchorSet()765 QDeclarativeAnchorSet::~QDeclarativeAnchorSet()
766 {
767 }
768
top() const769 QDeclarativeScriptString QDeclarativeAnchorSet::top() const
770 {
771 Q_D(const QDeclarativeAnchorSet);
772 return d->topScript;
773 }
774
setTop(const QDeclarativeScriptString & edge)775 void QDeclarativeAnchorSet::setTop(const QDeclarativeScriptString &edge)
776 {
777 Q_D(QDeclarativeAnchorSet);
778 d->usedAnchors |= QDeclarativeAnchors::TopAnchor;
779 d->topScript = edge;
780 if (edge.script() == QLatin1String("undefined"))
781 resetTop();
782 }
783
resetTop()784 void QDeclarativeAnchorSet::resetTop()
785 {
786 Q_D(QDeclarativeAnchorSet);
787 d->usedAnchors &= ~QDeclarativeAnchors::TopAnchor;
788 d->topScript = QDeclarativeScriptString();
789 d->resetAnchors |= QDeclarativeAnchors::TopAnchor;
790 }
791
bottom() const792 QDeclarativeScriptString QDeclarativeAnchorSet::bottom() const
793 {
794 Q_D(const QDeclarativeAnchorSet);
795 return d->bottomScript;
796 }
797
setBottom(const QDeclarativeScriptString & edge)798 void QDeclarativeAnchorSet::setBottom(const QDeclarativeScriptString &edge)
799 {
800 Q_D(QDeclarativeAnchorSet);
801 d->usedAnchors |= QDeclarativeAnchors::BottomAnchor;
802 d->bottomScript = edge;
803 if (edge.script() == QLatin1String("undefined"))
804 resetBottom();
805 }
806
resetBottom()807 void QDeclarativeAnchorSet::resetBottom()
808 {
809 Q_D(QDeclarativeAnchorSet);
810 d->usedAnchors &= ~QDeclarativeAnchors::BottomAnchor;
811 d->bottomScript = QDeclarativeScriptString();
812 d->resetAnchors |= QDeclarativeAnchors::BottomAnchor;
813 }
814
verticalCenter() const815 QDeclarativeScriptString QDeclarativeAnchorSet::verticalCenter() const
816 {
817 Q_D(const QDeclarativeAnchorSet);
818 return d->vCenterScript;
819 }
820
setVerticalCenter(const QDeclarativeScriptString & edge)821 void QDeclarativeAnchorSet::setVerticalCenter(const QDeclarativeScriptString &edge)
822 {
823 Q_D(QDeclarativeAnchorSet);
824 d->usedAnchors |= QDeclarativeAnchors::VCenterAnchor;
825 d->vCenterScript = edge;
826 if (edge.script() == QLatin1String("undefined"))
827 resetVerticalCenter();
828 }
829
resetVerticalCenter()830 void QDeclarativeAnchorSet::resetVerticalCenter()
831 {
832 Q_D(QDeclarativeAnchorSet);
833 d->usedAnchors &= ~QDeclarativeAnchors::VCenterAnchor;
834 d->vCenterScript = QDeclarativeScriptString();
835 d->resetAnchors |= QDeclarativeAnchors::VCenterAnchor;
836 }
837
baseline() const838 QDeclarativeScriptString QDeclarativeAnchorSet::baseline() const
839 {
840 Q_D(const QDeclarativeAnchorSet);
841 return d->baselineScript;
842 }
843
setBaseline(const QDeclarativeScriptString & edge)844 void QDeclarativeAnchorSet::setBaseline(const QDeclarativeScriptString &edge)
845 {
846 Q_D(QDeclarativeAnchorSet);
847 d->usedAnchors |= QDeclarativeAnchors::BaselineAnchor;
848 d->baselineScript = edge;
849 if (edge.script() == QLatin1String("undefined"))
850 resetBaseline();
851 }
852
resetBaseline()853 void QDeclarativeAnchorSet::resetBaseline()
854 {
855 Q_D(QDeclarativeAnchorSet);
856 d->usedAnchors &= ~QDeclarativeAnchors::BaselineAnchor;
857 d->baselineScript = QDeclarativeScriptString();
858 d->resetAnchors |= QDeclarativeAnchors::BaselineAnchor;
859 }
860
left() const861 QDeclarativeScriptString QDeclarativeAnchorSet::left() const
862 {
863 Q_D(const QDeclarativeAnchorSet);
864 return d->leftScript;
865 }
866
setLeft(const QDeclarativeScriptString & edge)867 void QDeclarativeAnchorSet::setLeft(const QDeclarativeScriptString &edge)
868 {
869 Q_D(QDeclarativeAnchorSet);
870 d->usedAnchors |= QDeclarativeAnchors::LeftAnchor;
871 d->leftScript = edge;
872 if (edge.script() == QLatin1String("undefined"))
873 resetLeft();
874 }
875
resetLeft()876 void QDeclarativeAnchorSet::resetLeft()
877 {
878 Q_D(QDeclarativeAnchorSet);
879 d->usedAnchors &= ~QDeclarativeAnchors::LeftAnchor;
880 d->leftScript = QDeclarativeScriptString();
881 d->resetAnchors |= QDeclarativeAnchors::LeftAnchor;
882 }
883
right() const884 QDeclarativeScriptString QDeclarativeAnchorSet::right() const
885 {
886 Q_D(const QDeclarativeAnchorSet);
887 return d->rightScript;
888 }
889
setRight(const QDeclarativeScriptString & edge)890 void QDeclarativeAnchorSet::setRight(const QDeclarativeScriptString &edge)
891 {
892 Q_D(QDeclarativeAnchorSet);
893 d->usedAnchors |= QDeclarativeAnchors::RightAnchor;
894 d->rightScript = edge;
895 if (edge.script() == QLatin1String("undefined"))
896 resetRight();
897 }
898
resetRight()899 void QDeclarativeAnchorSet::resetRight()
900 {
901 Q_D(QDeclarativeAnchorSet);
902 d->usedAnchors &= ~QDeclarativeAnchors::RightAnchor;
903 d->rightScript = QDeclarativeScriptString();
904 d->resetAnchors |= QDeclarativeAnchors::RightAnchor;
905 }
906
horizontalCenter() const907 QDeclarativeScriptString QDeclarativeAnchorSet::horizontalCenter() const
908 {
909 Q_D(const QDeclarativeAnchorSet);
910 return d->hCenterScript;
911 }
912
setHorizontalCenter(const QDeclarativeScriptString & edge)913 void QDeclarativeAnchorSet::setHorizontalCenter(const QDeclarativeScriptString &edge)
914 {
915 Q_D(QDeclarativeAnchorSet);
916 d->usedAnchors |= QDeclarativeAnchors::HCenterAnchor;
917 d->hCenterScript = edge;
918 if (edge.script() == QLatin1String("undefined"))
919 resetHorizontalCenter();
920 }
921
resetHorizontalCenter()922 void QDeclarativeAnchorSet::resetHorizontalCenter()
923 {
924 Q_D(QDeclarativeAnchorSet);
925 d->usedAnchors &= ~QDeclarativeAnchors::HCenterAnchor;
926 d->hCenterScript = QDeclarativeScriptString();
927 d->resetAnchors |= QDeclarativeAnchors::HCenterAnchor;
928 }
929
fill() const930 QDeclarativeItem *QDeclarativeAnchorSet::fill() const
931 {
932 Q_D(const QDeclarativeAnchorSet);
933 return d->fill;
934 }
935
setFill(QDeclarativeItem * f)936 void QDeclarativeAnchorSet::setFill(QDeclarativeItem *f)
937 {
938 Q_D(QDeclarativeAnchorSet);
939 d->fill = f;
940 }
941
resetFill()942 void QDeclarativeAnchorSet::resetFill()
943 {
944 setFill(0);
945 }
946
centerIn() const947 QDeclarativeItem *QDeclarativeAnchorSet::centerIn() const
948 {
949 Q_D(const QDeclarativeAnchorSet);
950 return d->centerIn;
951 }
952
setCenterIn(QDeclarativeItem * c)953 void QDeclarativeAnchorSet::setCenterIn(QDeclarativeItem* c)
954 {
955 Q_D(QDeclarativeAnchorSet);
956 d->centerIn = c;
957 }
958
resetCenterIn()959 void QDeclarativeAnchorSet::resetCenterIn()
960 {
961 setCenterIn(0);
962 }
963
964
965 class QDeclarativeAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
966 {
967 public:
QDeclarativeAnchorChangesPrivate()968 QDeclarativeAnchorChangesPrivate()
969 : target(0), anchorSet(new QDeclarativeAnchorSet),
970 leftBinding(0), rightBinding(0), hCenterBinding(0),
971 topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0),
972 origLeftBinding(0), origRightBinding(0), origHCenterBinding(0),
973 origTopBinding(0), origBottomBinding(0), origVCenterBinding(0),
974 origBaselineBinding(0)
975 {
976
977 }
~QDeclarativeAnchorChangesPrivate()978 ~QDeclarativeAnchorChangesPrivate() { delete anchorSet; }
979
980 QDeclarativeItem *target;
981 QDeclarativeAnchorSet *anchorSet;
982
983 QDeclarativeBinding *leftBinding;
984 QDeclarativeBinding *rightBinding;
985 QDeclarativeBinding *hCenterBinding;
986 QDeclarativeBinding *topBinding;
987 QDeclarativeBinding *bottomBinding;
988 QDeclarativeBinding *vCenterBinding;
989 QDeclarativeBinding *baselineBinding;
990
991 QDeclarativeAbstractBinding *origLeftBinding;
992 QDeclarativeAbstractBinding *origRightBinding;
993 QDeclarativeAbstractBinding *origHCenterBinding;
994 QDeclarativeAbstractBinding *origTopBinding;
995 QDeclarativeAbstractBinding *origBottomBinding;
996 QDeclarativeAbstractBinding *origVCenterBinding;
997 QDeclarativeAbstractBinding *origBaselineBinding;
998
999 QDeclarativeAnchorLine rewindLeft;
1000 QDeclarativeAnchorLine rewindRight;
1001 QDeclarativeAnchorLine rewindHCenter;
1002 QDeclarativeAnchorLine rewindTop;
1003 QDeclarativeAnchorLine rewindBottom;
1004 QDeclarativeAnchorLine rewindVCenter;
1005 QDeclarativeAnchorLine rewindBaseline;
1006
1007 qreal fromX;
1008 qreal fromY;
1009 qreal fromWidth;
1010 qreal fromHeight;
1011
1012 qreal toX;
1013 qreal toY;
1014 qreal toWidth;
1015 qreal toHeight;
1016
1017 qreal rewindX;
1018 qreal rewindY;
1019 qreal rewindWidth;
1020 qreal rewindHeight;
1021
1022 bool applyOrigLeft;
1023 bool applyOrigRight;
1024 bool applyOrigHCenter;
1025 bool applyOrigTop;
1026 bool applyOrigBottom;
1027 bool applyOrigVCenter;
1028 bool applyOrigBaseline;
1029
1030 QDeclarativeNullableValue<qreal> origWidth;
1031 QDeclarativeNullableValue<qreal> origHeight;
1032 qreal origX;
1033 qreal origY;
1034
1035 QList<QDeclarativeAbstractBinding*> oldBindings;
1036
1037 QDeclarativeProperty leftProp;
1038 QDeclarativeProperty rightProp;
1039 QDeclarativeProperty hCenterProp;
1040 QDeclarativeProperty topProp;
1041 QDeclarativeProperty bottomProp;
1042 QDeclarativeProperty vCenterProp;
1043 QDeclarativeProperty baselineProp;
1044 };
1045
1046 /*!
1047 \qmlproperty Item AnchorChanges::target
1048 This property holds the \l Item for which the anchor changes will be applied.
1049 */
1050
QDeclarativeAnchorChanges(QObject * parent)1051 QDeclarativeAnchorChanges::QDeclarativeAnchorChanges(QObject *parent)
1052 : QDeclarativeStateOperation(*(new QDeclarativeAnchorChangesPrivate), parent)
1053 {
1054 }
1055
~QDeclarativeAnchorChanges()1056 QDeclarativeAnchorChanges::~QDeclarativeAnchorChanges()
1057 {
1058 }
1059
actions()1060 QDeclarativeAnchorChanges::ActionList QDeclarativeAnchorChanges::actions()
1061 {
1062 Q_D(QDeclarativeAnchorChanges);
1063 d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
1064 = d->bottomBinding = d->vCenterBinding = d->baselineBinding = 0;
1065
1066 d->leftProp = QDeclarativeProperty(d->target, QLatin1String("anchors.left"));
1067 d->rightProp = QDeclarativeProperty(d->target, QLatin1String("anchors.right"));
1068 d->hCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.horizontalCenter"));
1069 d->topProp = QDeclarativeProperty(d->target, QLatin1String("anchors.top"));
1070 d->bottomProp = QDeclarativeProperty(d->target, QLatin1String("anchors.bottom"));
1071 d->vCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.verticalCenter"));
1072 d->baselineProp = QDeclarativeProperty(d->target, QLatin1String("anchors.baseline"));
1073
1074 QDeclarativeContext *ctxt = qmlContext(this);
1075
1076 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::LeftAnchor) {
1077 d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, ctxt);
1078 d->leftBinding->setTarget(d->leftProp);
1079 }
1080 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::RightAnchor) {
1081 d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, ctxt);
1082 d->rightBinding->setTarget(d->rightProp);
1083 }
1084 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
1085 d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, ctxt);
1086 d->hCenterBinding->setTarget(d->hCenterProp);
1087 }
1088 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::TopAnchor) {
1089 d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, ctxt);
1090 d->topBinding->setTarget(d->topProp);
1091 }
1092 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BottomAnchor) {
1093 d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, ctxt);
1094 d->bottomBinding->setTarget(d->bottomProp);
1095 }
1096 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
1097 d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, ctxt);
1098 d->vCenterBinding->setTarget(d->vCenterProp);
1099 }
1100 if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BaselineAnchor) {
1101 d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, ctxt);
1102 d->baselineBinding->setTarget(d->baselineProp);
1103 }
1104
1105 QDeclarativeAction a;
1106 a.event = this;
1107 return ActionList() << a;
1108 }
1109
anchors()1110 QDeclarativeAnchorSet *QDeclarativeAnchorChanges::anchors()
1111 {
1112 Q_D(QDeclarativeAnchorChanges);
1113 return d->anchorSet;
1114 }
1115
object() const1116 QDeclarativeItem *QDeclarativeAnchorChanges::object() const
1117 {
1118 Q_D(const QDeclarativeAnchorChanges);
1119 return d->target;
1120 }
1121
setObject(QDeclarativeItem * target)1122 void QDeclarativeAnchorChanges::setObject(QDeclarativeItem *target)
1123 {
1124 Q_D(QDeclarativeAnchorChanges);
1125 d->target = target;
1126 }
1127
1128 /*!
1129 \qmlproperty AnchorLine AnchorChanges::anchors.left
1130 \qmlproperty AnchorLine AnchorChanges::anchors.right
1131 \qmlproperty AnchorLine AnchorChanges::anchors.horizontalCenter
1132 \qmlproperty AnchorLine AnchorChanges::anchors.top
1133 \qmlproperty AnchorLine AnchorChanges::anchors.bottom
1134 \qmlproperty AnchorLine AnchorChanges::anchors.verticalCenter
1135 \qmlproperty AnchorLine AnchorChanges::anchors.baseline
1136
1137 These properties change the respective anchors of the item.
1138
1139 To reset an anchor you can assign \c undefined:
1140 \qml
1141 AnchorChanges {
1142 target: myItem
1143 anchors.left: undefined //remove myItem's left anchor
1144 anchors.right: otherItem.right
1145 }
1146 \endqml
1147 */
1148
execute(Reason reason)1149 void QDeclarativeAnchorChanges::execute(Reason reason)
1150 {
1151 Q_D(QDeclarativeAnchorChanges);
1152 if (!d->target)
1153 return;
1154
1155 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1156 //incorporate any needed "reverts"
1157 if (d->applyOrigLeft) {
1158 if (!d->origLeftBinding)
1159 targetPrivate->anchors()->resetLeft();
1160 QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
1161 }
1162 if (d->applyOrigRight) {
1163 if (!d->origRightBinding)
1164 targetPrivate->anchors()->resetRight();
1165 QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
1166 }
1167 if (d->applyOrigHCenter) {
1168 if (!d->origHCenterBinding)
1169 targetPrivate->anchors()->resetHorizontalCenter();
1170 QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
1171 }
1172 if (d->applyOrigTop) {
1173 if (!d->origTopBinding)
1174 targetPrivate->anchors()->resetTop();
1175 QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
1176 }
1177 if (d->applyOrigBottom) {
1178 if (!d->origBottomBinding)
1179 targetPrivate->anchors()->resetBottom();
1180 QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
1181 }
1182 if (d->applyOrigVCenter) {
1183 if (!d->origVCenterBinding)
1184 targetPrivate->anchors()->resetVerticalCenter();
1185 QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
1186 }
1187 if (d->applyOrigBaseline) {
1188 if (!d->origBaselineBinding)
1189 targetPrivate->anchors()->resetBaseline();
1190 QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
1191 }
1192
1193 //destroy old bindings
1194 if (reason == ActualChange) {
1195 for (int i = 0; i < d->oldBindings.size(); ++i) {
1196 QDeclarativeAbstractBinding *binding = d->oldBindings.at(i);
1197 if (binding)
1198 binding->destroy();
1199 }
1200 d->oldBindings.clear();
1201 }
1202
1203 //reset any anchors that have been specified as "undefined"
1204 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::LeftAnchor) {
1205 targetPrivate->anchors()->resetLeft();
1206 QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
1207 }
1208 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::RightAnchor) {
1209 targetPrivate->anchors()->resetRight();
1210 QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
1211 }
1212 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::HCenterAnchor) {
1213 targetPrivate->anchors()->resetHorizontalCenter();
1214 QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
1215 }
1216 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::TopAnchor) {
1217 targetPrivate->anchors()->resetTop();
1218 QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
1219 }
1220 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::BottomAnchor) {
1221 targetPrivate->anchors()->resetBottom();
1222 QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
1223 }
1224 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::VCenterAnchor) {
1225 targetPrivate->anchors()->resetVerticalCenter();
1226 QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
1227 }
1228 if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::BaselineAnchor) {
1229 targetPrivate->anchors()->resetBaseline();
1230 QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
1231 }
1232
1233 //set any anchors that have been specified
1234 if (d->leftBinding)
1235 QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding);
1236 if (d->rightBinding)
1237 QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding);
1238 if (d->hCenterBinding)
1239 QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding);
1240 if (d->topBinding)
1241 QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), d->topBinding);
1242 if (d->bottomBinding)
1243 QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding);
1244 if (d->vCenterBinding)
1245 QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding);
1246 if (d->baselineBinding)
1247 QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding);
1248 }
1249
isReversable()1250 bool QDeclarativeAnchorChanges::isReversable()
1251 {
1252 return true;
1253 }
1254
reverse(Reason reason)1255 void QDeclarativeAnchorChanges::reverse(Reason reason)
1256 {
1257 Q_D(QDeclarativeAnchorChanges);
1258 if (!d->target)
1259 return;
1260
1261 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1262 //reset any anchors set by the state
1263 if (d->leftBinding) {
1264 targetPrivate->anchors()->resetLeft();
1265 QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), 0);
1266 if (reason == ActualChange) {
1267 d->leftBinding->destroy(); d->leftBinding = 0;
1268 }
1269 }
1270 if (d->rightBinding) {
1271 targetPrivate->anchors()->resetRight();
1272 QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), 0);
1273 if (reason == ActualChange) {
1274 d->rightBinding->destroy(); d->rightBinding = 0;
1275 }
1276 }
1277 if (d->hCenterBinding) {
1278 targetPrivate->anchors()->resetHorizontalCenter();
1279 QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), 0);
1280 if (reason == ActualChange) {
1281 d->hCenterBinding->destroy(); d->hCenterBinding = 0;
1282 }
1283 }
1284 if (d->topBinding) {
1285 targetPrivate->anchors()->resetTop();
1286 QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), 0);
1287 if (reason == ActualChange) {
1288 d->topBinding->destroy(); d->topBinding = 0;
1289 }
1290 }
1291 if (d->bottomBinding) {
1292 targetPrivate->anchors()->resetBottom();
1293 QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), 0);
1294 if (reason == ActualChange) {
1295 d->bottomBinding->destroy(); d->bottomBinding = 0;
1296 }
1297 }
1298 if (d->vCenterBinding) {
1299 targetPrivate->anchors()->resetVerticalCenter();
1300 QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), 0);
1301 if (reason == ActualChange) {
1302 d->vCenterBinding->destroy(); d->vCenterBinding = 0;
1303 }
1304 }
1305 if (d->baselineBinding) {
1306 targetPrivate->anchors()->resetBaseline();
1307 QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), 0);
1308 if (reason == ActualChange) {
1309 d->baselineBinding->destroy(); d->baselineBinding = 0;
1310 }
1311 }
1312
1313 //restore previous anchors
1314 if (d->origLeftBinding)
1315 QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
1316 if (d->origRightBinding)
1317 QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
1318 if (d->origHCenterBinding)
1319 QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
1320 if (d->origTopBinding)
1321 QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
1322 if (d->origBottomBinding)
1323 QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
1324 if (d->origVCenterBinding)
1325 QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
1326 if (d->origBaselineBinding)
1327 QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
1328
1329 //restore any absolute geometry changed by the state's anchors
1330 QDeclarativeAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Vertical_Mask;
1331 QDeclarativeAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Vertical_Mask;
1332 QDeclarativeAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Horizontal_Mask;
1333 QDeclarativeAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Horizontal_Mask;
1334
1335 bool stateSetWidth = (stateHAnchors &&
1336 stateHAnchors != QDeclarativeAnchors::LeftAnchor &&
1337 stateHAnchors != QDeclarativeAnchors::RightAnchor &&
1338 stateHAnchors != QDeclarativeAnchors::HCenterAnchor);
1339 bool origSetWidth = (origHAnchors &&
1340 origHAnchors != QDeclarativeAnchors::LeftAnchor &&
1341 origHAnchors != QDeclarativeAnchors::RightAnchor &&
1342 origHAnchors != QDeclarativeAnchors::HCenterAnchor);
1343 if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
1344 d->target->setWidth(d->origWidth.value);
1345
1346 bool stateSetHeight = (stateVAnchors &&
1347 stateVAnchors != QDeclarativeAnchors::TopAnchor &&
1348 stateVAnchors != QDeclarativeAnchors::BottomAnchor &&
1349 stateVAnchors != QDeclarativeAnchors::VCenterAnchor &&
1350 stateVAnchors != QDeclarativeAnchors::BaselineAnchor);
1351 bool origSetHeight = (origVAnchors &&
1352 origVAnchors != QDeclarativeAnchors::TopAnchor &&
1353 origVAnchors != QDeclarativeAnchors::BottomAnchor &&
1354 origVAnchors != QDeclarativeAnchors::VCenterAnchor &&
1355 origVAnchors != QDeclarativeAnchors::BaselineAnchor);
1356 if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
1357 d->target->setHeight(d->origHeight.value);
1358
1359 if (stateHAnchors && !origHAnchors)
1360 d->target->setX(d->origX);
1361
1362 if (stateVAnchors && !origVAnchors)
1363 d->target->setY(d->origY);
1364 }
1365
typeName() const1366 QString QDeclarativeAnchorChanges::typeName() const
1367 {
1368 return QLatin1String("AnchorChanges");
1369 }
1370
additionalActions()1371 QList<QDeclarativeAction> QDeclarativeAnchorChanges::additionalActions()
1372 {
1373 Q_D(QDeclarativeAnchorChanges);
1374 QList<QDeclarativeAction> extra;
1375
1376 QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
1377 bool hChange = combined & QDeclarativeAnchors::Horizontal_Mask;
1378 bool vChange = combined & QDeclarativeAnchors::Vertical_Mask;
1379
1380 if (d->target) {
1381 QDeclarativeContext *ctxt = qmlContext(this);
1382 QDeclarativeAction a;
1383 if (hChange && d->fromX != d->toX) {
1384 a.property = QDeclarativeProperty(d->target, QLatin1String("x"), ctxt);
1385 a.toValue = d->toX;
1386 extra << a;
1387 }
1388 if (vChange && d->fromY != d->toY) {
1389 a.property = QDeclarativeProperty(d->target, QLatin1String("y"), ctxt);
1390 a.toValue = d->toY;
1391 extra << a;
1392 }
1393 if (hChange && d->fromWidth != d->toWidth) {
1394 a.property = QDeclarativeProperty(d->target, QLatin1String("width"), ctxt);
1395 a.toValue = d->toWidth;
1396 extra << a;
1397 }
1398 if (vChange && d->fromHeight != d->toHeight) {
1399 a.property = QDeclarativeProperty(d->target, QLatin1String("height"), ctxt);
1400 a.toValue = d->toHeight;
1401 extra << a;
1402 }
1403 }
1404
1405 return extra;
1406 }
1407
changesBindings()1408 bool QDeclarativeAnchorChanges::changesBindings()
1409 {
1410 return true;
1411 }
1412
saveOriginals()1413 void QDeclarativeAnchorChanges::saveOriginals()
1414 {
1415 Q_D(QDeclarativeAnchorChanges);
1416 if (!d->target)
1417 return;
1418
1419 d->origLeftBinding = QDeclarativePropertyPrivate::binding(d->leftProp);
1420 d->origRightBinding = QDeclarativePropertyPrivate::binding(d->rightProp);
1421 d->origHCenterBinding = QDeclarativePropertyPrivate::binding(d->hCenterProp);
1422 d->origTopBinding = QDeclarativePropertyPrivate::binding(d->topProp);
1423 d->origBottomBinding = QDeclarativePropertyPrivate::binding(d->bottomProp);
1424 d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp);
1425 d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp);
1426
1427 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1428 if (targetPrivate->widthValid)
1429 d->origWidth = d->target->width();
1430 if (targetPrivate->heightValid)
1431 d->origHeight = d->target->height();
1432 d->origX = d->target->x();
1433 d->origY = d->target->y();
1434
1435 d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
1436 = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
1437
1438 saveCurrentValues();
1439 }
1440
copyOriginals(QDeclarativeActionEvent * other)1441 void QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
1442 {
1443 Q_D(QDeclarativeAnchorChanges);
1444 QDeclarativeAnchorChanges *ac = static_cast<QDeclarativeAnchorChanges*>(other);
1445 QDeclarativeAnchorChangesPrivate *acp = ac->d_func();
1446
1447 QDeclarativeAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
1448 acp->anchorSet->d_func()->resetAnchors;
1449
1450 //probably also need to revert some things
1451 d->applyOrigLeft = (combined & QDeclarativeAnchors::LeftAnchor);
1452 d->applyOrigRight = (combined & QDeclarativeAnchors::RightAnchor);
1453 d->applyOrigHCenter = (combined & QDeclarativeAnchors::HCenterAnchor);
1454 d->applyOrigTop = (combined & QDeclarativeAnchors::TopAnchor);
1455 d->applyOrigBottom = (combined & QDeclarativeAnchors::BottomAnchor);
1456 d->applyOrigVCenter = (combined & QDeclarativeAnchors::VCenterAnchor);
1457 d->applyOrigBaseline = (combined & QDeclarativeAnchors::BaselineAnchor);
1458
1459 d->origLeftBinding = acp->origLeftBinding;
1460 d->origRightBinding = acp->origRightBinding;
1461 d->origHCenterBinding = acp->origHCenterBinding;
1462 d->origTopBinding = acp->origTopBinding;
1463 d->origBottomBinding = acp->origBottomBinding;
1464 d->origVCenterBinding = acp->origVCenterBinding;
1465 d->origBaselineBinding = acp->origBaselineBinding;
1466
1467 d->origWidth = acp->origWidth;
1468 d->origHeight = acp->origHeight;
1469 d->origX = acp->origX;
1470 d->origY = acp->origY;
1471
1472 d->oldBindings.clear();
1473 d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding
1474 << acp->topBinding << acp->bottomBinding << acp->baselineBinding;
1475
1476 saveCurrentValues();
1477 }
1478
clearBindings()1479 void QDeclarativeAnchorChanges::clearBindings()
1480 {
1481 Q_D(QDeclarativeAnchorChanges);
1482 if (!d->target)
1483 return;
1484
1485 //### should this (saving "from" values) be moved to saveCurrentValues()?
1486 d->fromX = d->target->x();
1487 d->fromY = d->target->y();
1488 d->fromWidth = d->target->width();
1489 d->fromHeight = d->target->height();
1490
1491 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1492 //reset any anchors with corresponding reverts
1493 //reset any anchors that have been specified as "undefined"
1494 //reset any anchors that we'll be setting in the state
1495 QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
1496 d->anchorSet->d_func()->usedAnchors;
1497 if (d->applyOrigLeft || (combined & QDeclarativeAnchors::LeftAnchor)) {
1498 targetPrivate->anchors()->resetLeft();
1499 QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
1500 }
1501 if (d->applyOrigRight || (combined & QDeclarativeAnchors::RightAnchor)) {
1502 targetPrivate->anchors()->resetRight();
1503 QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
1504 }
1505 if (d->applyOrigHCenter || (combined & QDeclarativeAnchors::HCenterAnchor)) {
1506 targetPrivate->anchors()->resetHorizontalCenter();
1507 QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
1508 }
1509 if (d->applyOrigTop || (combined & QDeclarativeAnchors::TopAnchor)) {
1510 targetPrivate->anchors()->resetTop();
1511 QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
1512 }
1513 if (d->applyOrigBottom || (combined & QDeclarativeAnchors::BottomAnchor)) {
1514 targetPrivate->anchors()->resetBottom();
1515 QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
1516 }
1517 if (d->applyOrigVCenter || (combined & QDeclarativeAnchors::VCenterAnchor)) {
1518 targetPrivate->anchors()->resetVerticalCenter();
1519 QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
1520 }
1521 if (d->applyOrigBaseline || (combined & QDeclarativeAnchors::BaselineAnchor)) {
1522 targetPrivate->anchors()->resetBaseline();
1523 QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
1524 }
1525 }
1526
override(QDeclarativeActionEvent * other)1527 bool QDeclarativeAnchorChanges::override(QDeclarativeActionEvent*other)
1528 {
1529 if (other->typeName() != QLatin1String("AnchorChanges"))
1530 return false;
1531 if (static_cast<QDeclarativeActionEvent*>(this) == other)
1532 return true;
1533 if (static_cast<QDeclarativeAnchorChanges*>(other)->object() == object())
1534 return true;
1535 return false;
1536 }
1537
rewind()1538 void QDeclarativeAnchorChanges::rewind()
1539 {
1540 Q_D(QDeclarativeAnchorChanges);
1541 if (!d->target)
1542 return;
1543
1544 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1545
1546 //restore previous values (but not previous bindings, i.e. anchors)
1547 d->target->setX(d->rewindX);
1548 d->target->setY(d->rewindY);
1549 if (targetPrivate->widthValid) {
1550 d->target->setWidth(d->rewindWidth);
1551 }
1552 if (targetPrivate->heightValid) {
1553 d->target->setHeight(d->rewindHeight);
1554 }
1555 }
1556
saveCurrentValues()1557 void QDeclarativeAnchorChanges::saveCurrentValues()
1558 {
1559 Q_D(QDeclarativeAnchorChanges);
1560 if (!d->target)
1561 return;
1562
1563 QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1564 d->rewindLeft = targetPrivate->anchors()->left();
1565 d->rewindRight = targetPrivate->anchors()->right();
1566 d->rewindHCenter = targetPrivate->anchors()->horizontalCenter();
1567 d->rewindTop = targetPrivate->anchors()->top();
1568 d->rewindBottom = targetPrivate->anchors()->bottom();
1569 d->rewindVCenter = targetPrivate->anchors()->verticalCenter();
1570 d->rewindBaseline = targetPrivate->anchors()->baseline();
1571
1572 d->rewindX = d->target->x();
1573 d->rewindY = d->target->y();
1574 d->rewindWidth = d->target->width();
1575 d->rewindHeight = d->target->height();
1576 }
1577
saveTargetValues()1578 void QDeclarativeAnchorChanges::saveTargetValues()
1579 {
1580 Q_D(QDeclarativeAnchorChanges);
1581 if (!d->target)
1582 return;
1583
1584 d->toX = d->target->x();
1585 d->toY = d->target->y();
1586 d->toWidth = d->target->width();
1587 d->toHeight = d->target->height();
1588 }
1589
1590 #include <qdeclarativestateoperations.moc>
1591 #include <moc_qdeclarativestateoperations_p.cpp>
1592
1593 QT_END_NAMESPACE
1594
1595