Commit 6c0ed148 authored by Eric Edlund's avatar Eric Edlund
Browse files

Clarify interface and improve documentation in gesture

Separate trigger progress and semantic progress in gesture.
Move effect activation and desktop switching over to semantic progress.
Allow semantic progress to exceed 1 for overshoot in animations.
parent bc15b72e
......@@ -279,6 +279,7 @@ void GestureTest::testSwipeUpdateTrigger()
SwipeGesture gesture;
QFETCH(GestureDirection, direction);
gesture.setDirection(direction);
gesture.setTriggerDelta(QSizeF(1, 1));
QSignalSpy triggeredSpy(&gesture, &SwipeGesture::triggered);
QVERIFY(triggeredSpy.isValid());
......
......@@ -62,6 +62,7 @@ DesktopGridEffect::DesktopGridEffect()
});
effects->registerGesture(GestureDeviceType::Touchpad, GestureDirection::Up, 4, m_realtimeToggleAction, [this](qreal progress) {
progress = std::clamp(progress, 0.0, 1.0);
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == this) {
switch (m_status) {
case Status::Inactive:
......
......@@ -52,6 +52,7 @@ OverviewEffect::OverviewEffect()
});
auto progressCallback = [this](qreal progress) {
progress = std::clamp(progress, 0.0, 1.1);
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == this) {
switch (m_status) {
case Status::Inactive:
......
......@@ -111,6 +111,7 @@ WindowViewEffect::WindowViewEffect()
});
const auto gestureCallback = [this](qreal progress) {
progress = std::clamp(progress, 0.0, 1.1);
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == this) {
switch (m_status) {
case Status::Inactive:
......
......@@ -47,17 +47,34 @@ qreal SwipeGesture::getTriggerProgress(const QSizeF &delta) const
return 1.0;
}
if (m_direction.testFlag(GestureDirection::DirectionlessSwipe)) {
return std::min(std::hypot(delta.width(), delta.height()) / m_triggerDelta.width(), 1.0);
}
qreal progress = 0.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);
if (m_direction & GestureDirection::Up) {
qreal candidate = -delta.height() / m_triggerDelta.height();
if (candidate > progress) {
progress = candidate;
}
}
if (m_direction & GestureDirection::Down) {
qreal candidate = delta.height() / m_triggerDelta.height();
if (candidate > progress) {
progress = candidate;
}
}
if (m_direction & GestureDirection::Left) {
qreal candidate = -delta.width() / m_triggerDelta.width();
if (candidate > progress) {
progress = candidate;
}
}
if (m_direction & GestureDirection::Right) {
qreal candidate = delta.width() / m_triggerDelta.width();
if (candidate > progress) {
progress = candidate;
}
}
return 1.0;
return std::clamp(progress, 0.0, 1.0);
}
bool SwipeGesture::triggerDeltaReached(const QSizeF &delta) const
......@@ -167,13 +184,12 @@ int GestureRecognizer::startSwipeGesture(uint fingerCount, const QPointF &startP
}
// Only add gestures who's direction aligns with current swipe axis
if (gesture->direction().testFlag(GestureDirection::DirectionlessSwipe)) {
} else if (gesture->direction() & GestureDirection::VerticalAxis) {
if (m_currentSwipeAxis == Axis::Horizontal) {
if (m_currentSwipeAxis == Axis::Vertical) {
if (!(gesture->direction() & (GestureDirection::Up | GestureDirection::Down))) {
continue;
}
} else if (gesture->direction() & GestureDirection::HorizontalAxis) {
if (m_currentSwipeAxis == Axis::Vertical) {
} else if (m_currentSwipeAxis == Axis::Horizontal) {
if (!(gesture->direction() & (GestureDirection::Left | GestureDirection::Right))) {
continue;
}
}
......@@ -250,36 +266,9 @@ void GestureRecognizer::updateSwipeGesture(const QSizeF &delta)
Q_EMIT g->triggerProgress(g->getTriggerProgress(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()
{
for (auto g : qAsConst(m_activeSwipeGestures)) {
......@@ -374,7 +363,6 @@ void GestureRecognizer::updatePinchGesture(qreal scale, qreal angleDelta, const
for (PinchGesture *g : std::as_const(m_activePinchGestures)) {
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());
}
}
......@@ -473,6 +461,7 @@ QSizeF SwipeGesture::triggerDelta() const
void SwipeGesture::setTriggerDelta(const QSizeF &delta)
{
Q_ASSERT(delta.width() >= 0 && delta.height() >= 0);
m_triggerDelta = delta;
m_triggerDeltaRelevant = true;
}
......@@ -503,25 +492,36 @@ int GestureRecognizer::startSwipeGesture(uint fingerCount)
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;
qreal progress = 0;
if (direction() & GestureDirection::Up) {
qreal val = -delta.height() / m_unitDelta;
if (val > progress) {
progress = val;
}
}
if (direction() & GestureDirection::Down) {
qreal val = delta.height() / m_unitDelta;
if (val > progress) {
progress = val;
}
}
if (direction() & GestureDirection::Left) {
qreal val = -delta.width() / m_unitDelta;
if (val > progress) {
progress = val;
}
}
if (direction() & GestureDirection::Right) {
qreal val = delta.width() / m_unitDelta;
if (val > progress) {
progress = val;
}
}
return 1.0;
return progress;
}
qreal PinchGesture::getSemanticProgress(const qreal scale) const
......@@ -529,22 +529,6 @@ 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)
{
return startSwipeGesture(1, startPos, StartPositionBehavior::Relevant);
......
......@@ -27,7 +27,7 @@ static const QSet<uint> DEFAULT_VALID_FINGER_COUNTS = {1, 2, 3, 4, 5, 6, 7, 8, 9
/**
* 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_DELTA = 200; // Pixels
static const qreal DEFAULT_UNIT_SCALE_DELTA = .2; // 20%
class Gesture : public QObject
......@@ -74,7 +74,7 @@ Q_SIGNALS:
*/
void cancelled();
/**
* Progress towards the minimum threshold to trigger
* Progress towards the minimum threshold to trigger. [0, 1]
*/
void triggerProgress(qreal);
/**
......@@ -84,13 +84,6 @@ Q_SIGNALS:
* 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:
QSet<uint> m_validFingerCounts = DEFAULT_VALID_FINGER_COUNTS;
......@@ -118,10 +111,19 @@ public:
bool maximumYIsRelevant() const;
void setStartGeometry(const QRect &geometry);
/**
* In pixels
*/
QSizeF triggerDelta() const;
void setTriggerDelta(const QSizeF &delta);
bool isTriggerDeltaRelevant() const;
/**
* Returns the progress [0, 1] of the gesture
* being triggered. Picks the largest possible value
* considering each direction available to the
* gesture.
*/
qreal getTriggerProgress(const QSizeF &delta) const;
bool triggerDeltaReached(const QSizeF &delta) const;
......@@ -134,17 +136,6 @@ public:
* 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:
/**
......@@ -152,17 +143,6 @@ Q_SIGNALS:
* started to where it is now.
*/
void pixelDelta(const QSizeF &delta, GestureDirections);
/**
* A 2d coordinate giving the semantic axis delta
* [-1, 1] on both horizontal and vertical axes.
*/
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:
bool m_minimumXRelevant = false;
......@@ -194,6 +174,9 @@ public:
void setTriggerScaleDelta(const qreal &scaleDelta);
bool isTriggerScaleDeltaRelevant() const;
/**
* [0, 1]
*/
qreal getTriggerProgress(const qreal &scaleDelta) const;
bool triggerScaleDeltaReached(const qreal &scaleDelta) const;
......@@ -206,18 +189,6 @@ public:
* 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:
/**
* The progress is reported in [0.0,1.0]
*/
void triggerProgress(qreal);
private:
bool m_triggerScaleDeltaRelevant = false;
......@@ -251,7 +222,6 @@ public:
private:
void cancelActiveGestures();
bool mutuallyExclusive(GestureDirections d, GestureDirections gestureDir);
enum class StartPositionBehavior {
Relevant,
Irrelevant,
......
......@@ -131,14 +131,14 @@ void GlobalShortcutsManager::registerGesture(GestureDeviceType device, GestureDi
std::unique_ptr<SwipeGesture> gesture = std::make_unique<SwipeGesture>();
gesture->addFingerCount(fingerCount);
gesture->setTriggerDelta(QSizeF(200, 200));
connect(gesture.get(), &SwipeGesture::triggerProgress, progressCallback);
connect(gesture.get(), &SwipeGesture::semanticProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
shortcut.swipeGesture = std::move(gesture);
} else if (isPinchDirection(direction)) {
std::unique_ptr<PinchGesture> gesture = std::make_unique<PinchGesture>();
gesture->addFingerCount(fingerCount);
connect(gesture.get(), &PinchGesture::triggerProgress, progressCallback);
connect(gesture.get(), &PinchGesture::semanticProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
shortcut.pinchGesture = std::move(gesture);
......@@ -154,7 +154,7 @@ void GlobalShortcutsManager::forceRegisterTouchscreenSwipe(QAction *onUp, std::f
gesture->addFingerCount(fingerCount);
gesture->setDirection(direction);
gesture->setTriggerDelta(QSizeF(200, 200));
connect(gesture.get(), &SwipeGesture::triggerProgress, progressCallback);
connect(gesture.get(), &SwipeGesture::semanticProgress, progressCallback);
connect(gesture.get(), &Gesture::triggered, onUp, &QAction::trigger, Qt::QueuedConnection);
connect(gesture.get(), &Gesture::cancelled, onUp, &QAction::trigger, Qt::QueuedConnection);
GestureShortcut gestureShortcut{GestureDeviceType::Touchscreen, direction};
......
......@@ -232,22 +232,18 @@ enum class GestureDirection {
Right = 1 << 4,
Expanding = 1 << 5,
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_OPERATORS_FOR_FLAGS(GestureDirections)
Q_DECLARE_METATYPE(GestureDirection)
static bool isSwipeDirection(GestureDirections d)
inline bool isSwipeDirection(GestureDirections d)
{
return d & (GestureDirection::Up | GestureDirection::Down | GestureDirection::Left | GestureDirection::Right);
}
static bool isPinchDirection(GestureDirections d)
inline bool isPinchDirection(GestureDirections d)
{
return d & (GestureDirection::Contracting | GestureDirection::Expanding);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment