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

source code of qtquickcontrols2/src/quicktemplates2/qquickdrawer.cpp