Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libgestures/gestures/swipe: add diagonal directions #34

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 56 additions & 30 deletions src/libgestures/libgestures/gestures/gesturerecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ void GestureRecognizer::unregisterGestures()
m_gestures.clear();
}

void GestureRecognizer::setWidthToHeightRatio(const qreal &ratio)
{
m_widthToHeightRatio = ratio;
}

void GestureRecognizer::setInputEventsToSample(const uint8_t &events)
{
m_inputEventsToSample = events;
Expand Down Expand Up @@ -107,7 +112,8 @@ bool GestureRecognizer::swipeGestureUpdate(const QPointF &delta, bool &endedPrem
{
if (m_sampledInputEvents++ != m_inputEventsToSample)
{
m_accumulatedAbsoluteSampledDelta += std::abs(delta.x()) + std::abs(delta.y());
m_accumulatedAbsoluteSampledDelta += std::sqrt(std::pow(delta.x(), 2) + std::pow(delta.y(), 2));
m_currentSwipeDelta = {};
return true;
}

Expand All @@ -119,38 +125,46 @@ bool GestureRecognizer::swipeGestureUpdate(const QPointF &delta, bool &endedPrem
m_isDeterminingSpeed = false;
}

SwipeDirection direction; // Overall direction
Axis swipeAxis;

// Pick an axis for gestures so horizontal ones don't change to vertical ones without lifting fingers
if (m_currentSwipeAxis == Axis::None)
{
if (std::abs(m_currentSwipeDelta.x()) >= std::abs(m_currentSwipeDelta.y()))
swipeAxis = Axis::Horizontal;
else
swipeAxis = Axis::Vertical;
SwipeDirection validDirection = SwipeDirection::None;
SwipeDirection direction = SwipeDirection::None;

if (m_validSwipeDirection == SwipeDirection::None) {
if (isSwipeDiagonal(m_currentSwipeDelta)) {
if ((m_currentSwipeDelta.x() > 0 && m_currentSwipeDelta.y() < 0)
|| (m_currentSwipeDelta.x() < 0 && m_currentSwipeDelta.y() > 0)) {
validDirection = SwipeDirection::LeftDownRightUp;
} else if ((m_currentSwipeDelta.x() > 0 && m_currentSwipeDelta.y() > 0)
|| (m_currentSwipeDelta.x() < 0 && m_currentSwipeDelta.y() < 0)) {
validDirection = SwipeDirection::LeftUpRightDown;
}
} else if (std::abs(m_currentSwipeDelta.x()) > std::abs(m_currentSwipeDelta.y())) {
validDirection = SwipeDirection::LeftRight;
} else {
validDirection = SwipeDirection::UpDown;
}

if (std::abs(m_currentSwipeDelta.x()) >= 5 || std::abs(m_currentSwipeDelta.y()) >= 5)
{
if (std::abs(m_currentSwipeDelta.x()) >= 5 || std::abs(m_currentSwipeDelta.y()) >= 5) {
// only lock in a direction if the delta is big enough
// to prevent accidentally choosing the wrong direction
m_currentSwipeAxis = swipeAxis;
m_validSwipeDirection = validDirection;
}
} else {
validDirection = m_validSwipeDirection;
}
else
swipeAxis = m_currentSwipeAxis;

// Find the current swipe direction
switch (swipeAxis)
{
case Axis::Vertical:
direction = m_currentSwipeDelta.y() < 0 ? SwipeDirection::Up : SwipeDirection::Down;
break;
case Axis::Horizontal:
direction = m_currentSwipeDelta.x() < 0 ? SwipeDirection::Left : SwipeDirection::Right;
break;
default:
Q_UNREACHABLE();
qreal deltaSingle = 0;
if (validDirection == SwipeDirection::LeftRight) {
direction = delta.x() < 0 ? SwipeDirection::Left : SwipeDirection::Right;
deltaSingle = delta.x();
} else if (validDirection == SwipeDirection::UpDown) {
direction = delta.y() < 0 ? SwipeDirection::Up : SwipeDirection::Down;
deltaSingle = delta.y();
} else if (validDirection == SwipeDirection::LeftDownRightUp) {
direction = delta.x() > 0 && delta.y() < 0 ? SwipeDirection::RightUp : SwipeDirection::LeftDown;
deltaSingle = std::sqrt(std::pow(delta.x(), 2) + std::pow(delta.y(), 2));
} else if (validDirection == SwipeDirection::LeftUpRightDown) {
direction = delta.x() < 0 && delta.y() < 0 ? SwipeDirection::LeftUp : SwipeDirection::RightDown;
deltaSingle = std::sqrt(std::pow(delta.x(), 2) + std::pow(delta.y(), 2));
}

for (auto it = m_activeSwipeGestures.begin(); it != m_activeSwipeGestures.end();)
Expand All @@ -160,7 +174,11 @@ bool GestureRecognizer::swipeGestureUpdate(const QPointF &delta, bool &endedPrem
if ((!((gesture->direction() == SwipeDirection::LeftRight
&& (direction == SwipeDirection::Left || direction == SwipeDirection::Right))
|| (gesture->direction() == SwipeDirection::UpDown
&& (direction == SwipeDirection::Up || direction == SwipeDirection::Down)))
&& (direction == SwipeDirection::Up || direction == SwipeDirection::Down))
|| (gesture->direction() == SwipeDirection::LeftDownRightUp
&& (direction == SwipeDirection::LeftDown || direction == SwipeDirection::RightUp))
|| (gesture->direction() == SwipeDirection::LeftUpRightDown
&& (direction == SwipeDirection::LeftUp || direction == SwipeDirection::RightDown)))
&& gesture->direction() != direction)
|| (gesture->speed() != GestureSpeed::Any && gesture->speed() != m_speed))
{
Expand All @@ -169,7 +187,7 @@ bool GestureRecognizer::swipeGestureUpdate(const QPointF &delta, bool &endedPrem
continue;
}

Q_EMIT gesture->updated(swipeAxis == Axis::Vertical ? delta.y() : delta.x(), endedPrematurely);
Q_EMIT gesture->updated(deltaSingle, endedPrematurely);
if (endedPrematurely)
return true;

Expand Down Expand Up @@ -266,13 +284,21 @@ void GestureRecognizer::gestureCancel(std::vector<std::shared_ptr<TGesture>> &ac
resetMembers();
}

bool GestureRecognizer::isSwipeDiagonal(const QPointF &delta) const
{
constexpr auto min = 35 * (M_PI / 180);
constexpr auto max = 70 * (M_PI / 180);
const auto angle = atan2(std::abs(delta.y() * m_widthToHeightRatio), std::abs(delta.x()));
return angle >= min && angle <= max;
}

void GestureRecognizer::resetMembers()
{
m_accumulatedAbsoluteSampledDelta = 0;
m_sampledInputEvents = 0;
m_isDeterminingSpeed = false;
m_previousPinchScale = 1;
m_currentSwipeAxis = Axis::None;
m_validSwipeDirection = SwipeDirection::None;
m_currentSwipeDelta = QPointF();
m_speed = GestureSpeed::Any;
}
Expand Down
9 changes: 8 additions & 1 deletion src/libgestures/libgestures/gestures/gesturerecognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class GestureRecognizer : public QObject
*/
void unregisterGestures();

void setWidthToHeightRatio(const qreal &ratio);
void setInputEventsToSample(const uint8_t &events);
void setSwipeFastThreshold(const qreal &threshold);
void setPinchInFastThreshold(const qreal &threshold);
Expand Down Expand Up @@ -104,19 +105,25 @@ class GestureRecognizer : public QObject
template <class TGesture>
void gestureCancel(std::vector<std::shared_ptr<TGesture>> &activeGestures);

/**
* Checks whether the swipe gesture the specified delta belongs to has been performed diagonally.
*/
bool isSwipeDiagonal(const QPointF &delta) const;

void resetMembers();

std::vector<std::shared_ptr<Gesture>> m_gestures;

std::vector<std::shared_ptr<SwipeGesture>> m_activeSwipeGestures;
Axis m_currentSwipeAxis = Axis::None;
SwipeDirection m_validSwipeDirection = SwipeDirection::None;
QPointF m_currentSwipeDelta;

std::vector<std::shared_ptr<PinchGesture>> m_activePinchGestures;
qreal m_previousPinchScale = 1;

std::vector<std::shared_ptr<HoldGesture>> m_activeHoldGestures;

qreal m_widthToHeightRatio = 1;
uint8_t m_inputEventsToSample = 3;
qreal m_swipeGestureFastThreshold = 20;
qreal m_pinchInFastThreshold = 0.04;
Expand Down
14 changes: 13 additions & 1 deletion src/libgestures/libgestures/gestures/swipegesture.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ enum class SwipeDirection
Right,
Down,
Up,

LeftUp,
LeftDown,
RightUp,
RightDown,

// Bi-directional
LeftRight,
UpDown
UpDown,

LeftUpRightDown,
LeftDownRightUp,

None
};

class SwipeGesture : public Gesture
Expand Down
30 changes: 18 additions & 12 deletions src/libgestures/libgestures/yaml_convert.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ struct convert<std::shared_ptr<libgestures::GestureRecognizer>>
gestureRecognizer->registerGesture(gestureNode.as<std::shared_ptr<libgestures::Gesture>>());
}

gestureRecognizer->setWidthToHeightRatio(node["width_to_height_ratio"].as<qreal>(gestureRecognizer->m_widthToHeightRatio));
const auto speedNode = node["speed"];
if (speedNode.IsDefined()) {
gestureRecognizer->setInputEventsToSample(
Expand Down Expand Up @@ -252,24 +253,29 @@ struct convert<libgestures::PinchDirection>
}
};

const std::map<QString, libgestures::SwipeDirection> directions =
{
{ "left", libgestures::SwipeDirection::Left },
{ "right", libgestures::SwipeDirection::Right },
{ "up", libgestures::SwipeDirection::Up },
{ "down", libgestures::SwipeDirection::Down },
{ "left_up", libgestures::SwipeDirection::LeftUp },
{ "left_down", libgestures::SwipeDirection::LeftDown },
{ "right_up", libgestures::SwipeDirection::RightUp },
{ "right_down", libgestures::SwipeDirection::RightDown },
{ "left_right", libgestures::SwipeDirection::LeftRight },
{ "up_down", libgestures::SwipeDirection::UpDown },
{ "left_up_right_down", libgestures::SwipeDirection::LeftUpRightDown },
{ "left_down_right_up", libgestures::SwipeDirection::LeftDownRightUp }
};
template <>
struct convert<libgestures::SwipeDirection>
{
static bool decode(const Node &node, libgestures::SwipeDirection &direction)
{
const auto directionRaw = node.as<QString>();
if (directionRaw == "left") {
direction = libgestures::SwipeDirection::Left;
} else if (directionRaw == "right") {
direction = libgestures::SwipeDirection::Right;
} else if (directionRaw == "left_right") {
direction = libgestures::SwipeDirection::LeftRight;
} else if (directionRaw == "up") {
direction = libgestures::SwipeDirection::Up;
} else if (directionRaw == "down") {
direction = libgestures::SwipeDirection::Down;
} else if (directionRaw == "up_down") {
direction = libgestures::SwipeDirection::UpDown;
if (directions.contains(directionRaw)) {
direction = directions.at(directionRaw);
} else {
throw Exception(node.Mark(), "Invalid swipe direction");
}
Expand Down