Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquickswipedelegate.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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
6#include "qquickcontrol_p_p.h"
9
10#include <QtGui/qstylehints.h>
11#include <QtGui/private/qguiapplication_p.h>
12#include <QtGui/private/qeventpoint_p.h>
13#include <QtGui/qpa/qplatformtheme.h>
14#include <QtQml/qqmlinfo.h>
15#include <QtQuick/private/qquickanimation_p.h>
16#include <QtQuick/private/qquicktransition_p.h>
17#include <QtQuick/private/qquicktransitionmanager_p_p.h>
18
20
25
74namespace {
76
78 return qobject_cast<Attached*>(qmlAttachedPropertiesObject<QQuickSwipeDelegate>(item, false));
79 }
80
84 };
85}
86
88{
89public:
91
93
94protected:
95 void finished() override;
96
97private:
98 QQuickSwipe *m_swipe = nullptr;
99};
100
102{
103 Q_DECLARE_PUBLIC(QQuickSwipe)
104
105public:
107
108 static QQuickSwipePrivate *get(QQuickSwipe *swipe);
109
113 void reposition(PositionAnimation animationPolicy);
114 void createLeftItem();
115 void createBehindItem();
116 void createRightItem();
120
123
124 bool hasDelegates() const;
125
126 bool isTransitioning() const;
128 void finishTransition();
129
131 // Same range as position, but is set before press events so that we can
132 // keep track of which direction the user must swipe when using left and right delegates.
135 // A "less strict" version of complete that is true if complete was true
136 // before the last press event.
137 bool wasComplete = false;
138 bool complete = false;
139 bool enabled = true;
140 bool waitForTransition = false;
142 QQmlComponent *left = nullptr;
150};
151
153 : m_swipe(swipe)
154{
155}
156
158{
160
161 QQmlProperty defaultTarget(m_swipe, QLatin1String("position"));
162 QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
163 const int count = animations.count(&animations);
164 for (int i = 0; i < count; ++i) {
165 QQuickAbstractAnimation *anim = animations.at(&animations, i);
166 anim->setDefaultTarget(defaultTarget);
167 }
168
170 actions << QQuickStateAction(m_swipe, QLatin1String("position"), position);
172}
173
175{
177}
178
180{
181 return swipe->d_func();
182}
183
185{
186 // If we don't use the correct context, it won't be possible to refer to
187 // the control's id from within the delegates.
188 QQmlContext *context = component->creationContext();
189 // The component might not have been created in QML, in which case
190 // the creation context will be null and we have to create it ourselves.
191 if (!context)
194 if (item) {
196 component->completeCreate();
198 }
199 return item;
200}
201
203{
205 return nullptr;
206
207 if (behind) {
209 return behindItem;
210 }
211
212 if (right && position < 0.0) {
214 return rightItem;
215 }
216
217 if (left && position > 0.0) {
219 return leftItem;
220 }
221
222 return nullptr;
223}
224
226{
228 return nullptr;
229
230 if (behind) {
232 return behindItem;
233 }
234
235 // a) If the position before the press was 0.0, we know that *any* movement
236 // whose distance is negative will result in the right item being shown and
237 // vice versa.
238 // b) Once the control has been exposed (that is, swiped to the left or right,
239 // and hence the position is either -1.0 or 1.0), we must use the width of the
240 // relevant item to determine if the distance is larger than that item,
241 // in order to know whether or not to display it.
242 // c) If the control has been exposed, and the swipe is larger than the width
243 // of the relevant item from which the swipe started from, we must show the
244 // item on the other side (if any).
245
246 if (right) {
247 if ((distance < 0.0 && positionBeforePress == 0.0) /* a) */
248 || (rightItem && positionBeforePress == -1.0 && distance < rightItem->width()) /* b) */
249 || (leftItem && positionBeforePress == 1.0 && qAbs(distance) > leftItem->width())) /* c) */ {
251 return rightItem;
252 }
253 }
254
255 if (left) {
256 if ((distance > 0.0 && positionBeforePress == 0.0) /* a) */
257 || (leftItem && positionBeforePress == 1.0 && qAbs(distance) < leftItem->width()) /* b) */
258 || (rightItem && positionBeforePress == -1.0 && qAbs(distance) > rightItem->width())) /* c) */ {
260 return leftItem;
261 }
262 }
263
264 return nullptr;
265}
266
267void QQuickSwipePrivate::reposition(PositionAnimation animationPolicy)
268{
270 const qreal relevantWidth = relevantItem ? relevantItem->width() : 0.0;
271 const qreal contentItemX = position * relevantWidth + control->leftPadding();
272
273 // "Behavior on x" relies on the property system to know when it should update,
274 // so we can prevent it from animating by setting the x position directly.
275 if (animationPolicy == AnimatePosition) {
276 if (QQuickItem *contentItem = control->contentItem())
277 contentItem->setProperty("x", contentItemX);
278 if (QQuickItem *background = control->background())
279 background->setProperty("x", position * relevantWidth);
280 } else {
281 if (QQuickItem *contentItem = control->contentItem())
282 contentItem->setX(contentItemX);
283 if (QQuickItem *background = control->background())
284 background->setX(position * relevantWidth);
285 }
286}
287
289{
290 if (!leftItem) {
291 Q_Q(QQuickSwipe);
292 q->setLeftItem(createDelegateItem(left));
293 if (!leftItem)
294 qmlWarning(control) << "Failed to create left item:" << left->errors();
295 }
296}
297
299{
300 if (!behindItem) {
301 Q_Q(QQuickSwipe);
302 q->setBehindItem(createDelegateItem(behind));
303 if (!behindItem)
304 qmlWarning(control) << "Failed to create behind item:" << behind->errors();
305 }
306}
307
309{
310 if (!rightItem) {
311 Q_Q(QQuickSwipe);
312 q->setRightItem(createDelegateItem(right));
313 if (!rightItem)
314 qmlWarning(control) << "Failed to create right item:" << right->errors();
315 }
316}
317
319{
321
322 if (leftItem)
323 leftItem->setVisible(true);
324
325 if (rightItem)
326 rightItem->setVisible(false);
327}
328
330{
332
333 if (behindItem)
334 behindItem->setVisible(true);
335}
336
338{
340
341 // This item may have already existed but was hidden.
342 if (rightItem)
343 rightItem->setVisible(true);
344
345 // The left item isn't visible when the right item is visible, so save rendering effort by hiding it.
346 if (leftItem)
347 leftItem->setVisible(false);
348}
349
351{
352 qmlWarning(control) << "cannot set both behind and left/right properties";
353}
354
356{
357 qmlWarning(control) << "left/right/behind properties may only be set when swipe.position is 0";
358}
359
361{
362 return left || right || behind;
363}
364
366{
368}
369
371{
373 return;
374 Q_Q(QQuickSwipe);
375 if (!transition) {
376 q->setPosition(newPosition);
378 return;
379 }
380
383
385}
386
388{
389 Q_Q(QQuickSwipe);
390 waitForTransition = false;
391 q->setComplete(qFuzzyCompare(qAbs(position), qreal(1.0)));
392 if (complete) {
393 emit q->opened();
394 } else {
396 wasComplete = false;
397 emit q->closed();
398 }
399}
400
402 : QObject(*(new QQuickSwipePrivate(control)))
403{
404}
405
407{
408 Q_D(const QQuickSwipe);
409 return d->left;
410}
411
413{
414 Q_D(QQuickSwipe);
415 if (left == d->left)
416 return;
417
418 if (d->behind) {
419 d->warnAboutMixingDelegates();
420 return;
421 }
422
423 if (!qFuzzyIsNull(d->position)) {
424 d->warnAboutSettingDelegatesWhileVisible();
425 return;
426 }
427
428 d->left = left;
429
430 if (!d->left) {
431 delete d->leftItem;
432 d->leftItem = nullptr;
433 }
434
435 d->control->setFiltersChildMouseEvents(d->hasDelegates());
436
438}
439
441{
442 Q_D(const QQuickSwipe);
443 return d->behind;
444}
445
447{
448 Q_D(QQuickSwipe);
449 if (behind == d->behind)
450 return;
451
452 if (d->left || d->right) {
453 d->warnAboutMixingDelegates();
454 return;
455 }
456
457 if (!qFuzzyIsNull(d->position)) {
458 d->warnAboutSettingDelegatesWhileVisible();
459 return;
460 }
461
462 d->behind = behind;
463
464 if (!d->behind) {
465 delete d->behindItem;
466 d->behindItem = nullptr;
467 }
468
469 d->control->setFiltersChildMouseEvents(d->hasDelegates());
470
472}
473
475{
476 Q_D(const QQuickSwipe);
477 return d->right;
478}
479
481{
482 Q_D(QQuickSwipe);
483 if (right == d->right)
484 return;
485
486 if (d->behind) {
487 d->warnAboutMixingDelegates();
488 return;
489 }
490
491 if (!qFuzzyIsNull(d->position)) {
492 d->warnAboutSettingDelegatesWhileVisible();
493 return;
494 }
495
496 d->right = right;
497
498 if (!d->right) {
499 delete d->rightItem;
500 d->rightItem = nullptr;
501 }
502
503 d->control->setFiltersChildMouseEvents(d->hasDelegates());
504
506}
507
509{
510 Q_D(const QQuickSwipe);
511 return d->leftItem;
512}
513
515{
516 Q_D(QQuickSwipe);
517 if (item == d->leftItem)
518 return;
519
520 delete d->leftItem;
521 d->leftItem = item;
522
523 if (d->leftItem) {
524 d->leftItem->setParentItem(d->control);
525
526 if (qFuzzyIsNull(d->leftItem->z()))
527 d->leftItem->setZ(-2);
528 }
529
531}
532
534{
535 Q_D(const QQuickSwipe);
536 return d->behindItem;
537}
538
540{
541 Q_D(QQuickSwipe);
542 if (item == d->behindItem)
543 return;
544
545 delete d->behindItem;
546 d->behindItem = item;
547
548 if (d->behindItem) {
549 d->behindItem->setParentItem(d->control);
550
551 if (qFuzzyIsNull(d->behindItem->z()))
552 d->behindItem->setZ(-2);
553 }
554
556}
557
559{
560 Q_D(const QQuickSwipe);
561 return d->rightItem;
562}
563
565{
566 Q_D(QQuickSwipe);
567 if (item == d->rightItem)
568 return;
569
570 delete d->rightItem;
571 d->rightItem = item;
572
573 if (d->rightItem) {
574 d->rightItem->setParentItem(d->control);
575
576 if (qFuzzyIsNull(d->rightItem->z()))
577 d->rightItem->setZ(-2);
578 }
579
581}
582
584{
585 Q_D(const QQuickSwipe);
586 return d->position;
587}
588
590{
591 Q_D(QQuickSwipe);
592 const qreal adjustedPosition = qBound<qreal>(-1.0, position, 1.0);
593 if (adjustedPosition == d->position)
594 return;
595
596 d->position = adjustedPosition;
597 d->reposition(AnimatePosition);
599}
600
602{
603 Q_D(const QQuickSwipe);
604 return d->complete;
605}
606
607void QQuickSwipe::setComplete(bool complete)
608{
609 Q_D(QQuickSwipe);
610 if (complete == d->complete)
611 return;
612
613 d->complete = complete;
615 if (d->complete)
616 emit completed();
617}
618
620{
621 Q_D(const QQuickSwipe);
622 return d->enabled;
623}
624
626{
627 Q_D(QQuickSwipe);
628 if (enabled == d->enabled)
629 return;
630
631 d->enabled = enabled;
633}
634
636{
637 Q_D(const QQuickSwipe);
638 return d->transition;
639}
640
642{
643 Q_D(QQuickSwipe);
644 if (transition == d->transition)
645 return;
646
647 d->transition = transition;
649}
650
651void QQuickSwipe::open(QQuickSwipeDelegate::Side side)
652{
653 Q_D(QQuickSwipe);
654 if (qFuzzyCompare(qAbs(d->position), qreal(1.0)))
655 return;
656
658 || (!d->left && !d->behind && side == QQuickSwipeDelegate::Left)
659 || (!d->right && !d->behind && side == QQuickSwipeDelegate::Right))
660 return;
661
662 d->beginTransition(side);
663 d->wasComplete = true;
664 d->velocityCalculator.reset();
665 d->positionBeforePress = d->position;
666}
667
668void QQuickSwipe::close()
669{
670 Q_D(QQuickSwipe);
671 if (qFuzzyIsNull(d->position))
672 return;
673
674 if (d->control->isPressed()) {
675 // We don't support closing when we're pressed; release() or clicked() should be used instead.
676 return;
677 }
678
679 d->beginTransition(0.0);
680 d->waitForTransition = true;
681 d->wasComplete = false;
682 d->positionBeforePress = 0.0;
683 d->velocityCalculator.reset();
684}
685
687 : swipe(control)
688{
689}
690
692{
693 if (!background)
694 return;
695
696 resizingBackground = true;
697
699 const bool extraAllocated = extra.isAllocated();
700 // Don't check for or set the x here since it will just be overwritten by reposition().
701 if (((!p->widthValid() || !extraAllocated || !extra->hasBackgroundWidth))
702 || (extraAllocated && (extra->hasLeftInset || extra->hasRightInset))) {
704 }
705 if (((!p->heightValid() || !extraAllocated || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
706 || (extraAllocated && (extra->hasTopInset || extra->hasBottomInset))) {
709 }
710
711 resizingBackground = false;
712}
713
715{
717 const auto posInItem = item->mapToItem(q, event->position().toPoint());
719 // If the position is 0, we want to handle events ourselves - we don't want child items to steal them.
720 // This code will only get called when a child item has been created;
721 // events will go through the regular channels (mousePressEvent()) until then.
722 if (qFuzzyIsNull(swipePrivate->position)) {
723 q->mousePressEvent(event);
724 // The press point could be incorrect if the press happened over a child item,
725 // so we correct it after calling the base class' mousePressEvent(), rather
726 // than having to duplicate its code just so we can set the pressPoint.
727 setPressPoint(posInItem);
728 return true;
729 }
730
731 // If the delegate is swiped open, send the event to the exposed item,
732 // in case it's an interactive child (like a Button).
733 if (swipePrivate->complete)
734 forwardMouseEvent(event, item, posInItem);
735
736 // The position is non-zero, this press could be either for a delegate or the control itself
737 // (the control can be clicked to e.g. close the swipe). Either way, we must begin measuring
738 // mouse movement in case it turns into a swipe, in which case we grab the mouse.
739 swipePrivate->positionBeforePress = swipePrivate->position;
740 swipePrivate->velocityCalculator.startMeasuring(event->position().toPoint(), event->timestamp());
741 setPressPoint(item->mapToItem(q, event->position().toPoint()));
742
743 // When a delegate or any of its children uses the attached properties and signals,
744 // it declares that it wants mouse events.
745 const bool delivered = attachedObjectsSetPressed(item, event->scenePosition(), true);
746 if (delivered)
747 event->accept();
748 return delivered;
749}
750
752{
754
755 if (holdTimer > 0) {
758 }
759
760 // The delegate can still be pressed when swipe.enabled is false,
761 // but the mouse moving shouldn't have any effect on swipe.position.
763 if (!swipePrivate->enabled)
764 return false;
765
766 // Protect against division by zero.
767 if (width == 0)
768 return false;
769
770 // Don't bother reacting to events if we don't have any delegates.
771 if (!swipePrivate->left && !swipePrivate->right && !swipePrivate->behind)
772 return false;
773
774 // Don't handle move events for the control if it wasn't pressed.
775 if (item == q && !pressed)
776 return false;
777
778 const QPointF mappedEventPos = item->mapToItem(q, event->position().toPoint());
779 const qreal distance = (mappedEventPos - pressPoint).x();
780 if (!q->keepMouseGrab()) {
781 // We used to use the custom threshold that QQuickDrawerPrivate::grabMouse used,
782 // but since it's larger than what Flickable uses, it results in Flickable
783 // stealing events from us (QTBUG-50045), so now we use the default.
785 if (window && overThreshold) {
786 QQuickItem *grabber = q->window()->mouseGrabberItem();
787 if (!grabber || !grabber->keepMouseGrab()) {
788 q->grabMouse();
789 q->setKeepMouseGrab(true);
790 q->setPressed(true);
791 swipe.setComplete(false);
792
793 attachedObjectsSetPressed(item, event->scenePosition(), false, true);
794 }
795 }
796 }
797
798 if (q->keepMouseGrab()) {
799 // Ensure we don't try to calculate a position when the user tried to drag
800 // to the left when the left item is already exposed, and vice versa.
801 // The code below assumes that the drag is valid, so if we don't have this check,
802 // the wrong items are visible and the swiping wraps.
803 if (swipePrivate->behind
804 || ((swipePrivate->left || swipePrivate->right)
805 && (qFuzzyIsNull(swipePrivate->positionBeforePress)
806 || (swipePrivate->positionBeforePress == -1.0 && distance >= 0.0)
807 || (swipePrivate->positionBeforePress == 1.0 && distance <= 0.0)))) {
808
809 // We must instantiate the items here so that we can calculate the
810 // position against the width of the relevant item.
811 QQuickItem *relevantItem = swipePrivate->createRelevantItemForDistance(distance);
812 // If there isn't any relevant item, the user may have swiped back to the 0 position,
813 // or they swiped back to a position that is equal to positionBeforePress.
814 const qreal normalizedDistance = relevantItem ? distance / relevantItem->width() : 0.0;
815 qreal position = 0;
816
817 // If the control was exposed before the drag begun, the distance should be inverted.
818 // For example, if the control had been swiped to the right, the position would be 1.0.
819 // If the control was then swiped to the left by a distance of -20 pixels, the normalized
820 // distance might be -0.2, for example, which cannot be used as the position; the swipe
821 // started from the right, so we account for that by adding the position.
822 if (qFuzzyIsNull(normalizedDistance)) {
823 // There are two cases when the normalizedDistance can be 0,
824 // and we must distinguish between them:
825 //
826 // a) The swipe returns to the position that it was at before the press event.
827 // In this case, the distance will be 0.
828 // There would have been many position changes in the meantime, so we can't just
829 // ignore the move event; we have to set position to what it was before the press.
830 //
831 // b) If the position was at, 1.0, for example, and the control was then swiped
832 // to the left by the exact width of the left item, there won't be any relevant item
833 // (because the swipe's position would be at 0.0). In turn, the normalizedDistance
834 // would be 0 (because of the lack of a relevant item), but the distance will be non-zero.
835 position = qFuzzyIsNull(distance) ? swipePrivate->positionBeforePress : 0;
836 } else if (!swipePrivate->wasComplete) {
837 position = normalizedDistance;
838 } else {
839 position = distance > 0 ? normalizedDistance - 1.0 : normalizedDistance + 1.0;
840 }
841
842 if (swipePrivate->isTransitioning())
843 swipePrivate->transitionManager->cancel();
845 }
846 } else {
847 // The swipe wasn't initiated.
848 if (event->position().toPoint().y() < 0 || event->position().toPoint().y() > height) {
849 // The mouse went outside the vertical bounds of the control, so
850 // we should no longer consider it pressed.
851 q->setPressed(false);
852 }
853 }
854
855 event->accept();
856
857 return q->keepMouseGrab();
858}
859
860static const qreal exposeVelocityThreshold = 300.0;
861
863{
866 swipePrivate->velocityCalculator.stopMeasuring(event->position().toPoint(), event->timestamp());
867
868 const bool hadGrabbedMouse = q->keepMouseGrab();
869 q->setKeepMouseGrab(false);
870
871 // QQuickSwipe::close() doesn't allow closing while pressed, but now we're releasing.
872 // So set the pressed state false if this release _could_ result in closing, so that check can be bypassed.
873 if (!qIsNull(swipePrivate->position))
874 q->setPressed(false);
875
876 // Animations for the background and contentItem delegates are typically
877 // only enabled when !control.down, so that the animations aren't running
878 // when the user is swiping. To ensure that the animations are enabled
879 // *before* the positions of these delegates change (via the swipe.setPosition() calls below),
880 // we must cancel the press. QQuickAbstractButton::mouseUngrabEvent() does this
881 // for us, but by then it's too late.
882 if (hadGrabbedMouse) {
883 // TODO: this is copied from QQuickAbstractButton::mouseUngrabEvent().
884 // Eventually it should be moved into a private helper so that we don't have to duplicate it.
885 q->setPressed(false);
888 emit q->canceled();
889 }
890
891 // Inform the given item that the mouse is released, in case it's an interactive child.
892 if (item != q && (swipePrivate->complete || swipePrivate->wasComplete))
893 forwardMouseEvent(event, item, item->mapFromScene(event->scenePosition()));
894
895 // The control can be exposed by either swiping past the halfway mark, or swiping fast enough.
896 const qreal swipeVelocity = swipePrivate->velocityCalculator.velocity().x();
897 if (swipePrivate->position > 0.5 ||
898 (swipePrivate->position > 0.0 && swipeVelocity > exposeVelocityThreshold)) {
899 swipePrivate->beginTransition(1.0);
900 swipePrivate->wasComplete = true;
901 } else if (swipePrivate->position < -0.5 ||
902 (swipePrivate->position < 0.0 && swipeVelocity < -exposeVelocityThreshold)) {
903 swipePrivate->beginTransition(-1.0);
904 swipePrivate->wasComplete = true;
905 } else if (!swipePrivate->isTransitioning()) {
906 // The position is either <= 0.5 or >= -0.5, so the position should go to 0.
907 // However, if the position was already 0 or close to it, we were just clicked,
908 // and we don't need to start a transition.
909 if (!qFuzzyIsNull(swipePrivate->position))
910 swipePrivate->beginTransition(0.0);
911 swipePrivate->wasComplete = false;
912 }
913
914 // Inform any QQuickSwipeDelegateAttached objects that the mouse is released.
915 attachedObjectsSetPressed(item, event->scenePosition(), false);
916
917 // Only consume child events if we had grabbed the mouse.
918 return hadGrabbedMouse;
919}
920
925{
927 QMutableSinglePointEvent localizedEvent(*event);
928 QMutableEventPoint::setPosition(localizedEvent.point(0), localPos);
929 QGuiApplication::sendEvent(destination, &localizedEvent);
930 q->setPressed(!localizedEvent.isAccepted());
931}
932
941{
942 bool found = false;
943 QVarLengthArray<QQuickItem *, 16> itemAndChildren;
944 itemAndChildren.append(item);
945 for (int i = 0; i < itemAndChildren.size(); ++i) {
946 auto item = itemAndChildren.at(i);
947 auto posInItem = item->mapFromScene(scenePos);
948 if (item->contains(posInItem)) {
949 if (Attached *attached = attachedObject(item)) {
950 const bool wasPressed = attached->isPressed();
951 attached->setPressed(pressed);
952 if (wasPressed && !pressed && !cancel)
953 emit attached->clicked();
954 found = true;
955 }
956 }
957 for (auto child : item->childItems())
958 itemAndChildren.append(child);
959 }
960 return found;
961}
962
963static void warnIfHorizontallyAnchored(QQuickItem *item, const QString &itemName)
964{
965 if (!item)
966 return;
967
969 if (anchors && (anchors->fill() || anchors->centerIn() || anchors->left().item || anchors->right().item)
970 && !item->property("_q_QQuickSwipeDelegate_warned").toBool()) {
971 qmlWarning(item) << QString::fromLatin1("SwipeDelegate: cannot use horizontal anchors with %1; unable to layout the item.").arg(itemName);
972 item->setProperty("_q_QQuickSwipeDelegate_warned", true);
973 }
974}
975
977{
980
981 // If the background and contentItem are repositioned due to a swipe,
982 // we don't want to call QQuickControlPrivate's implementation of this function,
983 // as it repositions the contentItem to be visible.
984 // However, we still want to position the contentItem vertically
985 // and resize it (in case the control was resized while open).
987 if (!swipePrivate->complete) {
989 } else if (contentItem) {
991 contentItem->setY(q->topPadding());
992 contentItem->setWidth(q->availableWidth());
993 contentItem->setHeight(q->availableHeight());
994 }
995}
996
998{
1000}
1001
1004{
1005 // QQuickSwipeDelegate still depends on synthesized mouse events
1006 setAcceptTouchEvents(false);
1007}
1008
1176{
1177 Q_D(const QQuickSwipeDelegate);
1178 return const_cast<QQuickSwipe*>(&d->swipe);
1179}
1180
1182{
1183 return new QQuickSwipeDelegateAttached(object);
1184}
1185
1187{
1188 return item && (child == item || item->isAncestorOf(child));
1189}
1190
1192{
1194 // The contentItem is, by default, usually a non-interactive item like Text, and
1195 // the same applies to the background. This means that simply stacking the left/right/behind
1196 // items before these items won't allow us to get mouse events when the control is not currently exposed
1197 // but has been previously. Therefore, we instead call setFiltersChildMouseEvents(true) in the constructor
1198 // and filter out child events only when the child is the left/right/behind item.
1199 const QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
1200 if (!isChildOrGrandchildOf(child, swipePrivate->leftItem) && !isChildOrGrandchildOf(child, swipePrivate->behindItem)
1201 && !isChildOrGrandchildOf(child, swipePrivate->rightItem)) {
1202 return false;
1203 }
1204
1205 switch (event->type()) {
1207 return d->handleMousePressEvent(child, static_cast<QMouseEvent *>(event));
1208 } case QEvent::MouseMove: {
1209 return d->handleMouseMoveEvent(child, static_cast<QMouseEvent *>(event));
1211 // Make sure that the control gets release events if it has created child
1212 // items that are stealing events from it.
1213 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
1215 return d->handleMouseReleaseEvent(child, mouseEvent);
1216 } case QEvent::UngrabMouse: {
1217 // If the mouse was pressed over e.g. rightItem and then dragged down,
1218 // the ListView would eventually grab the mouse, at which point we must
1219 // clear the pressed flag so that it doesn't stay pressed after the release.
1220 Attached *attached = attachedObject(child);
1221 if (attached)
1222 attached->setPressed(false);
1223 return false;
1224 } default:
1225 return false;
1226 }
1227}
1228
1229// We only override this to set positionBeforePress;
1230// otherwise, it's the same as the base class implementation.
1232{
1235
1236 QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
1237 if (!swipePrivate->enabled)
1238 return;
1239
1240 swipePrivate->positionBeforePress = swipePrivate->position;
1241 swipePrivate->velocityCalculator.startMeasuring(event->position().toPoint(), event->timestamp());
1242
1243 if (swipePrivate->complete) {
1244 auto item = d->swipe.rightItem();
1245 if (item && item->contains(item->mapFromScene(event->scenePosition()))) {
1246 d->pressedItem = item;
1247 d->handleMousePressEvent(item, event);
1248 } else {
1249 item = d->swipe.leftItem();
1250 if (item && item->contains(item->mapFromScene(event->scenePosition()))) {
1251 d->pressedItem = item;
1252 d->handleMousePressEvent(item, event);
1253 }
1254 }
1255 }
1256}
1257
1259{
1262 d->handleMouseMoveEvent(this, event);
1263 else
1265 if (d->pressedItem)
1266 d->handleMouseMoveEvent(d->pressedItem, event);
1267}
1268
1270{
1272 if (!filtersChildMouseEvents() || !d->handleMouseReleaseEvent(this, event))
1274
1275 if (d->pressedItem) {
1276 if (d->pressedItem->acceptedMouseButtons())
1277 d->handleMouseReleaseEvent(d->pressedItem, event);
1278 d->pressedItem = nullptr;
1279 }
1280}
1281
1283{
1285 setPressed(false);
1286
1287 auto item = d->swipe.rightItem();
1288 if (item) {
1289 if (auto control = qmlobject_cast<QQuickControl *>(item))
1291 Attached *attached = attachedObject(item);
1292 if (attached)
1293 attached->setPressed(false);
1294 } else {
1295 item = d->swipe.leftItem();
1296 if (item) {
1297 if (auto control = qmlobject_cast<QQuickControl *>(item))
1299 Attached *attached = attachedObject(item);
1300 if (attached)
1301 attached->setPressed(false);
1302 }
1303 }
1304
1305 d->pressedItem = nullptr;
1306}
1307
1309{
1310 // Don't allow QQuickControl accept the touch event, because QQuickSwipeDelegate
1311 // is still based on synthesized mouse events
1312 event->ignore();
1313}
1314
1316{
1319 QQuickSwipePrivate::get(&d->swipe)->reposition(DontAnimatePosition);
1320}
1321
1322void QQuickSwipeDelegate::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
1323{
1325 QQuickControl::geometryChange(newGeometry, oldGeometry);
1326
1327 if (isComponentComplete() && !qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
1328 QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
1329 swipePrivate->reposition(DontAnimatePosition);
1330 }
1331}
1332
1334{
1336}
1337
1338#if QT_CONFIG(accessibility)
1339QAccessible::Role QQuickSwipeDelegate::accessibleRole() const
1340{
1341 return QAccessible::ListItem;
1342}
1343#endif
1344
1346{
1347 Q_DECLARE_PUBLIC(QQuickSwipeDelegateAttached)
1348
1349public:
1350 // True when left/right/behind is non-interactive and is pressed.
1351 bool pressed = false;
1352};
1353
1376{
1378 if (item) {
1379 // This allows us to be notified when an otherwise non-interactive item
1380 // is pressed and clicked. The alternative is much more more complex:
1381 // iterating through children that contain the event pos and finding
1382 // the first one with an attached object.
1384 } else {
1385 qWarning() << "Attached properties of SwipeDelegate must be accessed through an Item";
1386 }
1387}
1388
1476{
1477 Q_D(const QQuickSwipeDelegateAttached);
1478 return d->pressed;
1479}
1480
1482{
1484 if (pressed == d->pressed)
1485 return;
1486
1487 d->pressed = pressed;
1489}
1490
1492
1493#include "moc_qquickswipe_p.cpp"
1494#include "moc_qquickswipedelegate_p.cpp"
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
\inmodule QtCore
Definition qcoreevent.h:45
@ UngrabMouse
Definition qcoreevent.h:234
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonPress
Definition qcoreevent.h:60
@ MouseButtonRelease
Definition qcoreevent.h:61
bool isAccepted() const
Definition qcoreevent.h:303
\reentrant
Definition qfont.h:20
virtual bool contains(const QPointF &point) const
Returns true if this item contains point, which is in local coordinates; otherwise,...
QPointF mapToItem(const QGraphicsItem *item, const QPointF &point) const
Maps the point point, which is in this item's coordinate system, to item's coordinate system,...
QList< QGraphicsItem * > childItems() const
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
void setAcceptedMouseButtons(Qt::MouseButtons buttons)
Sets the mouse buttons that this item accepts mouse events for.
QPointF mapFromScene(const QPointF &point) const
Maps the point point, which is in this item's scene's coordinate system, to this item's coordinate sy...
bool isAncestorOf(const QGraphicsItem *child) const
Returns true if this item is an ancestor of child (i.e., if this item is child's parent,...
static QStyleHints * styleHints()
Returns the application's style hints.
static void setObjectOwnership(QObject *, ObjectOwnership)
Sets the ownership of object.
@ JavaScriptOwnership
Definition qjsengine.h:275
\inmodule QtCore
Definition qline.h:182
qreal length() const
Returns the length of the line.
Definition qline.cpp:542
Definition qlist.h:74
\inmodule QtGui
Definition qevent.h:195
\inmodule QtCore
Definition qobject.h:90
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
QEventPoint & point(qsizetype i)
Returns a QEventPoint reference for the point at index i.
Definition qevent.cpp:237
The QQmlComponent class encapsulates a QML component definition.
QList< QQmlError > errors() const
Returns the list of errors that occurred during the last compile or create operation.
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
AtFunction at
Definition qqmllist.h:86
CountFunction count
Definition qqmllist.h:85
virtual void componentComplete()=0
Invoked after the root component that caused this instantiation has completed construction.
The QQmlProperty class abstracts accessing properties on objects created from QML.
void setDefaultTarget(const QQmlProperty &)
void setPressPoint(const QPointF &point)
void setPressed(bool pressed)
QQuickAnchorLine left
QQuickItem * fill
QQuickAnchorLine right
QQuickItem * centerIn
QQuickDeferredPointer< QQuickItem > background
QQuickDeferredPointer< QQuickItem > contentItem
qreal getRightInset() const
qreal getBottomInset() const
QLazilyAllocated< ExtraData > extra
virtual void handleUngrab()
virtual void resizeContent()
static QQuickControlPrivate * get(QQuickControl *control)
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
QQuickItem * contentItem
QQuickItem * background
QQuickAnchors * _anchors
QQuickWindow * window
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
virtual void mouseReleaseEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
qreal y
Defines the item's y position relative to its parent.
Definition qquickitem.h:74
void setAcceptTouchEvents(bool accept)
If enabled is true, this sets the item to accept touch events; otherwise, touch events are not accept...
void setHeight(qreal)
QQuickWindow * window() const
Returns the window in which this item is rendered.
virtual void mousePressEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
qreal width
This property holds the width of this item.
Definition qquickitem.h:76
bool filtersChildMouseEvents() const
Returns whether pointer events intended for this item's children should be filtered through this item...
void setVisible(bool)
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
bool keepMouseGrab() const
Returns whether mouse input should exclusively remain with this item.
void grabMouse()
void setWidth(qreal)
void setY(qreal)
virtual void mouseMoveEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
QQuickSwipeDelegateAttached(QObject *object=nullptr)
bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event)
void forwardMouseEvent(QMouseEvent *event, QQuickItem *destination, QPointF localPos)
QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control)
QPalette defaultPalette() const override
bool attachedObjectsSetPressed(QQuickItem *item, QPointF scenePos, bool pressed, bool cancel=false)
bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event)
bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event)
void mousePressEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
static QQuickSwipeDelegateAttached * qmlAttachedProperties(QObject *object)
void mouseUngrabEvent() override
This event handler can be reimplemented in a subclass to be notified when a mouse ungrab event has oc...
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
QQuickSwipeDelegate(QQuickItem *parent=nullptr)
void touchEvent(QTouchEvent *event) override
This event handler can be reimplemented in a subclass to receive touch events for an item.
void mouseMoveEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
void mouseReleaseEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override
Reimplement this method to filter the pointer events that are received by this item's children.
QFont defaultFont() const override
QQuickTransition * transition
QQuickSwipePrivate(QQuickSwipeDelegate *control)
QQuickVelocityCalculator velocityCalculator
QScopedPointer< QQuickSwipeTransitionManager > transitionManager
QQuickItem * showRelevantItemForPosition(qreal position)
void reposition(PositionAnimation animationPolicy)
QQuickItem * createDelegateItem(QQmlComponent *component)
static QQuickSwipePrivate * get(QQuickSwipe *swipe)
QQuickItem * createRelevantItemForDistance(qreal distance)
void beginTransition(qreal position)
QQuickSwipeDelegate * control
QQuickSwipeTransitionManager(QQuickSwipe *swipe)
void transition(QQuickTransition *transition, qreal position)
void leftItemChanged()
QQmlComponent * left
bool isEnabled() const
QQmlComponent * behind
void enabledChanged()
bool isComplete() const
void completeChanged()
void rightChanged()
void rightItemChanged()
void behindItemChanged()
void setRightItem(QQuickItem *item)
void setComplete(bool complete)
void setBehindItem(QQuickItem *item)
void setEnabled(bool enabled)
QQuickItem * leftItem
QQuickSwipe(QQuickSwipeDelegate *control)
void setBehind(QQmlComponent *behind)
QQuickItem * behindItem
void setTransition(QQuickTransition *transition)
QQuickItem * rightItem
void transitionChanged()
void completed()
void leftChanged()
QQmlComponent * right
void behindChanged()
void setPosition(qreal position)
void setLeftItem(QQuickItem *item)
QQuickTransition * transition
void setLeft(QQmlComponent *left)
void positionChanged()
void setRight(QQmlComponent *right)
static QPalette palette(Scope scope)
static QFont font(Scope scope)
void transition(const QList< QQuickStateAction > &, QQuickTransition *transition, QObject *defaultTarget=nullptr)
void startMeasuring(const QPointF &point1, qint64 timestamp=0)
void stopMeasuring(const QPointF &m_point2, qint64 timestamp=0)
static bool dragOverThreshold(qreal d, Qt::Axis axis, const QEventPoint *tp, int startDragThreshold=-1)
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
\inmodule QtCore
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
int startDragDistance
the distance, in pixels, that the mouse must be moved with a button held down before a drag and drop ...
Definition qstylehints.h:39
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:916
constexpr size_type size() const noexcept
const T & at(qsizetype idx) const
void append(const T &t)
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
@ AllButtons
Definition qnamespace.h:89
@ XAxis
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
bool qIsNull(qfloat16 f) noexcept
Definition qfloat16.h:308
#define qWarning
Definition qlogging.h:162
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLenum GLenum GLsizei count
GLuint object
[3]
GLdouble GLdouble right
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei GLsizei GLfloat distance
GLint GLsizei width
GLint left
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
void qmlExecuteDeferred(QObject *object)
Definition qqml.cpp:48
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static qreal adjustedPosition(QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static QQuickAttachedPropertyPropagator * attachedObject(const QMetaObject *type, QObject *object, bool create=false)
QQuickAnchors * anchors(QQuickItem *item)
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:483
static bool isChildOrGrandchildOf(QQuickItem *child, QQuickItem *item)
static const qreal exposeVelocityThreshold
static void warnIfHorizontallyAnchored(QQuickItem *item, const QString &itemName)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define emit
double qreal
Definition qtypes.h:92
future cancel()
QGraphicsItem * item
QLayoutItem * child
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent