Add new gestures and improve naming clarity in gesture.h

I've added VerticalAxis, HorizontalAxis, DirectionlessSwipe and BiDirectionalPinch gestures directions.
These are all combinations of other gesture directions that semantically work well together.
I've implemented these gestures as well as changed some labels and improved documentation,

Also,
Add vector signal to SwipeGesture
This commit is contained in:
Eric Edlund 2022-07-26 12:32:23 -04:00
parent 634182d489
commit bc15b72e3d
7 changed files with 225 additions and 75 deletions

View file

@ -343,11 +343,11 @@ void GestureTest::testNotEmitCallbacksBeforeDirectionDecided()
recognizer.registerPinchGesture(&expand); recognizer.registerPinchGesture(&expand);
recognizer.registerPinchGesture(&contract); recognizer.registerPinchGesture(&contract);
QSignalSpy upSpy(&up, &SwipeGesture::progress); QSignalSpy upSpy(&up, &SwipeGesture::triggerProgress);
QSignalSpy downSpy(&down, &SwipeGesture::progress); QSignalSpy downSpy(&down, &SwipeGesture::triggerProgress);
QSignalSpy rightSpy(&right, &SwipeGesture::progress); QSignalSpy rightSpy(&right, &SwipeGesture::triggerProgress);
QSignalSpy expandSpy(&expand, &PinchGesture::progress); QSignalSpy expandSpy(&expand, &PinchGesture::triggerProgress);
QSignalSpy contractSpy(&contract, &PinchGesture::progress); QSignalSpy contractSpy(&contract, &PinchGesture::triggerProgress);
// don't release callback until we know the direction of swipe gesture // don't release callback until we know the direction of swipe gesture
recognizer.startSwipeGesture(4); recognizer.startSwipeGesture(4);

View file

@ -41,24 +41,28 @@ void SwipeGesture::setStartGeometry(const QRect &geometry)
Q_ASSERT(m_maximumY >= m_minimumY); Q_ASSERT(m_maximumY >= m_minimumY);
} }
qreal SwipeGesture::deltaToProgress(const QSizeF &delta) const qreal SwipeGesture::getTriggerProgress(const QSizeF &delta) const
{ {
if (!m_minimumDeltaRelevant || m_minimumDelta.isNull()) { if (!m_triggerDeltaRelevant || m_triggerDelta.isNull()) {
return 1.0; return 1.0;
} }
if (m_direction & (GestureDirection::Up | GestureDirection::Down)) { if (m_direction.testFlag(GestureDirection::DirectionlessSwipe)) {
return std::min(std::abs(delta.height()) / std::abs(m_minimumDelta.height()), 1.0); return std::min(std::hypot(delta.width(), delta.height()) / m_triggerDelta.width(), 1.0);
} else if (m_direction & (GestureDirection::Left | GestureDirection::Right)) { }
return std::min(std::abs(delta.width()) / std::abs(m_minimumDelta.width()), 1.0);
if (m_direction & GestureDirection::VerticalAxis) {
return std::min(std::abs(delta.height()) / std::abs(m_triggerDelta.height()), 1.0);
} else if (m_direction & GestureDirection::HorizontalAxis) {
return std::min(std::abs(delta.width()) / std::abs(m_triggerDelta.width()), 1.0);
} }
return 1.0; return 1.0;
} }
bool SwipeGesture::minimumDeltaReached(const QSizeF &delta) const bool SwipeGesture::triggerDeltaReached(const QSizeF &delta) const
{ {
return deltaToProgress(delta) >= 1.0; return getTriggerProgress(delta) >= 1.0;
} }
PinchGesture::PinchGesture(QObject *parent) PinchGesture::PinchGesture(QObject *parent)
@ -68,14 +72,14 @@ PinchGesture::PinchGesture(QObject *parent)
PinchGesture::~PinchGesture() = default; PinchGesture::~PinchGesture() = default;
qreal PinchGesture::scaleDeltaToProgress(const qreal &scaleDelta) const qreal PinchGesture::getTriggerProgress(const qreal &scaleDelta) const
{ {
return std::clamp(std::abs(scaleDelta - 1) / minimumScaleDelta(), 0.0, 1.0); return std::clamp(std::abs(scaleDelta - 1) / triggerScaleDelta(), 0.0, 1.0);
} }
bool PinchGesture::minimumScaleDeltaReached(const qreal &scaleDelta) const bool PinchGesture::triggerScaleDeltaReached(const qreal &scaleDelta) const
{ {
return scaleDeltaToProgress(scaleDelta) >= 1.0; return getTriggerProgress(scaleDelta) >= 1.0;
} }
GestureRecognizer::GestureRecognizer(QObject *parent) GestureRecognizer::GestureRecognizer(QObject *parent)
@ -163,11 +167,12 @@ int GestureRecognizer::startSwipeGesture(uint fingerCount, const QPointF &startP
} }
// Only add gestures who's direction aligns with current swipe axis // Only add gestures who's direction aligns with current swipe axis
if (gesture->direction() & (GestureDirection::Up | GestureDirection::Down)) { if (gesture->direction().testFlag(GestureDirection::DirectionlessSwipe)) {
} else if (gesture->direction() & GestureDirection::VerticalAxis) {
if (m_currentSwipeAxis == Axis::Horizontal) { if (m_currentSwipeAxis == Axis::Horizontal) {
continue; continue;
} }
} else if (gesture->direction() & (GestureDirection::Left | GestureDirection::Right)) { } else if (gesture->direction() & GestureDirection::HorizontalAxis) {
if (m_currentSwipeAxis == Axis::Vertical) { if (m_currentSwipeAxis == Axis::Vertical) {
continue; continue;
} }
@ -242,11 +247,39 @@ void GestureRecognizer::updateSwipeGesture(const QSizeF &delta)
// Send progress update // Send progress update
for (SwipeGesture *g : std::as_const(m_activeSwipeGestures)) { for (SwipeGesture *g : std::as_const(m_activeSwipeGestures)) {
Q_EMIT g->progress(g->deltaToProgress(m_currentDelta)); Q_EMIT g->triggerProgress(g->getTriggerProgress(m_currentDelta));
Q_EMIT g->deltaProgress(m_currentDelta); Q_EMIT g->semanticProgress(g->getSemanticProgress(m_currentDelta), g->direction());
Q_EMIT g->pixelDelta(m_currentDelta, g->direction());
Q_EMIT g->semanticDelta(g->getSemanticDelta(m_currentDelta), g->direction());
if (!g->direction().testFlag(GestureDirection::DirectionlessSwipe)) {
Q_EMIT g->semanticProgressAxis(g->getSemanticAxisProgress(m_currentDelta), g->direction());
}
Q_EMIT g->swipePixelVector(QVector2D(m_currentDelta.width(), m_currentDelta.height()));
} }
} }
bool GestureRecognizer::mutuallyExclusive(GestureDirections currentDir, GestureDirections gestureDir)
{
if (currentDir == gestureDir) {
return false;
}
if (gestureDir.testFlag(GestureDirection::DirectionlessSwipe)) {
return false;
}
if (currentDir & GestureDirection::VerticalAxis) {
if (gestureDir.testFlag(GestureDirection::VerticalAxis)) {
return false;
}
} else if (currentDir & GestureDirection::HorizontalAxis) {
if (gestureDir.testFlag(GestureDirection::HorizontalAxis)) {
return false;
}
}
return true;
}
void GestureRecognizer::cancelActiveGestures() void GestureRecognizer::cancelActiveGestures()
{ {
for (auto g : qAsConst(m_activeSwipeGestures)) { for (auto g : qAsConst(m_activeSwipeGestures)) {
@ -274,7 +307,7 @@ void GestureRecognizer::endSwipeGesture()
{ {
const QSizeF delta = m_currentDelta; const QSizeF delta = m_currentDelta;
for (auto g : qAsConst(m_activeSwipeGestures)) { for (auto g : qAsConst(m_activeSwipeGestures)) {
if (static_cast<SwipeGesture *>(g)->minimumDeltaReached(delta)) { if (static_cast<SwipeGesture *>(g)->triggerDeltaReached(delta)) {
Q_EMIT g->triggered(); Q_EMIT g->triggered();
} else { } else {
Q_EMIT g->cancelled(); Q_EMIT g->cancelled();
@ -339,7 +372,9 @@ void GestureRecognizer::updatePinchGesture(qreal scale, qreal angleDelta, const
} }
for (PinchGesture *g : std::as_const(m_activePinchGestures)) { for (PinchGesture *g : std::as_const(m_activePinchGestures)) {
Q_EMIT g->progress(g->scaleDeltaToProgress(scale)); Q_EMIT g->triggerProgress(g->getTriggerProgress(scale));
Q_EMIT g->semanticProgress(g->getSemanticProgress(scale), g->direction());
Q_EMIT g->semanticProgressAxis(g->getSemanticAxisProgress(scale), g->direction());
} }
} }
@ -354,7 +389,7 @@ void GestureRecognizer::cancelPinchGesture()
void GestureRecognizer::endPinchGesture() // because fingers up void GestureRecognizer::endPinchGesture() // because fingers up
{ {
for (auto g : qAsConst(m_activePinchGestures)) { for (auto g : qAsConst(m_activePinchGestures)) {
if (g->minimumScaleDeltaReached(m_currentScale)) { if (g->triggerScaleDeltaReached(m_currentScale)) {
Q_EMIT g->triggered(); Q_EMIT g->triggered();
} else { } else {
Q_EMIT g->cancelled(); Q_EMIT g->cancelled();
@ -431,36 +466,36 @@ bool SwipeGesture::maximumYIsRelevant() const
return m_maximumYRelevant; return m_maximumYRelevant;
} }
QSizeF SwipeGesture::minimumDelta() const QSizeF SwipeGesture::triggerDelta() const
{ {
return m_minimumDelta; return m_triggerDelta;
} }
void SwipeGesture::setMinimumDelta(const QSizeF &delta) void SwipeGesture::setTriggerDelta(const QSizeF &delta)
{ {
m_minimumDelta = delta; m_triggerDelta = delta;
m_minimumDeltaRelevant = true; m_triggerDeltaRelevant = true;
} }
bool SwipeGesture::isMinimumDeltaRelevant() const bool SwipeGesture::isTriggerDeltaRelevant() const
{ {
return m_minimumDeltaRelevant; return m_triggerDeltaRelevant;
} }
qreal PinchGesture::minimumScaleDelta() const qreal PinchGesture::triggerScaleDelta() const
{ {
return m_minimumScaleDelta; return m_triggerScaleDelta;
} }
void PinchGesture::setMinimumScaleDelta(const qreal &scaleDelta) void PinchGesture::setTriggerScaleDelta(const qreal &scaleDelta)
{ {
m_minimumScaleDelta = scaleDelta; m_triggerScaleDelta = scaleDelta;
m_minimumScaleDeltaRelevant = true; m_triggerScaleDeltaRelevant = true;
} }
bool PinchGesture::isMinimumScaleDeltaRelevant() const bool PinchGesture::isTriggerScaleDeltaRelevant() const
{ {
return m_minimumScaleDeltaRelevant; return m_triggerScaleDeltaRelevant;
} }
int GestureRecognizer::startSwipeGesture(uint fingerCount) int GestureRecognizer::startSwipeGesture(uint fingerCount)
@ -468,6 +503,48 @@ int GestureRecognizer::startSwipeGesture(uint fingerCount)
return startSwipeGesture(fingerCount, QPointF(), StartPositionBehavior::Irrelevant); return startSwipeGesture(fingerCount, QPointF(), StartPositionBehavior::Irrelevant);
} }
QSizeF SwipeGesture::getSemanticDelta(const QSizeF &delta) const
{
QSizeF d = QSizeF();
d.setWidth(delta.width() / m_unitDelta);
d.setHeight(delta.height() / m_unitDelta);
return d;
}
qreal SwipeGesture::getSemanticProgress(const QSizeF &delta) const
{
if (m_direction.testFlag(GestureDirection::DirectionlessSwipe)) {
return std::hypot(delta.width(), delta.height()) / m_unitDelta;
} else if (m_direction & GestureDirection::VerticalAxis) {
return std::abs(delta.height()) / m_unitDelta;
} else if (m_direction & GestureDirection::HorizontalAxis) {
return std::abs(delta.width()) / m_unitDelta;
}
return 1.0;
}
qreal PinchGesture::getSemanticProgress(const qreal scale) const
{
return std::max(std::abs(1 - scale) / m_unitScaleDelta, 0.0);
}
qreal SwipeGesture::getSemanticAxisProgress(const QSizeF &delta) const
{
if (m_direction & GestureDirection::VerticalAxis) {
return delta.height() / m_unitDelta;
} else if (m_direction & GestureDirection::HorizontalAxis) {
return delta.width() / m_unitDelta;
}
return 1.0;
}
qreal PinchGesture::getSemanticAxisProgress(const qreal scale) const
{
return (scale - 1) / m_unitScaleDelta;
}
int GestureRecognizer::startSwipeGesture(const QPointF &startPos) int GestureRecognizer::startSwipeGesture(const QPointF &startPos)
{ {
return startSwipeGesture(1, startPos, StartPositionBehavior::Relevant); return startSwipeGesture(1, startPos, StartPositionBehavior::Relevant);

View file

@ -17,16 +17,17 @@
#include <QPointF> #include <QPointF>
#include <QSet> #include <QSet>
#include <QSizeF> #include <QSizeF>
#include <QVector2D>
#include <QVector> #include <QVector>
namespace KWin namespace KWin
{ {
static const QSet<uint> DEFAULT_VALID_FINGER_COUNTS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; static const QSet<uint> DEFAULT_VALID_FINGER_COUNTS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
/* /**
* Everytime the scale of the gesture changes by this much, the callback changes by 1.
* This is the amount of change for 1 unit of change, like switch by 1 desktop. * This is the amount of change for 1 unit of change, like switch by 1 desktop.
* */ */
static const qreal DEFAULT_UNIT_DELTA = 400; // Pixels
static const qreal DEFAULT_UNIT_SCALE_DELTA = .2; // 20% static const qreal DEFAULT_UNIT_SCALE_DELTA = .2; // 20%
class Gesture : public QObject class Gesture : public QObject
@ -72,6 +73,24 @@ Q_SIGNALS:
* This Gesture no longer matches. * This Gesture no longer matches.
*/ */
void cancelled(); void cancelled();
/**
* Progress towards the minimum threshold to trigger
*/
void triggerProgress(qreal);
/**
* The progress of the gesture if a minimumDelta is set.
* The progress is reported in [0.0,1.0+]
* Progress is always positive
* It can be more than 1, indicating an action should happen more than once.
*/
void semanticProgress(qreal, GestureDirections);
/**
* Like semantic progress except [-1, 1] and
* it captures both of something
* example: Up and Down (VerticalAxis), Contracting and Expanding (BiDirectionalPinch)
* Positive values are Up, Right and Expanding
*/
void semanticProgressAxis(qreal, GestureDirections);
private: private:
QSet<uint> m_validFingerCounts = DEFAULT_VALID_FINGER_COUNTS; QSet<uint> m_validFingerCounts = DEFAULT_VALID_FINGER_COUNTS;
@ -99,24 +118,51 @@ public:
bool maximumYIsRelevant() const; bool maximumYIsRelevant() const;
void setStartGeometry(const QRect &geometry); void setStartGeometry(const QRect &geometry);
QSizeF minimumDelta() const; QSizeF triggerDelta() const;
void setMinimumDelta(const QSizeF &delta); void setTriggerDelta(const QSizeF &delta);
bool isMinimumDeltaRelevant() const; bool isTriggerDeltaRelevant() const;
qreal deltaToProgress(const QSizeF &delta) const; qreal getTriggerProgress(const QSizeF &delta) const;
bool minimumDeltaReached(const QSizeF &delta) const; bool triggerDeltaReached(const QSizeF &delta) const;
/**
* Take the given pixel delta and
* map it to a simple [0, 1+] semantic scale.
* 0 = no progress
* 1 = complete something once
* The value can be greater than 1, indicating
* that the action should be done more times.
*/
qreal getSemanticProgress(const QSizeF &delta) const;
/**
* Like the last one, except [-1, 1]
* Positive values are Up and Right
*/
qreal getSemanticAxisProgress(const QSizeF &delta) const;
/**
* A two dimensional semantic delta.
* [-1, 1] on each axis.
* Positive is Up and Right
*/
QSizeF getSemanticDelta(const QSizeF &delta) const;
Q_SIGNALS: Q_SIGNALS:
/** /**
* The progress of the gesture if a minimumDelta is set. * Summative pixel delta from where the gesture
* The progress is reported in [0.0,1.0] * started to where it is now.
*/ */
void progress(qreal); void pixelDelta(const QSizeF &delta, GestureDirections);
/** /**
* The progress in actual pixel distance traveled by the fingers * A 2d coordinate giving the semantic axis delta
* [-1, 1] on both horizontal and vertical axes.
*/ */
void deltaProgress(const QSizeF &delta); void semanticDelta(const QSizeF &delta, GestureDirections);
/**
* GIves a 2d vector of pointing from
* where the gesture started to where
* it is now.
*/
void swipePixelVector(const QVector2D &vector);
private: private:
bool m_minimumXRelevant = false; bool m_minimumXRelevant = false;
@ -127,8 +173,9 @@ private:
int m_maximumX = 0; int m_maximumX = 0;
bool m_maximumYRelevant = false; bool m_maximumYRelevant = false;
int m_maximumY = 0; int m_maximumY = 0;
bool m_minimumDeltaRelevant = false; bool m_triggerDeltaRelevant = false;
QSizeF m_minimumDelta; QSizeF m_triggerDelta;
qreal m_unitDelta = DEFAULT_UNIT_DELTA;
}; };
class PinchGesture : public Gesture class PinchGesture : public Gesture
@ -138,28 +185,44 @@ public:
explicit PinchGesture(QObject *parent = nullptr); explicit PinchGesture(QObject *parent = nullptr);
~PinchGesture() override; ~PinchGesture() override;
qreal minimumScaleDelta() const; qreal triggerScaleDelta() const;
/** /**
* scaleDelta is the % scale difference needed to trigger * scaleDelta is the % scale difference needed to trigger
* 0.25 will trigger when scale reaches 0.75 or 1.25 * 0.25 will trigger when scale reaches 0.75 or 1.25
*/ */
void setMinimumScaleDelta(const qreal &scaleDelta); void setTriggerScaleDelta(const qreal &scaleDelta);
bool isMinimumScaleDeltaRelevant() const; bool isTriggerScaleDeltaRelevant() const;
qreal scaleDeltaToProgress(const qreal &scaleDelta) const; qreal getTriggerProgress(const qreal &scaleDelta) const;
bool minimumScaleDeltaReached(const qreal &scaleDelta) const; bool triggerScaleDeltaReached(const qreal &scaleDelta) const;
/**
* Take the given pixel delta and
* map it to a simple [0, 1+] semantic scale.
* 0 = no progress
* 1 = complete something once
* The value can be greater than 1, indicating
* that the action should be done more times.
*/
qreal getSemanticProgress(const qreal scale) const;
/**
* Like the last one, except [-1, 1]
* Positive is expanding.
* Positive values are Expanding
*/
qreal getSemanticAxisProgress(const qreal scale) const;
Q_SIGNALS: Q_SIGNALS:
/** /**
* The progress of the gesture if a minimumDelta is set.
* The progress is reported in [0.0,1.0] * The progress is reported in [0.0,1.0]
*/ */
void progress(qreal); void triggerProgress(qreal);
private: private:
bool m_minimumScaleDeltaRelevant = false; bool m_triggerScaleDeltaRelevant = false;
qreal m_minimumScaleDelta = DEFAULT_UNIT_SCALE_DELTA; qreal m_triggerScaleDelta = .2;
qreal m_unitScaleDelta = DEFAULT_UNIT_SCALE_DELTA;
}; };
class KWIN_EXPORT GestureRecognizer : public QObject class KWIN_EXPORT GestureRecognizer : public QObject
@ -188,6 +251,7 @@ public:
private: private:
void cancelActiveGestures(); void cancelActiveGestures();
bool mutuallyExclusive(GestureDirections d, GestureDirections gestureDir);
enum class StartPositionBehavior { enum class StartPositionBehavior {
Relevant, Relevant,
Irrelevant, Irrelevant,

View file

@ -24,6 +24,8 @@
#include <signal.h> #include <signal.h>
#include <variant> #include <variant>
#include <iostream>
namespace KWin namespace KWin
{ {
GlobalShortcut::GlobalShortcut(Shortcut &&sc, QAction *action) GlobalShortcut::GlobalShortcut(Shortcut &&sc, QAction *action)
@ -121,22 +123,22 @@ void GlobalShortcutsManager::registerAxisShortcut(QAction *action, Qt::KeyboardM
addIfNotExists(GlobalShortcut(PointerAxisShortcut{modifiers, axis}, action)); addIfNotExists(GlobalShortcut(PointerAxisShortcut{modifiers, axis}, action));
} }
void GlobalShortcutsManager::registerGesture(GestureDeviceType device, GestureDirection direction, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback) void GlobalShortcutsManager::registerGesture(GestureDeviceType device, GestureDirections direction, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback)
{ {
// Create and setup the GestureShortcut // Create and setup the GestureShortcut
GestureShortcut shortcut{device, direction}; GestureShortcut shortcut{device, direction};
if (isSwipeDirection(direction)) { if (isSwipeDirection(direction)) {
std::unique_ptr<SwipeGesture> gesture = std::make_unique<SwipeGesture>(); std::unique_ptr<SwipeGesture> gesture = std::make_unique<SwipeGesture>();
gesture->addFingerCount(fingerCount); gesture->addFingerCount(fingerCount);
gesture->setMinimumDelta(QSizeF(200, 200)); gesture->setTriggerDelta(QSizeF(200, 200));
connect(gesture.get(), &SwipeGesture::progress, progressCallback); connect(gesture.get(), &SwipeGesture::triggerProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
shortcut.swipeGesture = std::move(gesture); shortcut.swipeGesture = std::move(gesture);
} else if (isPinchDirection(direction)) { } else if (isPinchDirection(direction)) {
std::unique_ptr<PinchGesture> gesture = std::make_unique<PinchGesture>(); std::unique_ptr<PinchGesture> gesture = std::make_unique<PinchGesture>();
gesture->addFingerCount(fingerCount); gesture->addFingerCount(fingerCount);
connect(gesture.get(), &PinchGesture::progress, progressCallback); connect(gesture.get(), &PinchGesture::triggerProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
shortcut.pinchGesture = std::move(gesture); shortcut.pinchGesture = std::move(gesture);
@ -151,19 +153,21 @@ void GlobalShortcutsManager::forceRegisterTouchscreenSwipe(QAction *onUp, std::f
std::unique_ptr<SwipeGesture> gesture = std::make_unique<SwipeGesture>(); std::unique_ptr<SwipeGesture> gesture = std::make_unique<SwipeGesture>();
gesture->addFingerCount(fingerCount); gesture->addFingerCount(fingerCount);
gesture->setDirection(direction); gesture->setDirection(direction);
gesture->setMinimumDelta(QSizeF(200, 200)); gesture->setTriggerDelta(QSizeF(200, 200));
connect(gesture.get(), &SwipeGesture::progress, progressCallback); connect(gesture.get(), &SwipeGesture::triggerProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection); connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
GestureShortcut gestureShortcut{GestureDeviceType::Touchscreen, direction};
gestureShortcut.swipeGesture = std::move(gesture);
m_touchscreenGestureRecognizer->registerSwipeGesture(gestureShortcut.swipeGesture.get());
GlobalShortcut shortcut{GestureShortcut{GestureDeviceType::Touchscreen, direction, std::move(gesture)}, onUp}; GlobalShortcut shortcut{std::move(gestureShortcut), onUp};
const auto it = std::find_if(m_shortcuts.begin(), m_shortcuts.end(), [&shortcut](const auto &s) { const auto it = std::find_if(m_shortcuts.begin(), m_shortcuts.end(), [&shortcut](const auto &s) {
return shortcut.shortcut() == s.shortcut(); return shortcut.shortcut() == s.shortcut();
}); });
if (it != m_shortcuts.end()) { if (it != m_shortcuts.end()) {
m_shortcuts.erase(it); m_shortcuts.erase(it);
} }
m_touchscreenGestureRecognizer->registerSwipeGesture(gesture.get());
connect(shortcut.action(), &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted); connect(shortcut.action(), &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
m_shortcuts.push_back(std::move(shortcut)); m_shortcuts.push_back(std::move(shortcut));
} }

View file

@ -15,6 +15,7 @@
#include <QKeySequence> #include <QKeySequence>
#include <memory> #include <memory>
#include <vector>
class QAction; class QAction;
class KGlobalAccelD; class KGlobalAccelD;
@ -58,7 +59,7 @@ public:
*/ */
void registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis); void registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis);
void registerGesture(GestureDeviceType device, GestureDirection direction, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback = nullptr); void registerGesture(GestureDeviceType device, GestureDirections direction, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback = nullptr);
void forceRegisterTouchscreenSwipe(QAction *action, std::function<void(qreal)> progressCallback, GestureDirection direction, uint fingerCount); void forceRegisterTouchscreenSwipe(QAction *action, std::function<void(qreal)> progressCallback, GestureDirection direction, uint fingerCount);

View file

@ -232,6 +232,10 @@ enum class GestureDirection {
Right = 1 << 4, Right = 1 << 4,
Expanding = 1 << 5, Expanding = 1 << 5,
Contracting = 1 << 6, Contracting = 1 << 6,
VerticalAxis = Up | Down, // Up is positive values
HorizontalAxis = Left | Right, // Right is positive
DirectionlessSwipe = Left | Right | Up | Down, // Positive is Up/Right
BiDirectionalPinch = Expanding | Contracting, // Positive is Expanding
}; };
Q_DECLARE_FLAGS(GestureDirections, GestureDirection) Q_DECLARE_FLAGS(GestureDirections, GestureDirection)

View file

@ -121,14 +121,14 @@ Edge::Edge(ScreenEdges *parent)
handleTouchCallback(); handleTouchCallback();
} }
}); });
connect(m_gesture, &SwipeGesture::progress, this, [this](qreal progress) { connect(m_gesture, &SwipeGesture::triggerProgress, this, [this](qreal progress) {
int factor = progress * 256.0f; int factor = progress * 256.0f;
if (m_lastApproachingFactor != factor) { if (m_lastApproachingFactor != factor) {
m_lastApproachingFactor = factor; m_lastApproachingFactor = factor;
Q_EMIT approaching(border(), m_lastApproachingFactor / 256.0f, m_approachGeometry); Q_EMIT approaching(border(), m_lastApproachingFactor / 256.0f, m_approachGeometry);
} }
}); });
connect(m_gesture, &SwipeGesture::deltaProgress, this, [this](const QSizeF &progressDelta) { connect(m_gesture, &SwipeGesture::pixelDelta, this, [this](const QSizeF &progressDelta) {
if (!m_touchCallbacks.isEmpty()) { if (!m_touchCallbacks.isEmpty()) {
m_touchCallbacks.constFirst().progressCallback(border(), progressDelta, m_output); m_touchCallbacks.constFirst().progressCallback(border(), progressDelta, m_output);
} }
@ -569,7 +569,7 @@ void Edge::setGeometry(const QRect &geometry)
if (isScreenEdge()) { if (isScreenEdge()) {
const Output *output = workspace()->outputAt(m_geometry.center()); const Output *output = workspace()->outputAt(m_geometry.center());
m_gesture->setStartGeometry(m_geometry); m_gesture->setStartGeometry(m_geometry);
m_gesture->setMinimumDelta(QSizeF(MINIMUM_DELTA, MINIMUM_DELTA) / output->scale()); m_gesture->setTriggerDelta(QSizeF(MINIMUM_DELTA, MINIMUM_DELTA) / output->scale());
} }
} }