From 07400fad889528e025fee8a0a108ea9d8bc13f44 Mon Sep 17 00:00:00 2001 From: tasn Date: Mon, 17 Oct 2011 08:12:45 +0000 Subject: [PATCH] Elm Glayer: Fixed all tap, long tap, gestures bugs Signed-off-by: Aharon Hillel git-svn-id: https://svn.enlightenment.org/svn/e/trunk/elementary@64127 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/elm_gesture_layer.c | 272 ++++++++++++++++++++++++++------------------ 1 file changed, 161 insertions(+), 111 deletions(-) diff --git a/src/lib/elm_gesture_layer.c b/src/lib/elm_gesture_layer.c index 2150d6b..2843fa3 100644 --- a/src/lib/elm_gesture_layer.c +++ b/src/lib/elm_gesture_layer.c @@ -145,9 +145,9 @@ typedef struct _Pointer_Event Pointer_Event; struct _Taps_Type { Elm_Gesture_Taps_Info info; - unsigned int count_ups; unsigned int sum_x; unsigned int sum_y; + unsigned int n_taps_needed; unsigned int n_taps; Eina_List *l; }; @@ -606,7 +606,7 @@ _clear_if_finished(Evas_Object *obj) /* Clear history if all we have aborted gestures */ Eina_Bool reset_s = EINA_TRUE, all_undefined = EINA_TRUE; - for (i = ELM_GESTURE_FIRST ; i < ELM_GESTURE_LAST; i++) + for (i = ELM_GESTURE_FIRST; i < ELM_GESTURE_LAST; i++) { /* If no gesture started and all we have aborted gestures, reset all */ Gesture_Info *p = wd->gesture[i]; if ((p) && (p->state != ELM_GESTURE_STATE_UNDEFINED)) @@ -619,8 +619,6 @@ _clear_if_finished(Evas_Object *obj) } } -// if ((!wd->touched) || (reset_s && !all_undefined)) - /* (!wd->touched && reset_s) - don't stop zoom with mouse-wheel */ if (reset_s && (!all_undefined)) return _event_history_clear(obj); @@ -651,13 +649,12 @@ _inside(Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2) * This happens when we need to reset our tests. * for example when gesture is detected or all ABORTed. */ static void -_dbl_click_test_reset(Gesture_Info *gesture) +_tap_gestures_test_reset(Gesture_Info *gesture) { if (!gesture) return; Widget_Data *wd = elm_widget_data_get(gesture->obj); - if (wd->dbl_timeout) ecore_timer_del(wd->dbl_timeout); wd->dbl_timeout = NULL; Eina_List *data; Pointer_Event *pe; @@ -686,13 +683,13 @@ _n_long_tap_test_reset(Gesture_Info *gesture) return; Long_Tap_Type *st = gesture->data; - if (st->timeout) ecore_timer_del(st->timeout); Eina_List *l; Pointer_Event *p; EINA_LIST_FOREACH(st->touched, l, p) free(p); eina_list_free(st->touched); + if (st->timeout) ecore_timer_del(st->timeout); memset(gesture->data, 0, sizeof(Long_Tap_Type)); } @@ -973,11 +970,24 @@ _event_history_clear(Evas_Object *obj) _reset_states(wd); /* we are ready to start testing for gestures again */ - /* Clear all gestures intermediate date */ - _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]); - _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]); - _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]); - _dbl_click_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]); + /* Clear all gestures intermediate data */ + if (IS_TESTED(ELM_GESTURE_N_LONG_TAPS)) + { /* We do not clear a long-tap gesture if fingers still on surface */ + /* and gesture timer still pending to test gesture state */ + Long_Tap_Type *st = wd->gesture[ELM_GESTURE_N_LONG_TAPS]->data; + if((!eina_list_count(st->touched)) || (!st->timeout)) + _n_long_tap_test_reset(wd->gesture[ELM_GESTURE_N_LONG_TAPS]); + } + + if (wd->dbl_timeout) + { + ecore_timer_del(wd->dbl_timeout); + wd->dbl_timeout = NULL; + } + + _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TAPS]); + _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]); + _tap_gestures_test_reset(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]); _momentum_test_reset(wd->gesture[ELM_GESTURE_MOMENTUM]); _line_test_reset(wd->gesture[ELM_GESTURE_N_LINES]); _line_test_reset(wd->gesture[ELM_GESTURE_N_FLICKS]); @@ -1193,7 +1203,41 @@ _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe, /** * @internal * - * when this timer expires we ABORT double click gesture. + * This function sets state a tap-gesture to END or ABORT + * + * @param data gesture info pointer + * + * @ingroup Elm_Gesture_Layer + */ +static void +_tap_gesture_finish(void *data) +{ /* This function will test each tap gesture when timer expires */ + Gesture_Info *gesture = data; + Elm_Gesture_State s = ELM_GESTURE_STATE_END; + /* Here we check if taps-gesture was completed successfuly */ + /* Count how many taps were recieved on each device then */ + /* determine if it matches n_taps_needed defined on START */ + Taps_Type *st = gesture->data; + Eina_List *l; + Eina_List *pe_list; + EINA_LIST_FOREACH(st->l, l, pe_list) + { + if (eina_list_count(pe_list) != st->n_taps_needed) + { /* No match taps number on device, ABORT */ + s = ELM_GESTURE_STATE_ABORT; + break; + } + } + + st->info.n = eina_list_count(st->l); + _set_state(gesture, s, gesture->info, EINA_FALSE); + _tap_gestures_test_reset(gesture); +} + +/** + * @internal + * + * when this timer expires we finish tap gestures. * * @param data The gesture-layer object. * @return cancles callback for this timer. @@ -1201,17 +1245,22 @@ _record_pointer_event(Taps_Type *st, Eina_List *pe_list, Pointer_Event *pe, * @ingroup Elm_Gesture_Layer */ static Eina_Bool -_dbl_click_timeout(void *data) +_multi_tap_timeout(void *data) { - Gesture_Info *gesture = data; - Widget_Data *wd = elm_widget_data_get(gesture->obj); + Widget_Data *wd = elm_widget_data_get(data); + if (!wd) return EINA_FALSE; - wd->dbl_timeout = NULL; - _set_state(gesture, ELM_GESTURE_STATE_ABORT, - gesture->info, EINA_FALSE); + if (IS_TESTED(ELM_GESTURE_N_TAPS)) + _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TAPS]); + + if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS)) + _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS]); - _dbl_click_test_reset(gesture); - _clear_if_finished(gesture->obj); + if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) + _tap_gesture_finish(wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS]); + + _clear_if_finished(data); + wd->dbl_timeout = NULL; return ECORE_CALLBACK_CANCEL; } @@ -1238,40 +1287,34 @@ _long_tap_timeout(void *data) return ECORE_CALLBACK_CANCEL; } + /** * @internal * - * This function checks all click/tap and double/triple taps + * This function checks if a tap gesture should start * - * @param obj The gesture-layer object. + * @param wd Gesture Layer Widget Data. * @param pe The recent input event as stored in pe struct. * @param event_info Original input event pointer. * @param event_type Type of original input event. - * @param g_type what Gesture we are testing. - * @param taps How many click/taps we test for. + * @param gesture what gesture is tested + * @param how many taps for this gesture (1, 2 or 3) + * + * @return Flag to determine if we need to set a timer for finish * * @ingroup Elm_Gesture_Layer */ -static void -_dbl_click_test(Evas_Object *obj, Pointer_Event *pe, +static Eina_Bool +_tap_gesture_start(Widget_Data *wd, Pointer_Event *pe, void *event_info, Evas_Callback_Type event_type, - Elm_Gesture_Types g_type, int taps) -{ /* Here we fill Recent_Taps struct and fire-up click/tap timers */ - Widget_Data *wd = elm_widget_data_get(obj); - if (!wd) return; - - if (!pe) /* this happens when unhandled event arrived */ - return; /* see _make_pointer_event function */ - - Gesture_Info *gesture = wd->gesture[g_type]; - if (!gesture ) return; - + Gesture_Info *gesture, int taps) +{ /* Here we fill Tap struct */ Taps_Type *st = gesture->data; if (!st) { /* Allocated once on first time */ st = calloc(1, sizeof(Taps_Type)); gesture->data = st; - _dbl_click_test_reset(gesture); + _tap_gestures_test_reset(gesture); } Eina_List *pe_list = NULL; @@ -1289,52 +1332,20 @@ _dbl_click_test(Evas_Object *obj, Pointer_Event *pe, &st->info, EINA_FALSE); consume_event(wd, event_info, event_type, ev_flag); - /* To test dbl_click/dbl_tap */ - /* When this timer expires, gesture ABORTed if not completed */ - if (!wd->dbl_timeout && (taps > 1)) - wd->dbl_timeout = ecore_timer_add(0.4, _dbl_click_timeout, - gesture); + st->n_taps_needed = taps * 2; /* count DOWN and UP */ - return; + return EINA_TRUE; } break; + case EVAS_CALLBACK_MULTI_UP: case EVAS_CALLBACK_MOUSE_UP: pe_list = eina_list_search_unsorted(st->l, compare_pe_device, pe); if (!pe_list) - return; /* Got only first mouse_down and mouse_up */ + return EINA_FALSE; pe_list = _record_pointer_event(st, pe_list, pe, wd, event_info, event_type); - - if (eina_list_count(pe_list) <= (unsigned int) ((taps - 1) * 2)) - return; /* Got only first mouse_down and mouse_up */ - - /* Get first event in first list, this has to be Mouse Down event */ - pe_down = eina_list_data_get(pe_list); - - if (_inside(pe_down->x, pe_down->y, pe->x, pe->y)) - { - st->count_ups++; - } - else - { - ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, - &st->info, EINA_FALSE); - consume_event(wd, event_info, event_type, ev_flag); - break; - } - - if (st->count_ups == eina_list_count(st->l)) - { - st->info.n = st->count_ups; - ev_flag =_set_state(gesture, ELM_GESTURE_STATE_END, - &st->info, EINA_FALSE); - consume_event(wd, event_info, event_type, ev_flag); - - return; - } - break; case EVAS_CALLBACK_MULTI_MOVE: @@ -1347,15 +1358,60 @@ _dbl_click_test(Evas_Object *obj, Pointer_Event *pe, pe_down = eina_list_data_get(pe_list); if (!_inside(pe_down->x, pe_down->y, pe->x, pe->y)) { - ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, - &st->info, EINA_FALSE); - consume_event(wd, event_info, event_type, ev_flag); + ev_flag = _set_state(gesture, ELM_GESTURE_STATE_ABORT, + &st->info, EINA_FALSE); + consume_event(wd, event_info, event_type, ev_flag); } } break; default: - return; + return EINA_FALSE; + } + + return EINA_FALSE; +} + + +/** + * @internal + * + * This function checks all click/tap and double/triple taps + * + * @param obj The gesture-layer object. + * @param pe The recent input event as stored in pe struct. + * @param event_info Original input event pointer. + * @param event_type Type of original input event. + * + * @ingroup Elm_Gesture_Layer + */ +static void +_tap_gestures_test(Evas_Object *obj, Pointer_Event *pe, + void *event_info, Evas_Callback_Type event_type) +{ /* Here we fill Recent_Taps struct and fire-up click/tap timers */ + Eina_Bool need_timer = EINA_FALSE; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + if (!pe) /* this happens when unhandled event arrived */ + return; /* see _make_pointer_event function */ + + if (IS_TESTED(ELM_GESTURE_N_TAPS)) + need_timer |= _tap_gesture_start(wd, pe, event_info, event_type, + wd->gesture[ELM_GESTURE_N_TAPS], 1); + + if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS)) + need_timer |= _tap_gesture_start(wd, pe, event_info, event_type, + wd->gesture[ELM_GESTURE_N_DOUBLE_TAPS], 2); + + if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) + need_timer |= _tap_gesture_start(wd, pe, event_info, event_type, + wd->gesture[ELM_GESTURE_N_TRIPLE_TAPS], 3); + + if ((need_timer) && (!wd->dbl_timeout)) + { /* Set a timer to finish these gestures */ + wd->dbl_timeout = ecore_timer_add(0.4, _multi_tap_timeout, + obj); } } @@ -1437,14 +1493,6 @@ _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe, { case EVAS_CALLBACK_MULTI_DOWN: case EVAS_CALLBACK_MOUSE_DOWN: - if (st->info.n > eina_list_count(st->touched)) - { /* ABORT: user lifts finger then back before completing gesgure */ - if (st->timeout) ecore_timer_del(st->timeout); - st->timeout = NULL; - ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT, - &st->info, EINA_FALSE); - } - st->touched = _add_touched_device(st->touched, pe); st->info.n = eina_list_count(st->touched); if ((pe->device == 0) && (eina_list_count(st->touched) == 1)) @@ -1454,8 +1502,8 @@ _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe, /* To test long tap */ /* When this timer expires, gesture STARTED */ if (!st->timeout) - st->timeout = ecore_timer_add(wd->long_tap_start_timeout, _long_tap_timeout, - gesture); + st->timeout = ecore_timer_add(wd->long_tap_start_timeout, + _long_tap_timeout, gesture); } consume_event(wd, event_info, event_type, ev_flag); @@ -1476,6 +1524,15 @@ _n_long_tap_test(Evas_Object *obj, Pointer_Event *pe, consume_event(wd, event_info, event_type, ev_flag); } } + else + { /* Stop test, user lifts finger before long-start */ + if (st->timeout) ecore_timer_del(st->timeout); + st->timeout = NULL; + ev_flag =_set_state(gesture, ELM_GESTURE_STATE_ABORT, + &st->info, EINA_FALSE); + consume_event(wd, event_info, event_type, ev_flag); + } + break; case EVAS_CALLBACK_MULTI_MOVE: @@ -2898,16 +2955,6 @@ void continues_gestures_restart(void *data, Eina_Bool states_reset) /* Run through events to restart gestures */ Gesture_Info *g; Eina_Bool n_lines, n_flicks, zoom, rotate; -#if defined(DEBUG_GESTURE_LAYER) - int i; - printf("Gesture | State | is tested\n"); - for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++) - { - g = wd->gesture[i]; - if(g) - printf(" %d %d %d\n", i, g->state, g->test); - } -#endif /* We turn-on flag for finished, aborted, not-started gestures */ g = wd->gesture[ELM_GESTURE_N_LINES]; n_lines = (g) ? ((states_reset) | ((g->state != ELM_GESTURE_STATE_START) @@ -2982,6 +3029,18 @@ _event_process(void *data, Evas_Object *obj __UNUSED__, Widget_Data *wd = elm_widget_data_get(data); if (!wd) return; +#if defined(DEBUG_GESTURE_LAYER) + int i; + Gesture_Info *g; + printf("Gesture | State | is tested\n"); + for(i = ELM_GESTURE_N_TAPS; i < ELM_GESTURE_LAST; i++) + { + g = wd->gesture[i]; + if(g) + printf(" %d %d %d\n", i, g->state, g->test); + } +#endif + /* Start testing candidate gesture from here */ if (_make_pointer_event(data, event_info, event_type, &_pe)) pe = &_pe; @@ -2990,17 +3049,8 @@ _event_process(void *data, Evas_Object *obj __UNUSED__, _n_long_tap_test(data, pe, event_info, event_type, ELM_GESTURE_N_LONG_TAPS); - if (IS_TESTED(ELM_GESTURE_N_TAPS)) - _dbl_click_test(data, pe, event_info, event_type, - ELM_GESTURE_N_TAPS, 1); - - if (IS_TESTED(ELM_GESTURE_N_DOUBLE_TAPS)) - _dbl_click_test(data, pe, event_info, event_type, - ELM_GESTURE_N_DOUBLE_TAPS, 2); - - if (IS_TESTED(ELM_GESTURE_N_TRIPLE_TAPS)) - _dbl_click_test(data, pe, event_info, event_type, - ELM_GESTURE_N_TRIPLE_TAPS, 3); + /* This takes care of single, double and tripple tap */ + _tap_gestures_test(data, pe, event_info, event_type); if (IS_TESTED(ELM_GESTURE_MOMENTUM)) _momentum_test(data, pe, event_info, event_type, @@ -3285,7 +3335,7 @@ elm_gesture_layer_add(Evas_Object *parent) wd->flick_time_limit_ms = _elm_config->glayer_flick_time_limit_ms; wd->long_tap_start_timeout = _elm_config->glayer_long_tap_start_timeout; wd->repeat_events = EINA_TRUE; - wd->glayer_continues_enable = _elm_config->glayer_continues_enable; + wd->glayer_continues_enable = EINA_FALSE;//_elm_config->glayer_continues_enable; #if defined(DEBUG_GESTURE_LAYER) printf("size of Gestures = <%d>\n", sizeof(wd->gesture)); -- 2.7.4