Elm Glayer: Fixed all tap, long tap, gestures bugs

Signed-off-by: Aharon Hillel <a.hillel@partner.samsung.com>

SVN revision: 64127
This commit is contained in:
Aharon Hillel 2011-10-17 08:12:45 +00:00 committed by Tom Hacohen
parent 1df093390c
commit 14b0c8d207
1 changed files with 161 additions and 111 deletions

View File

@ -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;
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]);
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;
_set_state(gesture, ELM_GESTURE_STATE_ABORT,
gesture->info, EINA_FALSE);
_dbl_click_test_reset(gesture);
_clear_if_finished(gesture->obj);
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));