From 45388e45812275cdd5885ae0b6373e7f37456ccd Mon Sep 17 00:00:00 2001 From: WooHyun Jung Date: Sat, 23 Mar 2013 09:36:21 +0900 Subject: [PATCH] elementary/focus : Add four more focus direftions. ELM_FOCUS_UP, ELM_FOCUS_DOWN, ELM_FOCUS_RIGHT, and ELM_FOCUS_LEFT. These are for supporting elm_object_focus_next with four directions. And I added elm_object_focus_next_object_set(get). By setting focus next object manually, developer can set its own first candidate of focus next. Lastly I added elm_object_focused_object_get, for easy finding of current focused object in one object sub-tree. --- legacy/elementary/ChangeLog | 6 + legacy/elementary/NEWS | 3 + legacy/elementary/src/lib/elm_focus.h | 60 +++++++- legacy/elementary/src/lib/elm_main.c | 24 +++ legacy/elementary/src/lib/elm_widget.c | 200 ++++++++++++++++++++++++- legacy/elementary/src/lib/elm_widget.h | 30 ++++ 6 files changed, 319 insertions(+), 4 deletions(-) diff --git a/legacy/elementary/ChangeLog b/legacy/elementary/ChangeLog index deefb8d5f5..583036d624 100644 --- a/legacy/elementary/ChangeLog +++ b/legacy/elementary/ChangeLog @@ -1172,3 +1172,9 @@ * Fix elm box layout when an item has a max size, and that squashes all content even when the minimum size is greater. + +2013-03-23 WooHyun Jung + + * Add four more focus directions. ELM_FOCUS_UP/DOWN/RIGHT/LEFT. + * Add elm_object_focus_next_object_get/set. + * Add elm_object_focused_object_get. diff --git a/legacy/elementary/NEWS b/legacy/elementary/NEWS index ba1916067d..2a2fc15e7a 100644 --- a/legacy/elementary/NEWS +++ b/legacy/elementary/NEWS @@ -50,6 +50,9 @@ Additions: * Add elm_naviframe_item_pop_cb_set(). * Add elm_widget_newest_focus_order_get for knowing the last object(and its focus order) which got focus. * Add the smart signals in scroller. "scroll,left", "scroll,right", "scroll,up", "scroll,down". + * Add four more focus diretions. ELM_FOCUS_UP, ELM_FOCUS_DOWN, ELM_FOCUS_RIGHT, ELM_FOCUS_LEFT. + * Add APIs - elm_object_focus_next_object_get, elm_object_focus_next_object_set. + * Add API - elm_object_focused_object_get. Improvements: diff --git a/legacy/elementary/src/lib/elm_focus.h b/legacy/elementary/src/lib/elm_focus.h index 300ecaec23..282526a4f4 100644 --- a/legacy/elementary/src/lib/elm_focus.h +++ b/legacy/elementary/src/lib/elm_focus.h @@ -41,7 +41,11 @@ typedef enum { ELM_FOCUS_PREVIOUS, /**< previous direction */ - ELM_FOCUS_NEXT /**< next direction */ + ELM_FOCUS_NEXT, /**< next direction */ + ELM_FOCUS_UP, /**< up direction */ + ELM_FOCUS_DOWN, /**< down direction */ + ELM_FOCUS_RIGHT, /**< right direction */ + ELM_FOCUS_LEFT /**< left direction */ } Elm_Focus_Direction; /** @@ -187,10 +191,64 @@ EAPI void elm_object_focus_custom_chain_prepend(Evas_Object *obj * @param obj The object root of sub-tree * @param dir Direction to move the focus * + * @see elm_object_focus_next_object_get(), elm_object_focus_next_object_set() + * * @ingroup Focus */ EAPI void elm_object_focus_next(Evas_Object *obj, Elm_Focus_Direction dir); +/** + * Get next object which was set with specific focus direction. + * + * Get next object which was set by elm_object_focus_next_object_set + * with specific focus direction. + * + * @param obj The Elementary object + * @param dir Focus direction + * @return Focus next object or @c NULL, if there is no focus next object. + * + * @see elm_object_focus_next_object_set(), elm_object_focus_next() + * + * @since 1.8 + * + * @ingroup Focus + */ +EAPI Evas_Object * elm_object_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir); + +/** + * Set next object with specific focus direction. + * + * When focus next object is set with specific focus direction, this object + * will be the first candidate when finding next focusable object. + * Focus next object can be registered with six directions that are previous, + * next, up, down, right, and left. + * + * @param obj The Elementary object + * @param next Focus next object + * @param dir Focus direction + * + * @see elm_object_focus_next_object_get(), elm_object_focus_next() + * + * @since 1.8 + * + * @ingroup Focus + */ +EAPI void elm_object_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir); + +/** + * Get focused object in object tree. + * + * This function returns current focused object in one object sub-tree. + * + * @param obj The object root of sub-tree + * @return Current focused or @c NULL, if there is no focused object. + * + * @since 1.8 + * + * @ingroup Focus + */ +EAPI Evas_Object *elm_object_focused_object_get(const Evas_Object *obj); + /** * Make the elementary object and its children to be focusable * (or unfocusable). diff --git a/legacy/elementary/src/lib/elm_main.c b/legacy/elementary/src/lib/elm_main.c index a77849dcef..a83a72acdb 100644 --- a/legacy/elementary/src/lib/elm_main.c +++ b/legacy/elementary/src/lib/elm_main.c @@ -1295,6 +1295,30 @@ elm_object_focus_next(Evas_Object *obj, elm_widget_focus_cycle(obj, dir); } +EAPI Evas_Object * +elm_object_focus_next_object_get(const Evas_Object *obj, + Elm_Focus_Direction dir) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + return elm_widget_focus_next_object_get(obj, dir); +} + +EAPI void +elm_object_focus_next_object_set(Evas_Object *obj, + Evas_Object *next, + Elm_Focus_Direction dir) +{ + EINA_SAFETY_ON_NULL_RETURN(obj); + elm_widget_focus_next_object_set(obj, next, dir); +} + +EAPI Evas_Object * +elm_object_focused_object_get(const Evas_Object *obj) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL); + return elm_widget_focused_object_get(obj); +} + EAPI void elm_object_tree_focus_allow_set(Evas_Object *obj, Eina_Bool tree_focusable) diff --git a/legacy/elementary/src/lib/elm_widget.c b/legacy/elementary/src/lib/elm_widget.c index 193cfcfe99..4d4cc64342 100644 --- a/legacy/elementary/src/lib/elm_widget.c +++ b/legacy/elementary/src/lib/elm_widget.c @@ -2550,7 +2550,7 @@ _elm_widget_focus_list_direction_get(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, * focus before chain end, the first candidate will be returned. * * @param obj The widget root of sub-tree - * @param dir Direction os focus chain + * @param dir Direction of focus chain * @param next The next object in focus chain * @return EINA_TRUE if don't need focus chain restart/loop back * to use 'next' obj. @@ -2578,6 +2578,7 @@ _elm_widget_focus_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) Elm_Focus_Direction dir = va_arg(*list, Elm_Focus_Direction); Evas_Object **next = va_arg(*list, Evas_Object **); Eina_Bool *ret = va_arg(*list, Eina_Bool *); + Elm_Widget_Smart_Data *sd = _pd; *ret = EINA_FALSE; if (!next) @@ -2595,6 +2596,29 @@ _elm_widget_focus_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) { Eina_Bool int_ret = EINA_FALSE; eo_do((Eo *)obj, elm_wdg_focus_next(dir, next, &int_ret)); + if (!int_ret && elm_widget_focus_get(obj)) + { + Evas_Object *o = NULL; + if (dir == ELM_FOCUS_PREVIOUS) + o = sd->focus_previous; + else if (dir == ELM_FOCUS_NEXT) + o = sd->focus_next; + else if (dir == ELM_FOCUS_UP) + o = sd->focus_up; + else if (dir == ELM_FOCUS_DOWN) + o = sd->focus_down; + else if (dir == ELM_FOCUS_RIGHT) + o = sd->focus_right; + else if (dir == ELM_FOCUS_LEFT) + o = sd->focus_left; + + if (o) + { + *next = o; + *ret = EINA_TRUE; + return; + } + } *ret = int_ret; return; } @@ -2610,6 +2634,28 @@ _elm_widget_focus_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) if (!ac) return; } + if (elm_widget_focus_get(obj)) + { + if (dir == ELM_FOCUS_PREVIOUS) + *next = sd->focus_previous; + else if (dir == ELM_FOCUS_NEXT) + *next = sd->focus_next; + else if (dir == ELM_FOCUS_UP) + *next = sd->focus_up; + else if (dir == ELM_FOCUS_DOWN) + *next = sd->focus_down; + else if (dir == ELM_FOCUS_RIGHT) + *next = sd->focus_right; + else if (dir == ELM_FOCUS_LEFT) + *next = sd->focus_left; + + if (*next) + { + *ret = EINA_TRUE; + return; + } + } + /* Return */ *next = (Evas_Object *)obj; *ret = !ELM_WIDGET_FOCUS_GET(obj); @@ -2625,7 +2671,7 @@ _elm_widget_focus_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) * focus before list end, the first candidate will be returned. * * @param obj The widget root of sub-tree - * @param dir Direction os focus chain + * @param dir Direction of focus chain * @param items list with ordered objects * @param list_data_get function to get the object from one item of list * @param next The next object in focus chain @@ -2658,6 +2704,7 @@ _elm_widget_focus_list_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) if (ret) *ret = EINA_FALSE; Eina_List *(*list_next)(const Eina_List *list) = NULL; + Evas_Object *focused_object = NULL; if (!next) return; @@ -2669,13 +2716,55 @@ _elm_widget_focus_list_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) if (!items) return; + /* When Up, Down, Right, or Left, try direction_get first. */ + focused_object = elm_widget_focused_object_get(obj); + if (focused_object) + { + if((dir == ELM_FOCUS_UP) + || (dir == ELM_FOCUS_DOWN) + || (dir == ELM_FOCUS_RIGHT) + || (dir == ELM_FOCUS_LEFT)) + { + *next = elm_widget_focus_next_object_get(focused_object, dir); + if (*next) + { + if (ret) *ret = EINA_TRUE; + return; + } + else + { + Evas_Object *n; + double degree; + double weight; + + if (dir == ELM_FOCUS_UP) degree = 0.0; + else if (dir == ELM_FOCUS_DOWN) degree = 180.0; + else if (dir == ELM_FOCUS_RIGHT) degree = 90.0; + else if (dir == ELM_FOCUS_LEFT) degree = 270.0; + + if (elm_widget_focus_list_direction_get(obj, focused_object, + items, list_data_get, + degree, &n, &weight)) + { + *next = n; + if (ret) *ret = EINA_TRUE; + return; + } + } + } + } + /* Direction */ if (dir == ELM_FOCUS_PREVIOUS) { items = eina_list_last(items); list_next = eina_list_prev; } - else if (dir == ELM_FOCUS_NEXT) + else if ((dir == ELM_FOCUS_NEXT) + || (dir == ELM_FOCUS_UP) + || (dir == ELM_FOCUS_DOWN) + || (dir == ELM_FOCUS_RIGHT) + || (dir == ELM_FOCUS_LEFT)) list_next = eina_list_next; else return; @@ -2715,6 +2804,17 @@ _elm_widget_focus_list_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) if (ret) *ret = EINA_TRUE; return; } + else if ((dir == ELM_FOCUS_UP) + || (dir == ELM_FOCUS_DOWN) + || (dir == ELM_FOCUS_RIGHT) + || (dir == ELM_FOCUS_LEFT)) + { + if (tmp && elm_widget_focus_get(cur)) + { + *next = tmp; + return; + } + } else if ((tmp) && (!to_focus)) to_focus = tmp; } @@ -2743,6 +2843,96 @@ _elm_widget_focus_list_next_get(Eo *obj, void *_pd EINA_UNUSED, va_list *list) return; } +/** + * @internal + * + * Get next object which was set with specific focus direction. + * + * Get next object which was set by elm_widget_focus_next_object_set + * with specific focus directioin. + * + * @param obj The widget + * @param dir Direction of focus + * @return Widget which was registered with sepecific focus direction. + * + * @ingroup Widget + */ +EAPI Evas_Object * +elm_widget_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir) +{ + ELM_WIDGET_CHECK(obj) NULL; + + Evas_Object *ret = NULL; + eo_do((Eo *) obj, elm_wdg_focus_next_object_get(dir, &ret)); + return ret; +} + +static void +_elm_widget_focus_next_object_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +{ + Elm_Focus_Direction dir = va_arg(*list, Elm_Focus_Direction); + Evas_Object **ret = va_arg(*list, Evas_Object **); + Elm_Widget_Smart_Data *sd = _pd; + + if (dir == ELM_FOCUS_PREVIOUS) + *ret = sd->focus_previous; + else if (dir == ELM_FOCUS_NEXT) + *ret = sd->focus_next; + else if (dir == ELM_FOCUS_UP) + *ret = sd->focus_up; + else if (dir == ELM_FOCUS_DOWN) + *ret = sd->focus_down; + else if (dir == ELM_FOCUS_RIGHT) + *ret = sd->focus_right; + else if (dir == ELM_FOCUS_LEFT) + *ret = sd->focus_left; +} + +/** + * @internal + * + * Set next object with specific focus direction. + * + * When a widget is set with specific focus direction, this widget will be + * the first candidate when finding the next focus object. + * Focus next object can be registered with six directions that are previous, + * next, up, down, right, and left. + * + * @param obj The widget + * @param next Next focus object + * @param dir Direction of focus + * + * @ingroup Widget + */ +EAPI void +elm_widget_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir) +{ + ELM_WIDGET_CHECK(obj); + if (!next) return; + eo_do((Eo *) obj, elm_wdg_focus_next_object_set(next, dir)); +} + +static void +_elm_widget_focus_next_object_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list) +{ + Evas_Object *next = va_arg(*list, Evas_Object *); + Elm_Focus_Direction dir = va_arg(*list, Elm_Focus_Direction); + Elm_Widget_Smart_Data *sd = _pd; + + if (dir == ELM_FOCUS_PREVIOUS) + sd->focus_previous = next; + else if (dir == ELM_FOCUS_NEXT) + sd->focus_next = next; + else if (dir == ELM_FOCUS_UP) + sd->focus_up = next; + else if (dir == ELM_FOCUS_DOWN) + sd->focus_down = next; + else if (dir == ELM_FOCUS_RIGHT) + sd->focus_right = next; + else if (dir == ELM_FOCUS_LEFT) + sd->focus_left = next; +} + EAPI void elm_widget_parent_highlight_set(Evas_Object *obj, Eina_Bool highlighted) @@ -5717,6 +5907,8 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_LIST_DIRECTION_GET), _elm_widget_focus_list_direction_get), EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_GET), _elm_widget_focus_next_get), EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_LIST_NEXT_GET), _elm_widget_focus_list_next_get), + EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_GET), _elm_widget_focus_next_object_get), + EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_SET), _elm_widget_focus_next_object_set), EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_PARENT_HIGHLIGHT_SET), _elm_widget_parent_highlight_set), EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISPLAY_MODE_SET), _elm_widget_display_mode_set), EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISPLAY_MODE_GET), _elm_widget_display_mode_get), @@ -5858,6 +6050,8 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_FOCUS_LIST_DIRECTION_GET, "Get near object in one direction of base object in list."), EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_FOCUS_NEXT_GET, "Get next object in focus chain of object tree."), EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_FOCUS_LIST_NEXT_GET, "Get next object in focus chain of object tree in list."), + EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_GET, "Get next object specified by focus direction."), + EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_SET, "Set next object with specific focus direction."), EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_PARENT_HIGHLIGHT_SET, "Set highlighted value from itself to top parent object."), EO_OP_DESCRIPTION(ELM_WIDGET_SUB_ID_DISPLAY_MODE_SET, "Sets the widget and child widget's Evas_Display_Mode."), diff --git a/legacy/elementary/src/lib/elm_widget.h b/legacy/elementary/src/lib/elm_widget.h index 50d4cfc15d..5b6c9c9d03 100644 --- a/legacy/elementary/src/lib/elm_widget.h +++ b/legacy/elementary/src/lib/elm_widget.h @@ -377,6 +377,8 @@ typedef struct _Elm_Widget_Smart_Data Evas_Object *resize_obj; Evas_Object *hover_obj; Eina_List *tooltips, *cursors; + Evas_Object *focus_previous, *focus_next; + Evas_Object *focus_up, *focus_down, *focus_right, *focus_left; /* "show region" coordinates. all widgets got those because this * info may be set and queried recursively through the widget @@ -626,6 +628,8 @@ EAPI Eina_Bool elm_widget_focus_direction_get(const Evas_Object *obj, con EAPI Eina_Bool elm_widget_focus_next_get(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next); EAPI Eina_Bool elm_widget_focus_list_direction_get(const Evas_Object *obj, const Evas_Object *base, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), double degree, Evas_Object **direction, double *weight); EAPI Eina_Bool elm_widget_focus_list_next_get(const Evas_Object *obj, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), Elm_Focus_Direction dir, Evas_Object **next); +EAPI Evas_Object *elm_widget_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir); +EAPI void elm_widget_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir); EAPI void elm_widget_parent_highlight_set(Evas_Object *obj, Eina_Bool highlighted); EAPI void elm_widget_focus_set(Evas_Object *obj, int first); EAPI void elm_widget_focused_object_clear(Evas_Object *obj); @@ -1145,6 +1149,8 @@ enum ELM_WIDGET_SUB_ID_FOCUS_LIST_DIRECTION_GET, ELM_WIDGET_SUB_ID_FOCUS_NEXT_GET, ELM_WIDGET_SUB_ID_FOCUS_LIST_NEXT_GET, + ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_GET, + ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_SET, ELM_WIDGET_SUB_ID_PARENT_HIGHLIGHT_SET, ELM_WIDGET_SUB_ID_DISPLAY_MODE_SET, @@ -2332,6 +2338,30 @@ typedef void * (*list_data_get_func_type)(const Eina_List * l); */ #define elm_wdg_focus_list_next_get(items, list_data_get, dir, next, ret) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_LIST_NEXT_GET), EO_TYPECHECK(const Eina_List *, items), EO_TYPECHECK(list_data_get_func_type, list_data_get), EO_TYPECHECK(Elm_Focus_Direction, dir), EO_TYPECHECK(Evas_Object **, next), EO_TYPECHECK(Eina_Bool *, ret) +/** + * @def elm_wdg_focus_next_object_get + * @since 1.8 + * + * No description supplied by the EAPI. + * + * @param[in] dir + * @param[out] ret + * + */ +#define elm_wdg_focus_next_object_get(dir, ret) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_GET), EO_TYPECHECK(Elm_Focus_Direction, dir), EO_TYPECHECK(Evas_Object **, ret) + +/** + * @def elm_wdg_focus_next_object_set + * @since 1.8 + * + * No description supplied by the EAPI. + * + * @param[in] next + * @param[in] dir + * + */ +#define elm_wdg_focus_next_object_set(next, dir) ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_OBJECT_SET), EO_TYPECHECK(Evas_Object *, next), EO_TYPECHECK(Elm_Focus_Direction, dir) + /** * @def elm_wdg_parent_highlight_set * @since 1.8