Add gesture module to detect mouse gesture. 82/52582/2
authorSeunghun Lee <shiin.lee@samsung.com>
Fri, 20 Nov 2015 11:24:20 +0000 (20:24 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Wed, 2 Dec 2015 02:18:00 +0000 (11:18 +0900)
Change-Id: I8cec9a98f7a2e2ebf941aca3a60c9a9ae4159a8f

src/Makefile.am
src/e_mod_gesture.c [new file with mode: 0644]
src/e_mod_gesture.h [new file with mode: 0644]
src/e_mod_quickpanel.c

index a7730e4..9968a11 100644 (file)
@@ -28,7 +28,9 @@ module_la_SOURCES += e_mod_wl.c \
                                         e_mod_quickpanel.c \
                                         e_mod_quickpanel.h \
                                         e_mod_indicator.c \
-                                        e_mod_indicator.h
+                                        e_mod_indicator.h \
+                                        e_mod_gesture.c \
+                                        e_mod_gesture.h
 endif
 
 module_la_LIBADD       =
diff --git a/src/e_mod_gesture.c b/src/e_mod_gesture.c
new file mode 100644 (file)
index 0000000..39c89a7
--- /dev/null
@@ -0,0 +1,193 @@
+#include "e_mod_main.h"
+#include "e_mod_gesture.h"
+
+struct _Pol_Gesture
+{
+   Evas_Object *obj;
+   Pol_Gesture_Type type;
+
+   Eina_Bool active;
+
+   struct
+   {
+      int y;
+      int timestamp;
+      Eina_Bool pressed; /* to avoid processing that happened mouse move right after mouse up */
+   } mouse_info;
+
+   struct
+   {
+      Pol_Gesture_Start_Cb start;
+      Pol_Gesture_Move_Cb move;
+      Pol_Gesture_End_Cb end;
+      void *data;
+   } cb;
+};
+
+static void
+_gesture_obj_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   Pol_Gesture *gesture = data;
+   Evas_Event_Mouse_Up *ev = event;
+
+   gesture->mouse_info.pressed = EINA_FALSE;
+
+   if (!gesture->active)
+     return;
+
+   gesture->active = EINA_FALSE;
+
+   if (gesture->cb.end)
+     gesture->cb.end(gesture->cb.data, obj, ev->canvas.x, ev->canvas.y, ev->timestamp);
+}
+
+static Eina_Bool
+_gesture_line_check(Pol_Gesture *gesture, int x, int y)
+{
+   int dy;
+   const int sensitivity = 50; /* FIXME: hard coded, it sould be configurable. */
+
+   dy = y - gesture->mouse_info.y;
+   if (abs(dy) < sensitivity)
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_gesture_flick_check(Pol_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp)
+{
+   int dy;
+   int ox, oy, ow, oh;
+   unsigned int dt;
+   float vel = 0.0;
+   const float sensitivity = 0.25; /* FIXME: hard coded, it sould be configurable. */
+
+   evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
+   if (!E_INSIDE(x, y, ox, oy, ow, oh))
+     return EINA_FALSE;
+
+   dy = y - gesture->mouse_info.y;
+   dt = timestamp - gesture->mouse_info.timestamp;
+   if (dt == 0)
+     return EINA_FALSE;
+
+   vel = (float)dy / (float)dt;
+   if (fabs(vel) < sensitivity)
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_gesture_check(Pol_Gesture *gesture, Evas_Object *obj, int x, int y, unsigned int timestamp)
+{
+   Eina_Bool ret = EINA_FALSE;
+
+   switch (gesture->type)
+     {
+      case POL_GESTURE_TYPE_LINE:
+         ret = _gesture_line_check(gesture, x, y);
+         break;
+      case POL_GESTURE_TYPE_FLICK:
+         ret = _gesture_flick_check(gesture, obj, x, y, timestamp);
+         break;
+      default:
+         ERR("Unknown gesture type %d", gesture->type);
+         break;
+     }
+
+   return ret;
+}
+
+static void
+_gesture_obj_cb_mouse_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event)
+{
+   Pol_Gesture *gesture = data;
+   Evas_Event_Mouse_Move *ev = event;
+   int x, y;
+   unsigned int timestamp;
+
+   if (!gesture->mouse_info.pressed)
+     return;
+
+   x = ev->cur.canvas.x;
+   y = ev->cur.canvas.y;
+   timestamp = ev->timestamp;
+
+   if (!gesture->active)
+     {
+        gesture->active = _gesture_check(gesture, obj, x, y, timestamp);
+        if (gesture->active)
+          {
+             if (gesture->cb.start)
+               gesture->cb.start(gesture->cb.data, obj, x, y, timestamp);
+          }
+        return;
+     }
+
+   if (gesture->cb.move)
+     gesture->cb.move(gesture->cb.data, obj, x, y, timestamp);
+}
+
+static void
+_gesture_obj_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event)
+{
+   Pol_Gesture *gesture = data;
+   Evas_Event_Mouse_Down *ev = event;
+
+   gesture->active = EINA_FALSE;
+   gesture->mouse_info.pressed = EINA_TRUE;
+   gesture->mouse_info.y = ev->canvas.y;
+   gesture->mouse_info.timestamp = ev->timestamp;
+}
+
+EINTERN Pol_Gesture *
+e_mod_gesture_add(Evas_Object *obj, Pol_Gesture_Type type)
+{
+   Pol_Gesture *gesture;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+
+   gesture = E_NEW(Pol_Gesture, 1);
+   if (EINA_UNLIKELY(gesture == NULL))
+     return NULL;
+
+   gesture->obj = obj;
+   gesture->type = type;
+
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+                                  _gesture_obj_cb_mouse_down, gesture);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
+                                  _gesture_obj_cb_mouse_move, gesture);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
+                                  _gesture_obj_cb_mouse_up, gesture);
+
+   return gesture;
+}
+
+EINTERN void
+e_mod_gesture_del(Pol_Gesture *gesture)
+{
+   EINA_SAFETY_ON_NULL_RETURN(gesture);
+
+   evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_DOWN,
+                                  _gesture_obj_cb_mouse_down);
+   evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_MOVE,
+                                  _gesture_obj_cb_mouse_move);
+   evas_object_event_callback_del(gesture->obj, EVAS_CALLBACK_MOUSE_UP,
+                                  _gesture_obj_cb_mouse_up);
+
+   free(gesture);
+}
+
+EINTERN void
+e_mod_gesture_cb_set(Pol_Gesture *gesture, Pol_Gesture_Start_Cb cb_start, Pol_Gesture_Move_Cb cb_move, Pol_Gesture_End_Cb cb_end, void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(gesture);
+
+   gesture->cb.start = cb_start;
+   gesture->cb.move = cb_move;
+   gesture->cb.end = cb_end;
+   gesture->cb.data = data;
+}
diff --git a/src/e_mod_gesture.h b/src/e_mod_gesture.h
new file mode 100644 (file)
index 0000000..92d4c66
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef E_MOD_GESTURE
+#define E_MOD_GESTURE
+
+typedef struct _Pol_Gesture Pol_Gesture;
+
+typedef enum
+{
+   POL_GESTURE_TYPE_LINE,
+   POL_GESTURE_TYPE_FLICK,
+} Pol_Gesture_Type;
+
+typedef void (*Pol_Gesture_Start_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp);
+typedef void (*Pol_Gesture_Move_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp);
+typedef void (*Pol_Gesture_End_Cb)(void *data, Evas_Object *obj, int x, int y, unsigned int timestamp);
+
+EINTERN Pol_Gesture  *e_mod_gesture_add(Evas_Object *obj, Pol_Gesture_Type type);
+EINTERN void          e_mod_gesture_del(Pol_Gesture *gesture);
+EINTERN void          e_mod_gesture_cb_set(Pol_Gesture *gesture, Pol_Gesture_Start_Cb cb_start, Pol_Gesture_Move_Cb cb_move, Pol_Gesture_End_Cb cb_end, void *data);
+
+#endif /* E_MOD_GESTURE */
index 5ec6c2a..685ab9c 100644 (file)
@@ -1,9 +1,11 @@
 #include "e_mod_main.h"
 #include "e_mod_quickpanel.h"
+#include "e_mod_gesture.h"
 
-#define SMART_NAME      "quickpanel_object"
-#define QP_DATA_KEY     "qp_mover"
-#define QP_EC           _pol_quickpanel->ec
+#define SMART_NAME            "quickpanel_object"
+#define QP_DATA_KEY           "qp_mover_data"
+#define GESTURE_DATA_KEY      "gesture_data"
+#define QP_EC                 _pol_quickpanel->ec
 #define INTERNAL_ENTRY                    \
    Mover_Data *md;                        \
    md = evas_object_smart_data_get(obj);
@@ -346,6 +348,7 @@ _quickpanel_mover_effect_data_free(Elm_Transit_Effect *effect, Elm_Transit *tran
    ec = evas_object_data_get(ed->mover, "E_Client");
    pos = (ed->visible) ? 0 : -10000;
    evas_object_move(ec->frame, pos, pos);
+   evas_object_data_del(ec->frame, QP_DATA_KEY);
 
    evas_object_hide(ed->mover);
    evas_object_del(ed->mover);
@@ -531,12 +534,18 @@ e_mod_quickpanel_client_get(void)
 }
 
 static void
-_quickpanel_client_evas_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *handler, void *event)
+_quickpanel_handler_cb_gesture_start(void *data EINA_UNUSED, Evas_Object *handler, int x, int y, unsigned int timestamp)
 {
-   Evas_Event_Mouse_Down *ev = event;
    Evas_Object *mover;
 
-   mover = _quickpanel_mover_begin(QP_EC, 0, ev->canvas.y, ev->timestamp);
+   mover = evas_object_data_get(handler, QP_DATA_KEY);
+   if (mover)
+     {
+        DBG("Mover object already existed");
+        _quickpanel_mover_free(mover);
+     }
+
+   mover = _quickpanel_mover_begin(QP_EC, 0, y, timestamp);
    if (!mover)
      return;
 
@@ -544,25 +553,20 @@ _quickpanel_client_evas_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_O
 }
 
 static void
-_quickpanel_client_evas_cb_mouse_move(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *handler, void *event)
+_quickpanel_handler_cb_gesture_move(void *data EINA_UNUSED, Evas_Object *handler, int x, int y, unsigned int timestamp)
 {
-   Evas_Event_Mouse_Move *ev = event;
    Evas_Object *mover;
 
    mover = evas_object_data_get(handler, QP_DATA_KEY);
    if (!mover)
-     {
-        DBG("Could not find quickpanel mover object");
-        return;
-     }
+     return;
 
-   _quickpanel_mover_move(mover, 0, ev->cur.canvas.y, ev->timestamp);
+   _quickpanel_mover_move(mover, 0, y, timestamp);
 }
 
 static void
-_quickpanel_client_evas_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *handler, void *event)
+_quickpanel_handler_cb_gesture_end(void *data EINA_UNUSED, Evas_Object *handler, int x, int y, unsigned int timestamp)
 {
-   Evas_Event_Mouse_Up *ev = event;
    Evas_Object *mover;
 
    mover = evas_object_data_get(handler, QP_DATA_KEY);
@@ -572,13 +576,15 @@ _quickpanel_client_evas_cb_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Obj
         return;
      }
 
-   _quickpanel_mover_end(mover, 0, ev->canvas.y, ev->timestamp);
+   _quickpanel_mover_end(mover, 0, y, timestamp);
+
    evas_object_data_del(handler, QP_DATA_KEY);
 }
 
 EINTERN Evas_Object *
 e_mod_quickpanel_handler_object_add(int x, int y, int w, int h)
 {
+   Pol_Gesture *gesture;
    Evas_Object *handler;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(_pol_quickpanel, NULL);
@@ -588,15 +594,19 @@ e_mod_quickpanel_handler_object_add(int x, int y, int w, int h)
    /* make it transparent */
    evas_object_color_set(handler, 0, 0, 0, 0);
 
+   evas_object_repeat_events_set(handler, EINA_TRUE);
+
    evas_object_move(handler, x, y);
    evas_object_resize(handler, w, h);
 
-   evas_object_event_callback_add(handler, EVAS_CALLBACK_MOUSE_DOWN,
-                                  _quickpanel_client_evas_cb_mouse_down, NULL);
-   evas_object_event_callback_add(handler, EVAS_CALLBACK_MOUSE_MOVE,
-                                  _quickpanel_client_evas_cb_mouse_move, NULL);
-   evas_object_event_callback_add(handler, EVAS_CALLBACK_MOUSE_UP,
-                                  _quickpanel_client_evas_cb_mouse_up, NULL);
+   gesture = e_mod_gesture_add(handler, POL_GESTURE_TYPE_LINE);
+   e_mod_gesture_cb_set(gesture,
+                        _quickpanel_handler_cb_gesture_start,
+                        _quickpanel_handler_cb_gesture_move,
+                        _quickpanel_handler_cb_gesture_end,
+                        NULL);
+
+   evas_object_data_set(handler, GESTURE_DATA_KEY, gesture);
 
    return handler;
 }
@@ -604,11 +614,22 @@ e_mod_quickpanel_handler_object_add(int x, int y, int w, int h)
 EINTERN void
 e_mod_quickpanel_handler_object_del(Evas_Object *handler)
 {
+   Pol_Gesture *gesture;
    Evas_Object *mover;
 
    mover = evas_object_data_get(handler, QP_DATA_KEY);
    if (mover)
-     _quickpanel_mover_free(mover);
+     {
+        _quickpanel_mover_free(mover);
+        evas_object_data_del(handler, QP_DATA_KEY);
+     }
+
+   gesture = evas_object_data_get(handler, GESTURE_DATA_KEY);
+   if (gesture)
+     {
+        e_mod_gesture_del(gesture);
+        evas_object_data_del(handler, GESTURE_DATA_KEY);
+     }
 
    evas_object_del(handler);
 }
@@ -640,6 +661,7 @@ _quickpanel_client_evas_cb_move(void *data, Evas *evas, Evas_Object *qp_obj, voi
 
    evas_object_geometry_get(qp_obj, &x, &y, NULL, NULL);
    evas_object_move(handler, x + hx, y + hy);
+   evas_object_raise(handler);
 }
 
 EINTERN Eina_Bool