summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}