From 078d21d9c46f72dc7c1c6f62d327728e32461026 Mon Sep 17 00:00:00 2001 From: askmeaboutloom Date: Sat, 28 Sep 2024 01:03:02 +0200 Subject: [PATCH] WIP: touch and hold --- src/desktop/dialogs/settingsdialog/touch.cpp | 22 +++++ src/desktop/dialogs/settingsdialog/touch.h | 3 + src/desktop/scene/canvasview.cpp | 16 ++++ src/desktop/scene/canvasview.h | 2 + src/desktop/settings.h | 6 ++ src/desktop/settings_table.h | 1 + src/desktop/utils/touchhandler.cpp | 97 ++++++++++++++++---- src/desktop/utils/touchhandler.h | 11 +++ src/desktop/view/canvascontroller.cpp | 16 ++++ src/desktop/view/canvascontroller.h | 2 + 10 files changed, 160 insertions(+), 16 deletions(-) diff --git a/src/desktop/dialogs/settingsdialog/touch.cpp b/src/desktop/dialogs/settingsdialog/touch.cpp index c5e143bbd..5d40175c3 100644 --- a/src/desktop/dialogs/settingsdialog/touch.cpp +++ b/src/desktop/dialogs/settingsdialog/touch.cpp @@ -24,6 +24,8 @@ void Touch::setUp(desktop::settings::Settings &settings, QVBoxLayout *layout) initTouchActions(settings, utils::addFormSection(layout)); utils::addFormSeparator(layout); initTapActions(settings, utils::addFormSection(layout)); + utils::addFormSeparator(layout); + initTapAndHoldActions(settings, utils::addFormSection(layout)); } void Touch::initMode(desktop::settings::Settings &settings, QFormLayout *form) @@ -82,6 +84,26 @@ void Touch::initTapActions( form->addRow(tr("Four-finger tap:"), fourFingerTap); } +void Touch::initTapAndHoldActions( + desktop::settings::Settings &settings, QFormLayout *form) +{ + QComboBox *oneFingerTapAndHold = new QComboBox; + for(QComboBox *tapAndHold : {oneFingerTapAndHold}) { + tapAndHold->addItem( + tr("No action"), + int(desktop::settings::TouchTapAndHoldAction::Nothing)); + tapAndHold->addItem( + tr("Pick color"), + int(desktop::settings::TouchTapAndHoldAction::ColorPickMode)); + } + + settings.bindOneFingerTapAndHold(oneFingerTapAndHold, Qt::UserRole); + + settings.bindTouchGestures(oneFingerTapAndHold, &QComboBox::setDisabled); + + form->addRow(tr("One-finger tap and hold:"), oneFingerTapAndHold); +} + void Touch::initTouchActions( desktop::settings::Settings &settings, QFormLayout *form) { diff --git a/src/desktop/dialogs/settingsdialog/touch.h b/src/desktop/dialogs/settingsdialog/touch.h index a4a4492d8..4d70d2c98 100644 --- a/src/desktop/dialogs/settingsdialog/touch.h +++ b/src/desktop/dialogs/settingsdialog/touch.h @@ -29,6 +29,9 @@ class Touch final : public Page { void initTapActions(desktop::settings::Settings &settings, QFormLayout *form); + void initTapAndHoldActions( + desktop::settings::Settings &settings, QFormLayout *form); + void initTouchActions(desktop::settings::Settings &settings, QFormLayout *form); }; diff --git a/src/desktop/scene/canvasview.cpp b/src/desktop/scene/canvasview.cpp index a413f51fb..8d0921f01 100644 --- a/src/desktop/scene/canvasview.cpp +++ b/src/desktop/scene/canvasview.cpp @@ -178,6 +178,12 @@ CanvasView::CanvasView(QWidget *parent) connect( m_touch, &TouchHandler::touchTapActionActivated, this, &CanvasView::touchTapActionActivated, Qt::DirectConnection); + connect( + m_touch, &TouchHandler::touchColorPicked, this, + &CanvasView::touchColorPick, Qt::DirectConnection); + connect( + m_touch, &TouchHandler::touchColorPickFinished, this, + &CanvasView::finishTouchColorPick, Qt::DirectConnection); } @@ -2075,6 +2081,16 @@ void CanvasView::pickColor(const QPointF &point) m_pickingColor = m_scene->setColorPick(color); } +void CanvasView::touchColorPick(const QPointF &posf) +{ + pickColor(mapToCanvas(posf)); +} + +void CanvasView::finishTouchColorPick() +{ + m_scene->setColorPick(QColor()); +} + void CanvasView::updateCanvasTransform(const std::function &block) { QPointF outlinePoint = fromCanvasTransform().map(m_prevoutlinepoint); diff --git a/src/desktop/scene/canvasview.h b/src/desktop/scene/canvasview.h index 733bde6a8..bcfc9d90b 100644 --- a/src/desktop/scene/canvasview.h +++ b/src/desktop/scene/canvasview.h @@ -293,6 +293,8 @@ private slots: //! Drag the view void moveDrag(const QPoint &point); void pickColor(const QPointF &point); + void touchColorPick(const QPointF &posf); + void finishTouchColorPick(); QTransform fromCanvasTransform() const; QTransform toCanvasTransform() const; diff --git a/src/desktop/settings.h b/src/desktop/settings.h index e97f4c0f5..6ecc0c64a 100644 --- a/src/desktop/settings.h +++ b/src/desktop/settings.h @@ -85,6 +85,12 @@ enum class TouchTapAction : int { }; Q_ENUM_NS(TouchTapAction) +enum class TouchTapAndHoldAction : int { + Nothing, + ColorPickMode, +}; +Q_ENUM_NS(TouchTapAndHoldAction) + enum class ThemePalette : int { System, Light, diff --git a/src/desktop/settings_table.h b/src/desktop/settings_table.h index a16f9e9e3..63e352ce8 100644 --- a/src/desktop/settings_table.h +++ b/src/desktop/settings_table.h @@ -189,6 +189,7 @@ SETTING(oneFingerTap , OneFingerTap , "settings/input/ SETTING(twoFingerTap , TwoFingerTap , "settings/input/twofingertap" , int(TouchTapAction::Undo)) SETTING(threeFingerTap , ThreeFingerTap , "settings/input/threefingertap" , int(TouchTapAction::Redo)) SETTING(fourFingerTap , FourFingerTap , "settings/input/fourfingertap" , int(TouchTapAction::HideDocks)) +SETTING(oneFingerTapAndHold , OneFingerTapAndHold , "settings/input/onefingertapandhold" , int(TouchTapAndHoldAction::ColorPickMode)) SETTING(tabletPressTimerDelay , TabletPressTimerDelay , "settings/input/tabletpresstimerdelay" , 500) SETTING(touchGestures , TouchGestures , "settings/input/touchgestures" , false) SETTING(onionSkinsFrameCount , OnionSkinsFrameCount , "onionskins/framecount" , 8) diff --git a/src/desktop/utils/touchhandler.cpp b/src/desktop/utils/touchhandler.cpp index 8ea7b5840..c6f7e0de4 100644 --- a/src/desktop/utils/touchhandler.cpp +++ b/src/desktop/utils/touchhandler.cpp @@ -8,6 +8,7 @@ extern "C" { #include "libshared/util/qtcompat.h" #include #include +#include TouchHandler::TouchHandler(QObject *parent) : QObject(parent) @@ -19,8 +20,18 @@ TouchHandler::TouchHandler(QObject *parent) , m_twoFingerTapAction(int(desktop::settings::TouchTapAction::Undo)) , m_threeFingerTapAction(int(desktop::settings::TouchTapAction::Redo)) , m_fourFingerTapAction(int(desktop::settings::TouchTapAction::HideDocks)) + , m_oneFingerTapAndHoldAction( + int(desktop::settings::TouchTapAndHoldAction::ColorPickMode)) , m_tapTimer(Qt::CoarseTimer) + , m_tapAndHoldTimer(new QTimer(this)) { + m_tapAndHoldTimer->setTimerType(Qt::CoarseTimer); + m_tapAndHoldTimer->setSingleShot(true); + m_tapAndHoldTimer->setInterval(TAP_AND_HOLD_DELAY_MS); + connect( + m_tapAndHoldTimer, &QTimer::timeout, this, + &TouchHandler::triggerTapAndHold); + desktop::settings::Settings &settings = dpApp().settings(); settings.bindOneFingerTouch(this, &TouchHandler::setOneFingerTouchAction); settings.bindTwoFingerPinch(this, &TouchHandler::setTwoFingerPinchAction); @@ -29,6 +40,8 @@ TouchHandler::TouchHandler(QObject *parent) settings.bindTwoFingerTap(this, &TouchHandler::setTwoFingerTapAction); settings.bindThreeFingerTap(this, &TouchHandler::setThreeFingerTapAction); settings.bindFourFingerTap(this, &TouchHandler::setFourFingerTapAction); + settings.bindOneFingerTapAndHold( + this, &TouchHandler::setOneFingerTapAndHoldAction); } bool TouchHandler::isTouchDrawEnabled() const @@ -93,6 +106,7 @@ void TouchHandler::handleTouchBegin(QTouchEvent *event) m_touchDrawBuffer.clear(); m_touchDragging = false; m_touchRotating = false; + m_touchHeld = false; m_maxTouchPoints = pointsCount; m_tapTimer.setRemainingTime(TAP_MAX_DELAY_MS); if(isTouchDrawEnabled() && pointsCount == 1 && !compat::isTouchPad(event)) { @@ -105,7 +119,9 @@ void TouchHandler::handleTouchBegin(QTouchEvent *event) qulonglong(event->timestamp())); if(isTouchPanEnabled() || isTouchPinchOrTwistEnabled() || m_oneFingerTapAction != - int(desktop::settings::TouchTapAction::Nothing)) { + int(desktop::settings::TouchTapAction::Nothing) || + m_oneFingerTapAndHoldAction != + int(desktop::settings::TouchTapAndHoldAction::Nothing)) { // Buffer the touch first, since it might end up being the // beginning of an action that involves multiple fingers. m_touchDrawBuffer.append( @@ -127,6 +143,14 @@ void TouchHandler::handleTouchBegin(QTouchEvent *event) qulonglong(event->timestamp())); m_touchMode = TouchMode::Moving; } + + if(pointsCount == 1 && m_touchMode != TouchMode::Drawing && + m_oneFingerTapAndHoldAction != + int(desktop::settings::TouchTapAndHoldAction::Nothing)) { + m_tapAndHoldTimer->start(); + } else { + m_tapAndHoldTimer->stop(); + } } void TouchHandler::handleTouchUpdate( @@ -138,10 +162,23 @@ void TouchHandler::handleTouchUpdate( m_maxTouchPoints = pointsCount; } - if(isTouchDrawEnabled() && - ((pointsCount == 1 && m_touchMode == TouchMode::Unknown) || - m_touchMode == TouchMode::Drawing) && - !compat::isTouchPad(event)) { + if(pointsCount != 1) { + m_tapAndHoldTimer->stop(); + } + + m_touchPos = QPointF(0.0, 0.0); + for(const compat::TouchPoint &tp : compat::touchPoints(*event)) { + m_touchPos += compat::touchPos(tp); + } + m_touchPos /= pointsCount; + + if(m_touchHeld) { + emit touchColorPicked(m_touchPos); + } else if( + isTouchDrawEnabled() && + ((pointsCount == 1 && m_touchMode == TouchMode::Unknown) || + m_touchMode == TouchMode::Drawing) && + !compat::isTouchPad(event)) { QPointF posf = compat::touchPos(compat::touchPoints(*event).first()); DP_EVENT_LOG( "touch_draw_update x=%f y=%f touching=%d type=%d device=%s " @@ -155,6 +192,7 @@ void TouchHandler::handleTouchUpdate( if(m_touchMode == TouchMode::Drawing) { emit touchMoved(QDateTime::currentMSecsSinceEpoch(), posf); } else { // Shouldn't happen, but we'll deal with it anyway. + m_tapAndHoldTimer->stop(); m_touchMode = TouchMode::Drawing; emit touchPressed( event, QDateTime::currentMSecsSinceEpoch(), posf); @@ -172,6 +210,7 @@ void TouchHandler::handleTouchUpdate( m_touchDrawBuffer.append( {QDateTime::currentMSecsSinceEpoch(), posf}); } else { + m_tapAndHoldTimer->stop(); m_touchMode = TouchMode::Drawing; flushTouchDrawBuffer(); emit touchMoved(QDateTime::currentMSecsSinceEpoch(), posf); @@ -180,17 +219,15 @@ void TouchHandler::handleTouchUpdate( } else { m_touchMode = TouchMode::Moving; - QPointF startCenter, lastCenter, center; + QPointF startCenter, lastCenter; for(const compat::TouchPoint &tp : compat::touchPoints(*event)) { QPointF startPos = compat::touchStartPos(tp); startCenter += startPos; lastCenter += compat::touchLastPos(tp); - QPointF pos = compat::touchPos(tp); - center += pos; // This might be a tap gesture. Don't start a drag until there's // been sufficient movement on any of the fingers. if(!m_touchDragging && - squareDist(startPos - pos) > TAP_SLOP_SQUARED) { + squareDist(startPos - compat::touchPos(tp)) > TAP_SLOP_SQUARED) { m_touchDragging = true; } } @@ -206,9 +243,10 @@ void TouchHandler::handleTouchUpdate( } } + m_tapAndHoldTimer->stop(); startCenter /= pointsCount; lastCenter /= pointsCount; - center /= pointsCount; + QPointF center = m_touchPos; DP_EVENT_LOG( "touch_update x=%f y=%f touching=%d type=%d device=%s " @@ -294,12 +332,16 @@ void TouchHandler::handleTouchEnd(QTouchEvent *event, bool cancel) { event->accept(); const QList &points = compat::touchPoints(*event); - if(isTouchDrawEnabled() && - ((m_touchMode == TouchMode::Unknown && !m_touchDrawBuffer.isEmpty() && - (m_touchDragging || - m_oneFingerTapAction == - int(desktop::settings::TouchTapAction::Nothing))) || - m_touchMode == TouchMode::Drawing)) { + m_tapAndHoldTimer->stop(); + if(m_touchHeld) { + emit touchColorPickFinished(); + } else if( + isTouchDrawEnabled() && + ((m_touchMode == TouchMode::Unknown && !m_touchDrawBuffer.isEmpty() && + (m_touchDragging || + m_oneFingerTapAction == + int(desktop::settings::TouchTapAction::Nothing))) || + m_touchMode == TouchMode::Drawing)) { DP_EVENT_LOG( "touch_draw_%s touching=%d type=%d device=%s points=%s " "timestamp=%llu", @@ -474,6 +516,29 @@ void TouchHandler::setFourFingerTapAction(int fourFingerTapAction) m_fourFingerTapAction = fourFingerTapAction; } +void TouchHandler::setOneFingerTapAndHoldAction(int oneFingerTapAndHoldAction) +{ + m_oneFingerTapAndHoldAction = oneFingerTapAndHoldAction; +} + +void TouchHandler::triggerTapAndHold() +{ + m_tapAndHoldTimer->stop(); + if(m_maxTouchPoints == 1 && m_touchMode != TouchMode::Drawing) { + switch(m_oneFingerTapAndHoldAction) { + case int(desktop::settings::TouchTapAndHoldAction::ColorPickMode): + m_touchHeld = true; + emit touchColorPicked(m_touchPos); + break; + default: + qWarning( + "Unknown one finger tap and hold action %d", + m_oneFingerTapAndHoldAction); + break; + } + } +} + qreal TouchHandler::adjustTwistRotation(qreal degrees) const { if(m_twoFingerTwistAction == diff --git a/src/desktop/utils/touchhandler.h b/src/desktop/utils/touchhandler.h index 95bc59daf..c0a097363 100644 --- a/src/desktop/utils/touchhandler.h +++ b/src/desktop/utils/touchhandler.h @@ -6,6 +6,7 @@ #include class QGestureEvent; +class QTimer; class QTouchEvent; class TouchHandler : public QObject { @@ -38,10 +39,13 @@ class TouchHandler : public QObject { void touchScrolledBy(qreal dx, qreal dy); void touchZoomedRotated(qreal zoom, qreal rotation); void touchTapActionActivated(int action); + void touchColorPicked(const QPointF &posf); + void touchColorPickFinished(); private: static constexpr qreal TAP_SLOP_SQUARED = 16.0 * 16.0; static constexpr int TAP_MAX_DELAY_MS = 1000; + static constexpr int TAP_AND_HOLD_DELAY_MS = 500; static constexpr int DRAW_BUFFER_COUNT = 20; enum class TouchMode { Unknown, Drawing, Moving }; @@ -58,6 +62,9 @@ class TouchHandler : public QObject { void setTwoFingerTapAction(int twoFingerTapAction); void setThreeFingerTapAction(int threeFingerTapAction); void setFourFingerTapAction(int fourFingerTapAction); + void setOneFingerTapAndHoldAction(int oneFingerTapAndHoldAction); + + void triggerTapAndHold(); qreal adjustTwistRotation(qreal degrees) const; void flushTouchDrawBuffer(); @@ -66,6 +73,7 @@ class TouchHandler : public QObject { bool m_touching = false; bool m_touchDragging = false; bool m_touchRotating = false; + bool m_touchHeld = false; bool m_anyTabletEventsReceived = false; int m_oneFingerTouchAction; int m_twoFingerPinchAction; @@ -74,16 +82,19 @@ class TouchHandler : public QObject { int m_twoFingerTapAction; int m_threeFingerTapAction; int m_fourFingerTapAction; + int m_oneFingerTapAndHoldAction; int m_maxTouchPoints = 0; TouchMode m_touchMode = TouchMode::Unknown; QVector> m_touchDrawBuffer; QPointF m_touchStartPos; qreal m_touchStartZoom = 0.0; qreal m_touchStartRotate = 0.0; + QPointF m_touchPos; QPointF m_gestureStartPos; qreal m_gestureStartZoom = 0.0; qreal m_gestureStartRotation = 0.0; QDeadlineTimer m_tapTimer; + QTimer *m_tapAndHoldTimer; }; #endif diff --git a/src/desktop/view/canvascontroller.cpp b/src/desktop/view/canvascontroller.cpp index a3ea44c55..4d871ba5d 100644 --- a/src/desktop/view/canvascontroller.cpp +++ b/src/desktop/view/canvascontroller.cpp @@ -90,6 +90,12 @@ CanvasController::CanvasController(CanvasScene *scene, QWidget *parent) connect( m_touch, &TouchHandler::touchTapActionActivated, this, &CanvasController::touchTapActionActivated, Qt::DirectConnection); + connect( + m_touch, &TouchHandler::touchColorPicked, this, + &CanvasController::touchColorPick, Qt::DirectConnection); + connect( + m_touch, &TouchHandler::touchColorPickFinished, this, + &CanvasController::finishTouchColorPick, Qt::DirectConnection); resetCanvasTransform(); } @@ -1552,6 +1558,16 @@ void CanvasController::pickColor(const QPointF &point) m_pickingColor = m_scene->setColorPick(color); } +void CanvasController::touchColorPick(const QPointF &posf) +{ + pickColor(mapPointToCanvasF(posf)); +} + +void CanvasController::finishTouchColorPick() +{ + m_scene->setColorPick(QColor()); +} + void CanvasController::resetCursor() { if(m_dragMode != ViewDragMode::None) { diff --git a/src/desktop/view/canvascontroller.h b/src/desktop/view/canvascontroller.h index e69699a43..3ea44b200 100644 --- a/src/desktop/view/canvascontroller.h +++ b/src/desktop/view/canvascontroller.h @@ -233,6 +233,8 @@ class CanvasController : public QObject { void moveDrag(const QPoint &point); void pickColor(const QPointF &point); + void touchColorPick(const QPointF &posf); + void finishTouchColorPick(); void resetCursor(); void updateOutlinePos(QPointF point);