Gesture Layer: support multiple callbacks per type/state.

elm_gesture_layer_cb_add/del functions have been added to provide this
functionality.
elm_gesture_layer_cb_set provided only one callback and so was
overriding the callback with the new one.

For ABI compatibility, some rules were needed:
- when set function is called with NULL, all the callbacks of the state will be
removed (old behavior respect)
- try to use set or add/del exclusively with a preference to the new
APIs. This is because of the first rule and because it will be more correct.
- if you remove a callback, only one instance of this callback of this
type/state for this gesture will be removed, by comparing func and data.
It means that if you register twice the same callback/data, it will be added
twice and you will have to remove also twice too.
This commit is contained in:
Daniel Zaoui 2013-06-26 09:35:05 +03:00
parent 61dd0ba0ba
commit e49de4c97b
4 changed files with 197 additions and 13 deletions

View File

@ -1458,3 +1458,8 @@
2013-06-25 Ryuan Choi (ryuan)
* Fix crash of elm_notify when timeout is zero.
2013-06-26 Daniel Zaoui (JackDanielZ)
* Gesture Layer: add APIs to add/del multiple callbacks for a same
gesture/type/state.

View File

@ -44,10 +44,10 @@ _glayer_buf_dup(void *buf, size_t size)
#define SET_TEST_BIT(P) \
do { \
P->test = P->fn[ELM_GESTURE_STATE_START].cb || \
P->fn[ELM_GESTURE_STATE_MOVE].cb || \
P->fn[ELM_GESTURE_STATE_END].cb || \
P->fn[ELM_GESTURE_STATE_ABORT].cb; \
P->test = P->cbs[ELM_GESTURE_STATE_START] || \
P->cbs[ELM_GESTURE_STATE_MOVE] || \
P->cbs[ELM_GESTURE_STATE_END] || \
P->cbs[ELM_GESTURE_STATE_ABORT]; \
} while (0)
#define IS_TESTED_GESTURE(gesture) \
@ -118,6 +118,7 @@ typedef struct _Pointer_Event Pointer_Event;
*/
struct _Func_Data
{
EINA_INLIST;
void *user_data; /**< Holds user data to CB (like sd) */
Elm_Gesture_Event_Cb cb;
};
@ -144,7 +145,7 @@ struct _Gesture_Info
{
Evas_Object *obj;
void *data; /**< Holds gesture intemidiate processing data */
Func_Data fn[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info for states */
Eina_Inlist *cbs[ELM_GESTURE_STATE_ABORT + 1]; /**< Callback info (Func_Data) for states */
Elm_Gesture_Type g_type; /**< gesture type */
Elm_Gesture_State state; /**< gesture state */
void *info; /**< Data for the state callback */
@ -606,14 +607,16 @@ static Evas_Event_Flags
_state_report(Gesture_Info *gesture,
void *info)
{
Evas_Event_Flags flags = EVAS_EVENT_FLAG_NONE;
/* We report current state (START, MOVE, END, ABORT), once */
if ((gesture->state != ELM_GESTURE_STATE_UNDEFINED) &&
(gesture->fn[gesture->state].cb)) /* Fill state-info struct and
* send ptr to user
* callback */
(gesture->cbs[gesture->state])) /* Fill state-info struct and
* send ptr to user
* callback */
{
return gesture->fn[gesture->state].cb(
gesture->fn[gesture->state].user_data, info);
Func_Data *cb_info;
EINA_INLIST_FOREACH(gesture->cbs[gesture->state], cb_info)
flags |= cb_info->cb(cb_info->user_data, info);
}
return EVAS_EVENT_FLAG_NONE;
@ -3704,6 +3707,8 @@ _elm_gesture_layer_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
memset(priv->gesture, 0, sizeof(priv->gesture));
}
static void _cbs_clean(Elm_Gesture_Layer_Smart_Data *sd, Elm_Gesture_Type idx, Elm_Gesture_State cb_type);
static void
_elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
{
@ -3727,6 +3732,10 @@ _elm_gesture_layer_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
if (sd->gesture[i]->data)
free(sd->gesture[i]->data);
_cbs_clean(sd, i, ELM_GESTURE_STATE_START);
_cbs_clean(sd, i, ELM_GESTURE_STATE_MOVE);
_cbs_clean(sd, i, ELM_GESTURE_STATE_END);
_cbs_clean(sd, i, ELM_GESTURE_STATE_ABORT);
free(sd->gesture[i]);
}
if (sd->gest_taps_timeout) ecore_timer_del(sd->gest_taps_timeout);
@ -3888,6 +3897,23 @@ _attach(Eo *obj, void *_pd, va_list *list)
if (ret) *ret = EINA_TRUE;
}
static void
_cbs_clean(Elm_Gesture_Layer_Smart_Data *sd,
Elm_Gesture_Type idx,
Elm_Gesture_State cb_type)
{
if (!sd->gesture[idx]) return;
Func_Data *cb_info;
EINA_INLIST_FREE(sd->gesture[idx]->cbs[cb_type], cb_info)
{
sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
free(cb_info);
}
SET_TEST_BIT(sd->gesture[idx]);
}
EAPI void
elm_gesture_layer_cb_set(Evas_Object *obj,
Elm_Gesture_Type idx,
@ -3907,6 +3933,33 @@ _cb_set(Eo *obj, void *_pd, va_list *list)
Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
void *data = va_arg(*list, void *);
Elm_Gesture_Layer_Smart_Data *sd = _pd;
_cbs_clean(sd, idx, cb_type); // for ABI compat.
eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
}
EAPI void
elm_gesture_layer_cb_add(Evas_Object *obj,
Elm_Gesture_Type idx,
Elm_Gesture_State cb_type,
Elm_Gesture_Event_Cb cb,
void *data)
{
ELM_GESTURE_LAYER_CHECK(obj);
eo_do(obj, elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data));
}
static void
_cb_add(Eo *obj, void *_pd, va_list *list)
{
Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
void *data = va_arg(*list, void *);
if (!cb) return;
Gesture_Info *p;
Elm_Gesture_Layer_Smart_Data *sd = _pd;
@ -3914,15 +3967,58 @@ _cb_set(Eo *obj, void *_pd, va_list *list)
sd->gesture[idx] = calloc(1, sizeof(Gesture_Info));
if (!sd->gesture[idx]) return;
Func_Data *cb_info = calloc(1, sizeof(*cb_info));
if (!cb_info) return;
cb_info->cb = cb;
cb_info->user_data = data;
p = sd->gesture[idx];
p->obj = obj;
p->g_type = idx;
p->fn[cb_type].cb = cb;
p->fn[cb_type].user_data = data;
p->cbs[cb_type] = eina_inlist_append(p->cbs[cb_type],
EINA_INLIST_GET(cb_info));
p->state = ELM_GESTURE_STATE_UNDEFINED;
SET_TEST_BIT(p);
}
EAPI void
elm_gesture_layer_cb_del(Evas_Object *obj,
Elm_Gesture_Type idx,
Elm_Gesture_State cb_type,
Elm_Gesture_Event_Cb cb,
void *data)
{
ELM_GESTURE_LAYER_CHECK(obj);
eo_do(obj, elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data));
}
static void
_cb_del(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Elm_Gesture_Type idx = va_arg(*list, Elm_Gesture_Type);
Elm_Gesture_State cb_type = va_arg(*list, Elm_Gesture_State);
Elm_Gesture_Event_Cb cb = va_arg(*list, Elm_Gesture_Event_Cb);
void *data = va_arg(*list, void *);
Elm_Gesture_Layer_Smart_Data *sd = _pd;
if (!sd->gesture[idx]) return;
Eina_Inlist *itr;
Func_Data *cb_info;
EINA_INLIST_FOREACH_SAFE(sd->gesture[idx]->cbs[cb_type], itr, cb_info)
{
if (cb_info->cb == cb && cb_info->user_data == data)
{
sd->gesture[idx]->cbs[cb_type] = eina_inlist_remove(
sd->gesture[idx]->cbs[cb_type], EINA_INLIST_GET(cb_info));
free(cb_info);
SET_TEST_BIT(sd->gesture[idx]);
return;
}
}
}
EAPI void
elm_gesture_layer_line_min_length_set(Evas_Object *obj, int line_min_length)
{
@ -4158,6 +4254,8 @@ _class_constructor(Eo_Class *klass)
EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), _cb_set),
EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET), _tap_finger_size_set),
EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET), _tap_finger_size_get),
EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), _cb_add),
EO_OP_FUNC(ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), _cb_del),
EO_OP_FUNC_SENTINEL
};
eo_class_funcs_set(klass, func_desc);
@ -4176,6 +4274,8 @@ static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET, "Use function to set callbacks to be notified about change of state of gesture."),
EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET, "Use function to set valid touch-area size for finger."),
EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET, "This function returns the valid touch-area size for finger."),
EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD, "Use function to add callbacks to be notified about change of state of gesture."),
EO_OP_DESCRIPTION(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL, "Use function to remove added callbacks."),
EO_OP_DESCRIPTION_SENTINEL
};

View File

@ -16,6 +16,8 @@ enum
ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET,
ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_SET,
ELM_OBJ_GESTURE_LAYER_TAP_FINGER_SIZE_GET,
ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD,
ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL,
ELM_OBJ_GESTURE_LAYER_SUB_ID_LAST
};
@ -127,7 +129,10 @@ enum
* @since 1.8
*
* Use function to set callbacks to be notified about
* change of state of gesture.
* change of state of gesture. If a function was already
* set for this gesture/type/state, it will be replaced by the new one.
* For ABI compat, callbacks added by elm_obj_gesture_layer_cb_add will be removed. It is recommended
* to use only one of these functions for a gesture object.
*
* @param[in] idx
* @param[in] cb_type
@ -135,11 +140,48 @@ enum
* @param[in] data
*
* @see elm_gesture_layer_cb_set
* @see elm_gesture_layer_cb_add
*
* @ingroup Elm_Gesture_Layer
*/
#define elm_obj_gesture_layer_cb_set(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_SET), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data)
/**
* @def elm_obj_gesture_layer_cb_add
* @since 1.8
*
* Use function to add a callback to be notified about
* change of state of gesture.
*
* @param[in] idx
* @param[in] cb_type
* @param[in] cb
* @param[in] data
*
* @see elm_gesture_layer_cb_add
*
* @ingroup Elm_Gesture_Layer
*/
#define elm_obj_gesture_layer_cb_add(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_ADD), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data)
/**
* @def elm_obj_gesture_layer_cb_del
* @since 1.8
*
* Use function to remove a callback that has been added
* to be notified about change of state of gesture.
*
* @param[in] idx
* @param[in] cb_type
* @param[in] cb
* @param[in] data
*
* @see elm_gesture_layer_cb_del
*
* @ingroup Elm_Gesture_Layer
*/
#define elm_obj_gesture_layer_cb_del(idx, cb_type, cb, data) ELM_OBJ_GESTURE_LAYER_ID(ELM_OBJ_GESTURE_LAYER_SUB_ID_CB_DEL), EO_TYPECHECK(Elm_Gesture_Type, idx), EO_TYPECHECK(Elm_Gesture_State, cb_type), EO_TYPECHECK(Elm_Gesture_Event_Cb, cb), EO_TYPECHECK(void *, data)
/**
* @def elm_obj_gesture_layer_tap_finger_size_set
* @since 1.8

View File

@ -110,6 +110,43 @@ EAPI Eina_Bool elm_gesture_layer_attach(Evas_Object *obj, Evas_Object *target
*/
EAPI void elm_gesture_layer_cb_set(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data);
/**
* Use function to add callbacks to be notified about
* change of state of gesture.
* When a user registers a callback with this function
* this means this gesture has to be tested.
*
* When ALL callbacks for a gesture are set to NULL
* it means user isn't interested in gesture-state
* and it will not be tested.
*
* If a function was already set for this gesture/type/state, it will be
* replaced by the new one. For ABI compat, callbacks added by
* elm_gesture_layer_cb_add will be removed. It is recommended to
* use only one of these functions for a gesture object.
*
* @param obj gesture-layer.
* @param idx The gesture you would like to track its state.
* @param cb callback function pointer.
* @param cb_type what event this callback tracks: START, MOVE, END, ABORT.
* @param data user info to be sent to callback (usually, Smart Data)
*
*/
EAPI void elm_gesture_layer_cb_add(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data);
/**
* Use this function to remove a callback that has been added
* to be notified about change of state of gesture.
*
* @param obj gesture-layer.
* @param idx The gesture you would like to track its state.
* @param cb callback function pointer.
* @param cb_type what event this callback tracks: START, MOVE, END, ABORT.
* @param data user info for the callback (usually, Smart Data)
*
*/
EAPI void elm_gesture_layer_cb_del(Evas_Object *obj, Elm_Gesture_Type idx, Elm_Gesture_State cb_type, Elm_Gesture_Event_Cb cb, void *data);
/**
* @since 1.8
* This function sets the gesture layer finger-size for taps