1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQuick 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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qquickstateoperations_p.h"
41 #include "qquickitem_p.h"
42 
43 #include <private/qquickstate_p_p.h>
44 
45 #include <QtQml/qqmlinfo.h>
46 #include <QtCore/qmath.h>
47 #include <memory>
48 
49 QT_BEGIN_NAMESPACE
50 
51 class QQuickParentChangePrivate : public QQuickStateOperationPrivate
52 {
53     Q_DECLARE_PUBLIC(QQuickParentChange)
54 public:
55     QQuickItem *target = nullptr;
56     QPointer<QQuickItem> parent;
57 
58     struct StateSnapshot {
59         QPointer<QQuickItem> parent;
60         QPointer<QQuickItem> stackBefore;
61         qreal x = 0, y = 0, width = 0, height = 0, scale = 0, rotation = 0;
62     };
63 
64     std::unique_ptr<StateSnapshot> orig;
65     std::unique_ptr<StateSnapshot> rewind;
66 
67     QQmlNullableValue<QQmlScriptString> xString;
68     QQmlNullableValue<QQmlScriptString> yString;
69     QQmlNullableValue<QQmlScriptString> widthString;
70     QQmlNullableValue<QQmlScriptString> heightString;
71     QQmlNullableValue<QQmlScriptString> scaleString;
72     QQmlNullableValue<QQmlScriptString> rotationString;
73 
74     void doChange(QQuickItem *targetParent);
75     void reverseRewindHelper(const std::unique_ptr<StateSnapshot> &snapshot);
76 };
77 
doChange(QQuickItem * targetParent)78 void QQuickParentChangePrivate::doChange(QQuickItem *targetParent)
79 {
80     if (targetParent && target && target->parentItem()) {
81         Q_Q(QQuickParentChange);
82         bool ok;
83         const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
84         if (transform.type() >= QTransform::TxShear || !ok) {
85             qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under complex transform");
86             ok = false;
87         }
88 
89         qreal scale = 1;
90         qreal rotation = 0;
91         bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
92         if (ok && !isRotate) {
93             if (transform.m11() == transform.m22())
94                 scale = transform.m11();
95             else {
96                 qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under non-uniform scale");
97                 ok = false;
98             }
99         } else if (ok && isRotate) {
100             if (transform.m11() == transform.m22())
101                 scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
102             else {
103                 qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under non-uniform scale");
104                 ok = false;
105             }
106 
107             if (scale != 0)
108                 rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale));
109             else {
110                 qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under scale of 0");
111                 ok = false;
112             }
113         }
114 
115         const QPointF &point = transform.map(QPointF(target->x(),target->y()));
116         qreal x = point.x();
117         qreal y = point.y();
118 
119         // setParentItem will update the transformOriginPoint if needed
120         target->setParentItem(targetParent);
121 
122         if (ok && target->transformOrigin() != QQuickItem::TopLeft) {
123             qreal tempxt = target->transformOriginPoint().x();
124             qreal tempyt = target->transformOriginPoint().y();
125             QTransform t;
126             t.translate(-tempxt, -tempyt);
127             t.rotate(rotation);
128             t.scale(scale, scale);
129             t.translate(tempxt, tempyt);
130             const QPointF &offset = t.map(QPointF(0,0));
131             x += offset.x();
132             y += offset.y();
133         }
134 
135         if (ok) {
136             //qDebug() << x << y << rotation << scale;
137             target->setPosition(QPointF(x, y));
138             target->setRotation(target->rotation() + rotation);
139             target->setScale(target->scale() * scale);
140         }
141     } else if (target) {
142         target->setParentItem(targetParent);
143     }
144 }
145 
146 /*!
147     \qmltype ParentChange
148     \instantiates QQuickParentChange
149     \inqmlmodule QtQuick
150     \ingroup qtquick-states
151     \brief Specifies how to reparent an Item in a state change.
152 
153     ParentChange reparents an item while preserving its visual appearance (position, size,
154     rotation, and scale) on screen. You can then specify a transition to move/resize/rotate/scale
155     the item to its final intended appearance.
156 
157     ParentChange can only preserve visual appearance if no complex transforms are involved.
158     More specifically, it will not work if the transform property has been set for any
159     items involved in the reparenting (i.e. items in the common ancestor tree
160     for the original and new parent).
161 
162     The example below displays a large red rectangle and a small blue rectangle, side by side.
163     When the \c blueRect is clicked, it changes to the "reparented" state: its parent is changed to \c redRect and it is
164     positioned at (10, 10) within the red rectangle, as specified in the ParentChange.
165 
166     \snippet qml/parentchange.qml 0
167 
168     \image parentchange.png
169 
170     You can specify at which point in a transition you want a ParentChange to occur by
171     using a ParentAnimation.
172 
173     Note that unlike PropertyChanges, ParentChange expects an Item-based target; it will not work with
174     arbitrary objects (for example, you couldn't use it to reparent a Timer).
175 */
176 
QQuickParentChange(QObject * parent)177 QQuickParentChange::QQuickParentChange(QObject *parent)
178     : QQuickStateOperation(*(new QQuickParentChangePrivate), parent)
179 {
180 }
181 
~QQuickParentChange()182 QQuickParentChange::~QQuickParentChange()
183 {
184 }
185 
186 /*!
187     \qmlproperty real QtQuick::ParentChange::x
188     \qmlproperty real QtQuick::ParentChange::y
189     \qmlproperty real QtQuick::ParentChange::width
190     \qmlproperty real QtQuick::ParentChange::height
191     \qmlproperty real QtQuick::ParentChange::scale
192     \qmlproperty real QtQuick::ParentChange::rotation
193     These properties hold the new position, size, scale, and rotation
194     for the item in this state.
195 */
x() const196 QQmlScriptString QQuickParentChange::x() const
197 {
198     Q_D(const QQuickParentChange);
199     return d->xString.value;
200 }
201 
setX(const QQmlScriptString & x)202 void QQuickParentChange::setX(const QQmlScriptString &x)
203 {
204     Q_D(QQuickParentChange);
205     d->xString = x;
206 }
207 
xIsSet() const208 bool QQuickParentChange::xIsSet() const
209 {
210     Q_D(const QQuickParentChange);
211     return d->xString.isValid();
212 }
213 
y() const214 QQmlScriptString QQuickParentChange::y() const
215 {
216     Q_D(const QQuickParentChange);
217     return d->yString.value;
218 }
219 
setY(const QQmlScriptString & y)220 void QQuickParentChange::setY(const QQmlScriptString &y)
221 {
222     Q_D(QQuickParentChange);
223     d->yString = y;
224 }
225 
yIsSet() const226 bool QQuickParentChange::yIsSet() const
227 {
228     Q_D(const QQuickParentChange);
229     return d->yString.isValid();
230 }
231 
width() const232 QQmlScriptString QQuickParentChange::width() const
233 {
234     Q_D(const QQuickParentChange);
235     return d->widthString.value;
236 }
237 
setWidth(const QQmlScriptString & width)238 void QQuickParentChange::setWidth(const QQmlScriptString &width)
239 {
240     Q_D(QQuickParentChange);
241     d->widthString = width;
242 }
243 
widthIsSet() const244 bool QQuickParentChange::widthIsSet() const
245 {
246     Q_D(const QQuickParentChange);
247     return d->widthString.isValid();
248 }
249 
height() const250 QQmlScriptString QQuickParentChange::height() const
251 {
252     Q_D(const QQuickParentChange);
253     return d->heightString.value;
254 }
255 
setHeight(const QQmlScriptString & height)256 void QQuickParentChange::setHeight(const QQmlScriptString &height)
257 {
258     Q_D(QQuickParentChange);
259     d->heightString = height;
260 }
261 
heightIsSet() const262 bool QQuickParentChange::heightIsSet() const
263 {
264     Q_D(const QQuickParentChange);
265     return d->heightString.isValid();
266 }
267 
scale() const268 QQmlScriptString QQuickParentChange::scale() const
269 {
270     Q_D(const QQuickParentChange);
271     return d->scaleString.value;
272 }
273 
setScale(const QQmlScriptString & scale)274 void QQuickParentChange::setScale(const QQmlScriptString &scale)
275 {
276     Q_D(QQuickParentChange);
277     d->scaleString = scale;
278 }
279 
scaleIsSet() const280 bool QQuickParentChange::scaleIsSet() const
281 {
282     Q_D(const QQuickParentChange);
283     return d->scaleString.isValid();
284 }
285 
rotation() const286 QQmlScriptString QQuickParentChange::rotation() const
287 {
288     Q_D(const QQuickParentChange);
289     return d->rotationString.value;
290 }
291 
setRotation(const QQmlScriptString & rotation)292 void QQuickParentChange::setRotation(const QQmlScriptString &rotation)
293 {
294     Q_D(QQuickParentChange);
295     d->rotationString = rotation;
296 }
297 
rotationIsSet() const298 bool QQuickParentChange::rotationIsSet() const
299 {
300     Q_D(const QQuickParentChange);
301     return d->rotationString.isValid();
302 }
303 
originalParent() const304 QQuickItem *QQuickParentChange::originalParent() const
305 {
306     Q_D(const QQuickParentChange);
307     return d->orig ? d->orig->parent : nullptr;
308 }
309 
310 /*!
311     \qmlproperty Item QtQuick::ParentChange::target
312     This property holds the item to be reparented
313 */
object() const314 QQuickItem *QQuickParentChange::object() const
315 {
316     Q_D(const QQuickParentChange);
317     return d->target;
318 }
319 
setObject(QQuickItem * target)320 void QQuickParentChange::setObject(QQuickItem *target)
321 {
322     Q_D(QQuickParentChange);
323     d->target = target;
324 }
325 
326 /*!
327     \qmlproperty Item QtQuick::ParentChange::parent
328     This property holds the new parent for the item in this state.
329 */
parent() const330 QQuickItem *QQuickParentChange::parent() const
331 {
332     Q_D(const QQuickParentChange);
333     return d->parent;
334 }
335 
setParent(QQuickItem * parent)336 void QQuickParentChange::setParent(QQuickItem *parent)
337 {
338     Q_D(QQuickParentChange);
339     d->parent = parent;
340 }
341 
actions()342 QQuickStateOperation::ActionList QQuickParentChange::actions()
343 {
344     Q_D(QQuickParentChange);
345     if (!d->target || !d->parent)
346         return ActionList();
347 
348     ActionList actions;
349 
350     QQuickStateAction a;
351     a.event = this;
352     actions << a;
353 
354     if (d->xString.isValid()) {
355         bool ok = false;
356         qreal x = d->xString.value.numberLiteral(&ok);
357         if (ok) {
358             QQuickStateAction xa(d->target, QLatin1String("x"), x);
359             actions << xa;
360         } else {
361             QQmlProperty property(d->target, QLatin1String("x"));
362             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->xString.value, d->target, qmlContext(this));
363             newBinding->setTarget(property);
364             QQuickStateAction xa;
365             xa.property = property;
366             xa.toBinding = newBinding;
367             xa.fromValue = xa.property.read();
368             xa.deletableToBinding = true;
369             actions << xa;
370         }
371     }
372 
373     if (d->yString.isValid()) {
374         bool ok = false;
375         qreal y = d->yString.value.numberLiteral(&ok);
376         if (ok) {
377             QQuickStateAction ya(d->target, QLatin1String("y"), y);
378             actions << ya;
379         } else {
380             QQmlProperty property(d->target, QLatin1String("y"));
381             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->yString.value, d->target, qmlContext(this));
382             newBinding->setTarget(property);
383             QQuickStateAction ya;
384             ya.property = property;
385             ya.toBinding = newBinding;
386             ya.fromValue = ya.property.read();
387             ya.deletableToBinding = true;
388             actions << ya;
389         }
390     }
391 
392     if (d->scaleString.isValid()) {
393         bool ok = false;
394         qreal scale = d->scaleString.value.numberLiteral(&ok);
395         if (ok) {
396             QQuickStateAction sa(d->target, QLatin1String("scale"), scale);
397             actions << sa;
398         } else {
399             QQmlProperty property(d->target, QLatin1String("scale"));
400             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->scaleString.value, d->target, qmlContext(this));
401             newBinding->setTarget(property);
402             QQuickStateAction sa;
403             sa.property = property;
404             sa.toBinding = newBinding;
405             sa.fromValue = sa.property.read();
406             sa.deletableToBinding = true;
407             actions << sa;
408         }
409     }
410 
411     if (d->rotationString.isValid()) {
412         bool ok = false;
413         qreal rotation = d->rotationString.value.numberLiteral(&ok);
414         if (ok) {
415             QQuickStateAction ra(d->target, QLatin1String("rotation"), rotation);
416             actions << ra;
417         } else {
418             QQmlProperty property(d->target, QLatin1String("rotation"));
419             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->rotationString.value, d->target, qmlContext(this));
420             newBinding->setTarget(property);
421             QQuickStateAction ra;
422             ra.property = property;
423             ra.toBinding = newBinding;
424             ra.fromValue = ra.property.read();
425             ra.deletableToBinding = true;
426             actions << ra;
427         }
428     }
429 
430     if (d->widthString.isValid()) {
431         bool ok = false;
432         qreal width = d->widthString.value.numberLiteral(&ok);
433         if (ok) {
434             QQuickStateAction wa(d->target, QLatin1String("width"), width);
435             actions << wa;
436         } else {
437             QQmlProperty property(d->target, QLatin1String("width"));
438             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->widthString.value, d->target, qmlContext(this));
439             newBinding->setTarget(property);
440             QQuickStateAction wa;
441             wa.property = property;
442             wa.toBinding = newBinding;
443             wa.fromValue = wa.property.read();
444             wa.deletableToBinding = true;
445             actions << wa;
446         }
447     }
448 
449     if (d->heightString.isValid()) {
450         bool ok = false;
451         qreal height = d->heightString.value.numberLiteral(&ok);
452         if (ok) {
453             QQuickStateAction ha(d->target, QLatin1String("height"), height);
454             actions << ha;
455         } else {
456             QQmlProperty property(d->target, QLatin1String("height"));
457             QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->heightString.value, d->target, qmlContext(this));
458             newBinding->setTarget(property);
459             QQuickStateAction ha;
460             ha.property = property;
461             ha.toBinding = newBinding;
462             ha.fromValue = ha.property.read();
463             ha.deletableToBinding = true;
464             actions << ha;
465         }
466     }
467 
468     return actions;
469 }
470 
saveOriginals()471 void QQuickParentChange::saveOriginals()
472 {
473     Q_D(QQuickParentChange);
474     saveCurrentValues();
475     if (!d->orig)
476         d->orig.reset(new QQuickParentChangePrivate::StateSnapshot);
477     *d->orig = *d->rewind;
478 }
479 
execute()480 void QQuickParentChange::execute()
481 {
482     Q_D(QQuickParentChange);
483     d->doChange(d->parent);
484 }
485 
isReversable()486 bool QQuickParentChange::isReversable()
487 {
488     return true;
489 }
490 
reverseRewindHelper(const std::unique_ptr<QQuickParentChangePrivate::StateSnapshot> & snapshot)491 void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuickParentChangePrivate::StateSnapshot> &snapshot)
492 {
493     if (!target || !snapshot)
494         return;
495     target->setX(snapshot->x);
496     target->setY(snapshot->y);
497     target->setScale(snapshot->scale);
498     target->setWidth(snapshot->width);
499     target->setHeight(snapshot->height);
500     target->setRotation(snapshot->rotation);
501     target->setParentItem(snapshot->parent);
502     if (snapshot->stackBefore)
503         target->stackBefore(snapshot->stackBefore);
504 }
505 
506 
reverse()507 void QQuickParentChange::reverse()
508 {
509     Q_D(QQuickParentChange);
510     d->reverseRewindHelper(d->orig);
511 }
512 
type() const513 QQuickStateActionEvent::EventType QQuickParentChange::type() const
514 {
515     return ParentChange;
516 }
517 
mayOverride(QQuickStateActionEvent * other)518 bool QQuickParentChange::mayOverride(QQuickStateActionEvent*other)
519 {
520     Q_D(QQuickParentChange);
521     if (other->type() != ParentChange)
522         return false;
523     if (QQuickParentChange *otherPC = static_cast<QQuickParentChange*>(other))
524         return (d->target == otherPC->object());
525     return false;
526 }
527 
saveCurrentValues()528 void QQuickParentChange::saveCurrentValues()
529 {
530     Q_D(QQuickParentChange);
531     if (!d->target) {
532         d->rewind = nullptr;
533         return;
534     }
535 
536     d->rewind.reset(new QQuickParentChangePrivate::StateSnapshot);
537     d->rewind->x = d->target->x();
538     d->rewind->y = d->target->y();
539     d->rewind->scale = d->target->scale();
540     d->rewind->width = d->target->width();
541     d->rewind->height = d->target->height();
542     d->rewind->rotation = d->target->rotation();
543 
544     d->rewind->parent = d->target->parentItem();
545     d->rewind->stackBefore = nullptr;
546 
547     if (!d->rewind->parent)
548         return;
549 
550     QList<QQuickItem *> children = d->rewind->parent->childItems();
551     for (int ii = 0; ii < children.count() - 1; ++ii) {
552         if (children.at(ii) == d->target) {
553             d->rewind->stackBefore = children.at(ii + 1);
554             break;
555         }
556     }
557 }
558 
rewind()559 void QQuickParentChange::rewind()
560 {
561     Q_D(QQuickParentChange);
562     d->reverseRewindHelper(d->rewind);
563     d->rewind.reset();
564 }
565 
566 /*!
567     \qmltype AnchorChanges
568     \instantiates QQuickAnchorChanges
569     \inqmlmodule QtQuick
570     \ingroup qtquick-states
571     \brief Specifies how to change the anchors of an item in a state.
572 
573     The AnchorChanges type is used to modify the anchors of an item in a \l State.
574 
575     AnchorChanges cannot be used to modify the margins on an item. For this, use
576     PropertyChanges intead.
577 
578     In the following example we change the top and bottom anchors of an item
579     using AnchorChanges, and the top and bottom anchor margins using
580     PropertyChanges:
581 
582     \snippet qml/anchorchanges.qml 0
583 
584     \image anchorchanges.png
585 
586     AnchorChanges can be animated using AnchorAnimation.
587     \qml
588     //animate our anchor changes
589     Transition {
590         AnchorAnimation {}
591     }
592     \endqml
593 
594     Changes to anchor margins can be animated using NumberAnimation.
595 
596     For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
597 */
598 
599 class QQuickAnchorSetPrivate : public QObjectPrivate
600 {
601     Q_DECLARE_PUBLIC(QQuickAnchorSet)
602 public:
603     QQuickAnchors::Anchors usedAnchors;
604     QQuickAnchors::Anchors resetAnchors;
605 
606     QQmlScriptString leftScript;
607     QQmlScriptString rightScript;
608     QQmlScriptString topScript;
609     QQmlScriptString bottomScript;
610     QQmlScriptString hCenterScript;
611     QQmlScriptString vCenterScript;
612     QQmlScriptString baselineScript;
613 };
614 
QQuickAnchorSet(QObject * parent)615 QQuickAnchorSet::QQuickAnchorSet(QObject *parent)
616   : QObject(*new QQuickAnchorSetPrivate, parent)
617 {
618 }
619 
~QQuickAnchorSet()620 QQuickAnchorSet::~QQuickAnchorSet()
621 {
622 }
623 
top() const624 QQmlScriptString QQuickAnchorSet::top() const
625 {
626     Q_D(const QQuickAnchorSet);
627     return d->topScript;
628 }
629 
setTop(const QQmlScriptString & edge)630 void QQuickAnchorSet::setTop(const QQmlScriptString &edge)
631 {
632     Q_D(QQuickAnchorSet);
633     d->usedAnchors |= QQuickAnchors::TopAnchor;
634     d->topScript = edge;
635     if (edge.isUndefinedLiteral())
636         resetTop();
637 }
638 
resetTop()639 void QQuickAnchorSet::resetTop()
640 {
641     Q_D(QQuickAnchorSet);
642     d->usedAnchors &= ~QQuickAnchors::TopAnchor;
643     d->resetAnchors |= QQuickAnchors::TopAnchor;
644 }
645 
bottom() const646 QQmlScriptString QQuickAnchorSet::bottom() const
647 {
648     Q_D(const QQuickAnchorSet);
649     return d->bottomScript;
650 }
651 
setBottom(const QQmlScriptString & edge)652 void QQuickAnchorSet::setBottom(const QQmlScriptString &edge)
653 {
654     Q_D(QQuickAnchorSet);
655     d->usedAnchors |= QQuickAnchors::BottomAnchor;
656     d->bottomScript = edge;
657     if (edge.isUndefinedLiteral())
658         resetBottom();
659 }
660 
resetBottom()661 void QQuickAnchorSet::resetBottom()
662 {
663     Q_D(QQuickAnchorSet);
664     d->usedAnchors &= ~QQuickAnchors::BottomAnchor;
665     d->resetAnchors |= QQuickAnchors::BottomAnchor;
666 }
667 
verticalCenter() const668 QQmlScriptString QQuickAnchorSet::verticalCenter() const
669 {
670     Q_D(const QQuickAnchorSet);
671     return d->vCenterScript;
672 }
673 
setVerticalCenter(const QQmlScriptString & edge)674 void QQuickAnchorSet::setVerticalCenter(const QQmlScriptString &edge)
675 {
676     Q_D(QQuickAnchorSet);
677     d->usedAnchors |= QQuickAnchors::VCenterAnchor;
678     d->vCenterScript = edge;
679     if (edge.isUndefinedLiteral())
680         resetVerticalCenter();
681 }
682 
resetVerticalCenter()683 void QQuickAnchorSet::resetVerticalCenter()
684 {
685     Q_D(QQuickAnchorSet);
686     d->usedAnchors &= ~QQuickAnchors::VCenterAnchor;
687     d->resetAnchors |= QQuickAnchors::VCenterAnchor;
688 }
689 
baseline() const690 QQmlScriptString QQuickAnchorSet::baseline() const
691 {
692     Q_D(const QQuickAnchorSet);
693     return d->baselineScript;
694 }
695 
setBaseline(const QQmlScriptString & edge)696 void QQuickAnchorSet::setBaseline(const QQmlScriptString &edge)
697 {
698     Q_D(QQuickAnchorSet);
699     d->usedAnchors |= QQuickAnchors::BaselineAnchor;
700     d->baselineScript = edge;
701     if (edge.isUndefinedLiteral())
702         resetBaseline();
703 }
704 
resetBaseline()705 void QQuickAnchorSet::resetBaseline()
706 {
707     Q_D(QQuickAnchorSet);
708     d->usedAnchors &= ~QQuickAnchors::BaselineAnchor;
709     d->resetAnchors |= QQuickAnchors::BaselineAnchor;
710 }
711 
left() const712 QQmlScriptString QQuickAnchorSet::left() const
713 {
714     Q_D(const QQuickAnchorSet);
715     return d->leftScript;
716 }
717 
setLeft(const QQmlScriptString & edge)718 void QQuickAnchorSet::setLeft(const QQmlScriptString &edge)
719 {
720     Q_D(QQuickAnchorSet);
721     d->usedAnchors |= QQuickAnchors::LeftAnchor;
722     d->leftScript = edge;
723     if (edge.isUndefinedLiteral())
724         resetLeft();
725 }
726 
resetLeft()727 void QQuickAnchorSet::resetLeft()
728 {
729     Q_D(QQuickAnchorSet);
730     d->usedAnchors &= ~QQuickAnchors::LeftAnchor;
731     d->resetAnchors |= QQuickAnchors::LeftAnchor;
732 }
733 
right() const734 QQmlScriptString QQuickAnchorSet::right() const
735 {
736     Q_D(const QQuickAnchorSet);
737     return d->rightScript;
738 }
739 
setRight(const QQmlScriptString & edge)740 void QQuickAnchorSet::setRight(const QQmlScriptString &edge)
741 {
742     Q_D(QQuickAnchorSet);
743     d->usedAnchors |= QQuickAnchors::RightAnchor;
744     d->rightScript = edge;
745     if (edge.isUndefinedLiteral())
746         resetRight();
747 }
748 
resetRight()749 void QQuickAnchorSet::resetRight()
750 {
751     Q_D(QQuickAnchorSet);
752     d->usedAnchors &= ~QQuickAnchors::RightAnchor;
753     d->resetAnchors |= QQuickAnchors::RightAnchor;
754 }
755 
horizontalCenter() const756 QQmlScriptString QQuickAnchorSet::horizontalCenter() const
757 {
758     Q_D(const QQuickAnchorSet);
759     return d->hCenterScript;
760 }
761 
setHorizontalCenter(const QQmlScriptString & edge)762 void QQuickAnchorSet::setHorizontalCenter(const QQmlScriptString &edge)
763 {
764     Q_D(QQuickAnchorSet);
765     d->usedAnchors |= QQuickAnchors::HCenterAnchor;
766     d->hCenterScript = edge;
767     if (edge.isUndefinedLiteral())
768         resetHorizontalCenter();
769 }
770 
resetHorizontalCenter()771 void QQuickAnchorSet::resetHorizontalCenter()
772 {
773     Q_D(QQuickAnchorSet);
774     d->usedAnchors &= ~QQuickAnchors::HCenterAnchor;
775     d->resetAnchors |= QQuickAnchors::HCenterAnchor;
776 }
777 
778 class QQuickAnchorChangesPrivate : public QQuickStateOperationPrivate
779 {
780 public:
QQuickAnchorChangesPrivate()781     QQuickAnchorChangesPrivate()
782         : target(nullptr), anchorSet(new QQuickAnchorSet)
783     {
784 
785     }
~QQuickAnchorChangesPrivate()786     ~QQuickAnchorChangesPrivate() { delete anchorSet; }
787 
788     QQuickItem *target;
789     QQuickAnchorSet *anchorSet;
790 
791     QExplicitlySharedDataPointer<QQmlBinding> leftBinding;
792     QExplicitlySharedDataPointer<QQmlBinding> rightBinding;
793     QExplicitlySharedDataPointer<QQmlBinding> hCenterBinding;
794     QExplicitlySharedDataPointer<QQmlBinding> topBinding;
795     QExplicitlySharedDataPointer<QQmlBinding> bottomBinding;
796     QExplicitlySharedDataPointer<QQmlBinding> vCenterBinding;
797     QExplicitlySharedDataPointer<QQmlBinding> baselineBinding;
798 
799     QQmlAbstractBinding::Ptr origLeftBinding;
800     QQmlAbstractBinding::Ptr origRightBinding;
801     QQmlAbstractBinding::Ptr origHCenterBinding;
802     QQmlAbstractBinding::Ptr origTopBinding;
803     QQmlAbstractBinding::Ptr origBottomBinding;
804     QQmlAbstractBinding::Ptr origVCenterBinding;
805     QQmlAbstractBinding::Ptr origBaselineBinding;
806 
807     QQuickAnchorLine rewindLeft;
808     QQuickAnchorLine rewindRight;
809     QQuickAnchorLine rewindHCenter;
810     QQuickAnchorLine rewindTop;
811     QQuickAnchorLine rewindBottom;
812     QQuickAnchorLine rewindVCenter;
813     QQuickAnchorLine rewindBaseline;
814 
815     qreal fromX;
816     qreal fromY;
817     qreal fromWidth;
818     qreal fromHeight;
819 
820     qreal toX;
821     qreal toY;
822     qreal toWidth;
823     qreal toHeight;
824 
825     qreal rewindX;
826     qreal rewindY;
827     qreal rewindWidth;
828     qreal rewindHeight;
829 
830     bool applyOrigLeft;
831     bool applyOrigRight;
832     bool applyOrigHCenter;
833     bool applyOrigTop;
834     bool applyOrigBottom;
835     bool applyOrigVCenter;
836     bool applyOrigBaseline;
837 
838     QQmlNullableValue<qreal> origWidth;
839     QQmlNullableValue<qreal> origHeight;
840     qreal origX;
841     qreal origY;
842 
843     QQmlProperty leftProp;
844     QQmlProperty rightProp;
845     QQmlProperty hCenterProp;
846     QQmlProperty topProp;
847     QQmlProperty bottomProp;
848     QQmlProperty vCenterProp;
849     QQmlProperty baselineProp;
850 };
851 
QQuickAnchorChanges(QObject * parent)852 QQuickAnchorChanges::QQuickAnchorChanges(QObject *parent)
853  : QQuickStateOperation(*(new QQuickAnchorChangesPrivate), parent)
854 {
855 }
856 
~QQuickAnchorChanges()857 QQuickAnchorChanges::~QQuickAnchorChanges()
858 {
859 }
860 
actions()861 QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions()
862 {
863     Q_D(QQuickAnchorChanges);
864     //### ASSERT these are all 0?
865     d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
866                    = d->bottomBinding = d->vCenterBinding = d->baselineBinding = nullptr;
867 
868     d->leftProp = QQmlProperty(d->target, QLatin1String("anchors.left"));
869     d->rightProp = QQmlProperty(d->target, QLatin1String("anchors.right"));
870     d->hCenterProp = QQmlProperty(d->target, QLatin1String("anchors.horizontalCenter"));
871     d->topProp = QQmlProperty(d->target, QLatin1String("anchors.top"));
872     d->bottomProp = QQmlProperty(d->target, QLatin1String("anchors.bottom"));
873     d->vCenterProp = QQmlProperty(d->target, QLatin1String("anchors.verticalCenter"));
874     d->baselineProp = QQmlProperty(d->target, QLatin1String("anchors.baseline"));
875 
876     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::LeftAnchor) {
877         d->leftBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->leftProp)->core, d->anchorSet->d_func()->leftScript, d->target, qmlContext(this));
878         d->leftBinding->setTarget(d->leftProp);
879     }
880     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::RightAnchor) {
881         d->rightBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->rightProp)->core, d->anchorSet->d_func()->rightScript, d->target, qmlContext(this));
882         d->rightBinding->setTarget(d->rightProp);
883     }
884     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::HCenterAnchor) {
885         d->hCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->hCenterProp)->core, d->anchorSet->d_func()->hCenterScript, d->target, qmlContext(this));
886         d->hCenterBinding->setTarget(d->hCenterProp);
887     }
888     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::TopAnchor) {
889         d->topBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->topProp)->core, d->anchorSet->d_func()->topScript, d->target, qmlContext(this));
890         d->topBinding->setTarget(d->topProp);
891     }
892     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BottomAnchor) {
893         d->bottomBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->bottomProp)->core, d->anchorSet->d_func()->bottomScript, d->target, qmlContext(this));
894         d->bottomBinding->setTarget(d->bottomProp);
895     }
896     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::VCenterAnchor) {
897         d->vCenterBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->vCenterProp)->core, d->anchorSet->d_func()->vCenterScript, d->target, qmlContext(this));
898         d->vCenterBinding->setTarget(d->vCenterProp);
899     }
900     if (d->anchorSet->d_func()->usedAnchors & QQuickAnchors::BaselineAnchor) {
901         d->baselineBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(d->baselineProp)->core, d->anchorSet->d_func()->baselineScript, d->target, qmlContext(this));
902         d->baselineBinding->setTarget(d->baselineProp);
903     }
904 
905     QQuickStateAction a;
906     a.event = this;
907     return ActionList() << a;
908 }
909 
anchors() const910 QQuickAnchorSet *QQuickAnchorChanges::anchors() const
911 {
912     Q_D(const QQuickAnchorChanges);
913     return d->anchorSet;
914 }
915 
916 /*!
917     \qmlproperty Item QtQuick::AnchorChanges::target
918     This property holds the \l Item for which the anchor changes will be applied.
919 */
object() const920 QQuickItem *QQuickAnchorChanges::object() const
921 {
922     Q_D(const QQuickAnchorChanges);
923     return d->target;
924 }
925 
setObject(QQuickItem * target)926 void QQuickAnchorChanges::setObject(QQuickItem *target)
927 {
928     Q_D(QQuickAnchorChanges);
929     d->target = target;
930 }
931 
932 /*!
933     \qmlpropertygroup QtQuick::AnchorChanges::anchors
934     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.left
935     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.right
936     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.horizontalCenter
937     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.top
938     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.bottom
939     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.verticalCenter
940     \qmlproperty AnchorLine QtQuick::AnchorChanges::anchors.baseline
941 
942     These properties change the respective anchors of the item.
943 
944     To reset an anchor you can assign \c undefined:
945     \qml
946     AnchorChanges {
947         target: myItem
948         anchors.left: undefined          //remove myItem's left anchor
949         anchors.right: otherItem.right
950     }
951     \endqml
952 */
953 
execute()954 void QQuickAnchorChanges::execute()
955 {
956     Q_D(QQuickAnchorChanges);
957     if (!d->target)
958         return;
959 
960     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
961     //incorporate any needed "reverts"
962     if (d->applyOrigLeft) {
963         if (!d->origLeftBinding)
964             targetPrivate->anchors()->resetLeft();
965         QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data());
966     }
967     if (d->applyOrigRight) {
968         if (!d->origRightBinding)
969             targetPrivate->anchors()->resetRight();
970         QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data());
971     }
972     if (d->applyOrigHCenter) {
973         if (!d->origHCenterBinding)
974             targetPrivate->anchors()->resetHorizontalCenter();
975         QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data());
976     }
977     if (d->applyOrigTop) {
978         if (!d->origTopBinding)
979             targetPrivate->anchors()->resetTop();
980         QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data());
981     }
982     if (d->applyOrigBottom) {
983         if (!d->origBottomBinding)
984             targetPrivate->anchors()->resetBottom();
985         QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data());
986     }
987     if (d->applyOrigVCenter) {
988         if (!d->origVCenterBinding)
989             targetPrivate->anchors()->resetVerticalCenter();
990         QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data());
991     }
992     if (d->applyOrigBaseline) {
993         if (!d->origBaselineBinding)
994             targetPrivate->anchors()->resetBaseline();
995         QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data());
996     }
997 
998     //reset any anchors that have been specified as "undefined"
999     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::LeftAnchor) {
1000         targetPrivate->anchors()->resetLeft();
1001         QQmlPropertyPrivate::removeBinding(d->leftProp);
1002     }
1003     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::RightAnchor) {
1004         targetPrivate->anchors()->resetRight();
1005         QQmlPropertyPrivate::removeBinding(d->rightProp);
1006     }
1007     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::HCenterAnchor) {
1008         targetPrivate->anchors()->resetHorizontalCenter();
1009         QQmlPropertyPrivate::removeBinding(d->hCenterProp);
1010     }
1011     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::TopAnchor) {
1012         targetPrivate->anchors()->resetTop();
1013         QQmlPropertyPrivate::removeBinding(d->topProp);
1014     }
1015     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BottomAnchor) {
1016         targetPrivate->anchors()->resetBottom();
1017         QQmlPropertyPrivate::removeBinding(d->bottomProp);
1018     }
1019     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::VCenterAnchor) {
1020         targetPrivate->anchors()->resetVerticalCenter();
1021         QQmlPropertyPrivate::removeBinding(d->vCenterProp);
1022     }
1023     if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BaselineAnchor) {
1024         targetPrivate->anchors()->resetBaseline();
1025         QQmlPropertyPrivate::removeBinding(d->baselineProp);
1026     }
1027 
1028     //set any anchors that have been specified
1029     if (d->leftBinding)
1030         QQmlPropertyPrivate::setBinding(d->leftBinding.data());
1031     if (d->rightBinding)
1032         QQmlPropertyPrivate::setBinding(d->rightBinding.data());
1033     if (d->hCenterBinding)
1034         QQmlPropertyPrivate::setBinding(d->hCenterBinding.data());
1035     if (d->topBinding)
1036         QQmlPropertyPrivate::setBinding(d->topBinding.data());
1037     if (d->bottomBinding)
1038         QQmlPropertyPrivate::setBinding(d->bottomBinding.data());
1039     if (d->vCenterBinding)
1040         QQmlPropertyPrivate::setBinding(d->vCenterBinding.data());
1041     if (d->baselineBinding)
1042         QQmlPropertyPrivate::setBinding(d->baselineBinding.data());
1043 }
1044 
isReversable()1045 bool QQuickAnchorChanges::isReversable()
1046 {
1047     return true;
1048 }
1049 
reverse()1050 void QQuickAnchorChanges::reverse()
1051 {
1052     Q_D(QQuickAnchorChanges);
1053     if (!d->target)
1054         return;
1055 
1056     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
1057     //reset any anchors set by the state
1058     if (d->leftBinding) {
1059         targetPrivate->anchors()->resetLeft();
1060         QQmlPropertyPrivate::removeBinding(d->leftBinding.data());
1061     }
1062     if (d->rightBinding) {
1063         targetPrivate->anchors()->resetRight();
1064         QQmlPropertyPrivate::removeBinding(d->rightBinding.data());
1065     }
1066     if (d->hCenterBinding) {
1067         targetPrivate->anchors()->resetHorizontalCenter();
1068         QQmlPropertyPrivate::removeBinding(d->hCenterBinding.data());
1069     }
1070     if (d->topBinding) {
1071         targetPrivate->anchors()->resetTop();
1072         QQmlPropertyPrivate::removeBinding(d->topBinding.data());
1073     }
1074     if (d->bottomBinding) {
1075         targetPrivate->anchors()->resetBottom();
1076         QQmlPropertyPrivate::removeBinding(d->bottomBinding.data());
1077     }
1078     if (d->vCenterBinding) {
1079         targetPrivate->anchors()->resetVerticalCenter();
1080         QQmlPropertyPrivate::removeBinding(d->vCenterBinding.data());
1081     }
1082     if (d->baselineBinding) {
1083         targetPrivate->anchors()->resetBaseline();
1084         QQmlPropertyPrivate::removeBinding(d->baselineBinding.data());
1085     }
1086 
1087     //restore previous anchors
1088     if (d->origLeftBinding)
1089         QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data());
1090     if (d->origRightBinding)
1091         QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data());
1092     if (d->origHCenterBinding)
1093         QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data());
1094     if (d->origTopBinding)
1095         QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data());
1096     if (d->origBottomBinding)
1097         QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data());
1098     if (d->origVCenterBinding)
1099         QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data());
1100     if (d->origBaselineBinding)
1101         QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data());
1102 
1103     //restore any absolute geometry changed by the state's anchors
1104     QQuickAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Vertical_Mask;
1105     QQuickAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Vertical_Mask;
1106     QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask;
1107     QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask;
1108 
1109     bool stateSetWidth = (stateHAnchors &&
1110                           stateHAnchors != QQuickAnchors::LeftAnchor &&
1111                           stateHAnchors != QQuickAnchors::RightAnchor &&
1112                           stateHAnchors != QQuickAnchors::HCenterAnchor);
1113     bool origSetWidth = (origHAnchors &&
1114                          origHAnchors != QQuickAnchors::LeftAnchor &&
1115                          origHAnchors != QQuickAnchors::RightAnchor &&
1116                          origHAnchors != QQuickAnchors::HCenterAnchor);
1117     if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
1118         d->target->setWidth(d->origWidth.value);
1119 
1120     bool stateSetHeight = (stateVAnchors &&
1121                            stateVAnchors != QQuickAnchors::TopAnchor &&
1122                            stateVAnchors != QQuickAnchors::BottomAnchor &&
1123                            stateVAnchors != QQuickAnchors::VCenterAnchor &&
1124                            stateVAnchors != QQuickAnchors::BaselineAnchor);
1125     bool origSetHeight = (origVAnchors &&
1126                           origVAnchors != QQuickAnchors::TopAnchor &&
1127                           origVAnchors != QQuickAnchors::BottomAnchor &&
1128                           origVAnchors != QQuickAnchors::VCenterAnchor &&
1129                           origVAnchors != QQuickAnchors::BaselineAnchor);
1130     if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
1131         d->target->setHeight(d->origHeight.value);
1132 
1133     if (stateHAnchors && !origHAnchors)
1134         d->target->setX(d->origX);
1135 
1136     if (stateVAnchors && !origVAnchors)
1137         d->target->setY(d->origY);
1138 }
1139 
type() const1140 QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const
1141 {
1142     return AnchorChanges;
1143 }
1144 
additionalActions() const1145 QList<QQuickStateAction> QQuickAnchorChanges::additionalActions() const
1146 {
1147     Q_D(const QQuickAnchorChanges);
1148     QList<QQuickStateAction> extra;
1149 
1150     QQuickAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
1151     bool hChange = combined & QQuickAnchors::Horizontal_Mask;
1152     bool vChange = combined & QQuickAnchors::Vertical_Mask;
1153 
1154     if (d->target) {
1155         QQuickStateAction a;
1156         if (hChange && d->fromX != d->toX) {
1157             a.property = QQmlProperty(d->target, QLatin1String("x"));
1158             a.toValue = d->toX;
1159             extra << a;
1160         }
1161         if (vChange && d->fromY != d->toY) {
1162             a.property = QQmlProperty(d->target, QLatin1String("y"));
1163             a.toValue = d->toY;
1164             extra << a;
1165         }
1166         if (hChange && d->fromWidth != d->toWidth) {
1167             a.property = QQmlProperty(d->target, QLatin1String("width"));
1168             a.toValue = d->toWidth;
1169             extra << a;
1170         }
1171         if (vChange && d->fromHeight != d->toHeight) {
1172             a.property = QQmlProperty(d->target, QLatin1String("height"));
1173             a.toValue = d->toHeight;
1174             extra << a;
1175         }
1176     }
1177 
1178     return extra;
1179 }
1180 
changesBindings()1181 bool QQuickAnchorChanges::changesBindings()
1182 {
1183     return true;
1184 }
1185 
saveOriginals()1186 void QQuickAnchorChanges::saveOriginals()
1187 {
1188     Q_D(QQuickAnchorChanges);
1189     if (!d->target)
1190         return;
1191 
1192     d->origLeftBinding = QQmlPropertyPrivate::binding(d->leftProp);
1193     d->origRightBinding = QQmlPropertyPrivate::binding(d->rightProp);
1194     d->origHCenterBinding = QQmlPropertyPrivate::binding(d->hCenterProp);
1195     d->origTopBinding = QQmlPropertyPrivate::binding(d->topProp);
1196     d->origBottomBinding = QQmlPropertyPrivate::binding(d->bottomProp);
1197     d->origVCenterBinding = QQmlPropertyPrivate::binding(d->vCenterProp);
1198     d->origBaselineBinding = QQmlPropertyPrivate::binding(d->baselineProp);
1199 
1200     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
1201     if (targetPrivate->widthValid)
1202         d->origWidth = d->target->width();
1203     if (targetPrivate->heightValid)
1204         d->origHeight = d->target->height();
1205     d->origX = d->target->x();
1206     d->origY = d->target->y();
1207 
1208     d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
1209       = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
1210 
1211     saveCurrentValues();
1212 }
1213 
copyOriginals(QQuickStateActionEvent * other)1214 void QQuickAnchorChanges::copyOriginals(QQuickStateActionEvent *other)
1215 {
1216     Q_D(QQuickAnchorChanges);
1217     QQuickAnchorChanges *ac = static_cast<QQuickAnchorChanges*>(other);
1218     QQuickAnchorChangesPrivate *acp = ac->d_func();
1219 
1220     QQuickAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
1221                                             acp->anchorSet->d_func()->resetAnchors;
1222 
1223     //probably also need to revert some things
1224     d->applyOrigLeft = (combined & QQuickAnchors::LeftAnchor);
1225     d->applyOrigRight = (combined & QQuickAnchors::RightAnchor);
1226     d->applyOrigHCenter = (combined & QQuickAnchors::HCenterAnchor);
1227     d->applyOrigTop = (combined & QQuickAnchors::TopAnchor);
1228     d->applyOrigBottom = (combined & QQuickAnchors::BottomAnchor);
1229     d->applyOrigVCenter = (combined & QQuickAnchors::VCenterAnchor);
1230     d->applyOrigBaseline = (combined & QQuickAnchors::BaselineAnchor);
1231 
1232     d->origLeftBinding = acp->origLeftBinding;
1233     d->origRightBinding = acp->origRightBinding;
1234     d->origHCenterBinding = acp->origHCenterBinding;
1235     d->origTopBinding = acp->origTopBinding;
1236     d->origBottomBinding = acp->origBottomBinding;
1237     d->origVCenterBinding = acp->origVCenterBinding;
1238     d->origBaselineBinding = acp->origBaselineBinding;
1239 
1240     d->origWidth = acp->origWidth;
1241     d->origHeight = acp->origHeight;
1242     d->origX = acp->origX;
1243     d->origY = acp->origY;
1244 
1245     //clear old values from other
1246     //### could this be generalized for all QQuickStateActionEvents, and called after copyOriginals?
1247     acp->leftBinding = nullptr;
1248     acp->rightBinding = nullptr;
1249     acp->hCenterBinding = nullptr;
1250     acp->topBinding = nullptr;
1251     acp->bottomBinding = nullptr;
1252     acp->vCenterBinding = nullptr;
1253     acp->baselineBinding = nullptr;
1254     acp->origLeftBinding = nullptr;
1255     acp->origRightBinding = nullptr;
1256     acp->origHCenterBinding = nullptr;
1257     acp->origTopBinding = nullptr;
1258     acp->origBottomBinding = nullptr;
1259     acp->origVCenterBinding = nullptr;
1260     acp->origBaselineBinding = nullptr;
1261 
1262     saveCurrentValues();
1263 }
1264 
clearBindings()1265 void QQuickAnchorChanges::clearBindings()
1266 {
1267     Q_D(QQuickAnchorChanges);
1268     if (!d->target)
1269         return;
1270 
1271     //### should this (saving "from" values) be moved to saveCurrentValues()?
1272     d->fromX = d->target->x();
1273     d->fromY = d->target->y();
1274     d->fromWidth = d->target->width();
1275     d->fromHeight = d->target->height();
1276 
1277     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
1278     //reset any anchors with corresponding reverts
1279     //reset any anchors that have been specified as "undefined"
1280     //reset any anchors that we'll be setting in the state
1281     QQuickAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
1282                                             d->anchorSet->d_func()->usedAnchors;
1283     if (d->applyOrigLeft || (combined & QQuickAnchors::LeftAnchor)) {
1284         targetPrivate->anchors()->resetLeft();
1285         QQmlPropertyPrivate::removeBinding(d->leftProp);
1286     }
1287     if (d->applyOrigRight || (combined & QQuickAnchors::RightAnchor)) {
1288         targetPrivate->anchors()->resetRight();
1289         QQmlPropertyPrivate::removeBinding(d->rightProp);
1290     }
1291     if (d->applyOrigHCenter || (combined & QQuickAnchors::HCenterAnchor)) {
1292         targetPrivate->anchors()->resetHorizontalCenter();
1293         QQmlPropertyPrivate::removeBinding(d->hCenterProp);
1294     }
1295     if (d->applyOrigTop || (combined & QQuickAnchors::TopAnchor)) {
1296         targetPrivate->anchors()->resetTop();
1297         QQmlPropertyPrivate::removeBinding(d->topProp);
1298     }
1299     if (d->applyOrigBottom || (combined & QQuickAnchors::BottomAnchor)) {
1300         targetPrivate->anchors()->resetBottom();
1301         QQmlPropertyPrivate::removeBinding(d->bottomProp);
1302     }
1303     if (d->applyOrigVCenter || (combined & QQuickAnchors::VCenterAnchor)) {
1304         targetPrivate->anchors()->resetVerticalCenter();
1305         QQmlPropertyPrivate::removeBinding(d->vCenterProp);
1306     }
1307     if (d->applyOrigBaseline || (combined & QQuickAnchors::BaselineAnchor)) {
1308         targetPrivate->anchors()->resetBaseline();
1309         QQmlPropertyPrivate::removeBinding(d->baselineProp);
1310     }
1311 }
1312 
mayOverride(QQuickStateActionEvent * other)1313 bool QQuickAnchorChanges::mayOverride(QQuickStateActionEvent*other)
1314 {
1315     if (other->type() != AnchorChanges)
1316         return false;
1317     if (static_cast<QQuickStateActionEvent*>(this) == other)
1318         return true;
1319     if (static_cast<QQuickAnchorChanges*>(other)->object() == object())
1320         return true;
1321     return false;
1322 }
1323 
rewind()1324 void QQuickAnchorChanges::rewind()
1325 {
1326     Q_D(QQuickAnchorChanges);
1327     if (!d->target)
1328         return;
1329 
1330     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
1331 
1332     //restore previous values (but not previous bindings, i.e. anchors)
1333     d->target->setX(d->rewindX);
1334     d->target->setY(d->rewindY);
1335     if (targetPrivate->widthValid) {
1336         d->target->setWidth(d->rewindWidth);
1337     }
1338     if (targetPrivate->heightValid) {
1339         d->target->setHeight(d->rewindHeight);
1340     }
1341 }
1342 
saveCurrentValues()1343 void QQuickAnchorChanges::saveCurrentValues()
1344 {
1345     Q_D(QQuickAnchorChanges);
1346     if (!d->target)
1347         return;
1348 
1349     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
1350     d->rewindLeft = targetPrivate->anchors()->left();
1351     d->rewindRight = targetPrivate->anchors()->right();
1352     d->rewindHCenter = targetPrivate->anchors()->horizontalCenter();
1353     d->rewindTop = targetPrivate->anchors()->top();
1354     d->rewindBottom = targetPrivate->anchors()->bottom();
1355     d->rewindVCenter = targetPrivate->anchors()->verticalCenter();
1356     d->rewindBaseline = targetPrivate->anchors()->baseline();
1357 
1358     d->rewindX = d->target->x();
1359     d->rewindY = d->target->y();
1360     d->rewindWidth = d->target->width();
1361     d->rewindHeight = d->target->height();
1362 }
1363 
saveTargetValues()1364 void QQuickAnchorChanges::saveTargetValues()
1365 {
1366     Q_D(QQuickAnchorChanges);
1367     if (!d->target)
1368         return;
1369 
1370     d->toX = d->target->x();
1371     d->toY = d->target->y();
1372     d->toWidth = d->target->width();
1373     d->toHeight = d->target->height();
1374 }
1375 
1376 #include <moc_qquickstateoperations_p.cpp>
1377 
1378 QT_END_NAMESPACE
1379 
1380