Skip to content

Commit

Permalink
WIP: touch and hold
Browse files Browse the repository at this point in the history
  • Loading branch information
askmeaboutlo0m committed Sep 27, 2024
1 parent 94f59ae commit 078d21d
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 16 deletions.
22 changes: 22 additions & 0 deletions src/desktop/dialogs/settingsdialog/touch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions src/desktop/dialogs/settingsdialog/touch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down
16 changes: 16 additions & 0 deletions src/desktop/scene/canvasview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down Expand Up @@ -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<void()> &block)
{
QPointF outlinePoint = fromCanvasTransform().map(m_prevoutlinepoint);
Expand Down
2 changes: 2 additions & 0 deletions src/desktop/scene/canvasview.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/desktop/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/desktop/settings_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
97 changes: 81 additions & 16 deletions src/desktop/utils/touchhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern "C" {
#include "libshared/util/qtcompat.h"
#include <QDateTime>
#include <QGestureEvent>
#include <QTimer>

TouchHandler::TouchHandler(QObject *parent)
: QObject(parent)
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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)) {
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -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 "
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
}
}
Expand All @@ -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 "
Expand Down Expand Up @@ -294,12 +332,16 @@ void TouchHandler::handleTouchEnd(QTouchEvent *event, bool cancel)
{
event->accept();
const QList<compat::TouchPoint> &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",
Expand Down Expand Up @@ -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 ==
Expand Down
11 changes: 11 additions & 0 deletions src/desktop/utils/touchhandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <QPointF>

class QGestureEvent;
class QTimer;
class QTouchEvent;

class TouchHandler : public QObject {
Expand Down Expand Up @@ -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 };
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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<QPair<long long, QPointF>> 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
16 changes: 16 additions & 0 deletions src/desktop/view/canvascontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit 078d21d

Please sign in to comment.