diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 8ed6a32729..a37ccf65a6 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -769,6 +769,7 @@ SET(Inventor_CPP_SRCS SoNavigationDragger.cpp SoAxisCrossKit.cpp SoTextLabel.cpp + SoTouchEvents.cpp ) SET(Inventor_SRCS ${Inventor_CPP_SRCS} @@ -790,6 +791,7 @@ SET(Inventor_SRCS SoNavigationDragger.h SoAxisCrossKit.h SoTextLabel.h + SoTouchEvents.h ) SOURCE_GROUP("View3D\\Inventor" FILES ${Inventor_SRCS}) diff --git a/src/Gui/SoTouchEvents.cpp b/src/Gui/SoTouchEvents.cpp new file mode 100644 index 0000000000..37a38b9c54 --- /dev/null +++ b/src/Gui/SoTouchEvents.cpp @@ -0,0 +1,188 @@ +/*************************************************************************** + * 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" + +#include "SoTouchEvents.h" +#include +#include +#include + +SO_EVENT_SOURCE(SoGestureEvent); + +SbBool SoGestureEvent::isSoGestureEvent(const SoEvent *ev) const +{ + return ev->isOfType(SoGestureEvent::getClassTypeId()); +} + +//----------------------------SoGesturePanEvent-------------------------------- + +SO_EVENT_SOURCE(SoGesturePanEvent); + +SoGesturePanEvent::SoGesturePanEvent(QPanGesture* qpan, QWidget *widget) +{ + totalOffset = SbVec2f(qpan->offset().x(), -qpan->offset().y()); + deltaOffset = SbVec2f(qpan->delta().x(), -qpan->delta().y()); + state = SbGestureState(qpan->state()); + + Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); + this->setAltDown(mods.testFlag(Qt::AltModifier)); + this->setCtrlDown(mods.testFlag(Qt::ControlModifier)); + this->setShiftDown(mods.testFlag(Qt::ShiftModifier)); + this->setTime(SbTime::getTimeOfDay()); +} + +SbBool SoGesturePanEvent::isSoGesturePanEvent(const SoEvent *ev) const +{ + return ev->isOfType(SoGesturePanEvent::getClassTypeId()); +} + +//----------------------------SoGesturePinchEvent-------------------------------- + +SO_EVENT_SOURCE(SoGesturePinchEvent); + +SoGesturePinchEvent::SoGesturePinchEvent(QPinchGesture* qpinch, QWidget *widget) +{ + int h = widget->height(); + QPointF widgetCorner = QPointF(widget->mapToGlobal(QPoint(0,0))); + qreal scaleToWidget = (widget->mapFromGlobal(QPoint(800,800))-widget->mapFromGlobal(QPoint(0,0))).x()/800; + QPointF pnt;//temporary + pnt = qpinch->startCenterPoint(); + pnt = (pnt-widgetCorner)*scaleToWidget;//translate screen coord. into widget coord. + startCenter = SbVec2f(pnt.x(), h - pnt.y()); + + pnt = qpinch->centerPoint(); + pnt = (pnt-widgetCorner)*scaleToWidget; + curCenter = SbVec2f(pnt.x(), h - pnt.y()); + + pnt = qpinch->lastCenterPoint(); + pnt = (pnt-widgetCorner)*scaleToWidget; + deltaCenter = curCenter - SbVec2f(pnt.x(), h - pnt.y()); + + deltaZoom = qpinch->scaleFactor(); + totalZoom = qpinch->totalScaleFactor(); + + deltaAngle = qpinch->rotationAngle(); + totalAngle = qpinch->totalRotationAngle(); + + state = SbGestureState(qpinch->state()); + + this->setPosition(SbVec2s(curCenter)); + Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); + this->setAltDown(mods.testFlag(Qt::AltModifier)); + this->setCtrlDown(mods.testFlag(Qt::ControlModifier)); + this->setShiftDown(mods.testFlag(Qt::ShiftModifier)); + this->setTime(SbTime::getTimeOfDay()); +} + +SbBool SoGesturePinchEvent::isSoGesturePinchEvent(const SoEvent *ev) const +{ + return ev->isOfType(SoGesturePinchEvent::getClassTypeId()); +} + +//----------------------------SoGestureSwipeEvent-------------------------------- + +SO_EVENT_SOURCE(SoGestureSwipeEvent); + +SoGestureSwipeEvent::SoGestureSwipeEvent(QSwipeGesture *qwsipe, QWidget *widget) +{ + angle = qwsipe->swipeAngle(); + switch (qwsipe->verticalDirection()){ + case QSwipeGesture::Up : + vertDir = +1; + break; + case QSwipeGesture::Down : + vertDir = -1; + break; + default: + vertDir = 0; + break; + } + switch (qwsipe->horizontalDirection()){ + case QSwipeGesture::Right : + vertDir = +1; + break; + case QSwipeGesture::Left : + vertDir = -1; + break; + default: + vertDir = 0; + break; + } + + state = SbGestureState(qwsipe->state()); + + Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); + this->setAltDown(mods.testFlag(Qt::AltModifier)); + this->setCtrlDown(mods.testFlag(Qt::ControlModifier)); + this->setShiftDown(mods.testFlag(Qt::ShiftModifier)); + this->setTime(SbTime::getTimeOfDay()); +} + +SbBool SoGestureSwipeEvent::isSoGestureSwipeEvent(const SoEvent *ev) const +{ + return ev->isOfType(SoGestureSwipeEvent::getClassTypeId()); +} + + +//----------------------------GesturesDevice------------------------------- + +GesturesDevice::GesturesDevice(QWidget* widget) +{ + if (SoGestureEvent::getClassTypeId().isBad()){ + SoGestureEvent::initClass(); + SoGesturePanEvent::initClass(); + SoGesturePinchEvent::initClass(); + SoGestureSwipeEvent::initClass(); + } + if (! widget) + throw Base::Exception("Can't create a gestures quarter input device without widget (null pointer was passed)."); + this->widget = widget; +} + +const SoEvent* GesturesDevice::translateEvent(QEvent* event) +{ + if (event->type() == QEvent::Gesture + || event->type() == QEvent::GestureOverride) { + QGestureEvent* gevent = static_cast(event); + + QPinchGesture* zg = static_cast(gevent->gesture(Qt::PinchGesture)); + if(zg){ + gevent->setAccepted(Qt::PinchGesture,true);//prefer it over pan + return new SoGesturePinchEvent(zg,this->widget); + } + + QPanGesture* pg = static_cast(gevent->gesture(Qt::PanGesture)); + if(pg){ + gevent->setAccepted(Qt::PanGesture,true); + return new SoGesturePanEvent(pg,this->widget); + } + + QSwipeGesture* sg = static_cast(gevent->gesture(Qt::SwipeGesture)); + if(sg){ + gevent->setAccepted(Qt::SwipeGesture,true); + return new SoGesturePanEvent(pg,this->widget); + } + } + return 0; +} diff --git a/src/Gui/SoTouchEvents.h b/src/Gui/SoTouchEvents.h new file mode 100644 index 0000000000..5422939d6a --- /dev/null +++ b/src/Gui/SoTouchEvents.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * 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 * + * * + ***************************************************************************/ + +#ifndef SOTOUCHEVENTS_H +#define SOTOUCHEVENTS_H + +#include +#include +#include +#include +namespace Quarter = SIM::Coin3D::Quarter; + +class SoGestureEvent : public SoEvent { + SO_EVENT_HEADER(); +public: + static void initClass(){ + SO_EVENT_INIT_CLASS(SoGestureEvent, SoEvent); + }; + SoGestureEvent(){}; + ~SoGestureEvent(){}; + SbBool isSoGestureEvent(const SoEvent* ev) const; + + enum SbGestureState { + SbGSNoGesture = Qt::NoGesture, + SbGSStart = Qt::GestureStarted, + SbGSUpdate = Qt::GestureUpdated, + SbGSEnd = Qt::GestureFinished, + SbGsCanceled = Qt::GestureCanceled + }; + SbGestureState state; +}; + +class SoGesturePanEvent : public SoGestureEvent { + SO_EVENT_HEADER(); +public: + static void initClass(){//needs to be called before the class can be used. Initializes type IDs of the class. + SO_EVENT_INIT_CLASS(SoGesturePanEvent, SoGestureEvent); + }; + SoGesturePanEvent() {}; + SoGesturePanEvent(QPanGesture *qpan, QWidget *widget); + ~SoGesturePanEvent(){}; + SbBool isSoGesturePanEvent(const SoEvent* ev) const; + + SbVec2f deltaOffset; + SbVec2f totalOffset; +}; + +class SoGesturePinchEvent : public SoGestureEvent { + SO_EVENT_HEADER(); +public: + static void initClass(){ + SO_EVENT_INIT_CLASS(SoGesturePinchEvent, SoGestureEvent); + }; + SoGesturePinchEvent(){}; + SoGesturePinchEvent(QPinchGesture* qpinch, QWidget* widget); + ~SoGesturePinchEvent(){}; + SbBool isSoGesturePinchEvent(const SoEvent* ev) const; + + SbVec2f startCenter;//in GL pixel coordinates (from bottom left corner of view area) + SbVec2f curCenter; + SbVec2f deltaCenter; + double deltaZoom;//change of zoom factor (1.0 = no change, >1 - zoom in, 0..1 - zoom out) + double totalZoom;//zoom factor accumulated since start of gesture. + double deltaAngle; + double totalAngle; + +}; + +class SoGestureSwipeEvent : public SoGestureEvent { + SO_EVENT_HEADER(); +public: + static void initClass(){ + SO_EVENT_INIT_CLASS(SoGestureSwipeEvent, SoGestureEvent); + }; + SoGestureSwipeEvent(){}; + SoGestureSwipeEvent(QSwipeGesture* qwsipe, QWidget *widget); + ~SoGestureSwipeEvent(){}; + SbBool isSoGestureSwipeEvent(const SoEvent* ev) const; + + double angle; + int vertDir;//+1,0,-1 up/none/down + int horzDir;//+1,0,-1 right/none/left +}; + + +class GesturesDevice : public Quarter::InputDevice { +public: + GesturesDevice(QWidget* widget);//it needs to know the widget to do coordinate translation + + virtual ~GesturesDevice() {} + virtual const SoEvent* translateEvent(QEvent* event); +protected: + QWidget* widget; +}; + +#endif // SOTOUCHEVENTS_H diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 6860b3f581..79db2b1197 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -123,6 +123,7 @@ #include #include +#include #include #include @@ -482,6 +483,7 @@ void View3DInventorViewer::init() viewerEventFilter = new ViewerEventFilter; installEventFilter(viewerEventFilter); getEventFilter()->registerInputDevice(new SpaceNavigatorDevice); + getEventFilter()->registerInputDevice(new GesturesDevice(this)); this->grabGesture(Qt::PanGesture); this->grabGesture(Qt::PinchGesture);