From bfff8c3fe1e2fd8db0b3dbd2a2a458d8927d103a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 9 Oct 2023 09:02:36 +0200 Subject: [PATCH] using gestures to open the drawer --- playground/drawer/main.cpp | 73 +----------------------- src/controls/QskDrawer.cpp | 66 +++++++++++++++++++++ src/controls/QskDrawer.h | 2 + src/controls/QskGestureRecognizer.cpp | 13 +++++ src/controls/QskGestureRecognizer.h | 7 ++- src/controls/QskPanGestureRecognizer.cpp | 20 ++++--- src/controls/QskPanGestureRecognizer.h | 3 +- src/controls/QskSkinManager.cpp | 2 +- 8 files changed, 104 insertions(+), 82 deletions(-) diff --git a/playground/drawer/main.cpp b/playground/drawer/main.cpp index 76717669..be688b60 100644 --- a/playground/drawer/main.cpp +++ b/playground/drawer/main.cpp @@ -17,32 +17,6 @@ namespace { - inline qreal distanceToEdge( - const QRectF& rect, const QPointF& pos, int edge ) - { - qreal dt = 10e6; - switch( edge ) - { - case Qt::TopEdge: - dt = pos.y() - rect.top(); - break; - - case Qt::BottomEdge: - dt = rect.bottom() - pos.y(); - break; - - case Qt::LeftEdge: - dt = pos.x() - rect.left(); - break; - - case Qt::RightEdge: - dt = rect.right() - pos.x(); - break; - } - - return std::abs( dt ); - } - class Drawer : public QskDrawer { public: @@ -50,7 +24,7 @@ namespace : QskDrawer( parent ) { #if 1 - setAnimationHint( Panel | QskAspect::Position, 2000 ); + setAnimationHint( Panel | QskAspect::Position, 1000 ); #endif setEdge( edge ); @@ -101,51 +75,6 @@ namespace const auto edge = static_cast< Qt::Edge >( 1 << i ); m_drawers[i] = new Drawer( edge, this ); } - - setAcceptedMouseButtons( Qt::LeftButton ); - } - - protected: - virtual bool contains( const QPointF& pos ) const - { - if ( auto control = qskControlCast( parentItem() ) ) - { - // we want to catch clicks on the margins of the parent - - auto r = rect(); - if ( !r.contains( pos ) ) - { - r = r.marginsAdded( control->margins() ); - return r.contains( pos ); - } - - return false; - } - - return QskControl::contains( pos ); - } - - void mousePressEvent( QMouseEvent* event ) override - { - const auto pos = qskMousePosition( event ); - - int drawerIndex = -1; - qreal minDist = 10e6; - - for ( int i = 0; i < 4; i++ ) - { - const auto edge = static_cast< Qt::Edge >( 1 << i ); - const auto dist = distanceToEdge( rect(), pos, edge ); - - if ( dist < minDist ) - { - minDist = dist; - drawerIndex = i; - } - } - - if ( drawerIndex >= 0 ) - m_drawers[drawerIndex]->open(); } private: diff --git a/src/controls/QskDrawer.cpp b/src/controls/QskDrawer.cpp index 9ebe6045..01db4c3e 100644 --- a/src/controls/QskDrawer.cpp +++ b/src/controls/QskDrawer.cpp @@ -7,6 +7,10 @@ #include "QskAspect.h" #include "QskAnimationHint.h" #include "QskQuick.h" +#include "QskEvent.h" + +#include "QskPanGestureRecognizer.h" +#include "QskGesture.h" QSK_QT_PRIVATE_BEGIN #include @@ -77,6 +81,49 @@ namespace private: QskDrawer* m_drawer = nullptr; }; + + class GestureRecognizer : public QskPanGestureRecognizer + { + using Inherited = QskPanGestureRecognizer; + + public: + GestureRecognizer( QskDrawer* drawer ) + : QskPanGestureRecognizer( drawer ) + { + setWatchedItem( drawer->parentItem() ); + setTargetItem( drawer ); + } + + protected: + QRectF gestureRect() const override + { + auto drawer = qobject_cast< QskDrawer* >( parent() ); + + const auto dist = 50; + auto rect = qskItemRect( watchedItem() ); + + switch( drawer->edge() ) + { + case Qt::LeftEdge: + rect.setRight( rect.left() + dist ); + break; + + case Qt::RightEdge: + rect.setLeft( rect.right() - dist ); + break; + + case Qt::TopEdge: + rect.setBottom( rect.top() + dist ); + break; + + case Qt::BottomEdge: + rect.setTop( rect.bottom() - dist ); + break; + } + + return rect; + } + }; } class QskDrawer::PrivateData @@ -108,6 +155,11 @@ QskDrawer::QskDrawer( QQuickItem* parentItem ) setPlacementPolicy( QskPlacementPolicy::Ignore ); if ( parentItem ) m_data->listener = new GeometryListener( this ); + + (void) new GestureRecognizer( this ); +#if 1 + parentItem->setAcceptedMouseButtons( Qt::LeftButton ); +#endif } QskDrawer::~QskDrawer() @@ -130,6 +182,20 @@ void QskDrawer::setEdge( Qt::Edge edge ) edgeChanged( edge ); } +void QskDrawer::gestureEvent( QskGestureEvent* event ) +{ + if ( event->gesture()->type() == QskGesture::Pan ) + { + const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() ); + if ( gesture->state() == QskGesture::Finished ) + open(); + + return; + } + + Inherited::gestureEvent( event ); +} + QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const { return Inherited::layoutRectForSize( size ); diff --git a/src/controls/QskDrawer.h b/src/controls/QskDrawer.h index b5b26447..ad1ef93f 100644 --- a/src/controls/QskDrawer.h +++ b/src/controls/QskDrawer.h @@ -36,6 +36,8 @@ class QSK_EXPORT QskDrawer : public QskPopup void aboutToShow() override; void itemChange( ItemChange, const ItemChangeData& ) override; + void gestureEvent( QskGestureEvent* ) override; + private: void startFading( bool ); diff --git a/src/controls/QskGestureRecognizer.cpp b/src/controls/QskGestureRecognizer.cpp index 07a44f2d..bac4df8c 100644 --- a/src/controls/QskGestureRecognizer.cpp +++ b/src/controls/QskGestureRecognizer.cpp @@ -69,6 +69,9 @@ class QskGestureRecognizer::PrivateData } QQuickItem* watchedItem = nullptr; +#if 1 + QQuickItem* targetItem = nullptr; // QPointer ??? +#endif QVector< QMouseEvent* > pendingEvents; @@ -121,6 +124,16 @@ QQuickItem* QskGestureRecognizer::watchedItem() const return m_data->watchedItem; } +void QskGestureRecognizer::setTargetItem( QQuickItem* item ) +{ + m_data->targetItem = item; +} + +QQuickItem* QskGestureRecognizer::targetItem() const +{ + return m_data->targetItem; +} + void QskGestureRecognizer::setAcceptedMouseButtons( Qt::MouseButtons buttons ) { m_data->buttons = buttons; diff --git a/src/controls/QskGestureRecognizer.h b/src/controls/QskGestureRecognizer.h index 012aa839..b34cd012 100644 --- a/src/controls/QskGestureRecognizer.h +++ b/src/controls/QskGestureRecognizer.h @@ -43,11 +43,16 @@ class QSK_EXPORT QskGestureRecognizer : public QObject QskGestureRecognizer( QObject* parent = nullptr ); ~QskGestureRecognizer() override; - bool eventFilter( QObject* object, QEvent* event) override; + bool eventFilter( QObject*, QEvent* ) override; + // the item where the gesture happens void setWatchedItem( QQuickItem* ); QQuickItem* watchedItem() const; + // the item processing the gesture events + void setTargetItem( QQuickItem* ); + QQuickItem* targetItem() const; + // Qt::NoButton means: all buttons accepted void setAcceptedMouseButtons( Qt::MouseButtons ); Qt::MouseButtons acceptedMouseButtons() const; diff --git a/src/controls/QskPanGestureRecognizer.cpp b/src/controls/QskPanGestureRecognizer.cpp index f7db9f5a..859b8d91 100644 --- a/src/controls/QskPanGestureRecognizer.cpp +++ b/src/controls/QskPanGestureRecognizer.cpp @@ -7,10 +7,11 @@ #include "QskEvent.h" #include "QskGesture.h" -#include #include #include #include +#include +#include static inline bool qskIsInOrientation( const QPointF& from, const QPointF& to, Qt::Orientations orientations ) @@ -60,9 +61,14 @@ static inline qreal qskAngle( } static void qskSendPanGestureEvent( - QQuickItem* item, QskGesture::State state, qreal velocity, qreal angle, - const QPointF& origin, const QPointF& lastPosition, const QPointF& position ) + QskGestureRecognizer* recognizer, QskGesture::State state, + qreal velocity, qreal angle, const QPointF& origin, + const QPointF& lastPosition, const QPointF& position ) { + auto item = recognizer->targetItem(); + if ( item == nullptr ) + item = recognizer->watchedItem(); + auto gesture = std::make_shared< QskPanGesture >(); gesture->setState( state ); @@ -146,7 +152,7 @@ class QskPanGestureRecognizer::PrivateData public: Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical; - int minDistance = 15; + int minDistance = QGuiApplication::styleHints()->startDragDistance() + 5; quint64 timestampVelocity = 0.0; // timestamp of the last mouse event qreal angle = 0.0; @@ -243,12 +249,12 @@ void QskPanGestureRecognizer::processMove( const QPointF& pos, quint64 timestamp if ( started ) { - qskSendPanGestureEvent( watchedItem(), QskGesture::Started, + qskSendPanGestureEvent( this, QskGesture::Started, velocity, m_data->angle, m_data->origin, m_data->origin, m_data->pos ); } else { - qskSendPanGestureEvent( watchedItem(), QskGesture::Updated, + qskSendPanGestureEvent( this, QskGesture::Updated, velocity, m_data->angle, m_data->origin, oldPos, m_data->pos ); } } @@ -261,7 +267,7 @@ void QskPanGestureRecognizer::processRelease( const QPointF&, quint64 timestamp const ulong elapsedTotal = timestamp - timestampStarted(); const qreal velocity = m_data->velocityTracker.velocity( elapsedTotal ); - qskSendPanGestureEvent( watchedItem(), QskGesture::Finished, + qskSendPanGestureEvent( this, QskGesture::Finished, velocity, m_data->angle, m_data->origin, m_data->pos, m_data->pos ); } } diff --git a/src/controls/QskPanGestureRecognizer.h b/src/controls/QskPanGestureRecognizer.h index 26a72576..ba3bb121 100644 --- a/src/controls/QskPanGestureRecognizer.h +++ b/src/controls/QskPanGestureRecognizer.h @@ -23,11 +23,12 @@ class QSK_EXPORT QskPanGestureRecognizer : public QskGestureRecognizer void setOrientations( Qt::Orientations ); Qt::Orientations orientations() const; - private: + protected: void processPress( const QPointF&, quint64 timestamp, bool isFinal ) override; void processMove( const QPointF&, quint64 timestamp ) override; void processRelease( const QPointF&, quint64 timestamp ) override; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/controls/QskSkinManager.cpp b/src/controls/QskSkinManager.cpp index 218d2747..33864821 100644 --- a/src/controls/QskSkinManager.cpp +++ b/src/controls/QskSkinManager.cpp @@ -121,7 +121,7 @@ namespace scheme = Qt::ColorScheme::Unknown; } - const auto systemScheme = qGuiApp->styleHints()->colorScheme(); + const auto systemScheme = QGuiApplication::styleHints()->colorScheme(); if( scheme == systemScheme ) {