10#include <QtGui/qstylehints.h>
11#include <QtGui/private/qguiapplication_p.h>
12#include <QtQml/qqmlinfo.h>
13#include <QtQuick/private/qquickwindow_p.h>
14#include <QtQuick/private/qquickanimation_p.h>
15#include <QtQuick/private/qquicktransition_p.h>
16#include <QtQuickTemplates2/private/qquickoverlay_p.h>
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
145class QQuickDrawerPositioner :
public QQuickPopupPositioner
148 QQuickDrawerPositioner(QQuickDrawer *drawer) : QQuickPopupPositioner(drawer) { }
150 void reposition() override;
155 qreal offset = positionAt(point) - position;
158 if (offset > 0 && position > 0 && !contains(point))
166 Q_Q(
const QQuickDrawer);
167 QQuickWindow *window = q->window();
171 auto size = QSizeF(q->width(), q->height());
173 switch (effectiveEdge()) {
175 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
177 return point.y() / size.height();
179 if (edge == Qt::TopEdge || edge == Qt::BottomEdge)
181 return point.x() / size.width();
183 if (edge == Qt::TopEdge || edge == Qt::BottomEdge)
185 return (window->width() - point.x()) / size.width();
187 if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
189 return (window->height() - point.y()) / size.height();
199 positioner =
new QQuickDrawerPositioner(q);
203void QQuickDrawerPositioner::reposition()
208 QQuickDrawer *drawer =
static_cast<QQuickDrawer*>(popup());
212 QQuickOverlay *overlay = QQuickOverlay::overlay(drawer->window());
216 const qreal position = drawer->position();
217 QQuickItem *popupItem = drawer->popupItem();
218 switch (drawer->edge()) {
220 popupItem->setX((position - 1.0) * popupItem->width());
223 popupItem->setX(overlay->width() - position * popupItem->width());
226 popupItem->setY((position - 1.0) * popupItem->height());
229 popupItem->setY(overlay->height() - position * popupItem->height());
233 QQuickPopupPositioner::reposition();
248 if (!dimmer || !window)
251 const QQuickOverlay *overlay = QQuickOverlay::overlay(window);
253 QRectF geometry(0, 0, overlay ? overlay->width() : 0, overlay ? overlay->height() : 0);
255 if (edge == Qt::LeftEdge || edge == Qt::RightEdge) {
256 geometry.setY(popupItem->y());
257 geometry.setHeight(popupItem->height());
259 geometry.setX(popupItem->x());
260 geometry.setWidth(popupItem->width());
263 dimmer->setPosition(geometry.topLeft());
264 dimmer->setSize(geometry.size());
269 Q_Q(
const QQuickDrawer);
270 switch (effectiveEdge()) {
272 return pos.x() <= q->dragMargin();
274 return pos.x() >= q->window()->width() - q->dragMargin();
276 return pos.y() <= q->dragMargin();
278 return pos.y() >= q->window()->height() - q->dragMargin();
289 if (!window || !interactive || dragMargin < 0.0 || qFuzzyIsNull(dragMargin))
292 switch (event->type()) {
293 case QEvent::MouseButtonPress:
294 if (QMouseEvent *mouseEvent =
static_cast<QMouseEvent *>(event); isWithinDragMargin(mouseEvent->scenePosition())) {
297 delayedEnterTransition =
true;
298 mouseEvent->addPassiveGrabber(mouseEvent->point(0), popupItem);
299 handleMouseEvent(window->contentItem(), mouseEvent);
304#if QT_CONFIG(quicktemplates2_multitouch)
305 case QEvent::TouchBegin:
306 case QEvent::TouchUpdate: {
307 auto *touchEvent =
static_cast<QTouchEvent *>(event);
308 for (
const QTouchEvent::TouchPoint &point : touchEvent->points()) {
309 if (point.state() == QEventPoint::Pressed && isWithinDragMargin(point.scenePosition())) {
310 delayedEnterTransition =
true;
311 touchEvent->addPassiveGrabber(point, popupItem);
312 handleTouchEvent(window->contentItem(), touchEvent);
329 return item->keepMouseGrab() || item->keepTouchGrab();
335 handleMouseEvent(item, event);
337 if (!window || !interactive || keepGrab(popupItem) || keepGrab(item))
340 const QPointF movePoint = event->scenePosition();
345 const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
346 bool overThreshold =
false;
347 Qt::Edge effEdge = effectiveEdge();
348 if (position > 0 || dragMargin > 0) {
349 const bool xOverThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.x() - pressPoint.x(),
350 Qt::XAxis, event, threshold);
351 const bool yOverThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.y() - pressPoint.y(),
352 Qt::YAxis, event, threshold);
353 if (effEdge == Qt::LeftEdge || effEdge == Qt::RightEdge)
354 overThreshold = xOverThreshold && !yOverThreshold;
356 overThreshold = yOverThreshold && !xOverThreshold;
360 if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !contains(movePoint)) {
361 if (effEdge == Qt::LeftEdge || effEdge == Qt::RightEdge)
362 overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin;
364 overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
374 popupItem->grabMouse();
375 popupItem->setKeepMouseGrab(
true);
376 offset = offsetAt(movePoint);
379 return overThreshold;
382#if QT_CONFIG(quicktemplates2_multitouch)
383bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event)
386 bool handled = handleTouchEvent(item, event);
388 if (!window || !interactive || keepGrab(popupItem) || keepGrab(item) || !event->touchPointStates().testFlag(QEventPoint::Updated))
391 bool overThreshold =
false;
392 for (
const QTouchEvent::TouchPoint &point : event->points()) {
393 if (!acceptTouch(point) || point.state() != QEventPoint::Updated)
396 const QPointF movePoint = point.scenePosition();
401 const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
402 const Qt::Edge effEdge = effectiveEdge();
403 if (position > 0 || dragMargin > 0) {
404 const bool xOverThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.x() - pressPoint.x(),
405 Qt::XAxis, point, threshold);
406 const bool yOverThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.y() - pressPoint.y(),
407 Qt::YAxis, point, threshold);
408 if (effEdge == Qt::LeftEdge || effEdge == Qt::RightEdge)
409 overThreshold = xOverThreshold && !yOverThreshold;
411 overThreshold = yOverThreshold && !xOverThreshold;
415 if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !contains(movePoint)) {
416 if (effEdge == Qt::LeftEdge || effEdge == Qt::RightEdge)
417 overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin;
419 overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
423 if (delayedEnterTransition) {
424 prepareEnterTransition();
426 delayedEnterTransition =
false;
428 event->setExclusiveGrabber(point, popupItem);
429 popupItem->setKeepTouchGrab(
true);
430 offset = offsetAt(movePoint);
434 return overThreshold;
450 if (popupItem->keepMouseGrab() || popupItem->keepTouchGrab())
454 if (popupItem->isAncestorOf(item))
458 if (dimmer && !dimmer->contains(dimmer->mapFromScene(point)))
462 if (isWithinDragMargin(point))
472 velocityCalculator.startMeasuring(point, timestamp);
474 return QQuickPopupPrivate::handlePress(item, point, timestamp)
475 || (interactive && popupItem == item);
481 if (!QQuickPopupPrivate::handleMove(item, point, timestamp))
485 if (qFuzzyCompare(position, qreal(1.0)) && !contains(point))
488 bool isGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
490 q->setPosition(positionAt(point) - offset);
497 auto cleanup = qScopeGuard([
this] {
498 popupItem->setKeepMouseGrab(
false);
499 popupItem->setKeepTouchGrab(
false);
500 pressPoint = QPointF();
503 if (pressPoint.isNull())
505 if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) {
506 velocityCalculator.reset();
507 return QQuickPopupPrivate::handleRelease(item, point, timestamp);
510 velocityCalculator.stopMeasuring(point, timestamp);
511 Qt::Edge effEdge = effectiveEdge();
513 if (effEdge == Qt::LeftEdge || effEdge == Qt::RightEdge)
514 velocity = velocityCalculator.velocity().x();
516 velocity = velocityCalculator.velocity().y();
526 if (effEdge == Qt::RightEdge || effEdge == Qt::BottomEdge)
527 velocity = -velocity;
529 if (position > 0.7 || velocity > openCloseVelocityThreshold) {
530 transitionManager.transitionEnter();
531 }
else if (position < 0.3 || velocity < -openCloseVelocityThreshold) {
532 transitionManager.transitionExit();
536 if (point.x() - pressPoint.x() > 0)
537 transitionManager.transitionEnter();
539 transitionManager.transitionExit();
542 if (point.x() - pressPoint.x() < 0)
543 transitionManager.transitionEnter();
545 transitionManager.transitionExit();
548 if (point.y() - pressPoint.y() > 0)
549 transitionManager.transitionEnter();
551 transitionManager.transitionExit();
554 if (point.y() - pressPoint.y() < 0)
555 transitionManager.transitionEnter();
557 transitionManager.transitionExit();
563 return popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
568 QQuickPopupPrivate::handleUngrab();
570 velocityCalculator.reset();
575 QList<QQuickStateAction> actions;
576 if (!transition || !QQuickPopupPrivate::get(drawer)->window || !transition->enabled())
579 qmlExecuteDeferred(transition);
581 QQmlProperty defaultTarget(drawer, QLatin1String(
"position"));
582 QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
583 int count = animations.count(&animations);
584 for (
int i = 0; i < count; ++i) {
585 QQuickAbstractAnimation *anim = animations.at(&animations, i);
586 anim->setDefaultTarget(defaultTarget);
589 actions << QQuickStateAction(drawer, QLatin1String(
"position"), to);
596 enterActions = prepareTransition(q, enter, 1.0);
597 return QQuickPopupPrivate::prepareEnterTransition();
603 exitActions = prepareTransition(q, exit, 0.0);
604 return QQuickPopupPrivate::prepareExitTransition();
610 return QQuickPopup::Item;
619 allowVerticalMove =
true;
620 allowVerticalResize =
true;
621 allowHorizontalMove =
false;
622 allowHorizontalResize =
false;
626 allowVerticalMove =
false;
627 allowVerticalResize =
false;
628 allowHorizontalMove =
true;
629 allowHorizontalResize =
true;
632 qmlWarning(q) <<
"invalid edge value - valid values are: "
633 <<
"Qt.TopEdge, Qt.LeftEdge, Qt.RightEdge, Qt.BottomEdge";
641QQuickDrawer::QQuickDrawer(QObject *parent)
642 : QQuickPopup(*(
new QQuickDrawerPrivate), parent)
645 d->dragMargin = QGuiApplication::styleHints()->startDragDistance();
646 d->setEdge(Qt::LeftEdge);
651 QQuickItemPrivate::get(d->popupItem)->isTabFence = isModal();
652 connect(
this, &QQuickPopup::modalChanged,
this, [
this] {
653 QQuickItemPrivate::get(d_func()->popupItem)->isTabFence = isModal();
656 setFiltersChildMouseEvents(
true);
657 setClosePolicy(CloseOnEscape | CloseOnReleaseOutside);
661
662
663
664
665
666
667
668
669
670
671Qt::Edge QQuickDrawer::edge()
const
673 Q_D(
const QQuickDrawer);
679 auto realEdge = edge;
680 qreal rotation = window->contentItem()->rotation();
681 const bool clockwise = rotation > 0;
682 while (qAbs(rotation) >= 90) {
683 rotation -= clockwise ? 90 : -90;
686 realEdge = clockwise ? Qt::TopEdge : Qt::BottomEdge;
689 realEdge = clockwise ? Qt::RightEdge : Qt::LeftEdge;
692 realEdge = clockwise ? Qt::BottomEdge : Qt::TopEdge;
695 realEdge = clockwise ? Qt::LeftEdge : Qt::RightEdge;
702void QQuickDrawer::setEdge(Qt::Edge edge)
708 if (!d->setEdge(edge))
711 if (isComponentComplete())
717
718
719
720
721
722
723qreal QQuickDrawer::position()
const
725 Q_D(
const QQuickDrawer);
729void QQuickDrawer::setPosition(qreal position)
732 position = std::clamp(position, qreal(0.0), qreal(1.0));
733 if (qFuzzyCompare(d->position, position))
736 d->position = position;
737 if (isComponentComplete())
740 d->dimmer->setOpacity(position);
741 emit positionChanged();
745
746
747
748
749
750
751
752
753
754
755qreal QQuickDrawer::dragMargin()
const
757 Q_D(
const QQuickDrawer);
758 return d->dragMargin;
761void QQuickDrawer::setDragMargin(qreal margin)
764 if (qFuzzyCompare(d->dragMargin, margin))
767 d->dragMargin = margin;
768 emit dragMarginChanged();
771void QQuickDrawer::resetDragMargin()
773 setDragMargin(QGuiApplication::styleHints()->startDragDistance());
777
778
779
780
781
782
783
784
785
786
787bool QQuickDrawer::isInteractive()
const
789 Q_D(
const QQuickDrawer);
790 return d->interactive;
793void QQuickDrawer::setInteractive(
bool interactive)
796 if (d->interactive == interactive)
799 setFiltersChildMouseEvents(interactive);
800 d->interactive = interactive;
801 emit interactiveChanged();
804bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event)
807 switch (event->type()) {
808#if QT_CONFIG(quicktemplates2_multitouch)
809 case QEvent::TouchUpdate:
810 return d->grabTouch(child,
static_cast<QTouchEvent *>(event));
811 case QEvent::TouchBegin:
812 case QEvent::TouchEnd:
813 return d->handleTouchEvent(child,
static_cast<QTouchEvent *>(event));
815 case QEvent::MouseMove:
816 return d->grabMouse(child,
static_cast<QMouseEvent *>(event));
817 case QEvent::MouseButtonPress:
818 case QEvent::MouseButtonRelease:
819 return d->handleMouseEvent(child,
static_cast<QMouseEvent *>(event));
826void QQuickDrawer::mouseMoveEvent(QMouseEvent *event)
829 d->grabMouse(d->popupItem, event);
832bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event)
835 switch (event->type()) {
836#if QT_CONFIG(quicktemplates2_multitouch)
837 case QEvent::TouchUpdate:
838 return d->grabTouch(item,
static_cast<QTouchEvent *>(event));
840 case QEvent::MouseMove:
841 return d->grabMouse(item,
static_cast<QMouseEvent *>(event));
845 return QQuickPopup::overlayEvent(item, event);
848#if QT_CONFIG(quicktemplates2_multitouch)
849void QQuickDrawer::touchEvent(QTouchEvent *event)
852 d->grabTouch(d->popupItem, event);
856void QQuickDrawer::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
859 QQuickPopup::geometryChange(newGeometry, oldGeometry);
865#include "moc_qquickdrawer_p.cpp"
void showDimmer() override
void handleUngrab() override
bool prepareEnterTransition() override
bool delayedEnterTransition
void resizeDimmer() override
bool setEdge(Qt::Edge edge)
bool isWithinDragMargin(const QPointF &point) const
qreal positionAt(const QPointF &point) const
QQuickPopup::PopupType resolvedPopupType() const override
QQuickPopupPositioner * getPositioner() override
bool startDrag(QEvent *event)
Qt::Edge effectiveEdge() const
void hideDimmer() override
bool prepareExitTransition() override
static bool keepGrab(QQuickItem *item)
static QList< QQuickStateAction > prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to)
static const qreal openCloseVelocityThreshold