summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorm.zielonka <m.zielonka@samsung.com>2014-03-24 16:38:27 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2014-03-24 16:38:27 +0900
commit4fe82cc740eda0c6b50ee09aedcf173aac1e775d (patch)
tree65a83e288ed3d3741ae4fcdc568edfe57b8c59ac
parentda77baab86477e741b49d1e7338e32ab402849f5 (diff)
adding focus direction for gengrid
Summary: It is implementation of focus_direction method for gengrid widget. We need it in our project. We must service focus by directions and we want to use gengrid widget. Additionally we must support changing focus by keyboard (TV remote). Unfortunately gengrid hasn't default implementation to present its sub-objects as candidates for focus direction. Our solution can search for focusable sub-objects (from realized items) and change then focused and last selected variables in gengrid. If this candidate wins then object will receive focus. Reviewers: cedric, raster CC: raster, seoz Differential Revision: https://phab.enlightenment.org/D449
-rw-r--r--.gitignore2
-rw-r--r--config/default/base.src2
-rw-r--r--config/mobile/base.src2
-rw-r--r--config/standard/base.src2
-rw-r--r--configure.ac1
-rw-r--r--src/bin/test.c2
-rw-r--r--src/bin/test_gengrid.c115
-rw-r--r--src/lib/elm_gengrid.c92
-rw-r--r--src/lib/elm_gengrid_common.h10
-rw-r--r--src/lib/elm_widget_gengrid.h11
-rw-r--r--src/modules/Makefile.am3
-rw-r--r--src/modules/gengrid_focus_hook/Makefile.am38
-rw-r--r--src/modules/gengrid_focus_hook/gengrid_focus_hook.c537
13 files changed, 811 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 84e5f7e54..0944c10eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,3 +52,5 @@ tags
52*.gmo 52*.gmo
53/config.cache-env 53/config.cache-env
54/compile 54/compile
55build.conf
56.gitignore
diff --git a/config/default/base.src b/config/default/base.src
index c7860496c..29173631e 100644
--- a/config/default/base.src
+++ b/config/default/base.src
@@ -39,7 +39,7 @@ group "Elm_Config" struct {
39 value "finger_size" int: 40; 39 value "finger_size" int: 40;
40 value "fps" double: 60.0; 40 value "fps" double: 60.0;
41 value "theme" string: "default"; 41 value "theme" string: "default";
42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; 42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api";
43 value "tooltip_delay" double: 1.0; 43 value "tooltip_delay" double: 1.0;
44 value "cursor_engine_only" uchar: 1; 44 value "cursor_engine_only" uchar: 1;
45 value "focus_highlight_enable" uchar: 0; 45 value "focus_highlight_enable" uchar: 0;
diff --git a/config/mobile/base.src b/config/mobile/base.src
index 60a152129..de9111fad 100644
--- a/config/mobile/base.src
+++ b/config/mobile/base.src
@@ -39,7 +39,7 @@ group "Elm_Config" struct {
39 value "finger_size" int: 40; 39 value "finger_size" int: 40;
40 value "fps" double: 60.0; 40 value "fps" double: 60.0;
41 value "theme" string: "default"; 41 value "theme" string: "default";
42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; 42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api";
43 value "tooltip_delay" double: 1.0; 43 value "tooltip_delay" double: 1.0;
44 value "cursor_engine_only" uchar: 1; 44 value "cursor_engine_only" uchar: 1;
45 value "focus_highlight_enable" uchar: 0; 45 value "focus_highlight_enable" uchar: 0;
diff --git a/config/standard/base.src b/config/standard/base.src
index 838d95804..88bd1b486 100644
--- a/config/standard/base.src
+++ b/config/standard/base.src
@@ -39,7 +39,7 @@ group "Elm_Config" struct {
39 value "finger_size" int: 10; 39 value "finger_size" int: 10;
40 value "fps" double: 60.0; 40 value "fps" double: 60.0;
41 value "theme" string: "default"; 41 value "theme" string: "default";
42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; 42 value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api";
43 value "tooltip_delay" double: 1.0; 43 value "tooltip_delay" double: 1.0;
44 value "cursor_engine_only" uchar: 1; 44 value "cursor_engine_only" uchar: 1;
45 value "focus_highlight_enable" uchar: 0; 45 value "focus_highlight_enable" uchar: 0;
diff --git a/configure.ac b/configure.ac
index fcae23988..c3149c1d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -726,6 +726,7 @@ src/modules/Makefile
726src/modules/prefs/Makefile 726src/modules/prefs/Makefile
727src/modules/access_output/Makefile 727src/modules/access_output/Makefile
728src/modules/datetime_input_ctxpopup/Makefile 728src/modules/datetime_input_ctxpopup/Makefile
729src/modules/gengrid_focus_hook/Makefile
729src/modules/test_entry/Makefile 730src/modules/test_entry/Makefile
730src/modules/test_map/Makefile 731src/modules/test_map/Makefile
731src/edje_externals/Makefile 732src/edje_externals/Makefile
diff --git a/src/bin/test.c b/src/bin/test.c
index 1dd840c2c..7e6c43743 100644
--- a/src/bin/test.c
+++ b/src/bin/test.c
@@ -130,6 +130,7 @@ void test_gengrid(void *data, Evas_Object *obj, void *event_info);
130void test_gengrid2(void *data, Evas_Object *obj, void *event_info); 130void test_gengrid2(void *data, Evas_Object *obj, void *event_info);
131void test_gengrid3(void *data, Evas_Object *obj, void *event_info); 131void test_gengrid3(void *data, Evas_Object *obj, void *event_info);
132void test_gengrid_item_styles(void *data, Evas_Object *obj, void *event_info); 132void test_gengrid_item_styles(void *data, Evas_Object *obj, void *event_info);
133void test_gengrid_focus_direction(void *data, Evas_Object *obj, void *event_info);
133void test_gengrid4(void *data, Evas_Object *obj, void *event_info); 134void test_gengrid4(void *data, Evas_Object *obj, void *event_info);
134void test_gengrid_speed(void *data, Evas_Object *obj, void *event_info); 135void test_gengrid_speed(void *data, Evas_Object *obj, void *event_info);
135void test_gengrid_focus(void *data, Evas_Object *obj, void *event_info); 136void test_gengrid_focus(void *data, Evas_Object *obj, void *event_info);
@@ -665,6 +666,7 @@ add_tests:
665 ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Item Styles", test_gengrid_item_styles); 666 ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Item Styles", test_gengrid_item_styles);
666 ADD_TEST(NULL, "Lists - Gengrid", "Gengrid Update Speed", test_gengrid_speed); 667 ADD_TEST(NULL, "Lists - Gengrid", "Gengrid Update Speed", test_gengrid_speed);
667 ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus", test_gengrid_focus); 668 ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus", test_gengrid_focus);
669 ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus Direction", test_gengrid_focus_direction);
668 670
669 //------------------------------// 671 //------------------------------//
670 ADD_TEST(NULL, "General", "Scaling", test_scaling); 672 ADD_TEST(NULL, "General", "Scaling", test_scaling);
diff --git a/src/bin/test_gengrid.c b/src/bin/test_gengrid.c
index b153767e7..8150ef476 100644
--- a/src/bin/test_gengrid.c
+++ b/src/bin/test_gengrid.c
@@ -252,6 +252,23 @@ grid_content_get(void *data, Evas_Object *obj, const char *part)
252 return NULL; 252 return NULL;
253} 253}
254 254
255Evas_Object *
256grid_content_buttons_get(void *data, Evas_Object *obj, const char *part)
257{
258 const Item_Data *id = data;
259 if (!strcmp(part, "elm.swallow.icon"))
260 {
261 Evas_Object *bt = elm_button_add(obj);
262 Evas_Object *ic = elm_icon_add(obj);
263 elm_image_file_set(ic, id->path, NULL);
264 elm_image_aspect_fixed_set(ic, EINA_FALSE);
265 elm_object_part_content_set(bt, "icon", ic);
266 evas_object_show(bt);
267 return bt;
268 }
269 return NULL;
270}
271
255Eina_Bool 272Eina_Bool
256grid_state_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) 273grid_state_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
257{ 274{
@@ -348,6 +365,54 @@ create_gengrid(Evas_Object *obj, int items)
348 return grid; 365 return grid;
349} 366}
350 367
368static Evas_Object *
369create_gengrid_buttons(Evas_Object *obj, int items)
370{
371 Evas_Object *grid = NULL;
372 static Item_Data id[144];
373 int i, n;
374 char buf[PATH_MAX];
375
376 grid = elm_gengrid_add(obj);
377 elm_gengrid_item_size_set(grid,
378 elm_config_scale_get() * 200,
379 elm_config_scale_get() * 150);
380 elm_gengrid_reorder_mode_set(grid, EINA_TRUE);
381 evas_object_smart_callback_add(grid, "selected", grid_selected, NULL);
382 evas_object_smart_callback_add(grid, "clicked,double", grid_double_clicked, NULL);
383 evas_object_smart_callback_add(grid, "longpressed", grid_longpress, NULL);
384 evas_object_smart_callback_add(grid, "moved", grid_moved, NULL);
385 evas_object_smart_callback_add(grid, "drag,start,up", grid_drag_up, NULL);
386 evas_object_smart_callback_add(grid, "drag,start,right", grid_drag_right, NULL);
387 evas_object_smart_callback_add(grid, "drag,start,down", grid_drag_down, NULL);
388 evas_object_smart_callback_add(grid, "drag,start,left", grid_drag_left, NULL);
389 evas_object_smart_callback_add(grid, "drag,stop", grid_drag_stop, NULL);
390 evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
391 evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
392
393 gic = elm_gengrid_item_class_new();
394 gic->item_style = "default";
395 gic->func.text_get = grid_text_get;
396 gic->func.content_get = grid_content_buttons_get;
397 gic->func.state_get = grid_state_get;
398 gic->func.del = NULL;
399
400 n = 0;
401 for (i = 0; i < items; i++)
402 {
403 snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[n]);
404 n = (n + 1) % 9;
405 id[i].mode = i;
406 id[i].path = eina_stringshare_add(buf);
407 id[i].item = elm_gengrid_item_append(grid, gic, &(id[i]), grid_sel, NULL);
408 if (!(i % 5))
409 elm_gengrid_item_selected_set(id[i].item, EINA_TRUE);
410 }
411 elm_gengrid_item_class_free(gic);
412
413 return grid;
414}
415
351static void 416static void
352restore_bt_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) 417restore_bt_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
353{ 418{
@@ -1274,6 +1339,56 @@ test_gengrid4(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_
1274} 1339}
1275 1340
1276void 1341void
1342test_gengrid_focus_direction(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1343{
1344 Evas_Object *win, *bt, *bxx, *bx;
1345
1346
1347 win = elm_win_util_standard_add("gengrid", "GenGrid");
1348 elm_win_autodel_set(win, EINA_TRUE);
1349 evas_object_resize(win, 600, 600);
1350 evas_object_show(win);
1351
1352 elm_win_focus_highlight_enabled_set(win, EINA_TRUE);
1353 elm_win_focus_highlight_animate_set(win, EINA_TRUE);
1354
1355 bxx = elm_box_add(win);
1356 evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1357 elm_win_resize_object_add(win, bxx);
1358 evas_object_show(bxx);
1359
1360 bt = elm_button_add(win);
1361 elm_object_text_set(bt, "Next API function");
1362 elm_box_pack_end(bxx, bt);
1363 evas_object_show(bt);
1364
1365 /* Create GenGrid */
1366 Evas_Object *grid = create_gengrid_buttons(win, (12 * 12));
1367 elm_box_pack_end(bxx, grid);
1368 evas_object_show(grid);
1369
1370 elm_gengrid_focus_direction_allow_set(grid, EINA_TRUE);
1371// elm_object_focus_allow_set(grid, EINA_FALSE);
1372
1373 bx = elm_box_add(win);
1374 elm_box_horizontal_set(bx, EINA_TRUE);
1375 elm_box_pack_end(bxx, bx);
1376 evas_object_show(bx);
1377
1378 bt = elm_button_add(win);
1379 elm_object_text_set(bt, "Bring in");
1380 evas_object_smart_callback_add(bt, "clicked", _btn_bring_in_clicked_cb, grid);
1381 elm_box_pack_end(bx, bt);
1382 evas_object_show(bt);
1383
1384 bt = elm_button_add(win);
1385 elm_object_text_set(bt, "Show");
1386 evas_object_smart_callback_add(bt, "clicked", _btn_show_clicked_cb, grid);
1387 elm_box_pack_end(bx, bt);
1388 evas_object_show(bt);
1389}
1390
1391void
1277test_gengrid_speed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) 1392test_gengrid_speed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1278{ 1393{
1279 Evas_Object *win, *fr, *bx; 1394 Evas_Object *win, *fr, *bx;
diff --git a/src/lib/elm_gengrid.c b/src/lib/elm_gengrid.c
index a362aa968..3359aba45 100644
--- a/src/lib/elm_gengrid.c
+++ b/src/lib/elm_gengrid.c
@@ -87,6 +87,27 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = {
87}; 87};
88#undef ELM_PRIV_GENGRID_SIGNALS 88#undef ELM_PRIV_GENGRID_SIGNALS
89 89
90static Gengrid_Focus_Direction_Mod_Api *gengrid_focus_direction_mod = NULL;
91
92static Gengrid_Focus_Direction_Mod_Api *
93_gengrid_focus_direction_mod_init(void)
94{
95 Elm_Module *mod = NULL;
96
97 if (!(mod = _elm_module_find_as("gengrid_focus/api"))) return NULL;
98
99 mod->api = malloc(sizeof(Gengrid_Focus_Direction_Mod_Api));
100 if (!mod->api) return NULL;
101
102 ((Gengrid_Focus_Direction_Mod_Api *)(mod->api))->hook_ptr =
103 _elm_module_symbol_get(mod, "gen_focus_direction");
104
105 if (!((Gengrid_Focus_Direction_Mod_Api *)(mod->api))->hook_ptr)
106 return NULL;
107
108 return mod->api;
109}
110
90static void 111static void
91_item_show_region(void *data) 112_item_show_region(void *data)
92{ 113{
@@ -550,6 +571,34 @@ _elm_gengrid_item_unrealize(Elm_Gen_Item *it,
550 evas_event_thaw_eval(evas_object_evas_get(WIDGET(it))); 571 evas_event_thaw_eval(evas_object_evas_get(WIDGET(it)));
551} 572}
552 573
574
575static void
576_elm_gengrid_item_focused_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
577{
578 Elm_Gen_Item *it = data;
579 Elm_Gengrid_Smart_Data *sd = GG_IT(it)->wsd;
580 if (sd->focus_direction && gengrid_focus_direction_mod)
581 {
582 Evas_Coord x = 0;
583 Evas_Coord y = 0;
584 Evas_Coord v_w = 0;
585 Evas_Coord v_h = 0;
586 Evas_Coord step_x = 0;
587 Evas_Coord step_y = 0;
588 Evas_Coord page_x = 0;
589 Evas_Coord page_y = 0;
590
591 eo_do(sd->obj,
592 elm_interface_scrollable_content_pos_get(&x, &y),
593 elm_interface_scrollable_step_size_get(&step_x, &step_y),
594 elm_interface_scrollable_page_size_get(&page_x, &page_y),
595 elm_interface_scrollable_content_viewport_size_get(&v_w, &v_h));
596
597 elm_gengrid_item_selected_set((Elm_Object_Item *)it, EINA_TRUE);
598 elm_gengrid_item_show((Elm_Object_Item *)it, ELM_GENGRID_ITEM_SCROLLTO_IN);
599 }
600}
601
553static void 602static void
554_item_mouse_up_cb(void *data, 603_item_mouse_up_cb(void *data,
555 Evas *evas EINA_UNUSED, 604 Evas *evas EINA_UNUSED,
@@ -816,6 +865,7 @@ _item_realize(Elm_Gen_Item *it)
816 edje_object_part_swallow(VIEW(it), key, ic); 865 edje_object_part_swallow(VIEW(it), key, ic);
817 evas_object_show(ic); 866 evas_object_show(ic);
818 elm_widget_sub_object_add(WIDGET(it), ic); 867 elm_widget_sub_object_add(WIDGET(it), ic);
868 evas_object_smart_callback_add(ic, "focused", _elm_gengrid_item_focused_cb, it);
819 } 869 }
820 } 870 }
821 } 871 }
@@ -1914,6 +1964,8 @@ _elm_gengrid_smart_event(Eo *obj, void *_pd, va_list *list)
1914 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; 1964 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1915 if (!sd->items) return; 1965 if (!sd->items) return;
1916 1966
1967 if (sd->focus_direction && gengrid_focus_direction_mod) return;
1968
1917 eo_do(obj, 1969 eo_do(obj,
1918 elm_interface_scrollable_content_pos_get(&x, &y), 1970 elm_interface_scrollable_content_pos_get(&x, &y),
1919 elm_interface_scrollable_step_size_get(&step_x, &step_y), 1971 elm_interface_scrollable_step_size_get(&step_x, &step_y),
@@ -2173,7 +2225,13 @@ _elm_gengrid_smart_on_focus(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
2173 Elm_Object_Item *it = NULL; 2225 Elm_Object_Item *it = NULL;
2174 Eina_Bool is_sel = EINA_FALSE; 2226 Eina_Bool is_sel = EINA_FALSE;
2175 2227
2228 if (sd->focus_direction && gengrid_focus_direction_mod)
2229 {
2230 if (ret) *ret = EINA_TRUE;
2231 return;
2232 }
2176 eo_do_super(obj, MY_CLASS, elm_obj_widget_on_focus(&int_ret)); 2233 eo_do_super(obj, MY_CLASS, elm_obj_widget_on_focus(&int_ret));
2234
2177 if (!int_ret) return; 2235 if (!int_ret) return;
2178 2236
2179 if (elm_widget_focus_get(obj) && (sd->selected) && 2237 if (elm_widget_focus_get(obj) && (sd->selected) &&
@@ -2228,10 +2286,28 @@ _elm_gengrid_smart_focus_next_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNU
2228} 2286}
2229 2287
2230static void 2288static void
2231_elm_gengrid_smart_focus_direction_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) 2289_elm_gengrid_smart_focus_direction_manager_is(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
2232{ 2290{
2233 Eina_Bool *ret = va_arg(*list, Eina_Bool *); 2291 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
2292 Elm_Gengrid_Smart_Data *sd = _pd;
2234 *ret = EINA_FALSE; 2293 *ret = EINA_FALSE;
2294 if (sd->focus_direction && gengrid_focus_direction_mod)
2295 *ret = EINA_TRUE;
2296}
2297
2298static void
2299_elm_gengrid_smart_focus_direction(Eo *obj, void *_pd, va_list *list)
2300{
2301 Elm_Gengrid_Smart_Data *sd = _pd;
2302 if (sd->focus_direction && gengrid_focus_direction_mod)
2303 {
2304 gengrid_focus_direction_mod->hook_ptr(obj, _pd, list);
2305 }
2306 else
2307 {
2308 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
2309 *ret = EINA_FALSE;
2310 }
2235} 2311}
2236 2312
2237static void 2313static void
@@ -2737,6 +2813,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
2737 elm_widget_style_get(obj))) 2813 elm_widget_style_get(obj)))
2738 CRI("Failed to set layout!"); 2814 CRI("Failed to set layout!");
2739 2815
2816 if (!gengrid_focus_direction_mod) gengrid_focus_direction_mod = _gengrid_focus_direction_mod_init();
2740 eo_do(obj, elm_interface_scrollable_objects_set(wd->resize_obj, priv->hit_rect)); 2817 eo_do(obj, elm_interface_scrollable_objects_set(wd->resize_obj, priv->hit_rect));
2741 2818
2742 priv->old_h_bounce = bounce; 2819 priv->old_h_bounce = bounce;
@@ -2744,6 +2821,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
2744 2821
2745 eo_do(obj, elm_interface_scrollable_bounce_allow_set(bounce, bounce)); 2822 eo_do(obj, elm_interface_scrollable_bounce_allow_set(bounce, bounce));
2746 2823
2824
2747 eo_do(obj, 2825 eo_do(obj,
2748 elm_interface_scrollable_animate_start_cb_set 2826 elm_interface_scrollable_animate_start_cb_set
2749 (_scroll_animate_start_cb), 2827 (_scroll_animate_start_cb),
@@ -2760,6 +2838,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
2760 priv->align_x = 0.5; 2838 priv->align_x = 0.5;
2761 priv->align_y = 0.5; 2839 priv->align_y = 0.5;
2762 priv->highlight = EINA_TRUE; 2840 priv->highlight = EINA_TRUE;
2841 priv->focus_direction = EINA_FALSE;
2763 2842
2764 priv->pan_obj = eo_add(MY_PAN_CLASS, evas_object_evas_get(obj)); 2843 priv->pan_obj = eo_add(MY_PAN_CLASS, evas_object_evas_get(obj));
2765 pan_data = eo_data_scope_get(priv->pan_obj, MY_PAN_CLASS); 2844 pan_data = eo_data_scope_get(priv->pan_obj, MY_PAN_CLASS);
@@ -3247,6 +3326,15 @@ elm_gengrid_horizontal_set(Evas_Object *obj,
3247 eo_do(obj, elm_obj_gengrid_horizontal_set(horizontal)); 3326 eo_do(obj, elm_obj_gengrid_horizontal_set(horizontal));
3248} 3327}
3249 3328
3329EAPI void
3330elm_gengrid_focus_direction_allow_set(Evas_Object *obj,
3331 Eina_Bool flag)
3332{
3333 ELM_GENGRID_CHECK(obj);
3334 ELM_GENGRID_DATA_GET(obj, sd);
3335 sd->focus_direction = flag;
3336}
3337
3250static void 3338static void
3251_horizontal_set(Eo *obj, void *_pd, va_list *list) 3339_horizontal_set(Eo *obj, void *_pd, va_list *list)
3252{ 3340{
@@ -4136,7 +4224,6 @@ elm_gengrid_item_show(Elm_Object_Item *item,
4136 4224
4137 ELM_GENGRID_ITEM_CHECK_OR_RETURN(it); 4225 ELM_GENGRID_ITEM_CHECK_OR_RETURN(it);
4138 sd = GG_IT(it)->wsd; 4226 sd = GG_IT(it)->wsd;
4139
4140 if ((it->generation < sd->generation)) return; 4227 if ((it->generation < sd->generation)) return;
4141 4228
4142 sd->show_region = EINA_TRUE; 4229 sd->show_region = EINA_TRUE;
@@ -4484,6 +4571,7 @@ _class_constructor(Eo_Class *klass)
4484 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_DIRECTION_MANAGER_IS), _elm_gengrid_smart_focus_direction_manager_is), 4571 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_DIRECTION_MANAGER_IS), _elm_gengrid_smart_focus_direction_manager_is),
4485 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_HIGHLIGHT_GEOMETRY_GET), _elm_gengrid_focus_highlight_geometry_get), 4572 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_HIGHLIGHT_GEOMETRY_GET), _elm_gengrid_focus_highlight_geometry_get),
4486 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUSED_ITEM_GET), _elm_gengrid_focused_item_get), 4573 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUSED_ITEM_GET), _elm_gengrid_focused_item_get),
4574 EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_DIRECTION), _elm_gengrid_smart_focus_direction),
4487 4575
4488 EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SIZING_EVAL), _elm_gengrid_smart_sizing_eval), 4576 EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SIZING_EVAL), _elm_gengrid_smart_sizing_eval),
4489 4577
diff --git a/src/lib/elm_gengrid_common.h b/src/lib/elm_gengrid_common.h
index be770388d..eedc076ca 100644
--- a/src/lib/elm_gengrid_common.h
+++ b/src/lib/elm_gengrid_common.h
@@ -565,3 +565,13 @@ EAPI void elm_gengrid_item_select_mode_set(Elm_Object_I
565 */ 565 */
566EAPI Elm_Object_Select_Mode elm_gengrid_item_select_mode_get(const Elm_Object_Item *it); 566EAPI Elm_Object_Select_Mode elm_gengrid_item_select_mode_get(const Elm_Object_Item *it);
567 567
568
569/**
570 * Set if gengrid should manage focus direction.
571 *
572 * @param obj The gengrid object
573 * @param flag The state which should be set.
574 *
575 * @ingroup Gengrid
576 */
577EAPI void elm_gengrid_focus_direction_allow_set(Evas_Object *obj, Eina_Bool flag);
diff --git a/src/lib/elm_widget_gengrid.h b/src/lib/elm_widget_gengrid.h
index f551f8454..9be4ab7cb 100644
--- a/src/lib/elm_widget_gengrid.h
+++ b/src/lib/elm_widget_gengrid.h
@@ -15,6 +15,15 @@
15 * other widgets which are a gengrid with some more logic on top. 15 * other widgets which are a gengrid with some more logic on top.
16 */ 16 */
17 17
18
19typedef struct _Gengrid_Focus_Direction_Mod_Api Gengrid_Focus_Direction_Mod_Api;
20
21struct _Gengrid_Focus_Direction_Mod_Api
22{
23 eo_op_func_type hook_ptr;
24};
25
26
18/** 27/**
19 * Base widget smart data extended with gengrid instance data. 28 * Base widget smart data extended with gengrid instance data.
20 */ 29 */
@@ -110,6 +119,8 @@ struct _Elm_Gengrid_Smart_Data
110 Eina_Bool show_region : 1; 119 Eina_Bool show_region : 1;
111 Eina_Bool bring_in : 1; 120 Eina_Bool bring_in : 1;
112 Eina_Bool mouse_down : 1; /**< a flag that mouse is down on the list at the moment. this flag is set to true on mouse and reset to false on mouse up */ 121 Eina_Bool mouse_down : 1; /**< a flag that mouse is down on the list at the moment. this flag is set to true on mouse and reset to false on mouse up */
122 /* a flag for focus direction. by default it is false */
123 Eina_Bool focus_direction : 1;
113}; 124};
114 125
115struct Elm_Gen_Item_Type 126struct Elm_Gen_Item_Type
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index 00fbcc05c..7b9697058 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -6,4 +6,5 @@ prefs \
6test_entry \ 6test_entry \
7test_map \ 7test_map \
8access_output \ 8access_output \
9datetime_input_ctxpopup 9datetime_input_ctxpopup \
10gengrid_focus_hook
diff --git a/src/modules/gengrid_focus_hook/Makefile.am b/src/modules/gengrid_focus_hook/Makefile.am
new file mode 100644
index 000000000..54d5b48dd
--- /dev/null
+++ b/src/modules/gengrid_focus_hook/Makefile.am
@@ -0,0 +1,38 @@
1
2MAINTAINERCLEANFILES = Makefile.in
3
4AM_CPPFLAGS = \
5-DELM_INTERNAL_API_ARGESFSDFEFC=1 \
6-I. \
7-I$(top_builddir) \
8-I$(top_srcdir) \
9-I$(top_srcdir)/src/lib \
10-I$(top_builddir)/src/lib \
11-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
12-DPACKAGE_LIB_DIR=\"$(libdir)\" \
13@ELEMENTARY_CFLAGS@ \
14@ELEMENTARY_X_CFLAGS@ \
15@ELEMENTARY_FB_CFLAGS@ \
16@ELEMENTARY_SDL_CFLAGS@ \
17@ELEMENTARY_WIN32_CFLAGS@ \
18@ELEMENTARY_WINCE_CFLAGS@ \
19@ELEMENTARY_ELOCATION_CFLAGS@ \
20@ELEMENTARY_EWEATHER_CFLAGS@ \
21@ELEMENTARY_WEB_CFLAGS@ \
22@ELEMENTARY_EMAP_CFLAGS@ \
23@ELEMENTARY_WAYLAND_CFLAGS@ \
24@ELEMENTARY_EMAP_CFLAGS@ \
25@EVIL_CFLAGS@
26
27if ELEMENTARY_WINDOWS_BUILD
28AM_CPPFLAGS += -DELEMENTARY_BUILD
29endif
30
31pkgdir = $(libdir)/elementary/modules/gengrid_focus_hook/$(MODULE_ARCH)
32pkg_LTLIBRARIES = module.la
33
34module_la_SOURCES = gengrid_focus_hook.c
35
36module_la_LIBADD = @ELEMENTARY_LIBS@ $(top_builddir)/src/lib/libelementary.la
37module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
38module_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/gengrid_focus_hook/gengrid_focus_hook.c b/src/modules/gengrid_focus_hook/gengrid_focus_hook.c
new file mode 100644
index 000000000..8df840041
--- /dev/null
+++ b/src/modules/gengrid_focus_hook/gengrid_focus_hook.c
@@ -0,0 +1,537 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4#include <Elementary.h>
5#include <Elementary_Cursor.h>
6#include "elm_priv.h"
7#include "elm_widget_gengrid.h"
8
9#include <limits.h>
10
11#define GG_IT(_it) (_it->item)
12
13#define EINA_INLIST_REVERSE_FOREACH_INSIDE(list, it) \
14 for (it = NULL, it = (list ? _EINA_INLIST_CONTAINER(it, list) : NULL); it; \
15 it = (EINA_INLIST_GET(it)->prev \
16 ? _EINA_INLIST_CONTAINER(it, EINA_INLIST_GET(it)->prev) \
17 : NULL))
18
19#define EINA_LIST_REVERSE_FOREACH_INSIDE(list, l, data) \
20 for (l = list, data = eina_list_data_get(l); l; \
21 l = eina_list_prev(l), data = eina_list_data_get(l))
22
23#define WEIGHT_MAX ((double)INT_MAX / (double)1000000)
24
25/**
26 * Find the first parent of object.
27 * Parent must be type of elm_gengrid.
28 *
29 * @param base
30 *
31 * @return
32 */
33static const Evas_Object *
34_find_gengrid_parent_item(const Evas_Object *base)
35{
36 const Evas_Object *res = NULL;
37 if (base)
38 {
39 const Evas_Object *parent = NULL;
40 parent = elm_widget_parent_get(base);
41
42 while (parent)
43 {
44 if (evas_object_smart_type_check(parent, "elm_gengrid"))
45 {
46 res = parent;
47 break;
48 }
49 parent = elm_widget_parent_get(parent);
50 }
51 }
52 return res;
53}
54
55static Eina_Bool
56_can_focus(const Evas_Object *obj)
57{
58 if (obj && elm_object_focus_allow_get(obj) &&
59 elm_widget_can_focus_get(obj))
60 return EINA_TRUE;
61 return EINA_FALSE;
62}
63
64
65static Eina_List *
66_get_contents(const Evas_Object *obj)
67{
68 Eina_List *res = NULL;
69 if (!obj)
70 return NULL;
71
72 if (evas_object_smart_type_check(obj, "elm_layout"))
73 {
74 Evas_Object *edje = elm_layout_edje_get(obj);
75 if (edje)
76 {
77 const Eina_List *l = NULL;
78 const char *key;
79 const Eina_List *contents =
80 elm_widget_stringlist_get(
81 edje_object_data_get(edje, "contents"));
82
83 EINA_LIST_FOREACH(contents, l, key)
84 {
85 if (key)
86 {
87 const Evas_Object *child =
88 edje_object_part_swallow_get(edje, key);
89 if (child)
90 {
91 Eina_List *l1 = NULL;
92 res = eina_list_append(res, child);
93
94 l1 = _get_contents(child);
95 if (l1)
96 {
97 res = eina_list_merge(res, l1);
98 }
99 }
100 }
101 }
102 }
103 }
104 return res;
105}
106
107static Eina_List *
108_gengrid_item_contents_get(const Elm_Gen_Item *it)
109{
110 Eina_List *res = NULL;
111 Eina_List *l = NULL;
112 Evas_Object *child = NULL;
113 EINA_LIST_FOREACH(it->content_objs, l, child)
114 {
115 if (child)
116 {
117 Eina_List *l1 = NULL;
118 res = eina_list_append(res, child);
119
120 l1 = _get_contents(child);
121 if (l1)
122 {
123 res = eina_list_merge(res, l1);
124 }
125 }
126 }
127 return res;
128}
129
130static const Evas_Object *
131_find_focusable_object(const Elm_Gen_Item *it,
132 const Evas_Object *base,
133 Elm_Focus_Direction dir)
134{
135 const Evas_Object *obj = NULL;
136 Eina_List *l = NULL;
137 Eina_List *contents = NULL;
138
139 if (!it) return NULL;
140
141 contents = _gengrid_item_contents_get(it);
142
143 if (contents)
144 {
145 if (base)
146 {
147 l = eina_list_data_find_list(contents, base);
148 obj = base;
149 }
150
151 if (dir == ELM_FOCUS_LEFT || dir == ELM_FOCUS_UP)
152 {
153 if (l)
154 l = eina_list_prev(l);
155 else
156 l = eina_list_last(contents);
157
158 while (l)
159 {
160 obj = eina_list_data_get(l);
161 if (_can_focus(obj))
162 break;
163 obj = NULL;
164 l = eina_list_prev(l);
165 }
166 }
167 else if (dir == ELM_FOCUS_RIGHT || dir == ELM_FOCUS_DOWN)
168 {
169 if (l)
170 l = eina_list_next(l);
171 else
172 l = contents;
173 while (l)
174 {
175 obj = eina_list_data_get(l);
176 if (_can_focus(obj))
177 break;
178 obj = NULL;
179 l = eina_list_next(l);
180 }
181 }
182 eina_list_free(contents);
183 }
184 return obj;
185}
186
187
188
189static Eina_Bool
190_check_item_contains(Elm_Gen_Item *it, const Evas_Object *base)
191{
192 Eina_Bool res = EINA_FALSE;
193 Eina_List *contents = NULL;
194 contents = _gengrid_item_contents_get(it);
195
196 if (contents)
197 {
198 const Eina_List *l = NULL;
199 Evas_Object *content = NULL;
200
201 // loop contents (Evas_Object) of item
202 EINA_LIST_FOREACH(contents, l, content)
203 {
204 if (content == base)
205 {
206 res = EINA_TRUE;
207 break;
208 }
209 }
210 eina_list_free(contents);
211 }
212 return res;
213}
214
215static Elm_Gen_Item *
216_find_item_for_base(const Evas_Object *obj,
217 const Evas_Object *base)
218{
219 ELM_GENGRID_CHECK(obj) EINA_FALSE;
220 ELM_GENGRID_DATA_GET(obj, sd);
221 Elm_Gen_Item *res = NULL;
222 Elm_Gen_Item *it = (Elm_Gen_Item *)(sd->last_selected_item);
223
224 if (it && _check_item_contains(it, base))
225 {
226 res = it;
227 }
228 else
229 { // try find in all
230 EINA_INLIST_FOREACH(sd->items, it)
231 {
232 if (it && _check_item_contains(it, base))
233 {
234 res = it;
235 break;
236 }
237 }
238 }
239 return res;
240}
241
242static Eina_Bool
243_gengrid_self_focus_item_get(
244 const Evas_Object *obj, const Evas_Object *base,
245 // list of Elm_Gen_Items
246 const Eina_List *items, void *(*list_data_get)(const Eina_List *l),
247 double degree, Evas_Object **direction, double *weight)
248{
249 Evas_Coord ox, oy;
250 Evas_Coord vw, vh;
251 const Evas_Object *res_obj = NULL;
252 Elm_Focus_Direction dir = ELM_FOCUS_UP;
253
254 unsigned int items_count = 0;
255 unsigned int columns = 0, items_visible = 0;
256 unsigned int items_row = 0, items_col = 0, rows = 0;
257 int new_position = 0;
258 int cx = 0;
259 int cy = 0;
260
261 int focused_pos = 0;
262
263 Elm_Gen_Item *it = NULL;
264 Elm_Gen_Item *it_res = NULL;
265 Eina_List *list = NULL;
266 Eina_List *l = NULL;
267
268 Elm_Gen_Item *focused_item = NULL;
269
270 (void)list_data_get;
271
272 ELM_GENGRID_CHECK(obj) EINA_FALSE;
273 ELM_GENGRID_DATA_GET(obj, sd);
274
275 if (!direction || !weight || !base || !items) return EINA_FALSE;
276
277 evas_object_geometry_get(sd->pan_obj, &ox, &oy, &vw, &vh);
278
279 focused_item = _find_item_for_base(obj, base);
280
281 if (!focused_item) return EINA_FALSE;
282
283
284 if (degree == 0)
285 dir = ELM_FOCUS_UP;
286 else if (degree == 90)
287 dir = ELM_FOCUS_RIGHT;
288 else if (degree == 180)
289 dir = ELM_FOCUS_DOWN;
290 else if (degree == 270)
291 dir = ELM_FOCUS_LEFT;
292 else
293 return EINA_FALSE;
294
295 res_obj = _find_focusable_object(focused_item, base, dir);
296 if (res_obj && res_obj != base)
297 {
298 *direction = (Evas_Object *)res_obj;
299 *weight = WEIGHT_MAX;
300 return EINA_TRUE;
301 }
302
303 focused_pos = focused_item->position - 1;
304
305 items_count =
306 sd->item_count - eina_list_count(sd->group_items) + sd->items_lost;
307 if (sd->horizontal)
308 {
309 if (sd->item_height > 0) items_visible = vh / sd->item_height;
310 if (items_visible < 1) items_visible = 1;
311
312 columns = items_count / items_visible;
313 if (items_count % items_visible) columns++;
314
315 items_row = items_visible;
316 if (items_row > sd->item_count) items_row = sd->item_count;
317
318 cx = focused_pos / items_row;
319 cy = focused_pos % items_row;
320 }
321 else
322 {
323 if (sd->item_width > 0) items_visible = vw / sd->item_width;
324 if (items_visible < 1) items_visible = 1;
325
326 rows = items_count / items_visible;
327 if (items_count % items_visible) rows++;
328
329 items_col = items_visible;
330 if (items_col > sd->item_count) items_col = sd->item_count;
331
332 cy = focused_pos / items_col;
333 cx = focused_pos % items_col;
334 }
335
336
337 if (dir == ELM_FOCUS_UP)
338 cy--;
339 else if (dir == ELM_FOCUS_RIGHT)
340 cx++;
341 else if (dir == ELM_FOCUS_DOWN)
342 cy++;
343 else if (dir == ELM_FOCUS_LEFT)
344 cx--;
345
346 if (cx < 0 || cy < 0) return EINA_FALSE;
347
348 if (sd->horizontal)
349 {
350 if ((cy > (items_row - 1)) || (cx > (columns - 1))) return EINA_FALSE;
351 new_position = items_row * cx + cy;
352 }
353 else
354 {
355 if ((cx > (items_col - 1)) || (cy > (rows - 1))) return EINA_FALSE;
356 new_position = cx + items_col * cy;
357 }
358
359 if (new_position > (items_count - 1)) return EINA_FALSE;
360
361 focused_pos++;
362 new_position++;
363
364 list = eina_list_data_find_list(items, focused_item);
365
366 if (!list) return EINA_FALSE;
367
368 if (new_position > focused_pos)
369 {
370 /// New position should be after focused
371 EINA_LIST_FOREACH(list, l, it)
372 {
373 if (it->position == new_position)
374 {
375 it_res = it;
376 break;
377 }
378 }
379 }
380 else if (new_position < focused_pos)
381 {
382 /// New position should be before focused
383 EINA_LIST_REVERSE_FOREACH_INSIDE(list, l, it)
384 {
385 if (it->position == new_position)
386 {
387 it_res = it;
388 break;
389 }
390 }
391 }
392 else
393 {
394 return EINA_FALSE;
395 }
396
397 if (it_res)
398 {
399 res_obj = _find_focusable_object(it_res, base, dir);
400 *direction = (Evas_Object *)res_obj;
401 *weight = WEIGHT_MAX;
402 return EINA_TRUE;
403 }
404 return EINA_FALSE;
405}
406
407static Eina_Bool
408_gengrid_focus_list_direction_get(
409 const Evas_Object *obj, const Evas_Object *base,
410 // list of Elm_Gen_Items
411 const Eina_List *items, void *(*list_data_get)(const Eina_List *l),
412 double degree, Evas_Object **direction, double *weight)
413{
414 const Eina_List *l = NULL;
415 Evas_Object *current_best = NULL;
416 (void)list_data_get;
417 ELM_GENGRID_CHECK(obj) EINA_FALSE;
418 if (!direction || !weight || !base || !items) return EINA_FALSE;
419
420 l = items;
421 current_best = *direction;
422
423 // loop items Elm_Gen_Item
424 for (; l; l = eina_list_next(l))
425 {
426 Eina_List *contents = NULL;
427 Elm_Gen_Item *it = list_data_get(l);
428 contents = _gengrid_item_contents_get(it);
429 if (contents)
430 {
431 const Eina_List *l2 = NULL;
432 Evas_Object *content = NULL;
433
434 // loop contents (Evas_Object) of item
435 EINA_LIST_FOREACH(contents, l2, content)
436 {
437 // if better element than set new sd->focused and sd->selected
438 elm_widget_focus_direction_get(content, base, degree, direction,
439 weight);
440 }
441 eina_list_free(contents);
442 }
443 }
444 if (current_best != *direction)
445 return EINA_TRUE;
446 else
447 return EINA_FALSE;
448}
449
450EAPI void
451gen_focus_direction(Eo *obj, void *_pd, va_list *list)
452{
453 Eina_List *items = NULL;
454 const Evas_Object *parent = NULL;
455
456 void *(*list_data_get)(const Eina_List * list);
457 Eina_List *(*list_free)(Eina_List * list);
458
459 Elm_Gengrid_Smart_Data *sd = _pd;
460
461 Evas_Object *base = va_arg(*list, Evas_Object *);
462 double degree = va_arg(*list, double);
463 Evas_Object **direction = va_arg(*list, Evas_Object **);
464 double *weight = va_arg(*list, double *);
465 Eina_Bool *ret = va_arg(*list, Eina_Bool *);
466
467 if (!sd)
468 {
469 *ret = EINA_FALSE;
470 return;
471 }
472
473
474 *ret = EINA_FALSE;
475 list_data_get = NULL;
476
477 Eina_Bool (*list_direction_get)(
478 const Evas_Object * obj, const Evas_Object * base,
479 const Eina_List * items, void * (*list_data_get)(const Eina_List * l),
480 double degree, Evas_Object * *direction, double * weight);
481
482 list_direction_get = NULL;
483 list_free = NULL;
484 parent = _find_gengrid_parent_item(base);
485
486 /// If focused is subobject of this gengrid then we selected next
487 /// in direction
488 if (obj == parent)
489 {
490 items = elm_gengrid_realized_items_get(obj);
491 list_data_get = NULL;
492 list_direction_get = _gengrid_self_focus_item_get;
493 list_free = eina_list_free;
494 }
495
496 if (!items)
497 {
498 items = (Eina_List *)(elm_object_focus_custom_chain_get(obj));
499 list_data_get = eina_list_data_get;
500 list_direction_get = elm_widget_focus_list_direction_get;
501 list_free = NULL;
502 }
503
504 if (!items)
505 {
506 items = elm_gengrid_realized_items_get(obj);
507 list_data_get = eina_list_data_get;
508 list_direction_get = _gengrid_focus_list_direction_get;
509 list_free = eina_list_free;
510 }
511
512 if (!items)
513 {
514 *ret = EINA_FALSE;
515 return;
516 }
517
518 *ret = list_direction_get(obj, base, items, list_data_get, degree, direction,
519 weight);
520
521 if (list_free) list_free(items);
522}
523
524// module api funcs needed
525EAPI int
526elm_modapi_init(void *m)
527{
528 (void) m;
529 return 1; // succeed always
530}
531
532EAPI int
533elm_modapi_shutdown(void *m)
534{
535 (void) m;
536 return 1; // succeed always
537}