changeset 403:44cef6368690

Ensure drags are constrained to either horizontal or vertical once the user's primary direction has become clear, switching to free drag only if the user makes a big move in the other axis
author Chris Cannam
date Wed, 25 May 2011 16:16:01 +0100
parents 75003687f364
children 9510a32a96ab
files src/panned.cpp src/panned.h
diffstat 2 files changed, 69 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/panned.cpp	Wed May 25 16:05:40 2011 +0100
+++ b/src/panned.cpp	Wed May 25 16:16:01 2011 +0100
@@ -174,12 +174,55 @@
         ev->accept();
         m_dragging = true;
         m_lastDragPos = ev->pos();
+        m_lastDragStart = ev->pos();
         m_lastOrigin = QPoint(horizontalScrollBar()->value(),
                               verticalScrollBar()->value());
         m_velocity = QPointF(0, 0);
         m_dragTimer->start(m_dragTimerMs);
+        m_dragDirection = UnknownDrag;
+    }
+}
+
+void
+Panned::updateDragDirection(QPoint pos)
+{
+    if (m_dragDirection == FreeDrag) {
+        return;
     }
 
+    QPoint overall = pos - m_lastDragStart;
+
+    int smallThreshold = 10;
+    int largeThreshold = 30;
+    int dx = qAbs(overall.x());
+    int dy = qAbs(overall.y());
+
+    switch (m_dragDirection) {
+
+    case UnknownDrag:
+        if (dx > smallThreshold) {
+            if (dy > smallThreshold) {
+                m_dragDirection = FreeDrag;
+            } else {
+                m_dragDirection = HorizontalDrag;
+            }
+        } else if (dy > smallThreshold) {
+            m_dragDirection = VerticalDrag;
+        }
+        break;
+
+    case HorizontalDrag:
+        if (dy > largeThreshold) {
+            m_dragDirection = FreeDrag;
+        }
+        break;
+
+    case VerticalDrag:
+        if (dx > largeThreshold) {
+            m_dragDirection = FreeDrag;
+        }
+        break;
+    };
 }
 
 void
@@ -191,11 +234,17 @@
     }
     DEBUG << "Panned::mouseMoveEvent: dragging" << endl;
     ev->accept();
+    updateDragDirection(ev->pos());
     QScrollBar *hBar = horizontalScrollBar();
     QScrollBar *vBar = verticalScrollBar();
     QPoint delta = ev->pos() - m_lastDragPos;
-    hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
-    vBar->setValue(vBar->value() - delta.y());
+    if (m_dragDirection != VerticalDrag) {
+        hBar->setValue(hBar->value() +
+                       (isRightToLeft() ? delta.x() : -delta.x()));
+    }
+    if (m_dragDirection != HorizontalDrag) {
+        vBar->setValue(vBar->value() - delta.y());
+    }
     m_lastDragPos = ev->pos();
 }
 
@@ -235,10 +284,14 @@
         DEBUG << "Panned::dragTimerTimeout: velocity adjusted to " << m_velocity << endl;
         m_lastOrigin = origin;
         //!!! need to store origin in floats
-        horizontalScrollBar()->setValue(m_lastOrigin.x() +
-                                        m_velocity.x() * m_dragTimerMs);
-        verticalScrollBar()->setValue(m_lastOrigin.y() +
-                                      m_velocity.y() * m_dragTimerMs);
+        if (m_dragDirection != VerticalDrag) {
+            horizontalScrollBar()->setValue(m_lastOrigin.x() +
+                                            m_velocity.x() * m_dragTimerMs);
+        }
+        if (m_dragDirection != HorizontalDrag) {
+            verticalScrollBar()->setValue(m_lastOrigin.y() +
+                                          m_velocity.y() * m_dragTimerMs);
+        }
     }
 }
 
--- a/src/panned.h	Wed May 25 16:05:40 2011 +0100
+++ b/src/panned.h	Wed May 25 16:16:01 2011 +0100
@@ -54,12 +54,22 @@
     QRectF m_pannedRect;
 
     QPoint m_lastDragPos;
+    QPoint m_lastDragStart;
     QPoint m_lastOrigin;
     QPointF m_velocity;
     bool m_dragging;
     int m_dragTimerMs;
     QTimer *m_dragTimer;
 
+    enum DragDirection {
+        UnknownDrag,
+        HorizontalDrag,
+        VerticalDrag,
+        FreeDrag
+    };
+    DragDirection m_dragDirection;
+    void updateDragDirection(QPoint);
+
     virtual void mousePressEvent(QMouseEvent *);
     virtual void mouseMoveEvent(QMouseEvent *);
     virtual void mouseReleaseEvent(QMouseEvent *);