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
4#include "qquickdrawer_p.h"
5#include "qquickdrawer_p_p.h"
6#include "qquickpopupitem_p_p.h"
7#include "qquickpopuppositioner_p_p.h"
8
9#include <QtGui/qstylehints.h>
10#include <QtGui/private/qguiapplication_p.h>
11#include <QtQml/qqmlinfo.h>
12#include <QtQuick/private/qquickwindow_p.h>
13#include <QtQuick/private/qquickanimation_p.h>
14#include <QtQuick/private/qquicktransition_p.h>
15
16QT_BEGIN_NAMESPACE
17
18/*!
19 \qmltype Drawer
20 \inherits Popup
21//! \instantiates QQuickDrawer
22 \inqmlmodule QtQuick.Controls
23 \since 5.7
24 \ingroup qtquickcontrols-navigation
25 \ingroup qtquickcontrols-popups
26 \brief Side panel that can be opened and closed using a swipe gesture.
27
28 Drawer provides a swipe-based side panel, similar to those often used in
29 touch interfaces to provide a central location for navigation.
30
31 \image qtquickcontrols-drawer.gif
32
33 Drawer can be positioned at any of the four edges of the content item.
34 The drawer above is positioned against the left edge of the window. The
35 drawer is then opened by \e "dragging" it out from the left edge of the
36 window.
37
38 \code
39 import QtQuick
40 import QtQuick.Controls
41
42 ApplicationWindow {
43 id: window
44 visible: true
45
46 Drawer {
47 id: drawer
48 width: 0.66 * window.width
49 height: window.height
50
51 Label {
52 text: "Content goes here!"
53 anchors.centerIn: parent
54 }
55 }
56 }
57 \endcode
58
59 Drawer is a special type of popup that resides at one of the window \l {edge}{edges}.
60 By default, Drawer re-parents itself to the window \c overlay, and therefore operates
61 on window coordinates. It is also possible to manually set the \l{Popup::}{parent} to
62 something else to make the drawer operate in a specific coordinate space.
63
64 Drawer can be configured to cover only part of its window edge. The following example
65 illustrates how Drawer can be positioned to appear below a window header:
66
67 \code
68 import QtQuick
69 import QtQuick.Controls
70
71 ApplicationWindow {
72 id: window
73 visible: true
74
75 header: ToolBar { }
76
77 Drawer {
78 y: header.height
79 width: window.width * 0.6
80 height: window.height - header.height
81 }
82 }
83 \endcode
84
85 The \l position property determines how much of the drawer is visible, as
86 a value between \c 0.0 and \c 1.0. It is not possible to set the x-coordinate
87 (or horizontal margins) of a drawer at the left or right window edge, or the
88 y-coordinate (or vertical margins) of a drawer at the top or bottom window edge.
89
90 In the image above, the application's contents are \e "pushed" across the
91 screen. This is achieved by applying a translation to the contents:
92
93 \code
94 import QtQuick
95 import QtQuick.Controls
96
97 ApplicationWindow {
98 id: window
99 width: 200
100 height: 228
101 visible: true
102
103 Drawer {
104 id: drawer
105 width: 0.66 * window.width
106 height: window.height
107 }
108
109 Label {
110 id: content
111
112 text: "Aa"
113 font.pixelSize: 96
114 anchors.fill: parent
115 verticalAlignment: Label.AlignVCenter
116 horizontalAlignment: Label.AlignHCenter
117
118 transform: Translate {
119 x: drawer.position * content.width * 0.33
120 }
121 }
122 }
123 \endcode
124
125 If you would like the application's contents to stay where they are when
126 the drawer is opened, don't apply a translation.
127
128 Drawer can be configured as a non-closable persistent side panel by
129 making the Drawer \l {Popup::modal}{non-modal} and \l {interactive}
130 {non-interactive}. See the \l {Qt Quick Controls 2 - Gallery}{Gallery}
131 example for more details.
132
133 \note On some platforms, certain edges may be reserved for system
134 gestures and therefore cannot be used with Drawer. For example, the
135 top and bottom edges may be reserved for system notifications and
136 control centers on Android and iOS.
137
138 \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Popup Controls}
139*/
140
141class QQuickDrawerPositioner : public QQuickPopupPositioner
142{
143public:
144 QQuickDrawerPositioner(QQuickDrawer *drawer) : QQuickPopupPositioner(drawer) { }
145
146 void reposition() override;
147};
148
149qreal QQuickDrawerPrivate::offsetAt(const QPointF &point) const
150{
151 qreal offset = positionAt(point) - position;
152
153 // don't jump when dragged open
154 if (offset > 0 && position > 0 && !contains(scenePos: point))
155 offset = 0;
156
157 return offset;
158}
159
160qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const
161{
162 Q_Q(const QQuickDrawer);
163 QQuickWindow *window = q->window();
164 if (!window)
165 return 0;
166
167 switch (edge) {
168 case Qt::TopEdge:
169 return point.y() / q->height();
170 case Qt::LeftEdge:
171 return point.x() / q->width();
172 case Qt::RightEdge:
173 return (window->width() - point.x()) / q->width();
174 case Qt::BottomEdge:
175 return (window->height() - point.y()) / q->height();
176 default:
177 return 0;
178 }
179}
180
181QQuickPopupPositioner *QQuickDrawerPrivate::getPositioner()
182{
183 Q_Q(QQuickDrawer);
184 if (!positioner)
185 positioner = new QQuickDrawerPositioner(q);
186 return positioner;
187}
188
189void QQuickDrawerPositioner::reposition()
190{
191 if (m_positioning)
192 return;
193
194 QQuickDrawer *drawer = static_cast<QQuickDrawer*>(popup());
195 QQuickWindow *window = drawer->window();
196 if (!window)
197 return;
198
199 const qreal position = drawer->position();
200 QQuickItem *popupItem = drawer->popupItem();
201 switch (drawer->edge()) {
202 case Qt::LeftEdge:
203 popupItem->setX((position - 1.0) * popupItem->width());
204 break;
205 case Qt::RightEdge:
206 popupItem->setX(window->width() - position * popupItem->width());
207 break;
208 case Qt::TopEdge:
209 popupItem->setY((position - 1.0) * popupItem->height());
210 break;
211 case Qt::BottomEdge:
212 popupItem->setY(window->height() - position * popupItem->height());
213 break;
214 }
215
216 QQuickPopupPositioner::reposition();
217}
218
219void QQuickDrawerPrivate::showOverlay()
220{
221 // managed in setPosition()
222}
223
224void QQuickDrawerPrivate::hideOverlay()
225{
226 // managed in setPosition()
227}
228
229void QQuickDrawerPrivate::resizeOverlay()
230{
231 if (!dimmer || !window)
232 return;
233
234 QRectF geometry(0, 0, window->width(), window->height());
235
236 if (edge == Qt::LeftEdge || edge == Qt::RightEdge) {
237 geometry.setY(popupItem->y());
238 geometry.setHeight(popupItem->height());
239 } else {
240 geometry.setX(popupItem->x());
241 geometry.setWidth(popupItem->width());
242 }
243
244 dimmer->setPosition(geometry.topLeft());
245 dimmer->setSize(geometry.size());
246}
247
248static bool isWithinDragMargin(const QQuickDrawer *drawer, const QPointF &pos)
249{
250 switch (drawer->edge()) {
251 case Qt::LeftEdge:
252 return pos.x() <= drawer->dragMargin();
253 case Qt::RightEdge:
254 return pos.x() >= drawer->window()->width() - drawer->dragMargin();
255 case Qt::TopEdge:
256 return pos.y() <= drawer->dragMargin();
257 case Qt::BottomEdge:
258 return pos.y() >= drawer->window()->height() - drawer->dragMargin();
259 default:
260 Q_UNREACHABLE();
261 break;
262 }
263 return false;
264}
265
266bool QQuickDrawerPrivate::startDrag(QEvent *event)
267{
268 Q_Q(QQuickDrawer);
269 delayedEnterTransition = false;
270 if (!window || !interactive || dragMargin < 0.0 || qFuzzyIsNull(d: dragMargin))
271 return false;
272
273 switch (event->type()) {
274 case QEvent::MouseButtonPress:
275 if (QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); isWithinDragMargin(drawer: q, pos: mouseEvent->scenePosition())) {
276 // watch future events and grab the mouse once it has moved
277 // sufficiently fast or far (in grabMouse).
278 delayedEnterTransition = true;
279 mouseEvent->addPassiveGrabber(point: mouseEvent->point(i: 0), grabber: popupItem);
280 handleMouseEvent(item: window->contentItem(), event: mouseEvent);
281 return false;
282 }
283 break;
284
285#if QT_CONFIG(quicktemplates2_multitouch)
286 case QEvent::TouchBegin:
287 case QEvent::TouchUpdate: {
288 auto *touchEvent = static_cast<QTouchEvent *>(event);
289 for (const QTouchEvent::TouchPoint &point : touchEvent->points()) {
290 if (point.state() == QEventPoint::Pressed && isWithinDragMargin(drawer: q, pos: point.scenePosition())) {
291 delayedEnterTransition = true;
292 touchEvent->addPassiveGrabber(point, grabber: popupItem);
293 handleTouchEvent(item: window->contentItem(), event: touchEvent);
294 return false;
295 }
296 }
297 break;
298 }
299#endif
300
301 default:
302 break;
303 }
304
305 return false;
306}
307
308static inline bool keepGrab(QQuickItem *item)
309{
310 return item->keepMouseGrab() || item->keepTouchGrab();
311}
312
313bool QQuickDrawerPrivate::grabMouse(QQuickItem *item, QMouseEvent *event)
314{
315 Q_Q(QQuickDrawer);
316 handleMouseEvent(item, event);
317
318 if (!window || !interactive || keepGrab(item: popupItem) || keepGrab(item))
319 return false;
320
321 const QPointF movePoint = event->scenePosition();
322
323 // Flickable uses a hard-coded threshold of 15 for flicking, and
324 // QStyleHints::startDragDistance for dragging. Drawer uses a bit
325 // larger threshold to avoid being too eager to steal touch (QTBUG-50045)
326 const int threshold = qMax(a: 20, b: QGuiApplication::styleHints()->startDragDistance() + 5);
327 bool overThreshold = false;
328 if (position > 0 || dragMargin > 0) {
329 const bool xOverThreshold = QQuickWindowPrivate::dragOverThreshold(d: movePoint.x() - pressPoint.x(), axis: Qt::XAxis, event, startDragThreshold: threshold);
330 const bool yOverThreshold = QQuickWindowPrivate::dragOverThreshold(d: movePoint.y() - pressPoint.y(), axis: Qt::YAxis, event, startDragThreshold: threshold);
331 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
332 overThreshold = xOverThreshold && !yOverThreshold;
333 else
334 overThreshold = yOverThreshold && !xOverThreshold;
335 }
336
337 // Don't be too eager to steal presses outside the drawer (QTBUG-53929)
338 if (overThreshold && qFuzzyCompare(p1: position, p2: qreal(1.0)) && !contains(scenePos: movePoint)) {
339 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
340 overThreshold = qAbs(t: movePoint.x() - q->width()) < dragMargin;
341 else
342 overThreshold = qAbs(t: movePoint.y() - q->height()) < dragMargin;
343 }
344
345 if (overThreshold) {
346 if (delayedEnterTransition) {
347 prepareEnterTransition();
348 reposition();
349 delayedEnterTransition = false;
350 }
351
352 popupItem->grabMouse();
353 popupItem->setKeepMouseGrab(true);
354 offset = offsetAt(point: movePoint);
355 }
356
357 return overThreshold;
358}
359
360#if QT_CONFIG(quicktemplates2_multitouch)
361bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event)
362{
363 Q_Q(QQuickDrawer);
364 bool handled = handleTouchEvent(item, event);
365
366 if (!window || !interactive || keepGrab(item: popupItem) || keepGrab(item) || !event->touchPointStates().testFlag(flag: QEventPoint::Updated))
367 return handled;
368
369 bool overThreshold = false;
370 for (const QTouchEvent::TouchPoint &point : event->points()) {
371 if (!acceptTouch(point) || point.state() != QEventPoint::Updated)
372 continue;
373
374 const QPointF movePoint = point.scenePosition();
375
376 // Flickable uses a hard-coded threshold of 15 for flicking, and
377 // QStyleHints::startDragDistance for dragging. Drawer uses a bit
378 // larger threshold to avoid being too eager to steal touch (QTBUG-50045)
379 const int threshold = qMax(a: 20, b: QGuiApplication::styleHints()->startDragDistance() + 5);
380 if (position > 0 || dragMargin > 0) {
381 const bool xOverThreshold = QQuickWindowPrivate::dragOverThreshold(d: movePoint.x() - pressPoint.x(), axis: Qt::XAxis, tp: &point, startDragThreshold: threshold);
382 const bool yOverThreshold = QQuickWindowPrivate::dragOverThreshold(d: movePoint.y() - pressPoint.y(), axis: Qt::YAxis, tp: &point, startDragThreshold: threshold);
383 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
384 overThreshold = xOverThreshold && !yOverThreshold;
385 else
386 overThreshold = yOverThreshold && !xOverThreshold;
387 }
388
389 // Don't be too eager to steal presses outside the drawer (QTBUG-53929)
390 if (overThreshold && qFuzzyCompare(p1: position, p2: qreal(1.0)) && !contains(scenePos: movePoint)) {
391 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
392 overThreshold = qAbs(t: movePoint.x() - q->width()) < dragMargin;
393 else
394 overThreshold = qAbs(t: movePoint.y() - q->height()) < dragMargin;
395 }
396
397 if (overThreshold) {
398 if (delayedEnterTransition) {
399 prepareEnterTransition();
400 reposition();
401 delayedEnterTransition = false;
402 }
403 event->setExclusiveGrabber(point, exclusiveGrabber: popupItem);
404 popupItem->setKeepTouchGrab(true);
405 offset = offsetAt(point: movePoint);
406 }
407 }
408
409 return overThreshold;
410}
411#endif
412
413static const qreal openCloseVelocityThreshold = 300;
414
415// Overrides QQuickPopupPrivate::blockInput, which is called by
416// QQuickPopupPrivate::handlePress/Move/Release, which we call in our own
417// handlePress/Move/Release overrides.
418// This implementation conflates two things: should the event going to the item get
419// modally blocked by us? Or should we accept the event and become the grabber?
420// Those are two fundamentally different questions for the drawer as a (usually)
421// interactive control.
422bool QQuickDrawerPrivate::blockInput(QQuickItem *item, const QPointF &point) const
423{
424 Q_Q(const QQuickDrawer);
425
426 // We want all events, if mouse/touch is already grabbed.
427 if (popupItem->keepMouseGrab() || popupItem->keepTouchGrab())
428 return true;
429
430 // Don't block input to drawer's children/content.
431 if (popupItem->isAncestorOf(child: item))
432 return false;
433
434 // Don't block outside a drawer's background dimming
435 if (dimmer && !dimmer->contains(point: dimmer->mapFromScene(point)))
436 return false;
437
438 // Accept all events within drag area.
439 if (isWithinDragMargin(drawer: q, pos: point))
440 return true;
441
442 // Accept all other events if drawer is modal.
443 return modal;
444}
445
446bool QQuickDrawerPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
447{
448 offset = 0;
449 velocityCalculator.startMeasuring(point1: point, timestamp);
450
451 if (!QQuickPopupPrivate::handlePress(item, point, timestamp))
452 return interactive && popupItem == item;
453
454 return true;
455}
456
457bool QQuickDrawerPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
458{
459 Q_Q(QQuickDrawer);
460 if (!QQuickPopupPrivate::handleMove(item, point, timestamp))
461 return false;
462
463 // limit/reset the offset to the edge of the drawer when pushed from the outside
464 if (qFuzzyCompare(p1: position, p2: qreal(1.0)) && !contains(scenePos: point))
465 offset = 0;
466
467 bool isGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
468 if (isGrabbed)
469 q->setPosition(positionAt(point) - offset);
470
471 return isGrabbed;
472}
473
474bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
475{
476 auto cleanup = qScopeGuard(f: [this] {
477 popupItem->setKeepMouseGrab(false);
478 popupItem->setKeepTouchGrab(false);
479 pressPoint = QPointF();
480 touchId = -1;
481 });
482 if (pressPoint.isNull())
483 return false;
484 if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) {
485 velocityCalculator.reset();
486 return QQuickPopupPrivate::handleRelease(item, point, timestamp);
487 }
488
489 velocityCalculator.stopMeasuring(m_point2: point, timestamp);
490
491 qreal velocity = 0;
492 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
493 velocity = velocityCalculator.velocity().x();
494 else
495 velocity = velocityCalculator.velocity().y();
496
497 // the velocity is calculated so that swipes from left to right
498 // and top to bottom have positive velocity, and swipes from right
499 // to left and bottom to top have negative velocity.
500 //
501 // - top/left edge: positive velocity opens, negative velocity closes
502 // - bottom/right edge: negative velocity opens, positive velocity closes
503 //
504 // => invert the velocity for bottom and right edges, for the threshold comparison below
505 if (edge == Qt::RightEdge || edge == Qt::BottomEdge)
506 velocity = -velocity;
507
508 if (position > 0.7 || velocity > openCloseVelocityThreshold) {
509 transitionManager.transitionEnter();
510 } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) {
511 transitionManager.transitionExit();
512 } else {
513 switch (edge) {
514 case Qt::LeftEdge:
515 if (point.x() - pressPoint.x() > 0)
516 transitionManager.transitionEnter();
517 else
518 transitionManager.transitionExit();
519 break;
520 case Qt::RightEdge:
521 if (point.x() - pressPoint.x() < 0)
522 transitionManager.transitionEnter();
523 else
524 transitionManager.transitionExit();
525 break;
526 case Qt::TopEdge:
527 if (point.y() - pressPoint.y() > 0)
528 transitionManager.transitionEnter();
529 else
530 transitionManager.transitionExit();
531 break;
532 case Qt::BottomEdge:
533 if (point.y() - pressPoint.y() < 0)
534 transitionManager.transitionEnter();
535 else
536 transitionManager.transitionExit();
537 break;
538 }
539 }
540
541 // the cleanup() lambda will run before return
542 return popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
543}
544
545void QQuickDrawerPrivate::handleUngrab()
546{
547 QQuickPopupPrivate::handleUngrab();
548
549 velocityCalculator.reset();
550}
551
552static QList<QQuickStateAction> prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to)
553{
554 QList<QQuickStateAction> actions;
555 if (!transition || !QQuickPopupPrivate::get(popup: drawer)->window || !transition->enabled())
556 return actions;
557
558 qmlExecuteDeferred(transition);
559
560 QQmlProperty defaultTarget(drawer, QLatin1String("position"));
561 QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
562 int count = animations.count(&animations);
563 for (int i = 0; i < count; ++i) {
564 QQuickAbstractAnimation *anim = animations.at(&animations, i);
565 anim->setDefaultTarget(defaultTarget);
566 }
567
568 actions << QQuickStateAction(drawer, QLatin1String("position"), to);
569 return actions;
570}
571
572bool QQuickDrawerPrivate::prepareEnterTransition()
573{
574 Q_Q(QQuickDrawer);
575 enterActions = prepareTransition(drawer: q, transition: enter, to: 1.0);
576 return QQuickPopupPrivate::prepareEnterTransition();
577}
578
579bool QQuickDrawerPrivate::prepareExitTransition()
580{
581 Q_Q(QQuickDrawer);
582 exitActions = prepareTransition(drawer: q, transition: exit, to: 0.0);
583 return QQuickPopupPrivate::prepareExitTransition();
584}
585
586bool QQuickDrawerPrivate::setEdge(Qt::Edge e)
587{
588 Q_Q(QQuickDrawer);
589 switch (e) {
590 case Qt::LeftEdge:
591 case Qt::RightEdge:
592 allowVerticalMove = true;
593 allowVerticalResize = true;
594 allowHorizontalMove = false;
595 allowHorizontalResize = false;
596 break;
597 case Qt::TopEdge:
598 case Qt::BottomEdge:
599 allowVerticalMove = false;
600 allowVerticalResize = false;
601 allowHorizontalMove = true;
602 allowHorizontalResize = true;
603 break;
604 default:
605 qmlWarning(me: q) << "invalid edge value - valid values are: "
606 << "Qt.TopEdge, Qt.LeftEdge, Qt.RightEdge, Qt.BottomEdge";
607 return false;
608 }
609
610 edge = e;
611 return true;
612}
613
614QQuickDrawer::QQuickDrawer(QObject *parent)
615 : QQuickPopup(*(new QQuickDrawerPrivate), parent)
616{
617 Q_D(QQuickDrawer);
618 d->dragMargin = QGuiApplication::styleHints()->startDragDistance();
619 d->setEdge(Qt::LeftEdge);
620
621 setFocus(true);
622 setModal(true);
623 setFiltersChildMouseEvents(true);
624 setClosePolicy(CloseOnEscape | CloseOnReleaseOutside);
625}
626
627/*!
628 \qmlproperty enumeration QtQuick.Controls::Drawer::edge
629
630 This property holds the edge of the window at which the drawer will
631 open from. The acceptable values are:
632
633 \value Qt.TopEdge The top edge of the window.
634 \value Qt.LeftEdge The left edge of the window (default).
635 \value Qt.RightEdge The right edge of the window.
636 \value Qt.BottomEdge The bottom edge of the window.
637*/
638Qt::Edge QQuickDrawer::edge() const
639{
640 Q_D(const QQuickDrawer);
641 return d->edge;
642}
643
644void QQuickDrawer::setEdge(Qt::Edge edge)
645{
646 Q_D(QQuickDrawer);
647 if (d->edge == edge)
648 return;
649
650 if (!d->setEdge(edge))
651 return;
652
653 if (isComponentComplete())
654 d->reposition();
655 emit edgeChanged();
656}
657
658/*!
659 \qmlproperty real QtQuick.Controls::Drawer::position
660
661 This property holds the position of the drawer relative to its final
662 destination. That is, the position will be \c 0.0 when the drawer
663 is fully closed, and \c 1.0 when fully open.
664*/
665qreal QQuickDrawer::position() const
666{
667 Q_D(const QQuickDrawer);
668 return d->position;
669}
670
671void QQuickDrawer::setPosition(qreal position)
672{
673 Q_D(QQuickDrawer);
674 position = qBound<qreal>(min: 0.0, val: position, max: 1.0);
675 if (qFuzzyCompare(p1: d->position, p2: position))
676 return;
677
678 d->position = position;
679 if (isComponentComplete())
680 d->reposition();
681 if (d->dimmer)
682 d->dimmer->setOpacity(position);
683 emit positionChanged();
684}
685
686/*!
687 \qmlproperty real QtQuick.Controls::Drawer::dragMargin
688
689 This property holds the distance from the screen edge within which
690 drag actions will open the drawer. Setting the value to \c 0 or less
691 prevents opening the drawer by dragging.
692
693 The default value is \c Qt.styleHints.startDragDistance.
694
695 \sa interactive
696*/
697qreal QQuickDrawer::dragMargin() const
698{
699 Q_D(const QQuickDrawer);
700 return d->dragMargin;
701}
702
703void QQuickDrawer::setDragMargin(qreal margin)
704{
705 Q_D(QQuickDrawer);
706 if (qFuzzyCompare(p1: d->dragMargin, p2: margin))
707 return;
708
709 d->dragMargin = margin;
710 emit dragMarginChanged();
711}
712
713void QQuickDrawer::resetDragMargin()
714{
715 setDragMargin(QGuiApplication::styleHints()->startDragDistance());
716}
717
718/*!
719 \since QtQuick.Controls 2.2 (Qt 5.9)
720 \qmlproperty bool QtQuick.Controls::Drawer::interactive
721
722 This property holds whether the drawer is interactive. A non-interactive
723 drawer does not react to swipes.
724
725 The default value is \c true.
726
727 \sa dragMargin
728*/
729bool QQuickDrawer::isInteractive() const
730{
731 Q_D(const QQuickDrawer);
732 return d->interactive;
733}
734
735void QQuickDrawer::setInteractive(bool interactive)
736{
737 Q_D(QQuickDrawer);
738 if (d->interactive == interactive)
739 return;
740
741 setFiltersChildMouseEvents(interactive);
742 d->interactive = interactive;
743 emit interactiveChanged();
744}
745
746bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event)
747{
748 Q_D(QQuickDrawer);
749 switch (event->type()) {
750#if QT_CONFIG(quicktemplates2_multitouch)
751 case QEvent::TouchUpdate:
752 return d->grabTouch(item: child, event: static_cast<QTouchEvent *>(event));
753 case QEvent::TouchBegin:
754 case QEvent::TouchEnd:
755 return d->handleTouchEvent(item: child, event: static_cast<QTouchEvent *>(event));
756#endif
757 case QEvent::MouseMove:
758 return d->grabMouse(item: child, event: static_cast<QMouseEvent *>(event));
759 case QEvent::MouseButtonPress:
760 case QEvent::MouseButtonRelease:
761 return d->handleMouseEvent(item: child, event: static_cast<QMouseEvent *>(event));
762 default:
763 break;
764 }
765 return false;
766}
767
768void QQuickDrawer::mouseMoveEvent(QMouseEvent *event)
769{
770 Q_D(QQuickDrawer);
771 d->grabMouse(item: d->popupItem, event);
772}
773
774bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event)
775{
776 Q_D(QQuickDrawer);
777 switch (event->type()) {
778#if QT_CONFIG(quicktemplates2_multitouch)
779 case QEvent::TouchUpdate:
780 return d->grabTouch(item, event: static_cast<QTouchEvent *>(event));
781#endif
782 case QEvent::MouseMove:
783 return d->grabMouse(item, event: static_cast<QMouseEvent *>(event));
784 default:
785 break;
786 }
787 return QQuickPopup::overlayEvent(item, event);
788}
789
790#if QT_CONFIG(quicktemplates2_multitouch)
791void QQuickDrawer::touchEvent(QTouchEvent *event)
792{
793 Q_D(QQuickDrawer);
794 d->grabTouch(item: d->popupItem, event);
795}
796#endif
797
798void QQuickDrawer::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
799{
800 Q_D(QQuickDrawer);
801 QQuickPopup::geometryChange(newGeometry, oldGeometry);
802 d->resizeOverlay();
803}
804
805QT_END_NAMESPACE
806
807#include "moc_qquickdrawer_p.cpp"
808

source code of qtdeclarative/src/quicktemplates/qquickdrawer.cpp