qstmgesturelib/qstmgestureevent.cpp
changeset 16 3c88a81ff781
parent 3 0954f5dd2cd0
--- a/qstmgesturelib/qstmgestureevent.cpp	Thu Sep 23 15:32:11 2010 -0400
+++ b/qstmgesturelib/qstmgestureevent.cpp	Fri Oct 15 17:30:59 2010 -0400
@@ -19,14 +19,97 @@
 *
 */
 
-#include <QWidget>
-#include <QApplication>
 #include "qstmgestureevent.h"
 #include "qstmuievent_if.h"
 
+#include <QGraphicsSceneMouseEvent>
+
 using namespace qstmUiEventEngine;
+using namespace qstmGesture;
+
+static Qt::GestureType s_assignedType = Qt::CustomGesture;
+static int s_stmGestureEventType = QEvent::User;
+static QGraphicsItem* s_gestureGrabberItem = NULL;
+static QGraphicsItem* s_gestureFocusedItem = NULL;
+
+
+QStm_GestureEventFilter* QStm_GestureEventFilter::m_instance = 0;
+
+QStm_GestureEventFilter* QStm_GestureEventFilter::instance()
+{
+    if (!m_instance) {
+        m_instance = new QStm_GestureEventFilter();
+    }
+    return m_instance;
+}
+
+bool QStm_GestureEventFilter::eventFilter(QObject* receiver, QEvent* evt)
+{
+    return qstmIsGraphicsSceneMouseEvent(evt) || qstmIsMouseEvent(evt) || 
+           qstmIsTouchEvent(evt) || qstmIsContextMenuEvent(evt);
+}
+
+
+
+
+bool QStm_GestureEventFilter::sendGraphicsSceneMouseEvent(QEvent* event, QGraphicsObject* go)
+{
+    bool ret = false;
+    if (event->type() == QEvent::Gesture) {
+        QStm_Gesture* gesture = getQStmGesture(event);
+        if (gesture) {
+            ret = gesture->sendGraphicsSceneMouseEvent(go);
+        }
+
+    }
+    return ret;
+}
+
 
-Qt::GestureType QStm_Gesture::s_assignedType = Qt::CustomGesture;
+bool QStm_GestureEventFilter::event(QEvent* event)
+{
+    if (event->type() == QEvent::Gesture) {
+        QStm_Gesture* gesture = getQStmGesture(event);
+        if (gesture) {
+            QStm_GestureType gtype = gesture->getGestureStmType();
+            
+            /*
+             * Touch mapped to mouse press, Tap mapped to mouse release
+             * UpDown, LeftRight and Pan are mapped to mouse move.
+             */
+            if (gtype == QStmMaybeTapGestureType) {// in case of tap send mouse release
+                gesture->setGestureStmType(QStmReleaseGestureType);
+            }
+            
+            bool ret = (gtype == QStmTouchGestureType ||
+                        gtype == QStmMaybeTapGestureType ||
+                        gtype == QStmLeftRightGestureType || 
+                        gtype == QStmUpDownGestureType ||
+                        gtype == QStmPanGestureType ||
+                        gtype == QStmReleaseGestureType ||
+                        gtype == QStmFlickGestureType ||
+                        gtype == QStmUknownGestureType) ;
+                         
+            if (ret) {
+                gesture->sendMouseEvents();
+                (static_cast<QGestureEvent*>(event))->accept(QStm_Gesture::assignedType());
+                (static_cast<QGestureEvent*>(event))->accept();
+            }
+            
+            if (gtype == QStmTapGestureType) {// restore gesture type. 
+                gesture->setGestureStmType(QStmTapGestureType);
+            }
+            
+            return ret;
+        }
+    }
+    return false;
+}
+
+
+
+
+
 
 QStm_GestureEvent::QStm_GestureEvent():
                    QEvent(QStm_GestureEvent::stmGestureEventType())
@@ -39,8 +122,47 @@
 }
 
 
+QEvent::Type QStm_GestureEvent::stmGestureEventType() 
+{ 
+    if (s_stmGestureEventType == QEvent::User) {
+        s_stmGestureEventType = QEvent::registerEventType(QStmGestureEventType);    
+    }
+    return static_cast<QEvent::Type>(QStmGestureEventType); 
+}
+
+
+
+void QStm_Gesture::setAssignedGestureType(Qt::GestureType type) 
+{ 
+    s_assignedType = type; 
+}
+
+Qt::GestureType QStm_Gesture::assignedType() 
+{ 
+    return s_assignedType; 
+} 
 
 
+QGraphicsItem* QStm_Gesture::gestureGrabberItem()
+{ 
+    return s_gestureGrabberItem; 
+}
+
+void QStm_Gesture::setGestureGrabberItem(QGraphicsItem* item)
+{ 
+    s_gestureGrabberItem = item; 
+}
+
+
+QGraphicsItem* QStm_Gesture::gestureFocusedItem()
+{
+    return s_gestureFocusedItem;
+}
+
+void QStm_Gesture::setGestureFocusedItem(QGraphicsItem* item)
+{
+    s_gestureFocusedItem = item;
+}
 
 QStm_Gesture::QStm_Gesture(QObject* parent) : QGesture(parent)
 {
@@ -51,9 +173,11 @@
 	    m_state = Qt::NoGesture;
 	    m_gstSubType = 0;
 	    m_pos = QPoint(INT_MIN,INT_MIN);
+        m_pos2 = QPoint(INT_MIN,INT_MIN);
 	    m_details = NULL;
 	    m_speedVec = QPointF(0.0, 0.0);
 	    m_target = NULL;
+        m_timestamp = QTime::currentTime();
 };
 
 
@@ -66,9 +190,12 @@
     m_state = other.gestureState();
     m_gstSubType = other.getGestureSubType();
     m_pos = other.position();
+    m_pos2 = other.position2();
     m_details = other.getDetails();
     m_speedVec = other.getSpeedVec();
-    m_target = other.m_target;
+    m_target = other.target();
+    m_timestamp = other.timestamp();
+    setHotSpot(other.hotSpot());
 	return *this;
 }
 
@@ -109,6 +236,104 @@
     }	
 }
 
+
+
+QStm_GestureType  QStm_Gesture::gestureUidToStmType(QStm_GestureUid uid, int stmGestSubType)
+{
+    QStm_GestureType  gtype = QStmUknownGestureType;
+    
+    switch (uid) {
+        case EGestureUidTap:
+        {
+            QStm_TapType type = qstmGesture::QStm_TapType(stmGestSubType);
+            if (type == qstmGesture::ETapTypeDouble) {
+                gtype = QStmDoubleTapGestureType;
+            }
+            else  {
+                gtype = QStmTapGestureType;
+            }
+            break;
+        }
+
+        case EGestureUidTouch:
+        {
+            gtype = QStmTouchGestureType;
+            break;
+        }
+
+        case EGestureUidRelease:
+        {
+            gtype = QStmReleaseGestureType;
+            break;
+        }
+
+        case EGestureUidFlick:
+        {
+            gtype = QStmFlickGestureType;
+            break;
+        }
+
+        case EGestureUidLeftRight:
+        {
+            gtype = QStmLeftRightGestureType;
+            break;
+        }
+
+        case EGestureUidUpDown:
+        {
+            gtype = QStmUpDownGestureType;
+            break;
+        }
+
+        case EGestureUidPan:
+        {
+            gtype = QStmPanGestureType;
+            break;
+        }
+
+        case EGestureUidHover:
+        {
+            gtype = QStmHoverGestureType;
+            break;
+        }
+
+        case EGestureUidLongPress:
+        {
+            gtype = QStmLongPressGestureType;
+            break;
+        }
+
+        case EGestureUidEdgeScroll:
+        {
+            gtype = QStmEdgeScrollGestureType;
+            break;
+        }
+
+        case EGestureUidCornerZoom:
+        {
+            gtype = QStmCornerZoomGestureType;
+            break;
+        }
+
+        case EGestureUidPinch:
+        {
+            gtype = QStmPinchGestureType;
+            break;
+        }
+        case EGestureUidMaybeTap:
+        {
+            gtype = QStmMaybeTapGestureType;
+            break;
+        }
+        default:
+        {
+            gtype = QStmUknownGestureType;
+            break;
+        }
+    }    
+    return gtype;
+}
+
 void QStm_Gesture::gestureTypeToMouseTypes(QVarLengthArray<int, 4>& types)
 {
 	switch (m_gstType) {
@@ -133,11 +358,13 @@
 			break;
 		}
 		case QStmReleaseGestureType:
+		case QStmFlickGestureType:
 		{
 			types.append(QEvent::MouseButtonRelease);
 			break;
 		}
 		case QStmTapGestureType:
+        //case QStmMaybeTapGestureType:
 		{
 			types.append(QEvent::MouseButtonPress);
 			types.append(QEvent::MouseButtonRelease); 
@@ -152,7 +379,6 @@
 		    }
 		    break;
 		}
-		case QStmFlickGestureType:
 		case QStmEdgeScrollGestureType:
 		case QStmPinchGestureType:
 		case QStmLongPressGestureType:
@@ -162,6 +388,9 @@
 	return;
 }
 
+
+
+
 bool QStm_Gesture::sendOrPostMouseEvents(QObject* receiver, Qt::KeyboardModifier modifier, bool send)
 {
     bool ret = false;
@@ -176,25 +405,37 @@
     buttons &= Qt::MouseButtonMask;
     
     if (receiver->isWidgetType()) {
-    	QWidget* w = static_cast<QWidget*>(receiver);
+        w = static_cast<QWidget*>(receiver);
     	pos = w->mapFromGlobal(gpos);
     }    
     
+
     QVarLengthArray<int, 4> mouseTypes;
     gestureTypeToMouseTypes(mouseTypes);   
     
     for (int i = 0; i < mouseTypes.size(); i++) {
     	QEvent::Type mtype = static_cast<QEvent::Type>(mouseTypes[i]);
-    	
+
+        if (mtype == QEvent::None) {
+            continue;
+        }
+        else if (mtype != QEvent::MouseButtonRelease && w) {
+            QPoint wtl = w->mapToGlobal(w->pos());
+            QRect wgeom = QRect(wtl, w->size());
+            if (!wgeom.contains(m_pos)) {
+                continue;
+            }
+        }
+
     	if (mtype == QEvent::MouseButtonRelease) {
     		buttons = 0;
     	}
     	
     	if (send) {
     	    QMouseEvent evt(mtype, pos, gpos, Qt::LeftButton, buttons, modifier);
-    	    if (w) w->grabMouse();
+            //if (w) w->grabMouse();
     	    QApplication::sendEvent(receiver, &evt);
-    	    if (w) w->releaseMouse();
+            //if (w) w->releaseMouse();
     	}
     	else {
     		QMouseEvent* evt = new QMouseEvent(mtype, pos, gpos, Qt::LeftButton, buttons, modifier);
@@ -210,6 +451,13 @@
 {
     QWidget* target = static_cast<QWidget*>(m_target);
     QWidget* w = NULL;
+    QWidget* modal = QApplication::activeModalWidget();
+
+    
+    
+    if (modal) {
+        target = modal;
+    }
     
     if (target) {
         QPoint pos = target->mapFromGlobal(m_pos);
@@ -220,26 +468,97 @@
     }
     
     if (w) {
-        if (event->type() == QStm_GestureEvent::stmGestureEventType() && 
+        if (modal) { //we send mouse events to modal dialogs.
+            return(sendMouseEvents(w));
+        }
+        /*
+        else if (event->type() == QStm_GestureEvent::stmGestureEventType() && 
             m_gstType == QStmUknownGestureType) {
             QStm_UiEventIf* uiEvent = static_cast<QStm_UiEventIf*>(m_details);
-            QWidget* modal = QApplication::activeModalWidget();
+            
             if (uiEvent && m_target == modal) {
             //re-generate mouse events
-                sendMouseEvents(w);
+                return(sendMouseEvents(w));
             }
-        }        
+
         else {
-            QApplication::sendEvent(w, event);
+                return(QApplication::sendEvent(w, event));
+        }
+    }
+		*/
+        else {
+            if (!target->hasFocus()) {
+                target->setFocus(Qt::MouseFocusReason);
+            }
+            return(QApplication::sendEvent(w, event));
         }
     }
+    return false;
+}
+
+
+bool QStm_Gesture::sendGraphicsSceneMouseEvent(QGraphicsObject* go)
+{
+    QEvent::Type eventType = gestureType2GraphicsSceneMouseType();
+    bool ret = false;
+
+    if (eventType != QEvent::None) {
+        QGraphicsSceneMouseEvent gsme(eventType);
+        QPointF scenePos = qstmMapToScene(m_pos, go);
+        qstmSetGraphicsSceneMouseEvent(scenePos, go, gsme);
+        ret = go->event(&gsme);
+    }
+    return ret;
 }
 
 
+QEvent::Type QStm_Gesture::gestureType2GraphicsSceneMouseType()
+{
+    QEvent::Type type = QEvent::None;
+    switch(m_gstType)
+    {
+        case QStmTouchGestureType:
+            type = QEvent::GraphicsSceneMousePress;
+            break;
+        case QStmMaybeTapGestureType:
+        case QStmReleaseGestureType:
+        case QStmFlickGestureType:
+            type = QEvent::GraphicsSceneMouseRelease;
+            break;
+        case QStmLeftRightGestureType:
+        case QStmUpDownGestureType:
+        case QStmPanGestureType:
+            type = QEvent::GraphicsSceneMouseMove;
+            break;
+        case  QStmUknownGestureType:
+        {
+            QVarLengthArray<int, 4> mouseTypes;
+            gestureTypeToMouseTypes(mouseTypes);
+            switch (mouseTypes[0])
+            {
+                case QEvent::MouseButtonPress:
+                    type = QEvent::GraphicsSceneMousePress;
+                    break;
+                case QEvent::MouseButtonRelease:
+                    type = QEvent::GraphicsSceneMouseRelease;
+                    break;
+                case QEvent::MouseMove:
+                    type = QEvent::GraphicsSceneMouseMove;
+                    break;
+            }
+        }
+    }
+    return type;
+}
+
 bool QStm_Gesture::sendMouseEvents(Qt::KeyboardModifier modifier)
 {
-    Q_ASSERT(m_target);
     QWidget* target = static_cast<QWidget*>(m_target);
+
+    if (!target) {
+        target = QApplication::widgetAt(m_pos);
+    }
+    if (!target) return false;
     QPoint pos = target->mapFromGlobal(m_pos);
     QWidget* w = target->childAt(pos);
     if (!w) {
@@ -283,6 +602,160 @@
 }
 
 
+bool QStm_Gesture::isGestureEnded()
+{
+    bool gestureEnded = false;
+    
+    if (m_gstType == QStmUknownGestureType) {
+        QStm_UiEventIf* uiEvent = static_cast<QStm_UiEventIf*>(m_details);
+        if (uiEvent) {
+            QEvent::Type evType = uiEvent->mapToMouseEventType();
+            gestureEnded = (evType == ERelease);
+        }
+    }
+    else if (m_gstType == QStmReleaseGestureType ||
+             m_gstType == QStmFlickGestureType ||
+             m_gstType == QStmTapGestureType ||
+             m_gstType == QStmDoubleTapGestureType) {
+        gestureEnded = true;
+    }
+    return gestureEnded;
+}
+
+bool QStm_Gesture::clearGestureFocusedItemIfNeeded()
+{
+    bool reset = isGestureEnded();
+    if (reset) {
+        QStm_Gesture::setGestureFocusedItem(NULL);
+    }
+    return reset;
+}
+
+void QStm_Gesture::updateGestureFocusedItemIfNeeded(QGraphicsItem* gi)
+{
+    if (isGestureEnded()) {
+        QStm_Gesture::setGestureFocusedItem(NULL);        
+    }
+    else if (gestureState() != Qt::GestureFinished) { 
+        QStm_Gesture::setGestureFocusedItem(gi);
+    }    
+}
+
+QPointF QStm_Gesture::scenePosition(QGraphicsItem* i)
+{
+    return qstmMapToScene(m_pos, static_cast<QGraphicsObject*>(i));
+}
+
+QPointF QStm_Gesture::scenePosition2(QGraphicsItem* i)
+{
+    return qstmMapToScene(m_pos2, static_cast<QGraphicsObject*>(i));
+}
+
+QPointF QStm_Gesture::sceneSpeedVec(QGraphicsItem* i)
+{
+    QGraphicsObject* o = static_cast<QGraphicsObject*>(i);
+
+    return qstmMapToScene(m_speedVec,o) - qstmMapToScene(QPointF(0, 0), o);
+}
+
+QPointF QStm_Gesture::sceneLengthAndDirection(QGraphicsItem* i)
+{
+    QGraphicsObject* o = static_cast<QGraphicsObject*>(i);
+
+    return qstmMapToScene(QPointF(-m_vector.x(), m_vector.y()),o) - qstmMapToScene(QPointF(0, 0), o);
+}
+
+int QStm_Gesture::sceneDirection(QGraphicsItem *i)
+{
+    QStm_GestureDirection dir = ENorth ;
+    QPointF v = sceneLengthAndDirection(i);
+
+    qreal x = qAbs(v.x()) ;
+    qreal y = qAbs(v.y()) ;
+
+    if (y == 0 && x == 0) {
+        dir = ENoDirection;
+    }
+    else if (y <= x/2) {
+        if (v.x() < 0)
+            dir = EWest ;
+        else
+            dir = EEast ;
+    }
+    else if (y > x/2 && y <= (x+x/2)) {
+        if (v.x() < 0)  {
+            if (v.y() < 0 )
+                dir = ESouthWest ;
+            else
+                dir = ENorthWest ;
+        }
+        else {
+            if (v.y() < 0 )
+                dir = ESouthEast ;
+            else
+                dir = ENorthEast ;
+        }
+    }
+    else if (y > x+x/2) {
+        if (v.y() < 0)
+            dir = ESouth ;
+        else
+            dir = ENorth ;
+    }
+
+    return dir ;
+}
+
+QSTMGESTURELIB_EXPORT QPoint qstmMapFromScene(const QPointF& gpos, QGraphicsObject* graphicsObj)
+{
+    QGraphicsView* grView = qstmGetGraphicsView(graphicsObj);
+    QPointF pos = QPointF(0.0, 0.0);
+    if (grView) {
+        pos = grView->mapFromScene(gpos);
+        return grView->mapToGlobal(pos.toPoint());
+    }
+    return QPoint(0, 0);
+}
+
+
+QSTMGESTURELIB_EXPORT QPointF qstmMapToScene(const QPointF& gpos, QGraphicsObject* graphicsObj)
+{
+    QGraphicsView* grView = qstmGetGraphicsView(graphicsObj);
+    QPointF pos = QPointF(0.0, 0.0);
+    if (grView) {
+        pos = grView->mapFromGlobal(gpos.toPoint());
+        pos = grView->mapToScene(pos.toPoint());
+    }
+    return pos;
+}
+
+
+QSTMGESTURELIB_EXPORT QPointF qstmMapFromGlobal(const QPointF& gpos, QGraphicsObject* graphicsObj)
+{
+    QGraphicsView* grView = qstmGetGraphicsView(graphicsObj);
+    QPointF pos = QPointF(0.0, 0.0);
+    if (grView) {
+        pos = grView->mapFromGlobal(gpos.toPoint());
+    }
+    return pos;
+}
+
+QSTMGESTURELIB_EXPORT QGraphicsView* qstmGetGraphicsView(QGraphicsObject* graphicsObj)
+{
+    QGraphicsScene* scene = graphicsObj->scene();
+    QList<QGraphicsView*> gvList = scene->views();
+    QList<QGraphicsView*>::iterator it;
+    
+    /*
+    for (it = gvList.begin(); it != gvList.end(); it++) {
+        if (static_cast<QGraphicsView*>(*it)->hasFocus()) {
+            return static_cast<QGraphicsView*>(*it);
+        }
+    }
+    */
+    return gvList.isEmpty() ? NULL : gvList[0];
+}
+
 QSTMGESTURELIB_EXPORT QStm_Gesture*  getQStmGesture(QEvent* event)
 {	
 	QStm_Gesture* gesture = NULL;
@@ -297,3 +770,120 @@
 	return gesture;
 }
 
+QSTMGESTURELIB_EXPORT bool qstmDeliverGestureEventToGraphicsItem(QGraphicsView* gv, QEvent* event)
+{
+    if (event->type() != QEvent::Gesture) return false;
+    
+    bool ret = false;
+    QStm_Gesture* gesture = getQStmGesture(event);
+    if (gesture) {
+
+        QGraphicsScene* gs = gv->scene();
+        QGraphicsItem* gestureGrabber = QStm_Gesture::gestureGrabberItem();
+        QGraphicsItem* gi = QStm_Gesture::gestureFocusedItem();
+        QGraphicsItem* mgItem = gs->mouseGrabberItem();
+        
+        if (gestureGrabber) {
+            gs->sendEvent(gestureGrabber, event);
+            ret = true; //no fallback to mouse events   
+        }
+        else {
+            if (!gi) {
+                gi = mgItem;
+            }
+            if (!gi) {
+                QPoint pos = gv->mapFromGlobal(gesture->position());
+                pos = gv->mapToScene(pos).toPoint();
+                QList<QGraphicsItem *> itemsList = gs->items(pos, Qt::IntersectsItemShape,
+                                                             Qt::DescendingOrder);
+                for(int i = 0; i < itemsList.size(); i++) {
+
+                    if (itemsList[i] && (itemsList[i])->opacity() < qreal(0.001)) {
+                        continue;
+                    }
+                    gi = itemsList[i];
+                    gs->setFocusItem(gi, Qt::MouseFocusReason);
+                    break;
+                }
+            }
+            if (gi) {
+                //gs->setFocusItem(gi, Qt::MouseFocusReason);
+                //ret = gs->sendEvent(gi, event);
+                //gs->setFocusItem(0, Qt::MouseFocusReason);
+
+                QGraphicsObject* go = gi->toGraphicsObject();
+                if (go) {
+                    ret = go->event(event);
+                }
+
+            }
+        }
+        
+        if (!ret) { // fallback to mouse events
+            QStm_GestureEventFilter::instance()->event(event);
+            ret = true;
+        }
+        else if (!gestureGrabber) {
+            gesture->updateGestureFocusedItemIfNeeded(gi);
+        }
+    }
+    return ret;
+}
+
+
+QSTMGESTURELIB_EXPORT void qstmSetGraphicsSceneMouseEvent(const QPointF& scenePos, QGraphicsObject* graphicsObj,
+                                                         QGraphicsSceneMouseEvent& event, bool select)
+{
+    QPointF pos = scenePos;
+    QPoint gpos = qstmMapFromScene(pos, graphicsObj);
+
+    event.setScenePos(pos);
+    event.setScreenPos(gpos);
+    event.setPos(graphicsObj->mapFromScene(pos));
+    if (!select && event.type() != QEvent::GraphicsSceneMouseMove) {
+        event.setButton(Qt::LeftButton);
+    }
+    else {
+        event.setButton(Qt::NoButton);
+    }
+    if (!select) {
+        event.setButtons(Qt::NoButton);
+    }
+    else {
+        event.setButtons(Qt::LeftButton);
+    }
+    event.setModifiers(Qt::NoModifier);
+}
+
+QSTMGESTURELIB_EXPORT bool qstmIsGraphicsSceneMouseEvent(QEvent* event)
+{
+    QEvent::Type  type = event->type();
+    return type == QEvent::GraphicsSceneMouseMove ||
+           type == QEvent::GraphicsSceneMousePress ||
+           type == QEvent::GraphicsSceneMouseRelease ||
+           type == QEvent::GraphicsSceneMouseDoubleClick;
+}
+
+QSTMGESTURELIB_EXPORT bool qstmIsMouseEvent(QEvent* event)
+{
+    QEvent::Type  type = event->type();
+    return type == QEvent::MouseButtonPress ||
+           type == QEvent::MouseButtonRelease ||
+           type == QEvent::MouseMove ||
+           type == QEvent::MouseButtonDblClick;
+}
+
+QSTMGESTURELIB_EXPORT bool qstmIsTouchEvent(QEvent* event)
+{
+    QEvent::Type  type = event->type();
+    return type == QEvent::TouchBegin ||
+           type == QEvent::TouchEnd ||
+           type == QEvent::TouchUpdate;
+}
+
+QSTMGESTURELIB_EXPORT bool qstmIsContextMenuEvent(QEvent* event)
+{
+    QEvent::Type  type = event->type();
+    return type == QEvent::ContextMenu ||
+           type == QEvent::GraphicsSceneContextMenu;
+}