From d59d427a3ceef30b38e46be62c8029d2ffad6727 Mon Sep 17 00:00:00 2001 From: WooHyun Jung Date: Fri, 5 Aug 2011 08:25:07 +0000 Subject: [PATCH] elementary : Focus movement is possible with arrow keys. You can check this feature in elementary_test -> focus. SVN revision: 62125 --- src/bin/test_focus.c | 3 +- src/lib/Elementary.h.in | 6 +- src/lib/elm_widget.c | 263 ++++++++++++++++++++++++++++++++++++++++-------- src/lib/elm_widget.h | 1 + src/lib/elm_win.c | 28 ++++++ 5 files changed, 258 insertions(+), 43 deletions(-) diff --git a/src/bin/test_focus.c b/src/bin/test_focus.c index 34bc94c..721cadc 100644 --- a/src/bin/test_focus.c +++ b/src/bin/test_focus.c @@ -91,7 +91,8 @@ test_focus(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info { Evas_Object *lb = elm_label_add(win); elm_object_text_set(lb, - "Use Tab and Shift+Tab" + "Use Tab, Shift+Tab, and
" + "Arrow Keys
" ); evas_object_size_hint_weight_set(lb, 0.0, 0.0); evas_object_size_hint_align_set(lb, EVAS_HINT_FILL, diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index d519bde..0b62776 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -320,7 +320,11 @@ extern "C" { typedef enum _Elm_Focus_Direction { ELM_FOCUS_PREVIOUS, - ELM_FOCUS_NEXT + ELM_FOCUS_NEXT, + ELM_FOCUS_UP, + ELM_FOCUS_DOWN, + ELM_FOCUS_LEFT, + ELM_FOCUS_RIGHT } Elm_Focus_Direction; typedef enum _Elm_Text_Format diff --git a/src/lib/elm_widget.c b/src/lib/elm_widget.c index ecdf0f2..a87dc35 100644 --- a/src/lib/elm_widget.c +++ b/src/lib/elm_widget.c @@ -158,6 +158,10 @@ static void _if_focused_revert(Evas_Object *obj, static Evas_Object *_newest_focus_order_get(Evas_Object *obj, unsigned int *newest_focus_order, Eina_Bool can_focus_only); +static Eina_Bool _focus_list_direction_nearest_get(Evas_Object *obj, + Eina_List *list, + Elm_Focus_Direction dir, + Evas_Object **nearest); /* local subsystem globals */ static Evas_Smart *_e_smart = NULL; @@ -399,6 +403,96 @@ _elm_widget_focus_region_show(const Evas_Object *obj) } } +static Eina_Bool +_focus_list_direction_nearest_get(Evas_Object *obj, + Eina_List *list, + Elm_Focus_Direction dir, + Evas_Object **nearest) +{ + Evas_Object *cur, *next = NULL; + Eina_List *l; + double weight = 0.0; + Evas_Coord x, y, w, h, cx, cy; + + if (!nearest) return EINA_FALSE; + *nearest = NULL; + + evas_object_geometry_get(obj, &x, &y, &w, &h); + cx = x + (w / 2); + cy = y + (h / 2); + + EINA_LIST_FOREACH(list, l, cur) + { + if (obj == cur) continue; + Evas_Coord cur_x, cur_y, cur_w, cur_h; + int w_gap = 0, h_gap = 0; + double cur_weight = 0.0; + + evas_object_geometry_get(cur, &cur_x, &cur_y, &cur_w, &cur_h); + + if (dir == ELM_FOCUS_LEFT) + { + if (x < (cur_x + cur_w)) continue; + w_gap = x - (cur_x + cur_w); + if ((cy >= cur_y) && (cy <= (cur_y + cur_h))) + h_gap = 0; + else if (cy > (cur_y + cur_h)) + h_gap = cy - (cur_y + cur_h); + else if (cy < (cur_y)) + h_gap = cur_y - cy; + } + else if (dir == ELM_FOCUS_RIGHT) + { + if ((x + w) > cur_x) continue; + w_gap = cur_x - (x + w); + if ((cy >= cur_y) && (cy <= (cur_y + cur_h))) + h_gap = 0; + else if (cy > (cur_y + cur_h)) + h_gap = cy - (cur_y + cur_h); + else if (cy < (cur_y)) + h_gap = cur_y - cy; + } + else if (dir == ELM_FOCUS_UP) + { + if (y < (cur_y + cur_h)) continue; + h_gap = y - (cur_y + cur_h); + if ((cx >= cur_x) && (cx <= (cur_x + cur_w))) + w_gap = 0; + else if (cx < cur_x) + w_gap = cur_x - cx; + else if (cx > (cur_x + cur_w)) + w_gap = cur_x + cur_w - cx; + } + else if (dir == ELM_FOCUS_DOWN) + { + if ((y + h) > cur_y) continue; + h_gap = cur_y - (y + h); + if ((cx >= cur_x) && (cx <= (cur_x + cur_w))) w_gap = 0; + else if (cx < cur_x) + w_gap = cur_x - cx; + else if (cx > (cur_x + cur_w)) + w_gap = cur_x + cur_w - cx; + } + cur_weight = (w_gap * w_gap) + (h_gap * h_gap); + + if (cur_weight == 0.0) + { + *nearest = cur; + return EINA_TRUE; + } + cur_weight = 1.0 / cur_weight; + if (cur_weight > weight) + { + weight = cur_weight; + next = cur; + } + } + if (!next) return EINA_FALSE; + *nearest = next; + return EINA_TRUE; +} + + /** * @defgroup Widget Widget * @@ -1147,6 +1241,47 @@ elm_widget_tree_unfocusable_get(const Evas_Object *obj) return sd->tree_unfocusable; } +/** + * @internal + * + * Get the list of focusable child objects. + * + * This function retruns list of child objects which can get focus. + * + * @param obj The parent widget + * @retrun list of focusable child objects. + * + * @ingroup Widget + */ +EAPI Eina_List * +elm_widget_can_focus_child_list_get(const Evas_Object *obj) +{ + API_ENTRY return NULL; + + const Eina_List *l; + Eina_List *child_list = NULL; + Evas_Object *child; + + if (sd->subobjs) + { + EINA_LIST_FOREACH(sd->subobjs, l, child) + { + if ((elm_widget_can_focus_get(child)) && + (evas_object_visible_get(child)) && + (!elm_widget_disabled_get(child))) + child_list = eina_list_append(child_list, child); + else if (elm_widget_is(child)) + { + Eina_List *can_focus_list; + can_focus_list = elm_widget_can_focus_child_list_get(child); + if (can_focus_list) + child_list = eina_list_merge(child_list, can_focus_list); + } + } + } + return child_list; +} + EAPI void elm_widget_highlight_ignore_set(Evas_Object *obj, Eina_Bool ignore) @@ -1598,7 +1733,7 @@ elm_widget_focus_list_next_get(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next) { - Eina_List *(*list_next)(const Eina_List * list); + Eina_List *(*list_next)(const Eina_List * list) = NULL; if (!next) return EINA_FALSE; @@ -1617,64 +1752,110 @@ elm_widget_focus_list_next_get(const Evas_Object *obj, list_next = eina_list_prev; } else if (dir == ELM_FOCUS_NEXT) - list_next = eina_list_next; + { + list_next = eina_list_next; + } + else if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_RIGHT) || + (dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_DOWN)) + { + list_next = eina_list_next; + } else return EINA_FALSE; - const Eina_List *l = items; + if ((dir == ELM_FOCUS_PREVIOUS) || (dir == ELM_FOCUS_NEXT)) + { + const Eina_List *l = items; - /* Recovery last focused sub item */ - if (elm_widget_focus_get(obj)) - for (; l; l = list_next(l)) - { - Evas_Object *cur = list_data_get(l); - if (elm_widget_focus_get(cur)) break; - } + /* Recovery last focused sub item */ + if (elm_widget_focus_get(obj)) + for (; l; l = list_next(l)) + { + Evas_Object *cur = list_data_get(l); + if (elm_widget_focus_get(cur)) break; + } - const Eina_List *start = l; - Evas_Object *to_focus = NULL; + const Eina_List *start = l; + Evas_Object *to_focus = NULL; - /* Interate sub items */ - /* Go to end of list */ - for (; l; l = list_next(l)) - { - Evas_Object *tmp = NULL; - Evas_Object *cur = list_data_get(l); + /* Interate sub items */ + /* Go to end of list */ + for (; l; l = list_next(l)) + { + Evas_Object *tmp = NULL; + Evas_Object *cur = list_data_get(l); - if (elm_widget_parent_get(cur) != obj) - continue; + if (elm_widget_parent_get(cur) != obj) + continue; - /* Try Focus cycle in subitem */ - if (elm_widget_focus_next_get(cur, dir, &tmp)) - { - *next = tmp; - return EINA_TRUE; + /* Try Focus cycle in subitem */ + if (elm_widget_focus_next_get(cur, dir, &tmp)) + { + *next = tmp; + return EINA_TRUE; + } + else if ((tmp) && (!to_focus)) + to_focus = tmp; } - else if ((tmp) && (!to_focus)) - to_focus = tmp; - } - l = items; + l = items; + + /* Get First possible */ + for (; l != start; l = list_next(l)) + { + Evas_Object *tmp = NULL; + Evas_Object *cur = list_data_get(l); + + if (elm_widget_parent_get(cur) != obj) + continue; - /* Get First possible */ - for (; l != start; l = list_next(l)) + /* Try Focus cycle in subitem */ + elm_widget_focus_next_get(cur, dir, &tmp); + if (tmp) + { + *next = tmp; + return EINA_FALSE; + } + } + + *next = to_focus; + return EINA_FALSE; + } + else if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_RIGHT) || + (dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_DOWN)) { + Eina_List *can_focus_list; Evas_Object *tmp = NULL; - Evas_Object *cur = list_data_get(l); - - if (elm_widget_parent_get(cur) != obj) - continue; + Evas_Object *cur; - /* Try Focus cycle in subitem */ - elm_widget_focus_next_get(cur, dir, &tmp); - if (tmp) + can_focus_list = elm_widget_can_focus_child_list_get(obj); + if (can_focus_list) { - *next = tmp; - return EINA_FALSE; + Eina_List *l; + EINA_LIST_FOREACH(can_focus_list, l, cur) + { + if (elm_widget_focus_get(cur)) + { + if (_focus_list_direction_nearest_get(cur, can_focus_list, dir, &tmp)) + { + *next = tmp; + return EINA_TRUE; + } + else + { + *next = cur; + return EINA_FALSE; + } + } + } + if (elm_widget_focus_get(obj)) + { + *next = list_data_get(can_focus_list); + return EINA_FALSE; + } } } - *next = to_focus; return EINA_FALSE; } diff --git a/src/lib/elm_widget.h b/src/lib/elm_widget.h index 2165e1d..fb90163 100644 --- a/src/lib/elm_widget.h +++ b/src/lib/elm_widget.h @@ -269,6 +269,7 @@ EAPI void *elm_widget_signal_callback_del(Evas_Object *obj, const cha EAPI void elm_widget_can_focus_set(Evas_Object *obj, Eina_Bool can_focus); EAPI Eina_Bool elm_widget_can_focus_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_child_can_focus_get(const Evas_Object *obj); +EAPI Eina_List *elm_widget_can_focus_child_list_get(const Evas_Object *obj); EAPI void elm_widget_tree_unfocusable_set(Evas_Object *obj, Eina_Bool tree_unfocusable); EAPI Eina_Bool elm_widget_tree_unfocusable_get(const Evas_Object *obj); EAPI void elm_widget_highlight_ignore_set(Evas_Object *obj, Eina_Bool ignore); diff --git a/src/lib/elm_win.c b/src/lib/elm_win.c index fa8a83d..b471ac0 100644 --- a/src/lib/elm_win.c +++ b/src/lib/elm_win.c @@ -397,6 +397,34 @@ _elm_win_event_cb(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_T ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } + else if ((!strcmp(ev->keyname, "Left")) || + (!strcmp(ev->keyname, "KP_Left"))) + { + elm_widget_focus_cycle(obj, ELM_FOCUS_LEFT); + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + return EINA_TRUE; + } + else if ((!strcmp(ev->keyname, "Right")) || + (!strcmp(ev->keyname, "KP_Right"))) + { + elm_widget_focus_cycle(obj, ELM_FOCUS_RIGHT); + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + return EINA_TRUE; + } + else if ((!strcmp(ev->keyname, "Up")) || + (!strcmp(ev->keyname, "KP_Up"))) + { + elm_widget_focus_cycle(obj, ELM_FOCUS_UP); + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + return EINA_TRUE; + } + else if ((!strcmp(ev->keyname, "Down")) || + (!strcmp(ev->keyname, "KP_Down"))) + { + elm_widget_focus_cycle(obj, ELM_FOCUS_DOWN); + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + return EINA_TRUE; + } } return EINA_FALSE; -- 2.7.4