2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2017-03-18 10:00:30 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2017 Martin Gräßlin <mgraesslin@kde.org>
|
2017-03-18 10:00:30 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2017-03-18 10:00:30 +00:00
|
|
|
#ifndef KWIN_GESTURES_H
|
|
|
|
#define KWIN_GESTURES_H
|
|
|
|
|
2022-07-04 00:09:23 +00:00
|
|
|
#include "kwinglobals.h"
|
2017-03-22 20:03:04 +00:00
|
|
|
#include <kwin_export.h>
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
#include <QMap>
|
2017-03-18 10:00:30 +00:00
|
|
|
#include <QObject>
|
2017-03-19 10:40:03 +00:00
|
|
|
#include <QPointF>
|
2022-07-04 00:09:23 +00:00
|
|
|
#include <QSet>
|
2017-03-19 10:40:03 +00:00
|
|
|
#include <QSizeF>
|
2022-07-26 16:32:23 +00:00
|
|
|
#include <QVector2D>
|
2017-03-18 10:00:30 +00:00
|
|
|
#include <QVector>
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
2022-07-04 00:09:23 +00:00
|
|
|
static const QSet<uint> DEFAULT_VALID_FINGER_COUNTS = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
/**
|
2022-03-23 09:49:35 +00:00
|
|
|
* This is the amount of change for 1 unit of change, like switch by 1 desktop.
|
2022-07-26 16:32:23 +00:00
|
|
|
*/
|
2022-09-11 10:14:02 +00:00
|
|
|
static const qreal DEFAULT_UNIT_DELTA = 400; // Pixels
|
2022-03-23 09:49:35 +00:00
|
|
|
static const qreal DEFAULT_UNIT_SCALE_DELTA = .2; // 20%
|
|
|
|
|
2017-03-18 10:00:30 +00:00
|
|
|
class Gesture : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
~Gesture() override;
|
2022-03-23 10:13:38 +00:00
|
|
|
|
2022-07-04 00:09:23 +00:00
|
|
|
/**
|
|
|
|
* This gesture framework allows for one gesture to
|
|
|
|
* capture a range of fingers.
|
|
|
|
*
|
|
|
|
* This function adds an acceptable number of fingers
|
|
|
|
* to the set of finger counts this gesture can
|
|
|
|
* be identified by.
|
|
|
|
*
|
|
|
|
* By default, any number of fingers are accepted.
|
|
|
|
* (see DEFAULT_VALID_FINGER_COUNTS)
|
|
|
|
*/
|
|
|
|
void addFingerCount(uint numFingers);
|
|
|
|
bool isFingerCountAcceptable(uint fingers) const;
|
|
|
|
QSet<uint> acceptableFingerCounts() const;
|
|
|
|
|
2022-09-11 10:13:37 +00:00
|
|
|
GestureDirections direction() const;
|
|
|
|
void setDirection(GestureDirections direction);
|
2022-07-26 15:35:07 +00:00
|
|
|
|
2017-03-18 10:00:30 +00:00
|
|
|
protected:
|
|
|
|
explicit Gesture(QObject *parent);
|
2022-09-11 10:13:37 +00:00
|
|
|
GestureDirections m_direction;
|
2017-03-18 10:00:30 +00:00
|
|
|
|
|
|
|
Q_SIGNALS:
|
|
|
|
/**
|
|
|
|
* Matching of a gesture started and this Gesture might match.
|
2019-01-12 10:31:32 +00:00
|
|
|
* On further evaluation either the signal @ref triggered or
|
|
|
|
* @ref cancelled will get emitted.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2017-03-18 10:00:30 +00:00
|
|
|
void started();
|
|
|
|
/**
|
|
|
|
* Gesture matching ended and this Gesture matched.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2017-03-18 10:00:30 +00:00
|
|
|
void triggered();
|
|
|
|
/**
|
|
|
|
* This Gesture no longer matches.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2017-03-18 10:00:30 +00:00
|
|
|
void cancelled();
|
2022-07-26 16:32:23 +00:00
|
|
|
/**
|
2022-09-11 10:14:02 +00:00
|
|
|
* Progress towards the minimum threshold to trigger
|
2022-07-26 16:32:23 +00:00
|
|
|
*/
|
|
|
|
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.
|
|
|
|
*/
|
2022-09-11 10:13:37 +00:00
|
|
|
void semanticProgress(qreal, GestureDirections);
|
2022-09-11 10:14:02 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
2022-07-04 00:09:23 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QSet<uint> m_validFingerCounts = DEFAULT_VALID_FINGER_COUNTS;
|
2017-03-18 10:00:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class SwipeGesture : public Gesture
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
explicit SwipeGesture(QObject *parent = nullptr);
|
|
|
|
~SwipeGesture() override;
|
|
|
|
|
2022-02-02 21:51:39 +00:00
|
|
|
void setMinimumX(int x);
|
|
|
|
int minimumX() const;
|
|
|
|
bool minimumXIsRelevant() const;
|
|
|
|
void setMinimumY(int y);
|
|
|
|
int minimumY() const;
|
|
|
|
bool minimumYIsRelevant() const;
|
|
|
|
|
|
|
|
void setMaximumX(int x);
|
|
|
|
int maximumX() const;
|
|
|
|
bool maximumXIsRelevant() const;
|
|
|
|
void setMaximumY(int y);
|
|
|
|
int maximumY() const;
|
|
|
|
bool maximumYIsRelevant() const;
|
2017-03-19 10:40:03 +00:00
|
|
|
void setStartGeometry(const QRect &geometry);
|
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
QSizeF triggerDelta() const;
|
|
|
|
void setTriggerDelta(const QSizeF &delta);
|
|
|
|
bool isTriggerDeltaRelevant() const;
|
2017-03-19 10:40:03 +00:00
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
qreal getTriggerProgress(const QSizeF &delta) const;
|
|
|
|
bool triggerDeltaReached(const QSizeF &delta) const;
|
2017-03-19 10:40:03 +00:00
|
|
|
|
|
|
|
/**
|
2022-07-26 16:32:23 +00:00
|
|
|
* 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;
|
2022-09-11 10:14:02 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
2017-03-19 10:40:03 +00:00
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
Q_SIGNALS:
|
|
|
|
/**
|
|
|
|
* Summative pixel delta from where the gesture
|
|
|
|
* started to where it is now.
|
|
|
|
*/
|
2022-09-11 10:13:37 +00:00
|
|
|
void pixelDelta(const QSizeF &delta, GestureDirections);
|
2022-09-11 10:14:02 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
2022-03-09 16:17:37 +00:00
|
|
|
|
2017-03-18 10:00:30 +00:00
|
|
|
private:
|
2017-03-19 10:40:03 +00:00
|
|
|
bool m_minimumXRelevant = false;
|
|
|
|
int m_minimumX = 0;
|
|
|
|
bool m_minimumYRelevant = false;
|
|
|
|
int m_minimumY = 0;
|
|
|
|
bool m_maximumXRelevant = false;
|
|
|
|
int m_maximumX = 0;
|
|
|
|
bool m_maximumYRelevant = false;
|
|
|
|
int m_maximumY = 0;
|
2022-07-26 16:32:23 +00:00
|
|
|
bool m_triggerDeltaRelevant = false;
|
|
|
|
QSizeF m_triggerDelta;
|
|
|
|
qreal m_unitDelta = DEFAULT_UNIT_DELTA;
|
2017-03-18 10:00:30 +00:00
|
|
|
};
|
|
|
|
|
2022-02-02 21:51:39 +00:00
|
|
|
class PinchGesture : public Gesture
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
explicit PinchGesture(QObject *parent = nullptr);
|
|
|
|
~PinchGesture() override;
|
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
qreal triggerScaleDelta() const;
|
2022-02-02 21:51:39 +00:00
|
|
|
|
|
|
|
/**
|
2022-03-23 10:13:38 +00:00
|
|
|
* scaleDelta is the % scale difference needed to trigger
|
|
|
|
* 0.25 will trigger when scale reaches 0.75 or 1.25
|
|
|
|
*/
|
2022-07-26 16:32:23 +00:00
|
|
|
void setTriggerScaleDelta(const qreal &scaleDelta);
|
|
|
|
bool isTriggerScaleDeltaRelevant() const;
|
2022-02-02 21:51:39 +00:00
|
|
|
|
2022-07-26 16:32:23 +00:00
|
|
|
qreal getTriggerProgress(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;
|
2022-09-11 10:14:02 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
2022-02-02 21:51:39 +00:00
|
|
|
|
|
|
|
private:
|
2022-07-26 16:32:23 +00:00
|
|
|
bool m_triggerScaleDeltaRelevant = false;
|
|
|
|
qreal m_triggerScaleDelta = .2;
|
|
|
|
qreal m_unitScaleDelta = DEFAULT_UNIT_SCALE_DELTA;
|
2022-02-02 21:51:39 +00:00
|
|
|
};
|
|
|
|
|
2017-03-22 20:03:04 +00:00
|
|
|
class KWIN_EXPORT GestureRecognizer : public QObject
|
2017-03-18 10:00:30 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
GestureRecognizer(QObject *parent = nullptr);
|
|
|
|
~GestureRecognizer() override;
|
|
|
|
|
2022-02-02 21:51:39 +00:00
|
|
|
void registerSwipeGesture(SwipeGesture *gesture);
|
|
|
|
void unregisterSwipeGesture(SwipeGesture *gesture);
|
|
|
|
void registerPinchGesture(PinchGesture *gesture);
|
|
|
|
void unregisterPinchGesture(PinchGesture *gesture);
|
|
|
|
|
|
|
|
int startSwipeGesture(uint fingerCount);
|
|
|
|
int startSwipeGesture(const QPointF &startPos);
|
2017-03-18 10:00:30 +00:00
|
|
|
|
|
|
|
void updateSwipeGesture(const QSizeF &delta);
|
|
|
|
void cancelSwipeGesture();
|
|
|
|
void endSwipeGesture();
|
|
|
|
|
2022-02-02 21:51:39 +00:00
|
|
|
int startPinchGesture(uint fingerCount);
|
2022-03-23 10:13:38 +00:00
|
|
|
void updatePinchGesture(qreal scale, qreal angleDelta, const QSizeF &posDelta);
|
2022-02-02 21:51:39 +00:00
|
|
|
void cancelPinchGesture();
|
|
|
|
void endPinchGesture();
|
|
|
|
|
2017-03-18 10:00:30 +00:00
|
|
|
private:
|
2022-02-02 21:51:39 +00:00
|
|
|
void cancelActiveGestures();
|
2022-09-11 10:14:02 +00:00
|
|
|
bool mutuallyExclusive(GestureDirections d, GestureDirections gestureDir);
|
2017-03-19 10:40:03 +00:00
|
|
|
enum class StartPositionBehavior {
|
|
|
|
Relevant,
|
2022-02-02 21:51:39 +00:00
|
|
|
Irrelevant,
|
|
|
|
};
|
|
|
|
enum class Axis {
|
|
|
|
Horizontal,
|
|
|
|
Vertical,
|
|
|
|
None,
|
2017-03-19 10:40:03 +00:00
|
|
|
};
|
|
|
|
int startSwipeGesture(uint fingerCount, const QPointF &startPos, StartPositionBehavior startPosBehavior);
|
2022-02-02 21:51:39 +00:00
|
|
|
QVector<SwipeGesture *> m_swipeGestures;
|
|
|
|
QVector<PinchGesture *> m_pinchGestures;
|
|
|
|
QVector<SwipeGesture *> m_activeSwipeGestures;
|
|
|
|
QVector<PinchGesture *> m_activePinchGestures;
|
|
|
|
QMap<Gesture *, QMetaObject::Connection> m_destroyConnections;
|
|
|
|
|
2021-06-25 23:00:56 +00:00
|
|
|
QSizeF m_currentDelta = QSizeF(0, 0);
|
2022-02-02 21:51:39 +00:00
|
|
|
qreal m_currentScale = 1; // For Pinch Gesture recognition
|
|
|
|
uint m_currentFingerCount = 0;
|
|
|
|
Axis m_currentSwipeAxis = Axis::None;
|
2017-03-18 10:00:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|