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

source code of qtdeclarative/src/quick/items/qquickstateoperations.cpp