evas/gesture: Added gesture manager implementaion.
authorsmohanty <smohantty@gmail.com>
Tue, 19 Sep 2017 08:11:31 +0000 (17:11 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Thu, 19 Oct 2017 01:33:12 +0000 (10:33 +0900)
src/Makefile_Evas.am
src/lib/evas/gesture/efl_gesture_manager.c [new file with mode: 0644]

index a74ebd7..4c0a609 100644 (file)
@@ -270,6 +270,7 @@ lib/evas/gesture/efl_gesture.c \
 lib/evas/gesture/efl_gesture_tap.c \
 lib/evas/gesture/efl_gesture_recognizer.c \
 lib/evas/gesture/efl_gesture_recognizer_tap.c \
+lib/evas/gesture/efl_gesture_manager.c \
 $(NULL)
 
 EXTRA_DIST2 += \
diff --git a/src/lib/evas/gesture/efl_gesture_manager.c b/src/lib/evas/gesture/efl_gesture_manager.c
new file mode 100644 (file)
index 0000000..5936ded
--- /dev/null
@@ -0,0 +1,350 @@
+#include "efl_gesture_private.h"
+
+#define MY_CLASS EFL_GESTURE_MANAGER_CLASS
+
+typedef struct _Object_Gesture
+{
+   Eo                             *object;
+   const Efl_Event_Description    *type;
+   Efl_Gesture                    *gesture;
+   Efl_Gesture_Recognizer         *recognizer;
+}Object_Gesture;
+
+typedef struct _Efl_Gesture_Manager_Data
+{
+   // keeps track of all the gesture request for a particular target
+   Eina_Hash    *m_gesture_contex;  // (*target, *event_desc)
+   // keeps all the event directed to this particular object from touch_begin till touch_end
+   Eina_Hash    *m_object_events;  // (*target, *efl_gesture_touch)
+   // keeps all the recognizer registered to gesture manager
+   Eina_Hash    *m_recognizers; // (*gesture_type, *recognizer)
+   // keeps track of all current object gestures.
+   Eina_List    *m_object_gestures; //(List of *object_gesture)
+   // lazy deletion of gestures
+   Eina_List    *m_gestures_to_delete;
+
+   Eina_Hash    *m_config;
+} Efl_Gesture_Manager_Data;
+
+static void _cleanup_cached_gestures(Efl_Gesture_Manager_Data *pd,
+                                     Eo *target, const Efl_Event_Description *type);
+static Efl_Gesture*
+_get_state(Efl_Gesture_Manager_Data *pd, Eo *target,
+                       Efl_Gesture_Recognizer *recognizer, const Efl_Event_Description *type);
+
+static void
+_cleanup_object(Eina_List *list)
+{
+   Eina_List *l;
+   Eo *obj;
+
+   if (!list) return;
+
+   EINA_LIST_FOREACH(list, l, obj)
+     efl_del(obj);
+
+   eina_list_free(list);
+}
+
+static void
+_hash_free_cb(Eo *obj)
+{
+   efl_del(obj);
+}
+
+EOLIAN static Efl_Object *
+_efl_gesture_manager_efl_object_constructor(Eo *obj, Efl_Gesture_Manager_Data *pd EINA_UNUSED)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+
+   pd->m_recognizers = eina_hash_pointer_new(EINA_FREE_CB(_hash_free_cb));
+   pd->m_gesture_contex = eina_hash_pointer_new(NULL);
+   pd->m_object_events = eina_hash_pointer_new(EINA_FREE_CB(_hash_free_cb));
+   pd->m_object_gestures = NULL;
+   pd->m_gestures_to_delete = NULL;
+
+   pd->m_config = eina_hash_string_superfast_new(EINA_FREE_CB(eina_value_free));
+
+   efl_gesture_manager_recognizer_register(obj, efl_add(EFL_GESTURE_RECOGNIZER_TAP_CLASS, obj));
+   return obj;
+}
+
+
+EOLIAN static Eina_Value *
+_efl_gesture_manager_config_get(Eo *obj EINA_UNUSED, Efl_Gesture_Manager_Data *pd, const char *name)
+{
+   return eina_hash_find(pd->m_config, name);
+}
+
+EOLIAN static void
+_efl_gesture_manager_config_set(Eo *obj EINA_UNUSED, Efl_Gesture_Manager_Data *pd, const char *name, Eina_Value *value)
+{
+   Eina_Value *v = eina_value_new(eina_value_type_get(value));
+   eina_value_copy(value, v);
+   eina_hash_add(pd->m_config, name, v);
+}
+
+EOLIAN static void
+_efl_gesture_manager_efl_object_destructor(Eo *obj, Efl_Gesture_Manager_Data *pd EINA_UNUSED)
+{
+   eina_hash_free(pd->m_recognizers);
+   eina_hash_free(pd->m_gesture_contex);
+   eina_hash_free(pd->m_object_events);
+   _cleanup_object(pd->m_gestures_to_delete);
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+void
+_efl_gesture_manager_callback_add_hook(Eo *obj, Eo *target, const Efl_Event_Description *type)
+{
+   Efl_Gesture_Manager_Data *pd = efl_data_scope_get(obj, MY_CLASS);
+   // if there is a recognizer registered for that event then add it to the gesture context
+   Efl_Gesture_Recognizer *recognizer = eina_hash_find (pd->m_recognizers, &type);
+   if (recognizer)
+     {
+        // add it to the gesture context.
+        eina_hash_list_append(pd->m_gesture_contex, &target, type);
+     }
+
+}
+
+void
+_efl_gesture_manager_callback_del_hook(Eo *obj, Eo *target, const Efl_Event_Description *type)
+{
+   Efl_Gesture_Manager_Data *pd = efl_data_scope_get(obj, MY_CLASS);
+   // if there is a recognizer registered for that event then add it to the gesture context
+   Efl_Gesture_Recognizer *recognizer = eina_hash_find (pd->m_recognizers, &type);
+   if (recognizer)
+     {
+        eina_hash_list_remove(pd->m_gesture_contex, &target, type);
+        _cleanup_cached_gestures(pd, target, type);
+     }
+}
+
+void
+_efl_gesture_manager_filter_event(Eo *obj, Eo *target, void *event)
+{
+   Eina_List *l, *gesture_context;
+   Efl_Gesture_Manager_Data *pd;
+   const Efl_Event_Description *gesture_type;
+   Efl_Gesture_Recognizer *recognizer;
+   Efl_Gesture *gesture;
+   Efl_Gesture_Recognizer_Result recog_result;
+   Efl_Gesture_Recognizer_Result recog_state;
+   Efl_Gesture_Touch *touch_event;
+   Efl_Input_Pointer_Data *pointer_data = efl_data_scope_get(event, EFL_INPUT_POINTER_CLASS);
+
+   pd = efl_data_scope_get(obj, MY_CLASS);
+   gesture_context = eina_hash_find(pd->m_gesture_contex, &target);
+   if (gesture_context)
+     {
+        // get the touch event for this particular widget
+        touch_event = eina_hash_find(pd->m_object_events, &target);
+        if (touch_event)
+          {
+             efl_gesture_touch_point_record(touch_event, pointer_data->tool, pointer_data->cur.x, pointer_data->cur.y,
+                                          pointer_data->timestamp, pointer_data->action);
+          }
+        else
+          {
+             touch_event = efl_add(EFL_GESTURE_TOUCH_CLASS, NULL);
+             efl_gesture_touch_point_record(touch_event, pointer_data->tool, pointer_data->cur.x, pointer_data->cur.y,
+                                          pointer_data->timestamp, pointer_data->action);
+             eina_hash_add(pd->m_object_events, &target, touch_event);
+          }
+
+        if (efl_gesture_touch_state_get(touch_event) == EFL_GESTURE_TOUCH_UNKNOWN)
+          return;
+
+        EINA_LIST_FOREACH(gesture_context, l, gesture_type)
+          {
+             recognizer = eina_hash_find(pd->m_recognizers, &gesture_type);
+             gesture = _get_state(pd, target, recognizer, gesture_type);
+             if (!gesture)
+               continue;
+             recog_result = efl_gesture_recognizer_recognize(recognizer, gesture, target, touch_event);
+             recog_state = recog_result & EFL_GESTURE_RESULT_MASK;
+             if (recog_state == EFL_GESTURE_TRIGGER)
+               {
+                  if (efl_gesture_state_get(gesture) == EFL_GESTURE_NONE)
+                    efl_gesture_state_set(gesture, EFL_GESTURE_STARTED);
+                  else
+                    efl_gesture_state_set(gesture, EFL_GESTURE_UPDATED);
+               }
+             else if (recog_state == EFL_GESTURE_FINISH)
+               {
+                  efl_gesture_state_set(gesture, EFL_GESTURE_FINISHED);
+               }
+             else if (recog_state == EFL_GESTURE_MAYBE)
+               {
+                  continue;
+               }
+             else if (recog_state == EFL_GESTURE_CANCEL)
+               {
+                  if (efl_gesture_state_get(gesture) != EFL_GESTURE_NONE)
+                    {
+                       efl_gesture_state_set(gesture, EFL_GESTURE_CANCELED);
+                    }
+                  else
+                    continue;
+               }
+             else if (recog_state == EFL_GESTURE_IGNORE)
+               {
+                  continue;
+               }
+             efl_event_callback_call(target, gesture_type, gesture);
+          }
+
+        if (efl_gesture_touch_state_get(touch_event) == EFL_GESTURE_TOUCH_END)
+          {
+             EINA_LIST_FOREACH(gesture_context, l, gesture_type)
+               _cleanup_cached_gestures(pd, target, gesture_type);
+
+             eina_hash_del(pd->m_object_events, &target, NULL);
+             // free gesture_to_delete list
+             _cleanup_object(pd->m_gestures_to_delete);
+             pd->m_gestures_to_delete = NULL;
+          }
+     }
+}
+
+EOLIAN static const Efl_Event_Description *
+_efl_gesture_manager_recognizer_register(Eo *obj EINA_UNUSED, Efl_Gesture_Manager_Data *pd,
+                                            Efl_Gesture_Recognizer *recognizer)
+{
+   Efl_Gesture_Recognizer_Data *rpd;
+   Efl_Gesture *dummy = efl_gesture_recognizer_create(recognizer, 0);
+
+   if (!dummy)
+     return NULL;
+
+   const Efl_Event_Description *type = efl_gesture_type_get(dummy);
+
+   // Add the recognizer to the m_recognizers
+   eina_hash_add(pd->m_recognizers, &type, recognizer);
+   // update the manager
+   rpd = efl_data_scope_get(recognizer, EFL_GESTURE_RECOGNIZER_CLASS);
+   rpd->manager = obj;
+
+   efl_del(dummy);
+
+   return type;
+}
+
+EOLIAN static void
+_efl_gesture_manager_recognizer_unregister(Eo *obj EINA_UNUSED, Efl_Gesture_Manager_Data *pd,
+                                           Efl_Gesture_Recognizer *recognizer)
+{
+   Eina_List *l, *l_next;
+   Object_Gesture *object_gesture;
+   const Efl_Event_Description *type;
+   Efl_Gesture *dummy;
+
+   if (!recognizer) return;
+
+   // find the type of the recognizer
+   dummy = efl_gesture_recognizer_create(recognizer, 0);
+   if (!dummy)return;
+
+   type = efl_gesture_type_get(dummy);
+   efl_del(dummy);
+
+   // check if its already registered
+   recognizer = eina_hash_find(pd->m_recognizers, &type);
+
+   if (!recognizer) return;
+
+   // remove that gesture from the list of object gestures
+   EINA_LIST_FOREACH_SAFE(pd->m_object_gestures, l, l_next, object_gesture)
+     {
+        if (object_gesture->type == type)
+          {
+             pd->m_gestures_to_delete = eina_list_append(pd->m_gestures_to_delete, object_gesture->gesture);
+             free(object_gesture);
+             pd->m_object_gestures = eina_list_remove_list(pd->m_object_gestures, l);
+          }
+     }
+   eina_hash_del(pd->m_recognizers, &type, NULL);
+}
+
+// EOLIAN static void
+// _efl_gesture_manager_ungrab_all(Eo *obj EINA_UNUSED, Efl_Gesture_Manager_Data *pd,
+//                                    Eo *target)
+// {
+//    const Efl_Event_Description *type;
+//    Eina_List *l;
+
+//    Eina_List *gesture_type_list = eina_hash_find(pd->m_gesture_contex, &target);
+
+//    if (!gesture_type_list) return;
+
+//    EINA_LIST_FOREACH(gesture_type_list, l, type)
+//      {
+//         _cleanup_cached_gestures(obj, pd, target, type);
+//      }
+//    eina_hash_del(pd->m_gesture_contex, &target, NULL);
+// }
+
+// get or create a gesture object that will represent the state for a given object, used by the recognizer
+Efl_Gesture*
+_get_state(Efl_Gesture_Manager_Data *pd,
+           Eo *target, Efl_Gesture_Recognizer *recognizer, const Efl_Event_Description *type)
+{
+   Eina_List *l;
+   Object_Gesture *object_gesture;
+   Efl_Gesture *gesture;
+
+   // if the widget is being deleted we should be careful not to
+   // create a new state.
+   if (efl_destructed_is(target))
+     return 0;
+
+   //TODO find a optimized way of looking for gesture
+   EINA_LIST_FOREACH(pd->m_object_gestures, l, object_gesture)
+     {
+        if (object_gesture->object == target &&
+            object_gesture->recognizer == recognizer &&
+            object_gesture->type   == type)
+         {
+            // the gesture is already processed waiting for cleanup
+            if ((efl_gesture_state_get(object_gesture->gesture) == EFL_GESTURE_FINISHED) ||
+                (efl_gesture_state_get(object_gesture->gesture) == EFL_GESTURE_CANCELED))
+              return NULL;
+            return object_gesture->gesture;
+         }
+     }
+
+   gesture = efl_gesture_recognizer_create(recognizer, target);
+   if (!gesture)
+     return 0;
+   object_gesture = calloc(1, sizeof(Object_Gesture));
+   object_gesture->object = target;
+   object_gesture->recognizer = recognizer;
+   object_gesture->type = type;
+   object_gesture->gesture = gesture;
+
+   pd->m_object_gestures = eina_list_append(pd->m_object_gestures, object_gesture);
+
+   return gesture;
+}
+
+static void
+_cleanup_cached_gestures(Efl_Gesture_Manager_Data *pd,
+                         Eo *target, const Efl_Event_Description *type)
+{
+   Eina_List *l, *l_next;
+   Object_Gesture *object_gesture;
+
+   EINA_LIST_FOREACH_SAFE(pd->m_object_gestures, l, l_next, object_gesture)
+     {
+        if ( (object_gesture->type == type) && (target == object_gesture->object))
+          {
+             pd->m_gestures_to_delete = eina_list_append(pd->m_gestures_to_delete, object_gesture->gesture);
+             free(object_gesture);
+             pd->m_object_gestures = eina_list_remove_list(pd->m_object_gestures, l);
+          }
+     }
+}
+
+
+#include "efl_gesture_manager.eo.c"