jackdanielz pushed a commit to branch master.
commit 3628a8c4ea2485ee7ee5a81cfd4e0f0fe62b10d6
Author: Yossi Kantor <[email protected]>
Date: Wed Feb 20 12:00:49 2013 +0200
elementary: Focus improvement for elm_genlist and elm_list
Summary:
This patch applies automatic focus feature to elm_genlist and elm_list
containers.
Currently (prior to this patch), focusable widgets inside list items of both
containers receive focus by an explicit mouse click over them, and lose
focus
when focus goes to someone else in the window.
This change also adds the ability to:
- focus by default on the first-from-right focusable widget upon items
selection
- lose the focus when another item is selected (focused or not)
- move focus between focusable widgets inside the same item by left and
right
arrow keys accordingly (up and down keys when elm_list is in horizontal
mode)
Focus is supported for horizontal and vertical lists.
Tests have been added for genlists and lists to check focus feature.
---
src/bin/test.c | 8 ++-
src/bin/test_genlist.c | 146 +++++++++++++++++++++++++++++++++++++++++++
src/bin/test_list.c | 136 ++++++++++++++++++++++++++++++++++++++++
src/lib/elm_gen_common.h | 1 +
src/lib/elm_genlist.c | 123 ++++++++++++++++++++++++++++++++++++
src/lib/elm_genlist_eo.h | 25 ++++++++
src/lib/elm_genlist_legacy.h | 27 ++++++++
src/lib/elm_list.c | 127 +++++++++++++++++++++++++++++++++++--
src/lib/elm_list_eo.h | 26 ++++++++
src/lib/elm_list_legacy.h | 27 ++++++++
src/lib/elm_widget_genlist.h | 1 +
src/lib/elm_widget_list.h | 1 +
12 files changed, 643 insertions(+), 5 deletions(-)
diff --git a/src/bin/test.c b/src/bin/test.c
index 77de0bd..6390dad 100644
--- a/src/bin/test.c
+++ b/src/bin/test.c
@@ -78,6 +78,8 @@ void test_list4(void *data, Evas_Object *obj, void
*event_info);
void test_list5(void *data, Evas_Object *obj, void *event_info);
void test_list6(void *data, Evas_Object *obj, void *event_info);
void test_list7(void *data, Evas_Object *obj, void *event_info);
+void test_list8(void *data, Evas_Object *obj, void *event_info);
+void test_list9(void *data, Evas_Object *obj, void *event_info);
void test_list_separator(void *data, Evas_Object *obj, void *event_info);
void test_inwin(void *data, Evas_Object *obj, void *event_info);
void test_inwin2(void *data, Evas_Object *obj, void *event_info);
@@ -104,6 +106,7 @@ void test_genlist16(void *data, Evas_Object *obj, void
*event_info);
void test_genlist17(void *data, Evas_Object *obj, void *event_info);
void test_genlist18(void *data, Evas_Object *obj, void *event_info);
void test_genlist19(void *data, Evas_Object *obj, void *event_info);
+void test_genlist20(void *data, Evas_Object *obj, void *event_info);
void test_genlist_item_styles(void *data, Evas_Object *obj, void *event_info);
void test_gesture_layer(void *data, Evas_Object *obj, void *event_info);
void test_gesture_layer2(void *data, Evas_Object *obj, void *event_info);
@@ -365,7 +368,7 @@ my_win_main(char *autorun, Eina_Bool test_win_only)
* type is a basic window (the final parameter).
* You can call elm_win_util_standard_add() instead. This is a convenient
API
* for window and bg creation. You don't need to create bg object manually.
- * You can also set the title of the window at the same time.
+ * You can also set the title of the window at the same time.
* ex) win = elm_win_util_standard_add("main", "Elementary Tests"); */
win = elm_win_add(NULL, "main", ELM_WIN_BASIC);
/* Set the title of the window - This is in the titlebar. */
@@ -591,6 +594,8 @@ add_tests:
ADD_TEST(NULL, "Lists", "List 5", test_list5);
ADD_TEST(NULL, "Lists", "List 6", test_list6);
ADD_TEST(NULL, "Lists", "List 7", test_list7);
+ ADD_TEST(NULL, "Lists", "List Focus", test_list8);
+ ADD_TEST(NULL, "Lists", "List Focus Horizontal", test_list9);
ADD_TEST(NULL, "Lists", "List Separator", test_list_separator);
ADD_TEST(NULL, "Lists", "Genlist", test_genlist);
ADD_TEST(NULL, "Lists", "Genlist 2", test_genlist2);
@@ -614,6 +619,7 @@ add_tests:
ADD_TEST(NULL, "Lists", "Genlist Decorate Modes", test_genlist17);
ADD_TEST(NULL, "Lists", "Genlist Tree and Decorate All Mode",
test_genlist18);
ADD_TEST(NULL, "Lists", "Genlist Full Widget", test_genlist19);
+ ADD_TEST(NULL, "Lists", "Genlist Focus", test_genlist20);
ADD_TEST(NULL, "Lists", "Genlist Item Styles", test_genlist_item_styles);
ADD_TEST(NULL, "Lists", "GenGrid", test_gengrid);
ADD_TEST(NULL, "Lists", "GenGrid 2", test_gengrid2);
diff --git a/src/bin/test_genlist.c b/src/bin/test_genlist.c
index 943806b..329fa0f 100644
--- a/src/bin/test_genlist.c
+++ b/src/bin/test_genlist.c
@@ -3230,6 +3230,152 @@ test_genlist19(void *data __UNUSED__, Evas_Object *obj
__UNUSED__, void *event_i
evas_object_show(win);
}
+static unsigned _gl20_objects = 5;
+static const char *_gl20_object_names[] = {"None", "Square", "Button",
"Check", "Box"};
+
+static char *
+gl20_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part
__UNUSED__)
+{
+ char buf[256];
+ char op = (uintptr_t)data % 100;
+ snprintf(buf, sizeof(buf), " %s / %s ",
+ _gl20_object_names[op / 10],
+ _gl20_object_names[op % 10]);
+ return strdup(buf);
+}
+
+static Evas_Object *
+gl20_content_get(void *data, Evas_Object *obj, const char *part)
+{
+ Evas_Object *cnt = NULL;
+
+ char op = (uintptr_t)data % 100;
+ char type = (!strcmp(part,"elm.swallow.icon")) ? op / 10 : op % 10;
+
+ switch(type)
+ {
+ case 1:
+ cnt = elm_bg_add(obj);
+ evas_object_color_set(cnt, 128, 18, 128, 255);
+ break;
+ case 2:
+ cnt = elm_button_add(obj);
+ break;
+ case 3:
+ cnt = elm_check_add(obj);
+ break;
+ case 4:
+ cnt = elm_box_add(obj);
+ evas_object_size_hint_align_set(cnt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_horizontal_set(cnt, EINA_TRUE);
+ elm_box_pack_end(cnt, gl20_content_get((void *)2, obj, ""));
+ elm_box_pack_end(cnt, gl20_content_get((void *)3, obj, ""));
+ elm_box_pack_end(cnt, gl20_content_get((void *)2, obj, ""));
+ break;
+ default:
+ break;
+
+ }
+ if (cnt)
+ {
+ evas_object_size_hint_weight_set(cnt, EVAS_HINT_EXPAND,
EVAS_HINT_EXPAND);
+ evas_object_show(cnt);
+ }
+ return cnt;
+}
+
+static void
+gl20_focus_on_selection_set(Evas_Object *gl, Evas_Object *chk, Eina_Bool focus)
+{
+ elm_genlist_focus_on_selection_set(gl, focus);
+ elm_check_state_set(chk, focus);
+ printf("genlist_focus_on_selection = %s\n", (focus) ? "true" : "false");
+}
+
+static void
+gl20_focus_check_changed(void *data, Evas_Object *obj, void *event_info
__UNUSED__)
+{
+ Eina_Bool nextstate = !elm_genlist_focus_on_selection_get(data);
+ gl20_focus_on_selection_set(data, obj, nextstate);
+}
+
+void
+test_genlist20(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void
*event_info __UNUSED__)
+{
+ Evas_Object *win, *gl, *bx, *bxx, *chk;
+ unsigned lhand, rhand;
+
+ elm_config_focus_highlight_enabled_set(EINA_TRUE);
+
+ win = elm_win_util_standard_add("genlist-focus", "Genlist Focus");
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ bxx = elm_box_add(win);
+ elm_win_resize_object_add(win, bxx);
+ evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_show(bxx);
+
+ gl = elm_genlist_add(win);
+ evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(bxx, gl);
+ evas_object_show(gl);
+
+ bx = elm_box_add(win);
+ evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0);
+ evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_horizontal_set(bx, EINA_TRUE);
+ evas_object_show(bx);
+
+ chk = elm_check_add(win);
+ elm_object_text_set(chk, "Focus on selection");
+ evas_object_smart_callback_add(chk, "changed", gl20_focus_check_changed,
gl);
+ elm_box_pack_end(bx, chk);
+ evas_object_show(chk);
+
+ elm_box_pack_end(bxx, bx);
+
+ gl20_focus_on_selection_set(gl, chk, EINA_TRUE);
+
+ itc1 = elm_genlist_item_class_new();
+ itc1->item_style = "default";
+ itc1->func.text_get = gl20_text_get;
+ itc1->func.content_get = gl20_content_get;
+ itc1->func.state_get = NULL;
+ itc1->func.del = NULL;
+
+ itc4 = elm_genlist_item_class_new();
+ itc4->item_style = "tree_effect";
+ itc4->func.text_get = gl20_text_get;
+ itc4->func.content_get = gl20_content_get;
+ itc4->func.state_get = NULL;
+ itc4->func.del = NULL;
+
+ for (lhand = 0; lhand < _gl20_objects; lhand++)
+ {
+ for (rhand = 0; rhand < _gl20_objects; rhand++)
+ {
+ unsigned digit1 = lhand * 10 + rhand;
+ elm_genlist_item_append(gl, itc1, (void*)(uintptr_t)digit1,
+ NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ unsigned digit2 = (_gl20_objects - lhand -1) * 10 +
+ (_gl20_objects - rhand -1);
+ elm_genlist_item_append(gl, itc1, (void*)(uintptr_t)digit2,
+ NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ if (rhand == (_gl20_objects - 1))
+ elm_genlist_item_append(gl, itc4, (void*)(uintptr_t)digit1,
+ NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL);
+ }
+ }
+
+ elm_genlist_item_class_free(itc1);
+ elm_genlist_item_class_free(itc4);
+
+ evas_object_resize(win, 300, 500);
+ evas_object_show(win);
+}
+
+
/* test genlist item styles */
const char *_genlist_styles[] = {
diff --git a/src/bin/test_list.c b/src/bin/test_list.c
index eef6b52..3746ccb 100644
--- a/src/bin/test_list.c
+++ b/src/bin/test_list.c
@@ -1227,6 +1227,142 @@ test_list7(void *data __UNUSED__,
evas_object_show(win);
}
+static const unsigned _list_focus_objects = 5;
+static const char *_list_focus_names[] = {"None", "Square", "Button", "Check",
"Box"};
+static const int _list_focus_combo[] = { 1, 0, 2, 33, 43, 44, 10, 30, 22, 11,
10, -1 };
+
+static Evas_Object *
+test_list8_content_get(Evas_Object *obj, unsigned type, Eina_Bool horiz)
+{
+ Evas_Object *cnt = NULL;
+
+ switch(type)
+ {
+ case 1:
+ cnt = elm_bg_add(obj);
+ evas_object_color_set(cnt, 128, 18, 128, 255);
+ evas_object_size_hint_min_set(cnt, 50, 50);
+ break;
+ case 2:
+ cnt = elm_button_add(obj);
+ break;
+ case 3:
+ cnt = elm_check_add(obj);
+ break;
+ case 4:
+ cnt = elm_box_add(obj);
+ elm_box_horizontal_set(cnt, !horiz);
+ evas_object_size_hint_align_set(cnt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_pack_end(cnt, test_list8_content_get(obj, 2, horiz));
+ elm_box_pack_end(cnt, test_list8_content_get(obj, 3, horiz));
+ elm_box_pack_end(cnt, test_list8_content_get(obj, 2, horiz));
+ break;
+ default:
+ break;
+
+ }
+
+ if (cnt)
+ {
+ evas_object_size_hint_weight_set(cnt, EVAS_HINT_EXPAND,
EVAS_HINT_EXPAND);
+ evas_object_show(cnt);
+ }
+
+ return cnt;
+}
+
+static void
+test_list8_focus_on_selection_set(Evas_Object *gl, Evas_Object *chk, Eina_Bool
focus)
+{
+ elm_list_focus_on_selection_set(gl, focus);
+ elm_check_state_set(chk, focus);
+ printf("list_focus_on_selection = %s\n", (focus) ? "true" : "false");
+}
+
+static void
+test_list8_focus_check_changed(void *data, Evas_Object *obj, void *event_info
__UNUSED__)
+{
+ Eina_Bool nextstate = !elm_list_focus_on_selection_get(data);
+ test_list8_focus_on_selection_set(data, obj, nextstate);
+}
+
+void test_list_focus(const char *name, const char *title, Eina_Bool horiz)
+{
+ Evas_Object *win, *li, *bx, *bxx, *chk;
+ unsigned lhand, rhand, idx;
+ char buf[256];
+
+ elm_config_focus_highlight_enabled_set(EINA_TRUE);
+
+ win = elm_win_util_standard_add(name, title);
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ bxx = elm_box_add(win);
+ elm_win_resize_object_add(win, bxx);
+ evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_show(bxx);
+
+ li = elm_list_add(win);
+ evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(li, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_list_horizontal_set(li, horiz);
+ elm_box_pack_end(bxx, li);
+ evas_object_show(li);
+
+ bx = elm_box_add(win);
+ evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0);
+ evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_box_horizontal_set(bx, EINA_TRUE);
+ evas_object_show(bx);
+
+ chk = elm_check_add(win);
+ elm_object_text_set(chk, "Focus on selection");
+ evas_object_smart_callback_add(chk, "changed",
test_list8_focus_check_changed, li);
+ elm_box_pack_end(bx, chk);
+ evas_object_show(chk);
+
+ elm_box_pack_end(bxx, bx);
+
+ test_list8_focus_on_selection_set(li, chk, EINA_TRUE);
+
+ for (idx = 0; _list_focus_combo[idx] >= 0; idx++)
+ {
+ lhand = _list_focus_combo[idx] / 10;
+ rhand = _list_focus_combo[idx] % 10;
+
+ snprintf(buf, sizeof(buf), " %s / %s ",
+ _list_focus_names[lhand],
+ _list_focus_names[rhand]);
+
+ elm_list_item_append(li, buf,
+ test_list8_content_get(li, lhand, horiz),
+ test_list8_content_get(li, rhand, horiz),
+ NULL, NULL);
+ }
+
+ elm_list_go(li);
+ evas_object_show(li);
+
+ evas_object_resize(win, 320, 300);
+ evas_object_show(win);
+}
+
+void
+test_list8(void *data __UNUSED__,
+ Evas_Object *obj __UNUSED__,
+ void *event_info __UNUSED__)
+{
+ test_list_focus("list-focus", "List Focus", EINA_FALSE);
+}
+
+void
+test_list9(void *data __UNUSED__,
+ Evas_Object *obj __UNUSED__,
+ void *event_info __UNUSED__)
+{
+ test_list_focus("list-focus-horizontal", "List Focus Horizontal",
EINA_TRUE);
+}
+
void
test_list_separator(void *data __UNUSED__,
Evas_Object *obj __UNUSED__,
diff --git a/src/lib/elm_gen_common.h b/src/lib/elm_gen_common.h
index 568e1fc..ba22380 100644
--- a/src/lib/elm_gen_common.h
+++ b/src/lib/elm_gen_common.h
@@ -39,6 +39,7 @@ struct Elm_Gen_Item
int walking;
int generation; /**< a generation of an item. when
the item is created, this value is set to the value of genlist generation. this
value will be decreased when the item is going to be deleted */
const char *mouse_cursor;
+ Eina_List *item_focus_chain;
struct
{
diff --git a/src/lib/elm_genlist.c b/src/lib/elm_genlist.c
index 4f5a737..bc921f4 100644
--- a/src/lib/elm_genlist.c
+++ b/src/lib/elm_genlist.c
@@ -391,6 +391,9 @@ _elm_genlist_item_unrealize(Elm_Gen_Item *it,
EINA_LIST_FREE(it->content_objs, content)
evas_object_del(content);
+ eina_list_free(it->item_focus_chain);
+ it->item_focus_chain = NULL;
+
it->unrealize_cb(it);
it->realized = EINA_FALSE;
@@ -1687,6 +1690,18 @@ _item_realize(Elm_Gen_Item *it,
edje_object_signal_emit(VIEW(it), "elm,state,hide", "");
it->item->tree_effect_hide_me = EINA_FALSE;
}
+
+ if (it->item->type == ELM_GENLIST_ITEM_NONE)
+ {
+ Evas_Object* eobj;
+ Eina_List* l;
+ EINA_LIST_FOREACH(it->content_objs, l, eobj)
+ if (elm_object_focus_allow_get(eobj))
+ it->item_focus_chain = eina_list_append
+ (it->item_focus_chain, eobj);
+
+ }
+
evas_object_smart_callback_call(WIDGET(it), SIG_REALIZED, it);
}
@@ -2358,6 +2373,50 @@ _item_single_select_down(Elm_Genlist_Smart_Data *sd)
}
static void
+_elm_genlist_item_focus_set(Elm_Gen_Item *it, Elm_Focus_Direction dir)
+{
+ Evas_Object *focused_obj = NULL;
+ Eina_List *l;
+ if (!it) return;
+
+ if (!GL_IT(it)->wsd->focus_on_selection_enabled) return;
+
+ if (!it->item_focus_chain)
+ {
+ elm_object_focus_set(VIEW(it), EINA_TRUE);
+ return;
+ }
+
+ EINA_LIST_FOREACH(it->item_focus_chain, l, focused_obj)
+ if (elm_object_focus_get(focused_obj)) break;
+
+ if (focused_obj && (dir != ELM_FOCUS_PREVIOUS))
+ {
+ Evas_Object *nextfocus;
+ if (elm_widget_focus_next_get(focused_obj, dir, &nextfocus))
+ {
+ elm_object_focus_set(nextfocus, EINA_TRUE);
+ return;
+ }
+ }
+
+ if (!l) l = it->item_focus_chain;
+
+ if (dir == ELM_FOCUS_RIGHT)
+ {
+ l = eina_list_next(l);
+ if (!l) l = it->item_focus_chain;
+ }
+ else if (dir == ELM_FOCUS_LEFT)
+ {
+ l = eina_list_prev(l);
+ if (!l) l = eina_list_last(it->item_focus_chain);
+ }
+
+ elm_object_focus_set(eina_list_data_get(l), EINA_TRUE);
+}
+
+static void
_elm_genlist_smart_event(Eo *obj, void *_pd, va_list *list)
{
Evas_Object *src = va_arg(*list, Evas_Object *);
@@ -2396,11 +2455,17 @@ _elm_genlist_smart_event(Eo *obj, void *_pd, va_list
*list)
((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
{
x -= step_x;
+
+ Elm_Gen_Item *gt = (Elm_Gen_Item*)elm_genlist_selected_item_get(obj);
+ _elm_genlist_item_focus_set(gt, ELM_FOCUS_LEFT);
}
else if ((!strcmp(ev->keyname, "Right")) ||
((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
{
x += step_x;
+
+ Elm_Gen_Item *gt = (Elm_Gen_Item*)elm_genlist_selected_item_get(obj);
+ _elm_genlist_item_focus_set(gt, ELM_FOCUS_RIGHT);
}
else if ((!strcmp(ev->keyname, "Up")) ||
((!strcmp(ev->keyname, "KP_Up")) && (!ev->string)))
@@ -3048,6 +3113,14 @@ _item_unselect(Elm_Gen_Item *it)
_item_unhighlight(it); /* unhighlight the item first */
if (!it->selected) return; /* then check whether the item is selected */
+ if (GL_IT(it)->wsd->focus_on_selection_enabled)
+ {
+ Evas_Object* eobj;
+ Eina_List* l;
+ EINA_LIST_FOREACH(it->item_focus_chain, l, eobj)
+ elm_object_focus_set(eobj, EINA_FALSE);
+ }
+
it->selected = EINA_FALSE;
sd->selected = eina_list_remove(sd->selected, it);
evas_object_smart_callback_call(WIDGET(it), SIG_UNSELECTED, it);
@@ -5069,6 +5142,8 @@ _item_select(Elm_Gen_Item *it)
if (it->generation == sd->generation)
evas_object_smart_callback_call(WIDGET(it), SIG_SELECTED, it);
+ _elm_genlist_item_focus_set(it, ELM_FOCUS_PREVIOUS);
+
it->walking--;
sd->walking--;
if ((sd->clear_me) && (!sd->walking))
@@ -6317,6 +6392,17 @@ elm_genlist_item_fields_update(Elm_Object_Item *item,
it->content_objs = _item_content_realize(it, VIEW(it),
&it->contents, parts);
+ if (it->item->type == ELM_GENLIST_ITEM_NONE)
+ {
+ Evas_Object* eobj;
+ Eina_List* l;
+ eina_list_free(it->item_focus_chain);
+ it->item_focus_chain = NULL;
+ EINA_LIST_FOREACH(it->content_objs, l, eobj)
+ if (elm_object_focus_allow_get(eobj))
+ it->item_focus_chain = eina_list_append(it->item_focus_chain,
eobj);
+ }
+
if (it->flipped)
{
it->item->flip_content_objs =
@@ -7341,6 +7427,39 @@ _tree_effect_enabled_get(Eo *obj EINA_UNUSED, void *_pd,
va_list *list)
*ret = sd->tree_effect_enabled;
}
+EAPI void
+elm_genlist_focus_on_selection_set(Evas_Object *obj,
+ Eina_Bool enabled)
+{
+ ELM_GENLIST_CHECK(obj);
+ eo_do(obj, elm_obj_genlist_focus_on_selection_set(enabled));
+}
+
+static void
+_focus_on_selection_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ Eina_Bool enabled = va_arg(*list, int);
+ Elm_Genlist_Smart_Data *sd = _pd;
+ sd->focus_on_selection_enabled = !!enabled;
+}
+
+EAPI Eina_Bool
+elm_genlist_focus_on_selection_get(const Evas_Object *obj)
+{
+ ELM_GENLIST_CHECK(obj) EINA_FALSE;
+ Eina_Bool ret = EINA_FALSE;
+ eo_do((Eo *) obj, elm_obj_genlist_focus_on_selection_get(&ret));
+ return ret;
+}
+
+static void
+_focus_on_selection_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ Eina_Bool *ret = va_arg(*list, Eina_Bool *);
+ Elm_Genlist_Smart_Data *sd = _pd;
+ *ret = sd->focus_on_selection_enabled;
+}
+
EAPI Elm_Object_Item *
elm_genlist_nth_item_get(const Evas_Object *obj, unsigned int nth)
{
@@ -7427,6 +7546,8 @@ _class_constructor(Eo_Class *klass)
EO_OP_FUNC(ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_HIGHLIGHT_MODE_GET),
_highlight_mode_get),
EO_OP_FUNC(ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_SET),
_tree_effect_enabled_set),
EO_OP_FUNC(ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_GET),
_tree_effect_enabled_get),
+
EO_OP_FUNC(ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_SET),
_focus_on_selection_set),
+
EO_OP_FUNC(ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_GET),
_focus_on_selection_get),
EO_OP_FUNC_SENTINEL
};
eo_class_funcs_set(klass, func_desc);
@@ -7473,6 +7594,8 @@ static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(ELM_OBJ_GENLIST_SUB_ID_HIGHLIGHT_MODE_GET, "Get whether
the genlist items' should be highlighted when item selected."),
EO_OP_DESCRIPTION(ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_SET, "Set
Genlist tree effect."),
EO_OP_DESCRIPTION(ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_GET, "Get
Genlist tree effect."),
+ EO_OP_DESCRIPTION(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_SET, "Set
focus upon item's selection mode."),
+ EO_OP_DESCRIPTION(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_GET, "Get
focus upon item's selection mode."),
EO_OP_DESCRIPTION_SENTINEL
};
diff --git a/src/lib/elm_genlist_eo.h b/src/lib/elm_genlist_eo.h
index ec4bffa..42079ca 100644
--- a/src/lib/elm_genlist_eo.h
+++ b/src/lib/elm_genlist_eo.h
@@ -50,6 +50,8 @@ enum
ELM_OBJ_GENLIST_SUB_ID_HIGHLIGHT_MODE_GET,
ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_SET,
ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_GET,
+ ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_SET,
+ ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_GET,
ELM_OBJ_GENLIST_SUB_ID_LAST
};
@@ -511,6 +513,29 @@ enum
#define elm_obj_genlist_tree_effect_enabled_get(ret)
ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_TREE_EFFECT_ENABLED_GET),
EO_TYPECHECK(Eina_Bool *, ret)
/**
+ * @def elm_obj_genlist_focus_on_selection_set
+ * @since 1.8
+ *
+ * Set focus to a first from left focusable widget upon item selection.
+ *
+ * @param[in] enabled
+ *
+ * @see elm_obj_genlist_focus_on_selection_get
+ */
+#define elm_obj_genlist_focus_on_selection_set(enabled)
ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_SET),
EO_TYPECHECK(Eina_Bool, enabled)
+
+/**
+ * @def elm_obj_genlist_focus_on_selection_get
+ * @since 1.8
+ *
+ * Get whether the focus will be set to a widget on an item upon it's
selection.
+ *
+ * @param[out] ret
+ *
+ * @see elm_obj_genlist_focus_on_selection_set
+ */
+#define elm_obj_genlist_focus_on_selection_get(ret)
ELM_OBJ_GENLIST_ID(ELM_OBJ_GENLIST_SUB_ID_FOCUS_ON_SELECTION_GET),
EO_TYPECHECK(Eina_Bool *, ret)
+/**
* @}
*/
diff --git a/src/lib/elm_genlist_legacy.h b/src/lib/elm_genlist_legacy.h
index 5f76bd2..41db846 100644
--- a/src/lib/elm_genlist_legacy.h
+++ b/src/lib/elm_genlist_legacy.h
@@ -643,3 +643,30 @@ EAPI Eina_Bool
elm_genlist_highlight_mode_get(const Evas_Object *obj);
EAPI Elm_Object_Item *
elm_genlist_nth_item_get(const Evas_Object *obj, unsigned int nth);
+/**
+ * Set focus upon items selection mode
+ *
+ * @param obj The genlist object
+ * @param enabled The tree effect status
+ * (EINA_TRUE = enabled, EINA_FALSE = disabled)
+ *
+ * When enabled, every selection of an item inside the genlist will
automatically set focus to
+ * its first focusable widget from the left. This is true of course if the
selection was made by
+ * clicking an unfocusable area in an item or selecting it with a key
movement. Clicking on a
+ * focusable widget inside an item will couse this particular item to get
focus as usual.
+ *
+ * @ingroup Genlist
+ */
+EAPI void elm_genlist_focus_on_selection_set(Evas_Object *obj, Eina_Bool
enabled);
+
+
+/**
+ * Gets whether focus upon item's selection mode is enabled.
+ *
+ * @param obj The genlist object
+ * @return The tree effect status
+ * (EINA_TRUE = enabled, EINA_FALSE = disabled)
+ *
+ * @ingroup Genlist
+ */
+EAPI Eina_Bool elm_genlist_focus_on_selection_get(const Evas_Object *obj);
diff --git a/src/lib/elm_list.c b/src/lib/elm_list.c
index b9c9325..ba31f20 100644
--- a/src/lib/elm_list.c
+++ b/src/lib/elm_list.c
@@ -192,6 +192,67 @@ _item_single_select_down(Elm_List_Smart_Data *sd)
return EINA_TRUE;
}
+static Eina_Bool
+_elm_list_item_focus_set(Elm_List_Item *it, Elm_Focus_Direction dir, Eina_Bool
h_mode)
+{
+ if (!it) return EINA_FALSE;
+
+ if (!it->sd->focus_on_selection_enabled) return EINA_FALSE;
+
+ int focus_objs = 0;
+ Evas_Object *focus_chain[2];
+ Evas_Object *focused = NULL;
+ int idx;
+
+ if (it->icon && elm_object_focus_allow_get(it->icon))
+ focus_chain[focus_objs++] = it->icon;
+ if (it->end && elm_object_focus_allow_get(it->end))
+ focus_chain[focus_objs++] = it->end;
+
+ if (!focus_objs)
+ {
+ elm_object_focus_set(VIEW(it), EINA_TRUE);
+ return EINA_FALSE;
+ }
+
+ for (idx = 0; idx < focus_objs; idx++)
+ {
+ if (elm_object_focus_get(focus_chain[idx]))
+ {
+ focused = focus_chain[idx];
+ break;
+ }
+ }
+
+ if (!focused)
+ {
+ elm_object_focus_set(focus_chain[0], EINA_TRUE);
+ return EINA_FALSE;
+ }
+
+ if (dir != ELM_FOCUS_PREVIOUS)
+ {
+ Evas_Object *nextfocus;
+ if (elm_widget_focus_next_get(focused, dir, &nextfocus))
+ {
+ elm_object_focus_set(nextfocus, EINA_TRUE);
+ return EINA_TRUE;
+ }
+
+ if ((h_mode && (dir != ELM_FOCUS_UP) && (dir != ELM_FOCUS_DOWN)) ||
+ (!h_mode && (dir != ELM_FOCUS_LEFT) && (dir != ELM_FOCUS_RIGHT)))
+ return EINA_FALSE;
+
+ idx += ((dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_LEFT)) ? -1 : 1;
+ if (idx < 0) idx = focus_objs - 1;
+ if (idx >= focus_objs) idx = 0;
+ focused = focus_chain[idx];
+ }
+
+ elm_object_focus_set(focused, EINA_TRUE);
+ return EINA_TRUE;
+}
+
static void
_elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
{
@@ -230,7 +291,10 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
if ((!strcmp(ev->keyname, "Left")) ||
((!strcmp(ev->keyname, "KP_Left")) && !ev->string))
{
- if ((sd->h_mode) &&
+ it = (Elm_List_Item *)elm_list_selected_item_get(obj);
+ Eina_Bool focused = _elm_list_item_focus_set(it, ELM_FOCUS_LEFT,
sd->h_mode);
+
+ if ((sd->h_mode && !focused) &&
(((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
(_item_multi_select_up(sd)))
|| (_item_single_select_up(sd))))
@@ -245,7 +309,10 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
else if ((!strcmp(ev->keyname, "Right")) ||
((!strcmp(ev->keyname, "KP_Right")) && !ev->string))
{
- if ((sd->h_mode) &&
+ it = (Elm_List_Item *)elm_list_selected_item_get(obj);
+ Eina_Bool focused = _elm_list_item_focus_set(it, ELM_FOCUS_RIGHT,
sd->h_mode);
+
+ if ((sd->h_mode && !focused) &&
(((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
(_item_multi_select_down(sd)))
|| (_item_single_select_down(sd))))
@@ -260,7 +327,10 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
else if ((!strcmp(ev->keyname, "Up")) ||
((!strcmp(ev->keyname, "KP_Up")) && !ev->string))
{
- if ((!sd->h_mode) &&
+ it = (Elm_List_Item *)elm_list_selected_item_get(obj);
+ Eina_Bool focused = _elm_list_item_focus_set(it, ELM_FOCUS_UP,
sd->h_mode);
+
+ if ((!sd->h_mode && !focused) &&
(((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
(_item_multi_select_up(sd)))
|| (_item_single_select_up(sd))))
@@ -275,7 +345,10 @@ _elm_list_smart_event(Eo *obj, void *_pd, va_list *list)
else if ((!strcmp(ev->keyname, "Down")) ||
((!strcmp(ev->keyname, "KP_Down")) && !ev->string))
{
- if ((!sd->h_mode) &&
+ it = (Elm_List_Item *)elm_list_selected_item_get(obj);
+ Eina_Bool focused = _elm_list_item_focus_set(it, ELM_FOCUS_DOWN,
sd->h_mode);
+
+ if ((!sd->h_mode && !focused) &&
(((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
(_item_multi_select_down(sd)))
|| (_item_single_select_down(sd))))
@@ -915,6 +988,9 @@ _item_select(Elm_List_Item *it)
if (sd->select_mode == ELM_OBJECT_SELECT_MODE_ALWAYS) goto call;
return;
}
+
+ _elm_list_item_focus_set(it, ELM_FOCUS_PREVIOUS, sd->h_mode);
+
it->selected = EINA_TRUE;
sd->selected = eina_list_append(sd->selected, it);
@@ -943,6 +1019,12 @@ _item_unselect(Elm_List_Item *it)
evas_object_ref(obj);
_elm_list_walk(sd);
+ if (it->sd->focus_on_selection_enabled)
+ {
+ if (it->icon) elm_object_focus_set(it->icon, EINA_FALSE);
+ if (it->end) elm_object_focus_set(it->end, EINA_FALSE);
+ }
+
edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm");
evas_object_smart_callback_call(obj, SIG_UNHIGHLIGHTED, it);
stacking = edje_object_data_get(VIEW(it), "stacking");
@@ -2545,6 +2627,39 @@ _at_xy_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list
*list)
*ret = NULL;
}
+EAPI void
+elm_list_focus_on_selection_set(Evas_Object *obj,
+ Eina_Bool enabled)
+{
+ ELM_LIST_CHECK(obj);
+ eo_do(obj, elm_obj_list_focus_on_selection_set(enabled));
+}
+
+static void
+_focus_on_selection_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ Eina_Bool enabled = va_arg(*list, int);
+ Elm_List_Smart_Data *sd = _pd;
+ sd->focus_on_selection_enabled = !!enabled;
+}
+
+EAPI Eina_Bool
+elm_list_focus_on_selection_get(const Evas_Object *obj)
+{
+ ELM_LIST_CHECK(obj) EINA_FALSE;
+ Eina_Bool ret = EINA_FALSE;
+ eo_do((Eo *) obj, elm_obj_list_focus_on_selection_get(&ret));
+ return ret;
+}
+
+static void
+_focus_on_selection_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ Eina_Bool *ret = va_arg(*list, Eina_Bool *);
+ Elm_List_Smart_Data *sd = _pd;
+ *ret = sd->focus_on_selection_enabled;
+}
+
static void
_class_constructor(Eo_Class *klass)
{
@@ -2593,6 +2708,8 @@ _class_constructor(Eo_Class *klass)
EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET),
_first_item_get),
EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET),
_last_item_get),
EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET),
_at_xy_item_get),
+
EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_SET),
_focus_on_selection_set),
+
EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_GET),
_focus_on_selection_get),
EO_OP_FUNC_SENTINEL
};
eo_class_funcs_set(klass, func_desc);
@@ -2625,6 +2742,8 @@ static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET, "Get the first item
in the list."),
EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET, "Get the last item
in the list."),
EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET, "Get the item that
is at the x, y canvas coords."),
+ EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_SET, "Set focus
upon item's selection mode."),
+ EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_GET, "Get focus
upon item's selection mode."),
EO_OP_DESCRIPTION_SENTINEL
};
diff --git a/src/lib/elm_list_eo.h b/src/lib/elm_list_eo.h
index e443ba1..91bbf76 100644
--- a/src/lib/elm_list_eo.h
+++ b/src/lib/elm_list_eo.h
@@ -32,6 +32,8 @@
ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET,
ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET,
ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET,
+ ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_SET,
+ ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_GET,
ELM_OBJ_LIST_SUB_ID_LAST
};
@@ -372,5 +374,29 @@
#define elm_obj_list_at_xy_item_get(x, y, posret, ret)
ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET), EO_TYPECHECK(Evas_Coord,
x), EO_TYPECHECK(Evas_Coord, y), EO_TYPECHECK(int *, posret),
EO_TYPECHECK(Elm_Object_Item **, ret)
/**
+ * @def elm_obj_list_focus_on_selection_set
+ * @since 1.8
+ *
+ * Set focus to a first from left focusable widget upon item selection.
+ *
+ * @param[in] enabled
+ *
+ * @see elm_obj_list_focus_on_selection_get
+ */
+#define elm_obj_list_focus_on_selection_set(enabled)
ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_SET),
EO_TYPECHECK(Eina_Bool, enabled)
+
+/**
+ * @def elm_obj_list_focus_on_selection_get
+ * @since 1.8
+ *
+ * Get whether the focus will be set to a widget on an item upon it's
selection.
+ *
+ * @param[out] ret
+ *
+ * @see elm_obj_list_focus_on_selection_set
+ */
+#define elm_obj_list_focus_on_selection_get(ret)
ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FOCUS_ON_SELECTION_GET),
EO_TYPECHECK(Eina_Bool *, ret)
+
+/**
* @}
*/
diff --git a/src/lib/elm_list_legacy.h b/src/lib/elm_list_legacy.h
index 98aac27..11bbb13 100644
--- a/src/lib/elm_list_legacy.h
+++ b/src/lib/elm_list_legacy.h
@@ -524,3 +524,30 @@ EAPI Elm_Object_Item
*elm_list_last_item_get(const Evas_Object *obj)
* @ingroup List
*/
EAPI Elm_Object_Item *elm_list_at_xy_item_get(const Evas_Object
*obj, Evas_Coord x, Evas_Coord y, int *posret);
+
+/**
+ * Set focus upon items selection mode
+ *
+ * @param obj The genlist object
+ * @param enabled The tree effect status
+ * (EINA_TRUE = enabled, EINA_FALSE = disabled)
+ *
+ * When enabled, every selection of an item inside the genlist will
automatically set focus to
+ * its first focusable widget from the left. This is true of course if the
selection was made by
+ * clicking an unfocusable area in an item or selecting it with a key
movement. Clicking on a
+ * focusable widget inside an item will couse this particular item to get
focus as usual.
+ *
+ * @ingroup List
+ */
+EAPI void elm_list_focus_on_selection_set(Evas_Object *obj, Eina_Bool enabled);
+
+/**
+ * Gets whether focus upon item's selection mode is enabled.
+ *
+ * @param obj The genlist object
+ * @return The tree effect status
+ * (EINA_TRUE = enabled, EINA_FALSE = disabled)
+ *
+ * @ingroup List
+ */
+EAPI Eina_Bool elm_list_focus_on_selection_get(const Evas_Object *obj);
diff --git a/src/lib/elm_widget_genlist.h b/src/lib/elm_widget_genlist.h
index 075ea6f..4d450eb 100644
--- a/src/lib/elm_widget_genlist.h
+++ b/src/lib/elm_widget_genlist.h
@@ -131,6 +131,7 @@ struct _Elm_Genlist_Smart_Data
Ecore_Animator *tree_effect_animator;
Elm_Genlist_Item_Move_Effect_Mode move_effect_mode;
+ Eina_Bool focus_on_selection_enabled : 1;
Eina_Bool tree_effect_enabled : 1;
Eina_Bool auto_scroll_enabled : 1;
Eina_Bool decorate_all_mode : 1;
diff --git a/src/lib/elm_widget_list.h b/src/lib/elm_widget_list.h
index 628de21..bc72908 100644
--- a/src/lib/elm_widget_list.h
+++ b/src/lib/elm_widget_list.h
@@ -39,6 +39,7 @@ struct _Elm_List_Smart_Data
Evas_Coord x, y;
} history[ELM_LIST_SWIPE_MOVES];
+ Eina_Bool focus_on_selection_enabled : 1;
Eina_Bool was_selected : 1;
Eina_Bool fix_pending : 1;
Eina_Bool longpressed : 1;
--
------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and
their applications. This 200-page book is written by three acclaimed
leaders in the field. The early access version is available now.
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may