From: smohanty Date: Tue, 19 Sep 2017 08:11:31 +0000 (+0900) Subject: evas/gesture: Added gesture manager implementaion. X-Git-Tag: submit/sandbox/upgrade/efl120/20180319.053334~2156 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9da7a7f0d23f0240a1af721fd771667b9e0de3ba;p=platform%2Fupstream%2Fefl.git evas/gesture: Added gesture manager implementaion. --- diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index a74ebd7..4c0a609 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -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 index 0000000..5936ded --- /dev/null +++ b/src/lib/evas/gesture/efl_gesture_manager.c @@ -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"