This commit is contained in:
Luis Ángel San Martín Rodríguez 2023-05-23 18:56:47 +02:00
parent b45fabe057
commit 194f33c6e7
6 changed files with 578 additions and 2 deletions

View File

@ -30,7 +30,8 @@ CONFIG(force_angle) {
}
}
SOURCES += main.cpp
SOURCES += main.cpp \
viewer_gesture_handler.cpp
INCLUDEPATH += ../common \
../custom_widgets
@ -90,6 +91,7 @@ HEADERS += ../common/comic.h \
goto_flow_widget.h \
page_label_widget.h \
goto_flow_toolbar.h \
viewer_gesture_handler.h \
width_slider.h \
notifications_label_widget.h \
../common/pictureflow.h \

View File

@ -88,7 +88,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
int main(int argc, char *argv[])
{
qInstallMessageHandler(messageHandler);
// qInstallMessageHandler(messageHandler);
static const char ENV_VAR_QT_DEVICE_PIXEL_RATIO[] = "QT_DEVICE_PIXEL_RATIO";
if (!qEnvironmentVariableIsSet(ENV_VAR_QT_DEVICE_PIXEL_RATIO) && !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR") && !qEnvironmentVariableIsSet("QT_SCALE_FACTOR") && !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
@ -97,6 +97,7 @@ int main(int argc, char *argv[])
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
QApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QImageReader::setAllocationLimit(0);

View File

@ -16,11 +16,13 @@
#include "notifications_label_widget.h"
#include "comic_db.h"
#include "shortcuts_manager.h"
#include "viewer_gesture_handler.h"
#include "opengl_checker.h"
#include <QFile>
#include <QKeyEvent>
#include <QEvent>
#include <QsLog.h>
@ -40,6 +42,9 @@ Viewer::Viewer(QWidget *parent)
magnifyingGlassShown(false),
restoreMagnifyingGlass(false)
{
viewerGestureHandler = new ViewerGestureHandler(this);
viewerGestureHandler->setupGestureHandler(this);
translator = new YACReaderTranslator(this);
translator->hide();
translatorAnimation = new QPropertyAnimation(translator, "pos");
@ -727,6 +732,15 @@ void Viewer::mouseMoveEvent(QMouseEvent *event)
}
}
bool Viewer::event(QEvent *event)
{
if (viewerGestureHandler->handleEvent(event)) {
return true;
}
return QScrollArea::event(event);
}
QPixmap Viewer::pixmap() const
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)

View File

@ -30,6 +30,7 @@ class GoToFlowWidget;
class Bookmarks;
class PageLabelWidget;
class NotificationsLabelWidget;
class ViewerGestureHandler;
class Viewer : public QScrollArea, public ScrollManagement
{
@ -153,6 +154,8 @@ private:
bool shouldOpenNext;
bool shouldOpenPrevious;
ViewerGestureHandler *viewerGestureHandler;
private:
//! Magnifying glass
MagnifyingGlass *mglass;
@ -164,6 +167,7 @@ private:
void resizeEvent(QResizeEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
bool event(QEvent *event) override;
int verticalScrollStep() const;
int horizontalScrollStep() const;

View File

@ -0,0 +1,430 @@
#include "viewer_gesture_handler.h"
#include <QtWidgets>
#include <QTouchEvent>
ViewerGestureHandler::ViewerGestureHandler(QObject *parent)
: QObject { parent }, oneFingerSwiperGestureRecognizer(new OneFingerSwipeGestureRecognizer()), twoFingerSwiperGestureRecognizer(new TwoFingerSwipeGestureRecognizer())
{
}
bool ViewerGestureHandler::handleEvent(QEvent *event)
{
// GESTURE HANDLING
if (event->type() == QEvent::Gesture) {
QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
// three fingers swipe, the default in Qt
if (QGesture *swipe = gestureEvent->gesture(Qt::SwipeGesture)) {
QSwipeGesture *swipeGesture = static_cast<QSwipeGesture *>(swipe);
if (swipeGesture->state() == Qt::GestureFinished) {
qDebug() << "Qt Native swipe";
if (swipeGesture->horizontalDirection() == QSwipeGesture::Left) {
// emit swipeLeft();
return true;
} else if (swipeGesture->horizontalDirection() == QSwipeGesture::Right) {
// emit swipeRight();
return true;
}
}
}
if (QGesture *tap = gestureEvent->gesture(Qt::TapGesture)) {
QTapGesture *tapGesture = static_cast<QTapGesture *>(tap);
if (tapGesture->state() == Qt::GestureFinished) {
// emit tapGestureDetected();
qDebug() << "TAP yay";
return true;
}
}
if (QGesture *oneFingersSwipe = gestureEvent->gesture(oneFingerSwiperGestureRecognizerType)) {
SwipeGesture *oneFingersSwipeGesture = static_cast<SwipeGesture *>(oneFingersSwipe);
if (oneFingersSwipeGesture->state() == Qt::GestureFinished) {
qDebug() << "yay 1";
return true;
}
}
if (QGesture *twoFingersSwipe = gestureEvent->gesture(twoFingerSwiperGestureRecognizerType)) {
SwipeGesture *twoFingersSwipeGesture = static_cast<SwipeGesture *>(twoFingersSwipe);
if (twoFingersSwipeGesture->state() == Qt::GestureFinished) {
qDebug() << "yay 2";
return true;
}
}
}
// TOUCH HANDLING
return false;
}
void ViewerGestureHandler::setupGestureHandler(Viewer *widget)
{
// widget->setAttribute(Qt::WA_AcceptTouchEvents);
widget->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
// widget->grabGesture(Qt::SwipeGesture);
// widget->grabGesture(Qt::TapGesture);
// oneFingerSwiperGestureRecognizerType = QGestureRecognizer::registerRecognizer(oneFingerSwiperGestureRecognizer);
twoFingerSwiperGestureRecognizerType = QGestureRecognizer::registerRecognizer(twoFingerSwiperGestureRecognizer);
// widget->grabGesture(oneFingerSwiperGestureRecognizerType);
widget->viewport()->grabGesture(twoFingerSwiperGestureRecognizerType);
}
//--
SwipeGesture::SwipeGesture(QObject *parent)
: QGesture(parent), swipeGesturePrivate(new SwipeGesturePrivate)
{
swipeGesturePrivate->gestureType = Qt::SwipeGesture;
}
/*!
Destructor.
*/
SwipeGesture::~SwipeGesture()
{
}
SwipeGesture::SwipeDirection SwipeGesture::horizontalDirection() const
{
auto d = swipeGesturePrivate;
if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270)
return SwipeGesture::NoDirection;
else if (d->swipeAngle < 90 || d->swipeAngle > 270)
return SwipeGesture::Right;
else
return SwipeGesture::Left;
}
SwipeGesture::SwipeDirection SwipeGesture::verticalDirection() const
{
auto d = swipeGesturePrivate;
if (d->swipeAngle <= 0 || d->swipeAngle == 180)
return SwipeGesture::NoDirection;
else if (d->swipeAngle < 180)
return SwipeGesture::Up;
else
return SwipeGesture::Down;
}
qreal SwipeGesture::swipeAngle() const
{
return swipeGesturePrivate->swipeAngle;
}
void SwipeGesture::setSwipeAngle(qreal value)
{
swipeGesturePrivate->swipeAngle = value;
}
OneFingerSwipeGestureRecognizer::OneFingerSwipeGestureRecognizer()
: QGestureRecognizer()
{
}
QGesture *OneFingerSwipeGestureRecognizer::create(QObject *target)
{
return new SwipeGesture(target);
}
QGestureRecognizer::Result OneFingerSwipeGestureRecognizer::recognize(QGesture *state,
QObject *,
QEvent *event)
{
SwipeGesture *q = static_cast<SwipeGesture *>(state);
SwipeGesturePrivate *d = q->swipeGesturePrivate;
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
switch (event->type()) {
case QEvent::TouchBegin: {
d->velocityValue = 1;
d->time.start();
d->state = SwipeGesturePrivate::Started;
result = QGestureRecognizer::MayBeGesture;
break;
}
case QEvent::TouchEnd: {
if (q->state() != Qt::NoGesture) {
result = QGestureRecognizer::FinishGesture;
} else {
result = QGestureRecognizer::CancelGesture;
}
break;
}
case QEvent::TouchUpdate: {
const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
if (d->state == SwipeGesturePrivate::NoGesture)
result = QGestureRecognizer::CancelGesture;
else if (ev->points().size() == 1) {
d->state = SwipeGesturePrivate::PointsReached;
const QEventPoint &p1 = ev->points().at(0);
if (d->lastPositions[0].isNull()) {
d->lastPositions[0] = p1.globalPressPosition().toPoint();
}
d->hotSpot = p1.globalPosition();
d->isHotSpotSet = true;
int xDistance = p1.globalPosition().x() - d->lastPositions[0].x();
int yDistance = p1.globalPosition().y() - d->lastPositions[0].y();
const int distance = xDistance >= yDistance ? xDistance : yDistance;
int elapsedTime = d->time.restart();
if (!elapsedTime)
elapsedTime = 1;
d->velocityValue = 0.9 * d->velocityValue + (qreal)distance / elapsedTime;
d->swipeAngle = QLineF(p1.globalPressPosition(), p1.globalPosition()).angle();
static const int MoveThreshold = 50;
static const int directionChangeThreshold = MoveThreshold / 8;
if (qAbs(xDistance) > MoveThreshold || qAbs(yDistance) > MoveThreshold) {
// measure the distance to check if the direction changed
d->lastPositions[0] = p1.globalPosition().toPoint();
result = QGestureRecognizer::TriggerGesture;
// QTBUG-46195, small changes in direction should not cause the gesture to be canceled.
if (d->verticalDirection == SwipeGesture::NoDirection || qAbs(yDistance) > directionChangeThreshold) {
const SwipeGesture::SwipeDirection vertical = yDistance > 0
? SwipeGesture::Down
: SwipeGesture::Up;
if (d->verticalDirection != SwipeGesture::NoDirection && d->verticalDirection != vertical)
result = QGestureRecognizer::CancelGesture;
d->verticalDirection = vertical;
}
if (d->horizontalDirection == SwipeGesture::NoDirection || qAbs(xDistance) > directionChangeThreshold) {
const SwipeGesture::SwipeDirection horizontal = xDistance > 0
? SwipeGesture::Right
: SwipeGesture::Left;
if (d->horizontalDirection != SwipeGesture::NoDirection && d->horizontalDirection != horizontal)
result = QGestureRecognizer::CancelGesture;
d->horizontalDirection = horizontal;
}
} else {
if (q->state() != Qt::NoGesture)
result = QGestureRecognizer::TriggerGesture;
else
result = QGestureRecognizer::MayBeGesture;
}
} else if (ev->points().size() > 1) {
result = QGestureRecognizer::CancelGesture;
} else { // less than 1 touch points, so it wont happen?
switch (d->state) {
case SwipeGesturePrivate::NoGesture:
result = QGestureRecognizer::MayBeGesture;
break;
case SwipeGesturePrivate::Started:
result = QGestureRecognizer::Ignore;
break;
case SwipeGesturePrivate::PointsReached:
result = (ev->touchPointStates() & QEventPoint::State::Pressed)
? QGestureRecognizer::CancelGesture
: QGestureRecognizer::Ignore;
break;
}
}
break;
}
default:
break;
}
return result;
}
void OneFingerSwipeGestureRecognizer::reset(QGesture *state)
{
SwipeGesture *q = static_cast<SwipeGesture *>(state);
SwipeGesturePrivate *d = q->swipeGesturePrivate;
d->verticalDirection = d->horizontalDirection = SwipeGesture::NoDirection;
d->swipeAngle = 0;
d->lastPositions[0] = QPoint();
d->state = SwipeGesturePrivate::NoGesture;
d->velocityValue = 0;
d->time.invalidate();
QGestureRecognizer::reset(state);
}
TwoFingerSwipeGestureRecognizer::TwoFingerSwipeGestureRecognizer()
: QGestureRecognizer()
{
}
QGesture *TwoFingerSwipeGestureRecognizer::create(QObject *target)
{
return new SwipeGesture(target);
}
QGestureRecognizer::Result TwoFingerSwipeGestureRecognizer::recognize(QGesture *state,
QObject *,
QEvent *event)
{
// qDebug() << "TWO" << state;
SwipeGesture *q = static_cast<SwipeGesture *>(state);
SwipeGesturePrivate *d = q->swipeGesturePrivate;
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
switch (event->type()) {
case QEvent::TouchBegin: {
qDebug() << "TOUCH BEGIN";
}
case QEvent::TouchEnd: {
qDebug() << "TOUCH END";
}
case QEvent::TouchUpdate: {
qDebug() << "TOUCH UPDATE";
}
default: {
// qDebug() << event->type();
break;
}
}
return result;
switch (event->type()) {
case QEvent::TouchBegin: {
qDebug() << "TOUCH BEGIN";
d->velocityValue = 1;
d->time.start();
d->state = SwipeGesturePrivate::Started;
result = QGestureRecognizer::MayBeGesture;
break;
}
case QEvent::TouchEnd: {
qDebug() << "TOUCH END";
if (d->state != SwipeGesturePrivate::NoGesture) {
result = QGestureRecognizer::FinishGesture;
} else {
result = QGestureRecognizer::CancelGesture;
}
break;
}
case QEvent::TouchUpdate: {
qDebug() << "TOUCH UPDATE";
const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
if (d->state == SwipeGesturePrivate::NoGesture) {
qDebug() << "NoGesture";
d->velocityValue = 1;
d->time.start();
d->state = SwipeGesturePrivate::Started;
result = QGestureRecognizer::CancelGesture;
} else if (ev->points().size() == 2) {
qDebug() << "HMMMMMM";
d->state = SwipeGesturePrivate::PointsReached;
const QEventPoint &p1 = ev->points().at(0);
const QEventPoint &p2 = ev->points().at(1);
if (d->lastPositions[0].isNull()) {
d->lastPositions[0] = p1.globalPressPosition().toPoint();
d->lastPositions[1] = p2.globalPressPosition().toPoint();
}
d->hotSpot = p1.globalPosition();
d->isHotSpotSet = true;
int xDistance = (p1.globalPosition().x() - d->lastPositions[0].x() +
p2.globalPosition().x() - d->lastPositions[1].x()) /
2;
int yDistance = (p1.globalPosition().y() - d->lastPositions[0].y() +
p2.globalPosition().y() - d->lastPositions[1].y()) /
2;
const int distance = xDistance >= yDistance ? xDistance : yDistance;
int elapsedTime = d->time.restart();
if (!elapsedTime)
elapsedTime = 1;
d->velocityValue = 0.9 * d->velocityValue + (qreal)distance / elapsedTime;
d->swipeAngle = QLineF(p1.globalPressPosition(), p1.globalPosition()).angle();
static const int MoveThreshold = 50;
static const int directionChangeThreshold = MoveThreshold / 8;
if (qAbs(xDistance) > MoveThreshold || qAbs(yDistance) > MoveThreshold) {
qDebug() << "distance " << qAbs(xDistance) << " - " << qAbs(yDistance);
// measure the distance to check if the direction changed
d->lastPositions[0] = p1.globalPosition().toPoint();
d->lastPositions[1] = p2.globalPosition().toPoint();
result = QGestureRecognizer::TriggerGesture;
// QTBUG-46195, small changes in direction should not cause the gesture to be canceled.
if (d->verticalDirection == SwipeGesture::NoDirection || qAbs(yDistance) > directionChangeThreshold) {
const SwipeGesture::SwipeDirection vertical = yDistance > 0
? SwipeGesture::Down
: SwipeGesture::Up;
if (d->verticalDirection != SwipeGesture::NoDirection && d->verticalDirection != vertical)
result = QGestureRecognizer::CancelGesture;
d->verticalDirection = vertical;
}
if (d->horizontalDirection == SwipeGesture::NoDirection || qAbs(xDistance) > directionChangeThreshold) {
const SwipeGesture::SwipeDirection horizontal = xDistance > 0
? SwipeGesture::Right
: SwipeGesture::Left;
if (d->horizontalDirection != SwipeGesture::NoDirection && d->horizontalDirection != horizontal)
result = QGestureRecognizer::CancelGesture;
d->horizontalDirection = horizontal;
}
result = QGestureRecognizer::MayBeGesture;
} else {
qDebug() << "not enough distance " << qAbs(xDistance) << " - " << qAbs(yDistance);
if (d->state != SwipeGesturePrivate::NoGesture)
result = QGestureRecognizer::TriggerGesture;
else
result = QGestureRecognizer::MayBeGesture;
}
} else if (ev->points().size() > 2) {
qDebug() << "Cancel gesture";
result = QGestureRecognizer::CancelGesture;
} else { // less than 2 touch points
qDebug() << "less than 2";
switch (d->state) {
case SwipeGesturePrivate::NoGesture:
result = QGestureRecognizer::MayBeGesture;
break;
case SwipeGesturePrivate::Started:
result = QGestureRecognizer::Ignore;
break;
case SwipeGesturePrivate::PointsReached:
result = (ev->touchPointStates() & QEventPoint::State::Pressed)
? QGestureRecognizer::CancelGesture
: QGestureRecognizer::Ignore;
break;
}
}
break;
}
default:
break;
}
return result;
}
void TwoFingerSwipeGestureRecognizer::reset(QGesture *state)
{
qDebug() << "Reset";
SwipeGesture *q = static_cast<SwipeGesture *>(state);
SwipeGesturePrivate *d = q->swipeGesturePrivate;
d->verticalDirection = d->horizontalDirection = SwipeGesture::NoDirection;
d->swipeAngle = 0;
d->lastPositions[0] = d->lastPositions[1] = QPoint();
d->state = SwipeGesturePrivate::NoGesture;
d->velocityValue = 0;
d->time.invalidate();
QGestureRecognizer::reset(state);
}

View File

@ -0,0 +1,125 @@
#ifndef VIEWERGESTUREHANDLER_H
#define VIEWERGESTUREHANDLER_H
#include <QtWidgets>
#include <QtGui>
#include "viewer.h"
class SwipeGesturePrivate;
class SwipeGesture : public QGesture
{
Q_OBJECT
Q_DECLARE_PRIVATE(SwipeGesture)
Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection STORED false)
Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection STORED false)
Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle)
Q_PRIVATE_PROPERTY(SwipeGesture::d_func(), qreal velocity READ velocity WRITE setVelocity)
public:
SwipeGesturePrivate *swipeGesturePrivate;
enum SwipeDirection { NoDirection,
Left,
Right,
Up,
Down };
Q_ENUM(SwipeDirection)
explicit SwipeGesture(QObject *parent = nullptr);
~SwipeGesture();
SwipeDirection horizontalDirection() const;
SwipeDirection verticalDirection() const;
qreal swipeAngle() const;
void setSwipeAngle(qreal value);
friend class TwoFingerSwipeGestureRecognizer;
friend class OneFingerSwipeGestureRecognizer;
};
class GesturePrivate : public QObject
{
public:
GesturePrivate()
: gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false), gestureCancelPolicy(0)
{
}
Qt::GestureType gestureType;
Qt::GestureState state;
QPointF hotSpot;
QPointF sceneHotSpot;
uint isHotSpotSet : 1;
uint gestureCancelPolicy : 2;
};
class SwipeGesturePrivate : public GesturePrivate
{
public:
enum State {
NoGesture,
Started,
PointsReached
};
SwipeGesturePrivate()
: horizontalDirection(SwipeGesture::NoDirection),
verticalDirection(SwipeGesture::NoDirection),
swipeAngle(0),
state(NoGesture),
velocityValue(0)
{
}
qreal velocity() const { return velocityValue; }
void setVelocity(qreal value) { velocityValue = value; }
SwipeGesture::SwipeDirection horizontalDirection;
SwipeGesture::SwipeDirection verticalDirection;
qreal swipeAngle;
QPoint lastPositions[3];
State state;
qreal velocityValue;
QElapsedTimer time;
};
class OneFingerSwipeGestureRecognizer : public QGestureRecognizer
{
public:
OneFingerSwipeGestureRecognizer();
QGesture *create(QObject *target) override;
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override;
void reset(QGesture *state) override;
};
class TwoFingerSwipeGestureRecognizer : public QGestureRecognizer
{
public:
TwoFingerSwipeGestureRecognizer();
QGesture *create(QObject *target) override;
QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event) override;
void reset(QGesture *state) override;
};
class ViewerGestureHandler : public QObject
{
Q_OBJECT
public:
explicit ViewerGestureHandler(QObject *parent = nullptr);
void setupGestureHandler(Viewer *widget);
bool handleEvent(QEvent *event);
signals:
private:
OneFingerSwipeGestureRecognizer *oneFingerSwiperGestureRecognizer;
Qt::GestureType oneFingerSwiperGestureRecognizerType;
TwoFingerSwipeGestureRecognizer *twoFingerSwiperGestureRecognizer;
Qt::GestureType twoFingerSwiperGestureRecognizerType;
};
#endif // VIEWERGESTUREHANDLER_H