]> git.tdb.fi Git - libs/gui.git/blobdiff - source/input/gesturedetector.cpp
Add missing initializer
[libs/gui.git] / source / input / gesturedetector.cpp
index d626c5d08efc6dcbd909083651045c7f056c98db..49ddba2b8478173dfbd65b9e80233ab356c0da03 100644 (file)
@@ -1,3 +1,4 @@
+#define _USE_MATH_DEFINES
 #include <cmath>
 #include <sigc++/bind_return.h>
 #include "gesturedetector.h"
@@ -12,6 +13,7 @@ GestureDetector::GestureDetector(Touchscreen &ts):
        touchscreen(ts),
        current_gesture(GESTURE_NONE),
        active_points(0),
+       pending_tap(GESTURE_NONE),
        invalid_gesture(false)
 {
        name = "Gesture";
@@ -26,16 +28,14 @@ GestureDetector::GestureDetector(Touchscreen &ts):
 
 string GestureDetector::get_button_name(unsigned btn) const
 {
-       if(btn==GESTURE_SWIPE_DOWN)
-               return "Swipe down";
-       else if(btn==GESTURE_SWIPE_UP)
-               return "Swipe up";
-       else if(btn==GESTURE_SWIPE_LEFT)
-               return "Swipe left";
-       else if(btn==GESTURE_SWIPE_RIGHT)
-               return "Swipe right";
+       if(btn==GESTURE_DRAG)
+               return "Drag";
+       else if(btn==GESTURE_DRAG_2)
+               return "Two-finger drag";
        else if(btn==GESTURE_PINCH)
                return "Pinch";
+       else if(btn==GESTURE_ROTATE)
+               return "Rotate";
        else
                return Device::get_button_name(btn);
 }
@@ -64,6 +64,14 @@ void GestureDetector::touch_down(unsigned btn)
        p.x = 0;
        p.y = 0;
        p.threshold_exceeded = false;
+
+       if(current_gesture==GESTURE_NONE && !invalid_gesture)
+       {
+               if(btn==0)
+                       pending_tap = GESTURE_TAP;
+               else if(btn==1)
+                       pending_tap = GESTURE_TAP_2;
+       }
 }
 
 void GestureDetector::touch_up(unsigned btn)
@@ -85,6 +93,16 @@ void GestureDetector::touch_up(unsigned btn)
                invalid_gesture = false;
                for(unsigned i=0; (i<MAX_POINTS && !invalid_gesture); ++i)
                        invalid_gesture = points[i].down;
+
+               if(!invalid_gesture && pending_tap!=GESTURE_NONE)
+               {
+                       unsigned n_points = min<unsigned>((pending_tap-GESTURE_TAP)+1, MAX_POINTS);
+                       set_gesture_location((1<<n_points)-1);
+                       set_button_state(pending_tap, true, true);
+                       set_button_state(pending_tap, false, true);
+
+                       pending_tap = GESTURE_NONE;
+               }
        }
 }
 
@@ -104,7 +122,10 @@ void GestureDetector::touch_move(unsigned axis, float value, float)
        if(p.down)
        {
                if(p.x*p.x/threshold_x_sq+p.y*p.y/threshold_y_sq>=1)
+               {
                        p.threshold_exceeded = true;
+                       pending_tap = GESTURE_NONE;
+               }
 
                if(current_gesture==GESTURE_NONE && !invalid_gesture)
                        start_gesture();
@@ -141,53 +162,67 @@ void GestureDetector::start_gesture()
                        /* If the points moved away from or towards each other without rotating
                        significantly, it's a pinch gesture. */
                        current_gesture = GESTURE_PINCH;
-               else
-                       invalid_gesture = true;
+               else if(turn*turn2>0 && abs(turn)>abs(away) && abs(turn2)>abs(away2))
+                       /* If the points both turned in the same direction without significant
+                       changes in distance, it's a rotate gesture. */
+                       current_gesture = GESTURE_ROTATE;
+               else if((p.x*p2.x+p.y*p2.y)>2*abs(p.x*p2.y-p.y*p2.x))
+                       // If both points moved in the same direction, it's a two-finger drag.
+                       current_gesture = GESTURE_DRAG_2;
 
                if(current_gesture!=GESTURE_NONE)
-               {
                        active_points = 3;
-                       set_axis_value(0, (p.down_x+p2.down_x)/2, true);
-                       set_axis_value(1, (p.down_y+p2.down_y)/2, true);
-               }
        }
        else
        {
-               // Allow a maximum deviation of about 26° to recognize a swipe gesture.
-               if(abs(p.x)>2*abs(p.y))
-                       current_gesture = (p.x>0 ? GESTURE_SWIPE_RIGHT : GESTURE_SWIPE_LEFT);
-               else if(abs(p.y)>2*abs(p.x))
-                       current_gesture = (p.y>0 ? GESTURE_SWIPE_UP : GESTURE_SWIPE_DOWN);
-               else
-                       invalid_gesture = true;
-
-               if(current_gesture!=GESTURE_NONE)
-               {
-                       active_points = 1;
-                       set_axis_value(0, p.down_x, true);
-                       set_axis_value(1, p.down_y, true);
-               }
+               current_gesture = GESTURE_DRAG;
+               active_points = 1;
        }
 
-       update_progress();
 
        if(current_gesture!=GESTURE_NONE)
+       {
+               set_gesture_location(active_points);
+               update_progress();
                set_button_state(current_gesture, true, true);
+       }
+       else
+               invalid_gesture = true;
+}
+
+void GestureDetector::set_gesture_location(unsigned mask)
+{
+       float x = 0;
+       float y = 0;
+       unsigned count = 0;
+       for(unsigned i=0; i<MAX_POINTS; ++i)
+               if(mask&(1<<i))
+               {
+                       x += points[i].down_x;
+                       y += points[i].down_y;
+                       ++count;
+               }
+
+       set_axis_value(0, x/count, true);
+       set_axis_value(1, y/count, true);
 }
 
 void GestureDetector::update_progress()
 {
        TouchPoint &p = points[0];
 
-       if(current_gesture==GESTURE_SWIPE_DOWN)
-               set_axis_value(2, -p.y, true);
-       else if(current_gesture==GESTURE_SWIPE_UP)
-               set_axis_value(2, p.y, true);
-       else if(current_gesture==GESTURE_SWIPE_LEFT)
-               set_axis_value(2, -p.x, true);
-       else if(current_gesture==GESTURE_SWIPE_RIGHT)
+       if(current_gesture==GESTURE_DRAG)
+       {
                set_axis_value(2, p.x, true);
-       else if(current_gesture==GESTURE_PINCH)
+               set_axis_value(3, p.y, true);
+       }
+       else if(current_gesture==GESTURE_DRAG_2)
+       {
+               TouchPoint &p2 = points[1];
+               set_axis_value(2, (p.x+p2.x)/2, true);
+               set_axis_value(3, (p.y+p2.y)/2, true);
+       }
+       else if(current_gesture==GESTURE_PINCH || current_gesture==GESTURE_ROTATE)
        {
                TouchPoint &p2 = points[1];
                /* Pinch progress is the ratio between the current distance of the points
@@ -196,7 +231,16 @@ void GestureDetector::update_progress()
                float ddy = p.down_y-p2.down_y;
                float dx = ddx+p.x-p2.x;
                float dy = ddy+p.y-p2.y;
-               set_axis_value(2, sqrt(dx*dx+dy*dy)/sqrt(ddx*ddx+ddy*ddy)-1, true);
+               if(current_gesture==GESTURE_PINCH)
+               {
+                       set_axis_value(2, sqrt(dx*dx+dy*dy)/sqrt(ddx*ddx+ddy*ddy)-1, true);
+                       set_axis_value(3, 0, true);
+               }
+               else if(current_gesture==GESTURE_ROTATE)
+               {
+                       set_axis_value(2, atan2(dy*ddx-dx*ddy, dx*ddx+dy*ddy)/M_PI/2, true);
+                       set_axis_value(3, 0, true);
+               }
        }
 }
 
@@ -206,6 +250,7 @@ void GestureDetector::end_gesture()
        set_axis_value(2, 0, false);
        current_gesture = GESTURE_NONE;
        active_points = 0;
+       pending_tap = GESTURE_NONE;
 }
 
 void GestureDetector::window_resized(unsigned w, unsigned h)
@@ -220,7 +265,8 @@ GestureDetector::TouchPoint::TouchPoint():
        down_x(0),
        down_y(0),
        x(0),
-       y(0)
+       y(0),
+       threshold_exceeded(false)
 { }
 
 } // namespace Input