Elm Glayer: Added multi-touch support to momentum gesture
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 25 Oct 2011 09:51:22 +0000 (09:51 +0000)
committerJaehwan Kim <jae.hwan.kim@samsung.com>
Mon, 31 Oct 2011 06:12:00 +0000 (15:12 +0900)
Signed-off-by: Aharon Hillel <a.hillel@partner.samsung.com>
git-svn-id: https://svn.enlightenment.org/svn/e/trunk/elementary@64378 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/elm_gesture_layer.c

index 8cd9496..4b516f2 100644 (file)
@@ -7,6 +7,7 @@
 /* ELM_GESTURE_NEGATIVE_ANGLE - magic number says we didn't compute this yet */
 #define ELM_GESTURE_NEGATIVE_ANGLE (-1.0) /* Magic number */
 #define ELM_GESTURE_MOMENTUM_TIMEOUT 50
+#define ELM_GESTURE_MULTI_TIMEOUT 50
 
 /* Some Trigo values */
 #define RAD_90DEG  M_PI_2
@@ -172,6 +173,8 @@ struct _Momentum_Type
    unsigned int t_st_x;  /* Time start on X */
    unsigned int t_st_y;  /* Time start on Y */
    unsigned int t_end;   /* Time end        */
+   unsigned int t_up; /* Recent up event time */
+   int n_fingers;
    int xdir, ydir;
 };
 typedef struct _Momentum_Type Momentum_Type;
@@ -1733,7 +1736,7 @@ _momentum_test(Evas_Object *obj, Pointer_Event *pe,
    if (!gesture ) return;
 
    Momentum_Type *st = gesture->data;
-   Elm_Gesture_State state_to_report;
+   Elm_Gesture_State state_to_report = ELM_GESTURE_STATE_MOVE;
    if (!st)
      {  /* Allocated once on first time */
         st = calloc(1, sizeof(Momentum_Type));
@@ -1744,38 +1747,69 @@ _momentum_test(Evas_Object *obj, Pointer_Event *pe,
    if (!pe)
      return;
 
+   /* First make avarage of all touched devices to determine center point */
+   Eina_List *l;
+   Pointer_Event *p;
+   Pointer_Event pe_local = *pe;  /* Copy pe event info to local */
+   int cnt = 1;    /* We start counter counting current pe event */
+   EINA_LIST_FOREACH(wd->touched, l, p)
+      if (p->device != pe_local.device)
+        {
+           pe_local.x += p->x;
+           pe_local.y += p->y;
+           cnt++;
+        }
+
+
+   /* Compute avarage to get center point */
+   pe_local.x /= cnt;
+   pe_local.y /= cnt;
+
+   /* If user added finger - reset gesture */
+   if ((st->n_fingers) && (st->n_fingers < cnt))
+     state_to_report = ELM_GESTURE_STATE_ABORT;
+
+   st->n_fingers = cnt;
+
    Evas_Event_Flags ev_flag = EVAS_EVENT_FLAG_NONE;
    switch (event_type)
      {
       case EVAS_CALLBACK_MOUSE_DOWN:
+      case EVAS_CALLBACK_MULTI_DOWN:
       case EVAS_CALLBACK_MOUSE_MOVE:
+      case EVAS_CALLBACK_MULTI_MOVE:
          if (!st->t_st_x)
            {
               if ((event_type == EVAS_CALLBACK_MOUSE_DOWN) ||
+                    (event_type == EVAS_CALLBACK_MULTI_DOWN) ||
                     (wd->glayer_continues_enable)) /* start also on MOVE */
                 {  /* We start on MOVE when cont-enabled only */
-                   st->line_st.x = st->line_end.x = pe->x;
-                   st->line_st.y = st->line_end.y = pe->y;
-                   st->t_st_x = st->t_st_y = st->t_end = pe->timestamp;
+                   st->line_st.x = st->line_end.x = pe_local.x;
+                   st->line_st.y = st->line_end.y = pe_local.y;
+                   st->t_st_x = st->t_st_y = st->t_end = pe_local.timestamp;
                    st->xdir = st->ydir = 0;
-                   st->info.x2 = st->info.x1 = pe->x;
-                   st->info.y2 = st->info.y1 = pe->y;
-                   st->info.tx = st->info.ty = pe->timestamp;
+                   st->info.x2 = st->info.x1 = pe_local.x;
+                   st->info.y2 = st->info.y1 = pe_local.y;
+                   st->info.tx = st->info.ty = pe_local.timestamp;
                    ev_flag = _set_state(gesture, ELM_GESTURE_STATE_START,
                          &st->info, EINA_FALSE);
                    consume_event(wd, event_info, event_type, ev_flag);
-
                 }
 
               return;
            }
 
-         state_to_report = ELM_GESTURE_STATE_MOVE;
-         if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
+
+         /* ABORT gesture if got DOWN or MOVE event after UP+timeout */
+         if ((st->t_up) &&
+         ((st->t_up + ELM_GESTURE_MULTI_TIMEOUT) < pe_local.timestamp))
+           state_to_report = ELM_GESTURE_STATE_ABORT;
+
+         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
            {  /*  Too long of a wait, reset all values */
-              st->line_st.x = pe->x;
-              st->line_st.y = pe->y;
-              st->t_st_y = st->t_st_x = pe->timestamp;
+              st->line_st.x = pe_local.x;
+              st->line_st.y = pe_local.y;
+              st->t_st_y = st->t_st_x = pe_local.timestamp;
               st->info.tx = st->t_st_x;
               st->info.ty = st->t_st_y;
               st->xdir = st->ydir = 0;
@@ -1783,8 +1817,8 @@ _momentum_test(Evas_Object *obj, Pointer_Event *pe,
          else
            {
               int xdir, ydir;
-              xdir = _get_direction(st->line_st.x, pe->x);
-              ydir = _get_direction(st->line_st.y, pe->y);
+              xdir = _get_direction(st->line_st.x, pe_local.x);
+              ydir = _get_direction(st->line_st.y, pe_local.y);
               if (!xdir || (xdir == (-st->xdir)))
                 {
                    st->line_st.x = st->line_end.x;
@@ -1800,11 +1834,11 @@ _momentum_test(Evas_Object *obj, Pointer_Event *pe,
                 }
            }
 
-         st->info.x2 = st->line_end.x = pe->x;
-         st->info.y2 = st->line_end.y = pe->y;
-         st->t_end = pe->timestamp;
-         _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
-               st->t_st_x, st->t_st_y, pe->timestamp);
+         st->info.x2 = st->line_end.x = pe_local.x;
+         st->info.y2 = st->line_end.y = pe_local.y;
+         st->t_end = pe_local.timestamp;
+         _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
+               st->t_st_x, st->t_st_y, pe_local.timestamp);
          ev_flag = _set_state(gesture, state_to_report, &st->info,
                EINA_TRUE);
          consume_event(wd, event_info, event_type, ev_flag);
@@ -1812,36 +1846,30 @@ _momentum_test(Evas_Object *obj, Pointer_Event *pe,
 
 
       case EVAS_CALLBACK_MOUSE_UP:
-         /* IGNORE if line info was cleared, like long press, move */
-         if (!st->t_st_x)
+      case EVAS_CALLBACK_MULTI_UP:
+         st->t_up = pe_local.timestamp;       /* Record recent up event time */
+         if ((cnt > 1) ||     /* Ignore if more fingers touch surface        */
+               (!st->t_st_x)) /* IGNORE if info was cleared, long press,move */
            return;
-         state_to_report = ELM_GESTURE_STATE_END;
 
-         if ((pe->timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
+         if ((pe_local.timestamp - ELM_GESTURE_MOMENTUM_TIMEOUT) > st->t_end)
            {  /* Too long of a wait, reset all values */
-              st->line_st.x = pe->x;
-              st->line_st.y = pe->y;
-              st->t_st_y = st->t_st_x = pe->timestamp;
+              st->line_st.x = pe_local.x;
+              st->line_st.y = pe_local.y;
+              st->t_st_y = st->t_st_x = pe_local.timestamp;
               st->xdir = st->ydir = 0;
            }
 
-         st->info.x2 = pe->x;
-         st->info.y2 = pe->y;
-         st->line_end.x = pe->x;
-         st->line_end.y = pe->y;
-         st->t_end = pe->timestamp;
+         st->info.x2 = pe_local.x;
+         st->info.y2 = pe_local.y;
+         st->line_end.x = pe_local.x;
+         st->line_end.y = pe_local.y;
+         st->t_end = pe_local.timestamp;
 
-         _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe->x, pe->y,
-               st->t_st_x, st->t_st_y, pe->timestamp);
+         _set_momentum(&st->info, st->line_st.x, st->line_st.y, pe_local.x, pe_local.y,
+               st->t_st_x, st->t_st_y, pe_local.timestamp);
 
-         ev_flag = _set_state(gesture, state_to_report, &st->info,
-               EINA_FALSE);
-         consume_event(wd, event_info, event_type, ev_flag);
-
-         return;
-
-      case EVAS_CALLBACK_MULTI_UP:
-         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, &st->info,
+         ev_flag = _set_state(gesture, ELM_GESTURE_STATE_END, &st->info,
                EINA_FALSE);
          consume_event(wd, event_info, event_type, ev_flag);
          return;