Gestures: custom Windows gesture recognizer

Translates native Windows pinch and rotate gestures into Qt's pinch
gestures.
This commit is contained in:
DeepSOIC 2015-03-28 00:34:28 +03:00 committed by wmayer
parent 862e65df6c
commit 77ef990fa7
3 changed files with 299 additions and 0 deletions

View File

@ -897,6 +897,7 @@ SET(FreeCADGui_CPP_SRCS
Utilities.cpp
WaitCursor.cpp
ManualAlignment.cpp
WinNativeGestureRecognizers.cpp
)
SET(FreeCADGui_SRCS
Application.h
@ -918,6 +919,7 @@ SET(FreeCADGui_SRCS
Utilities.h
WaitCursor.h
ManualAlignment.h
WinNativeGestureRecognizers.h
)
SET(FreeCADGui_SRCS

View File

@ -0,0 +1,227 @@
/***************************************************************************
* Copyright (c) Victor Titov (DeepSOIC) *
* (vv.titov@gmail.com) 2015 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <qevent.h>
#include <qgraphicsitem.h>
#include <QWidget>
#include <Windows.h>
#include <assert.h>
#endif
#include "WinNativeGestureRecognizers.h"
#ifdef GESTURE_MESS
//this implementation is a bit incompatible with Qt5, since
//nativegesture members were transformed into properties, and
//the whole event was made public
#include <qgesture.h>
#include <private/qevent_p.h>
QT_BEGIN_NAMESPACE
#if !defined(QT_NO_NATIVE_GESTURES)
QGesture* WinNativeGestureRecognizerPinch::create(QObject* target)
{
if (!target)
return new QPinchGestureN; // a special case
if (!target->isWidgetType())
return 0;
if (qobject_cast<QGraphicsObject *>(target))
return 0;
//QWidget* q = static_cast<QWidget *>(target);
/*QWidgetPrivate *d = q->d_func();
d->nativeGesturePanEnabled = true;
d->winSetupGestures();*/ //fails to compile =(, but we can rely on this being done by grabGesture(Pan...
return new QPinchGestureN;
}
QGestureRecognizer::Result WinNativeGestureRecognizerPinch::recognize(QGesture *gesture, QObject *watched, QEvent *event)
{
QPinchGestureN* q = static_cast<QPinchGestureN*> (gesture);
//QPinchGesturePrivate* d = q->d_func();//this fails to compile =( But we can get away without it.
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
if (event->type() == QEvent::NativeGesture) {
bool bZoom = false;
bool bRotate = false;
QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
switch(ev->gestureType) {
case QNativeGestureEvent::GestureBegin:
break;
case QNativeGestureEvent::Zoom:
case QNativeGestureEvent::Rotate:
bZoom = ev->gestureType == QNativeGestureEvent::Zoom;
bRotate = ev->gestureType == QNativeGestureEvent::Rotate;
result = QGestureRecognizer::TriggerGesture;
event->accept();
break;
case QNativeGestureEvent::GestureEnd:
if (q->state() == Qt::NoGesture)
return QGestureRecognizer::Ignore; // some other gesture has ended
result = QGestureRecognizer::FinishGesture;
break;
default:
return QGestureRecognizer::Ignore;
}
double ang = 0.0;
if (bRotate)
ang=GID_ROTATE_ANGLE_FROM_ARGUMENT(LOWORD(ev->argument));
if (q->state() == Qt::NoGesture) {
//start of a new gesture, prefill stuff
//d->isNewSequence = true;
q->setTotalChangeFlags(0); q->setChangeFlags(0);
q->setLastCenterPoint(QPointF());
q->setCenterPoint(
QPointF(
qreal(ev->position.x()),
qreal(ev->position.y())
)
);
q->setStartCenterPoint(q->centerPoint());
q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0); q->setRotationAngle(0.0);
q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
if(bZoom) {
q->lastFingerDistance = ev->argument;
q->fingerDistance = ev->argument;
} else if (bRotate) {
q->myLastRotationAngle = 0;
q->myRotationAngle = 0;
}
} else {//in the middle of gesture
//store new last values
q->setLastCenterPoint(q->centerPoint());
q->setLastRotationAngle(q->rotationAngle());
q->setLastScaleFactor(q->scaleFactor());
q->lastFingerDistance = q->fingerDistance;
q->myLastRotationAngle = q->myRotationAngle;
//update the current values
if (bZoom)
q->fingerDistance = ev->argument;
if (bRotate)
q->myRotationAngle = ang;
if(ev->gestureType == QNativeGestureEvent::GestureEnd){
q->fingerDistance = q->lastFingerDistance;//the end-of-gesture event holds no finger separation data, hence we are using the last value.
q->myRotationAngle = q->myLastRotationAngle;
}
if (bZoom)
q->setScaleFactor(
(qreal)(q->fingerDistance) / (qreal)(q->lastFingerDistance)
);
if (bRotate)
q->setRotationAngle(qreal(unbranchAngle(q->myRotationAngle - q->myLastRotationAngle)));
q->setCenterPoint(
QPointF(
qreal(ev->position.x()),
qreal(ev->position.y())
)
);
//compute the changes
QPinchGesture::ChangeFlags cf = 0;
if ( q->scaleFactor() != 1.0 )
cf |= QPinchGesture::ScaleFactorChanged;
if (q->lastCenterPoint() != q->centerPoint())
cf |= QPinchGesture::CenterPointChanged;
if (q->rotationAngle() != 0.0)
cf |= QPinchGesture::RotationAngleChanged;
q->setChangeFlags(cf);
//increment totals
q->setTotalChangeFlags (q->totalChangeFlags() | q->changeFlags());
q->setTotalScaleFactor (q->totalScaleFactor() * q->scaleFactor());
q->setTotalRotationAngle (q->totalRotationAngle() + q->rotationAngle());
}
}
return result;
}
void WinNativeGestureRecognizerPinch::reset(QGesture* gesture)
{
QGestureRecognizer::reset(gesture);//resets the state of the gesture, which is not write-accessible otherwise
QPinchGestureN *q = static_cast<QPinchGestureN*>(gesture);
q->lastFingerDistance = 0;
q->setTotalChangeFlags(0); q->setChangeFlags(0);
q->setLastCenterPoint(QPointF());
q->setCenterPoint(
QPointF(
0.0,
0.0
)
);
q->setStartCenterPoint(q->centerPoint());
q->setTotalRotationAngle(0.0); q->setLastRotationAngle(0.0); q->setRotationAngle(0.0);
q->setTotalScaleFactor(1.0); q->setLastScaleFactor(1.0); q->setScaleFactor(1.0);
q->lastFingerDistance = 0;
q->fingerDistance = 0;
}
void WinNativeGestureRecognizerPinch::TuneWindowsGestures(QWidget* target)
{
//modify windows-specific gesture options
#if WINVER >= _WIN32_WINNT_WIN7
HWND w = target->winId();
//fill in the options
const UINT nCfg = 2;
GESTURECONFIG cfgs[nCfg];
ZeroMemory(&cfgs, sizeof(cfgs));
cfgs[0].dwID = GID_PAN;
cfgs[0].dwWant = GC_PAN;
cfgs[0].dwBlock = GC_PAN_WITH_GUTTER;//disables stickiness to pure vertical/pure horizontal pans
cfgs[1].dwID = GID_ROTATE;
cfgs[1].dwWant = GC_ROTATE;
//set the options
bool ret = SetGestureConfig(w, 0, nCfg, cfgs, sizeof(GESTURECONFIG));
assert(ret); //if(!ret) throw
if(!ret){
DWORD err = GetLastError();//for debugging
}
#endif
}
/*!
* \brief WinNativeGestureRecognizerPinch::unbranchAngle utility function to bring an angle into -pi..pi region.
* \param ang
* \return
*/
double WinNativeGestureRecognizerPinch::unbranchAngle(double ang)
{
const double Pi = 3.14159265358979323846;
return ang - 2.0*Pi*floor((ang+Pi)/(2.0*Pi));
}
#endif //!defined(QT_NO_NATIVE_GESTURES)
#endif // GESTURE_MESS

View File

@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (c) Victor Titov (DeepSOIC) *
* (vv.titov@gmail.com) 2015 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
/*! This file adds support for pinch gestures in Windows 8 to Qt4.8. I think it
* may not be necessary for Qt5. I also think this was actually not absolutely
* necessary, and it may be possible to force Qt gesture recognition from plain
* touch input. --DeepSOIC
*/
#ifndef WINNATIVEGESTURERECOGNIZERS_H
#define WINNATIVEGESTURERECOGNIZERS_H
#include <QGestureRecognizer>
#include <QPinchGesture>
#ifdef Q_WS_WIN
#if QT_VERSION < 0x050000
#define GESTURE_MESS
#endif // QT_VERSION < 0x050000
#endif // Q_WS_WIN
#ifdef GESTURE_MESS
/*!
* \brief The QPinchGestureN class is a special version of QPinchGesture,
* containing a few extra fields for state tracking.
*/
class QPinchGestureN: public QPinchGesture
{
public:
int lastFingerDistance;//distance between fingers, in pixels
int fingerDistance;
double myRotationAngle;
double myLastRotationAngle;
};
class WinNativeGestureRecognizerPinch : public QGestureRecognizer
{
public:
WinNativeGestureRecognizerPinch(){}
virtual QGesture* create ( QObject* target );
virtual Result recognize ( QGesture* gesture, QObject* watched, QEvent* event );
virtual void reset ( QGesture* gesture );
static void TuneWindowsGestures(QWidget* target);
static double unbranchAngle(double ang);
};
#endif //GESTUREMESS
#endif // WINNATIVEGESTURERECOGNIZERS_H