Touch Screen Controls (#1437)

* Touch Screen Controls
One finger for pan.
Two fingers for zoom or rotate.
Double tap for fits to the viewer.
Three finger drag for undo and redo.
This commit is contained in:
Jeremy Bullock 2017-11-16 04:26:36 -07:00 committed by shun-iwasawa
parent 52a220b89a
commit 3e4fd55ba5
3 changed files with 169 additions and 4 deletions

View file

@ -505,6 +505,10 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent)
// if (Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() &&
// Ghibli3DLutUtil::m_isValid)
// m_ghibli3DLutUtil = new Ghibli3DLutUtil();
setAttribute(Qt::WA_AcceptTouchEvents);
grabGesture(Qt::SwipeGesture);
grabGesture(Qt::PanGesture);
grabGesture(Qt::PinchGesture);
}
//-----------------------------------------------------------------------------

View file

@ -34,6 +34,8 @@ class Ruler;
class QMenu;
class SceneViewer;
class LocatorPopup;
class QGestureEvent;
class QTouchEvent;
namespace ImageUtils {
class FullScreenWidget;
@ -66,13 +68,21 @@ class SceneViewer final : public GLWidgetForHighDpi,
QPoint m_lastMousePos;
QPoint m_pos;
Qt::MouseButton m_mouseButton;
bool m_foregroundDrawing;
bool m_tabletEvent, m_tabletPressed, m_tabletReleased, m_tabletMove,
m_tabletActive;
// used to handle wrong mouse drag events!
bool m_buttonClicked, m_toolSwitched;
bool m_shownOnce = false;
bool m_shownOnce = false;
bool m_gestureActive = false;
bool m_touchActive = false;
bool m_rotating = false;
bool m_zooming = false;
bool m_panning = false;
QPointF m_firstPanPoint;
QPointF m_undoPoint;
double m_scaleFactor; // used for zoom gesture
double m_rotationDelta; // used for rotate gesture
int m_referenceMode;
int m_previewMode;
bool m_isMouseEntered, m_forceGlFlush;
@ -285,6 +295,8 @@ protected:
void showEvent(QShowEvent *) override;
void hideEvent(QHideEvent *) override;
void gestureEvent(QGestureEvent *e);
void touchEvent(QTouchEvent *e, int type);
void tabletEvent(QTabletEvent *) override;
void leaveEvent(QEvent *) override;
void enterEvent(QEvent *) override;

View file

@ -25,6 +25,7 @@
#include "tools/toolhandle.h"
#include "tools/cursormanager.h"
#include "tools/toolcommandids.h"
#include "toonzqt/viewcommandids.h"
// TnzLib includes
#include "toonz/toonzscene.h"
@ -60,6 +61,7 @@
#include <QApplication>
#include <QDebug>
#include <QMimeData>
#include <QGestureEvent>
// definito - per ora - in tapp.cpp
extern QString updateToolEnableStatus(TTool *tool);
@ -351,7 +353,9 @@ void SceneViewer::enterEvent(QEvent *) {
void SceneViewer::mouseMoveEvent(QMouseEvent *event) {
// if this is called just after tabletEvent, skip the execution
if (m_tabletEvent) return;
if (m_gestureActive) {
return;
}
// there are three cases to come here :
// 1. on mouse is moved (no tablet is used)
// 2. on tablet is moved, with middle or right button is pressed
@ -510,9 +514,15 @@ void SceneViewer::onMove(const TMouseEvent &event) {
//-----------------------------------------------------------------------------
void SceneViewer::mousePressEvent(QMouseEvent *event) {
// source can be useful for detecting touch vs mouse,
// but has reports of being unreliable on mac
// so m_gestureActive is the marker for rejecting touch events
int source = event->source();
// if this is called just after tabletEvent, skip the execution
if (m_tabletEvent) return;
if (m_gestureActive) {
return;
}
// For now OSX has a critical problem that mousePressEvent is called just
// after releasing the stylus, which causes the irregular stroke while
// float-moving.
@ -619,6 +629,15 @@ void SceneViewer::mouseReleaseEvent(QMouseEvent *event) {
m_tabletEvent = false;
return;
}
if (m_gestureActive) {
m_gestureActive = false;
m_rotating = false;
m_zooming = false;
m_panning = false;
m_scaleFactor = 0.0;
m_rotationDelta = 0.0;
return;
}
TMouseEvent mouseEvent;
initToonzEvent(mouseEvent, event, height(), 1.0, getDevPixRatio());
@ -792,7 +811,132 @@ void SceneViewer::wheelEvent(QWheelEvent *event) {
//-----------------------------------------------------------------------------
void SceneViewer::gestureEvent(QGestureEvent *e) {
m_gestureActive = false;
if (QGesture *swipe = e->gesture(Qt::SwipeGesture)) {
m_gestureActive = true;
} else if (QGesture *pan = e->gesture(Qt::PanGesture)) {
m_gestureActive = true;
}
if (QGesture *pinch = e->gesture(Qt::PinchGesture)) {
QPinchGesture *gesture = static_cast<QPinchGesture *>(pinch);
QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
QPoint firstCenter = gesture->centerPoint().toPoint();
if (gesture->state() == Qt::GestureStarted) {
m_gestureActive = true;
} else if (gesture->state() == Qt::GestureFinished) {
m_gestureActive = false;
m_rotating = false;
m_zooming = false;
m_scaleFactor = 0.0;
m_rotationDelta = 0.0;
} else {
if (changeFlags & QPinchGesture::RotationAngleChanged) {
qreal rotationDelta =
gesture->rotationAngle() - gesture->lastRotationAngle();
TAffine aff = getViewMatrix().inv();
TPointD center = aff * TPointD(0, 0);
if (!m_rotating && !m_zooming) {
m_rotationDelta += rotationDelta;
double absDelta = abs(m_rotationDelta);
if (absDelta >= 10) {
m_rotating = true;
}
}
if (m_rotating) {
rotate(center, -rotationDelta);
}
}
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
double scaleFactor = gesture->scaleFactor();
// the scale factor makes for too sensitive scaling
// divide the change in half
if (scaleFactor > 1) {
double decimalValue = scaleFactor - 1;
decimalValue /= 3;
scaleFactor = 1 + decimalValue;
} else if (scaleFactor < 1) {
double decimalValue = 1 - scaleFactor;
decimalValue /= 3;
scaleFactor = 1 - decimalValue;
}
if (!m_rotating && !m_zooming) {
double delta = scaleFactor - 1;
m_scaleFactor += delta;
if (m_scaleFactor > .2 || m_scaleFactor < -.2) {
m_zooming = true;
}
}
if (m_zooming) {
zoomQt(firstCenter * getDevPixRatio(), scaleFactor);
}
m_gestureActive = true;
}
if (changeFlags & QPinchGesture::CenterPointChanged) {
QPointF centerDelta = (gesture->centerPoint() * getDevPixRatio()) -
(gesture->lastCenterPoint() * getDevPixRatio());
if (centerDelta.manhattanLength() > 1) {
// panQt(centerDelta.toPoint());
}
m_gestureActive = true;
}
}
}
e->accept();
}
void SceneViewer::touchEvent(QTouchEvent *e, int type) {
if (type == QEvent::TouchBegin) {
m_touchActive = true;
m_firstPanPoint = e->touchPoints().at(0).pos();
m_undoPoint = m_firstPanPoint;
}
if (e->touchPoints().count() == 1 && m_touchActive) {
QTouchEvent::TouchPoint panPoint = e->touchPoints().at(0);
if (!m_panning) {
QPointF deltaPoint = panPoint.pos() - m_firstPanPoint;
if (deltaPoint.manhattanLength() > 100) {
m_panning = true;
}
}
if (m_panning) {
QPointF centerDelta = (panPoint.pos() * getDevPixRatio()) -
(panPoint.lastPos() * getDevPixRatio());
panQt(centerDelta.toPoint());
}
}
if (e->touchPoints().count() == 3 && m_touchActive) {
QPointF newPoint = e->touchPoints().at(0).pos();
if (m_undoPoint.x() - newPoint.x() > 100) {
CommandManager::instance()->execute("MI_Undo");
m_undoPoint = newPoint;
}
if (m_undoPoint.x() - newPoint.x() < -100) {
CommandManager::instance()->execute("MI_Redo");
m_undoPoint = newPoint;
}
}
if (type == QEvent::TouchEnd || type == QEvent::TouchCancel) {
m_touchActive = false;
m_panning = false;
}
e->accept();
}
//-----------------------------------------------------------------------------
bool SceneViewer::event(QEvent *e) {
if (e->type() == QEvent::Gesture) {
gestureEvent(static_cast<QGestureEvent *>(e));
return true;
}
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchEnd ||
e->type() == QEvent::TouchCancel || e->type() == QEvent::TouchUpdate) {
touchEvent(static_cast<QTouchEvent *>(e), e->type());
m_gestureActive = true;
return true;
}
if (e->type() == QEvent::ShortcutOverride || e->type() == QEvent::KeyPress) {
if (!((QKeyEvent *)e)->isAutoRepeat()) {
TApp::instance()->getCurrentTool()->storeTool();
@ -1156,6 +1300,11 @@ void SceneViewer::keyReleaseEvent(QKeyEvent *event) {
//-----------------------------------------------------------------------------
void SceneViewer::mouseDoubleClickEvent(QMouseEvent *event) {
if (m_gestureActive) {
fitToCamera();
m_gestureActive = false;
return;
}
if (m_freezedStatus != NO_FREEZED) return;
int frame = TApp::instance()->getCurrentFrame()->getFrame();