diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | config/default/base.src | 2 | ||||
-rw-r--r-- | config/mobile/base.src | 2 | ||||
-rw-r--r-- | config/standard/base.src | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/bin/test.c | 2 | ||||
-rw-r--r-- | src/bin/test_gengrid.c | 115 | ||||
-rw-r--r-- | src/lib/elm_gengrid.c | 92 | ||||
-rw-r--r-- | src/lib/elm_gengrid_common.h | 10 | ||||
-rw-r--r-- | src/lib/elm_widget_gengrid.h | 11 | ||||
-rw-r--r-- | src/modules/Makefile.am | 3 | ||||
-rw-r--r-- | src/modules/gengrid_focus_hook/Makefile.am | 38 | ||||
-rw-r--r-- | src/modules/gengrid_focus_hook/gengrid_focus_hook.c | 537 |
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 *.gmo /config.cache-env /compile +build.conf +.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 { value "finger_size" int: 40; value "fps" double: 60.0; value "theme" string: "default"; - value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; + value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api"; value "tooltip_delay" double: 1.0; value "cursor_engine_only" uchar: 1; 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 { value "finger_size" int: 40; value "fps" double: 60.0; value "theme" string: "default"; - value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; + value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api"; value "tooltip_delay" double: 1.0; value "cursor_engine_only" uchar: 1; 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 { value "finger_size" int: 10; value "fps" double: 60.0; value "theme" string: "default"; - value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api"; + value "modules" string: "prefs>prefs_iface:access_output>access/api:datetime_input_ctxpopup>datetime/api:gengrid_focus_hook>gengrid_focus/api"; value "tooltip_delay" double: 1.0; value "cursor_engine_only" uchar: 1; 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 src/modules/prefs/Makefile src/modules/access_output/Makefile src/modules/datetime_input_ctxpopup/Makefile +src/modules/gengrid_focus_hook/Makefile src/modules/test_entry/Makefile src/modules/test_map/Makefile src/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); void test_gengrid2(void *data, Evas_Object *obj, void *event_info); void test_gengrid3(void *data, Evas_Object *obj, void *event_info); void test_gengrid_item_styles(void *data, Evas_Object *obj, void *event_info); +void test_gengrid_focus_direction(void *data, Evas_Object *obj, void *event_info); void test_gengrid4(void *data, Evas_Object *obj, void *event_info); void test_gengrid_speed(void *data, Evas_Object *obj, void *event_info); void test_gengrid_focus(void *data, Evas_Object *obj, void *event_info); @@ -665,6 +666,7 @@ add_tests: ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Item Styles", test_gengrid_item_styles); ADD_TEST(NULL, "Lists - Gengrid", "Gengrid Update Speed", test_gengrid_speed); ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus", test_gengrid_focus); + ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus Direction", test_gengrid_focus_direction); //------------------------------// 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) return NULL; } +Evas_Object * +grid_content_buttons_get(void *data, Evas_Object *obj, const char *part) +{ + const Item_Data *id = data; + if (!strcmp(part, "elm.swallow.icon")) + { + Evas_Object *bt = elm_button_add(obj); + Evas_Object *ic = elm_icon_add(obj); + elm_image_file_set(ic, id->path, NULL); + elm_image_aspect_fixed_set(ic, EINA_FALSE); + elm_object_part_content_set(bt, "icon", ic); + evas_object_show(bt); + return bt; + } + return NULL; +} + Eina_Bool grid_state_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) { @@ -348,6 +365,54 @@ create_gengrid(Evas_Object *obj, int items) return grid; } +static Evas_Object * +create_gengrid_buttons(Evas_Object *obj, int items) +{ + Evas_Object *grid = NULL; + static Item_Data id[144]; + int i, n; + char buf[PATH_MAX]; + + grid = elm_gengrid_add(obj); + elm_gengrid_item_size_set(grid, + elm_config_scale_get() * 200, + elm_config_scale_get() * 150); + elm_gengrid_reorder_mode_set(grid, EINA_TRUE); + evas_object_smart_callback_add(grid, "selected", grid_selected, NULL); + evas_object_smart_callback_add(grid, "clicked,double", grid_double_clicked, NULL); + evas_object_smart_callback_add(grid, "longpressed", grid_longpress, NULL); + evas_object_smart_callback_add(grid, "moved", grid_moved, NULL); + evas_object_smart_callback_add(grid, "drag,start,up", grid_drag_up, NULL); + evas_object_smart_callback_add(grid, "drag,start,right", grid_drag_right, NULL); + evas_object_smart_callback_add(grid, "drag,start,down", grid_drag_down, NULL); + evas_object_smart_callback_add(grid, "drag,start,left", grid_drag_left, NULL); + evas_object_smart_callback_add(grid, "drag,stop", grid_drag_stop, NULL); + evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL); + + gic = elm_gengrid_item_class_new(); + gic->item_style = "default"; + gic->func.text_get = grid_text_get; + gic->func.content_get = grid_content_buttons_get; + gic->func.state_get = grid_state_get; + gic->func.del = NULL; + + n = 0; + for (i = 0; i < items; i++) + { + snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[n]); + n = (n + 1) % 9; + id[i].mode = i; + id[i].path = eina_stringshare_add(buf); + id[i].item = elm_gengrid_item_append(grid, gic, &(id[i]), grid_sel, NULL); + if (!(i % 5)) + elm_gengrid_item_selected_set(id[i].item, EINA_TRUE); + } + elm_gengrid_item_class_free(gic); + + return grid; +} + static void restore_bt_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { @@ -1274,6 +1339,56 @@ test_gengrid4(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_ } void +test_gengrid_focus_direction(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Evas_Object *win, *bt, *bxx, *bx; + + + win = elm_win_util_standard_add("gengrid", "GenGrid"); + elm_win_autodel_set(win, EINA_TRUE); + evas_object_resize(win, 600, 600); + evas_object_show(win); + + elm_win_focus_highlight_enabled_set(win, EINA_TRUE); + elm_win_focus_highlight_animate_set(win, EINA_TRUE); + + bxx = elm_box_add(win); + evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bxx); + evas_object_show(bxx); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Next API function"); + elm_box_pack_end(bxx, bt); + evas_object_show(bt); + + /* Create GenGrid */ + Evas_Object *grid = create_gengrid_buttons(win, (12 * 12)); + elm_box_pack_end(bxx, grid); + evas_object_show(grid); + + elm_gengrid_focus_direction_allow_set(grid, EINA_TRUE); +// elm_object_focus_allow_set(grid, EINA_FALSE); + + bx = elm_box_add(win); + elm_box_horizontal_set(bx, EINA_TRUE); + elm_box_pack_end(bxx, bx); + evas_object_show(bx); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Bring in"); + evas_object_smart_callback_add(bt, "clicked", _btn_bring_in_clicked_cb, grid); + elm_box_pack_end(bx, bt); + evas_object_show(bt); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Show"); + evas_object_smart_callback_add(bt, "clicked", _btn_show_clicked_cb, grid); + elm_box_pack_end(bx, bt); + evas_object_show(bt); +} + +void test_gengrid_speed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { 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[] = { }; #undef ELM_PRIV_GENGRID_SIGNALS +static Gengrid_Focus_Direction_Mod_Api *gengrid_focus_direction_mod = NULL; + +static Gengrid_Focus_Direction_Mod_Api * +_gengrid_focus_direction_mod_init(void) +{ + Elm_Module *mod = NULL; + + if (!(mod = _elm_module_find_as("gengrid_focus/api"))) return NULL; + + mod->api = malloc(sizeof(Gengrid_Focus_Direction_Mod_Api)); + if (!mod->api) return NULL; + + ((Gengrid_Focus_Direction_Mod_Api *)(mod->api))->hook_ptr = + _elm_module_symbol_get(mod, "gen_focus_direction"); + + if (!((Gengrid_Focus_Direction_Mod_Api *)(mod->api))->hook_ptr) + return NULL; + + return mod->api; +} + static void _item_show_region(void *data) { @@ -550,6 +571,34 @@ _elm_gengrid_item_unrealize(Elm_Gen_Item *it, evas_event_thaw_eval(evas_object_evas_get(WIDGET(it))); } + +static void +_elm_gengrid_item_focused_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Elm_Gen_Item *it = data; + Elm_Gengrid_Smart_Data *sd = GG_IT(it)->wsd; + if (sd->focus_direction && gengrid_focus_direction_mod) + { + Evas_Coord x = 0; + Evas_Coord y = 0; + Evas_Coord v_w = 0; + Evas_Coord v_h = 0; + Evas_Coord step_x = 0; + Evas_Coord step_y = 0; + Evas_Coord page_x = 0; + Evas_Coord page_y = 0; + + eo_do(sd->obj, + elm_interface_scrollable_content_pos_get(&x, &y), + elm_interface_scrollable_step_size_get(&step_x, &step_y), + elm_interface_scrollable_page_size_get(&page_x, &page_y), + elm_interface_scrollable_content_viewport_size_get(&v_w, &v_h)); + + elm_gengrid_item_selected_set((Elm_Object_Item *)it, EINA_TRUE); + elm_gengrid_item_show((Elm_Object_Item *)it, ELM_GENGRID_ITEM_SCROLLTO_IN); + } +} + static void _item_mouse_up_cb(void *data, Evas *evas EINA_UNUSED, @@ -816,6 +865,7 @@ _item_realize(Elm_Gen_Item *it) edje_object_part_swallow(VIEW(it), key, ic); evas_object_show(ic); elm_widget_sub_object_add(WIDGET(it), ic); + evas_object_smart_callback_add(ic, "focused", _elm_gengrid_item_focused_cb, it); } } } @@ -1914,6 +1964,8 @@ _elm_gengrid_smart_event(Eo *obj, void *_pd, va_list *list) if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (!sd->items) return; + if (sd->focus_direction && gengrid_focus_direction_mod) return; + eo_do(obj, elm_interface_scrollable_content_pos_get(&x, &y), 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) Elm_Object_Item *it = NULL; Eina_Bool is_sel = EINA_FALSE; + if (sd->focus_direction && gengrid_focus_direction_mod) + { + if (ret) *ret = EINA_TRUE; + return; + } eo_do_super(obj, MY_CLASS, elm_obj_widget_on_focus(&int_ret)); + if (!int_ret) return; 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 } static void -_elm_gengrid_smart_focus_direction_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list) +_elm_gengrid_smart_focus_direction_manager_is(Eo *obj EINA_UNUSED, void *_pd, va_list *list) { Eina_Bool *ret = va_arg(*list, Eina_Bool *); + Elm_Gengrid_Smart_Data *sd = _pd; *ret = EINA_FALSE; + if (sd->focus_direction && gengrid_focus_direction_mod) + *ret = EINA_TRUE; +} + +static void +_elm_gengrid_smart_focus_direction(Eo *obj, void *_pd, va_list *list) +{ + Elm_Gengrid_Smart_Data *sd = _pd; + if (sd->focus_direction && gengrid_focus_direction_mod) + { + gengrid_focus_direction_mod->hook_ptr(obj, _pd, list); + } + else + { + Eina_Bool *ret = va_arg(*list, Eina_Bool *); + *ret = EINA_FALSE; + } } static void @@ -2737,6 +2813,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED) elm_widget_style_get(obj))) CRI("Failed to set layout!"); + if (!gengrid_focus_direction_mod) gengrid_focus_direction_mod = _gengrid_focus_direction_mod_init(); eo_do(obj, elm_interface_scrollable_objects_set(wd->resize_obj, priv->hit_rect)); priv->old_h_bounce = bounce; @@ -2744,6 +2821,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED) eo_do(obj, elm_interface_scrollable_bounce_allow_set(bounce, bounce)); + eo_do(obj, elm_interface_scrollable_animate_start_cb_set (_scroll_animate_start_cb), @@ -2760,6 +2838,7 @@ _elm_gengrid_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED) priv->align_x = 0.5; priv->align_y = 0.5; priv->highlight = EINA_TRUE; + priv->focus_direction = EINA_FALSE; priv->pan_obj = eo_add(MY_PAN_CLASS, evas_object_evas_get(obj)); pan_data = eo_data_scope_get(priv->pan_obj, MY_PAN_CLASS); @@ -3247,6 +3326,15 @@ elm_gengrid_horizontal_set(Evas_Object *obj, eo_do(obj, elm_obj_gengrid_horizontal_set(horizontal)); } +EAPI void +elm_gengrid_focus_direction_allow_set(Evas_Object *obj, + Eina_Bool flag) +{ + ELM_GENGRID_CHECK(obj); + ELM_GENGRID_DATA_GET(obj, sd); + sd->focus_direction = flag; +} + static void _horizontal_set(Eo *obj, void *_pd, va_list *list) { @@ -4136,7 +4224,6 @@ elm_gengrid_item_show(Elm_Object_Item *item, ELM_GENGRID_ITEM_CHECK_OR_RETURN(it); sd = GG_IT(it)->wsd; - if ((it->generation < sd->generation)) return; sd->show_region = EINA_TRUE; @@ -4484,6 +4571,7 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_DIRECTION_MANAGER_IS), _elm_gengrid_smart_focus_direction_manager_is), EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_HIGHLIGHT_GEOMETRY_GET), _elm_gengrid_focus_highlight_geometry_get), EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUSED_ITEM_GET), _elm_gengrid_focused_item_get), + EO_OP_FUNC(ELM_OBJ_WIDGET_ID(ELM_OBJ_WIDGET_SUB_ID_FOCUS_DIRECTION), _elm_gengrid_smart_focus_direction), EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SIZING_EVAL), _elm_gengrid_smart_sizing_eval), 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 */ EAPI Elm_Object_Select_Mode elm_gengrid_item_select_mode_get(const Elm_Object_Item *it); + +/** + * Set if gengrid should manage focus direction. + * + * @param obj The gengrid object + * @param flag The state which should be set. + * + * @ingroup Gengrid + */ +EAPI 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 @@ * other widgets which are a gengrid with some more logic on top. */ + +typedef struct _Gengrid_Focus_Direction_Mod_Api Gengrid_Focus_Direction_Mod_Api; + +struct _Gengrid_Focus_Direction_Mod_Api +{ + eo_op_func_type hook_ptr; +}; + + /** * Base widget smart data extended with gengrid instance data. */ @@ -110,6 +119,8 @@ struct _Elm_Gengrid_Smart_Data Eina_Bool show_region : 1; Eina_Bool bring_in : 1; 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 */ + /* a flag for focus direction. by default it is false */ + Eina_Bool focus_direction : 1; }; struct 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 \ test_entry \ test_map \ access_output \ -datetime_input_ctxpopup +datetime_input_ctxpopup \ +gengrid_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 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-DELM_INTERNAL_API_ARGESFSDFEFC=1 \ +-I. \ +-I$(top_builddir) \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/lib \ +-I$(top_builddir)/src/lib \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +@ELEMENTARY_CFLAGS@ \ +@ELEMENTARY_X_CFLAGS@ \ +@ELEMENTARY_FB_CFLAGS@ \ +@ELEMENTARY_SDL_CFLAGS@ \ +@ELEMENTARY_WIN32_CFLAGS@ \ +@ELEMENTARY_WINCE_CFLAGS@ \ +@ELEMENTARY_ELOCATION_CFLAGS@ \ +@ELEMENTARY_EWEATHER_CFLAGS@ \ +@ELEMENTARY_WEB_CFLAGS@ \ +@ELEMENTARY_EMAP_CFLAGS@ \ +@ELEMENTARY_WAYLAND_CFLAGS@ \ +@ELEMENTARY_EMAP_CFLAGS@ \ +@EVIL_CFLAGS@ + +if ELEMENTARY_WINDOWS_BUILD +AM_CPPFLAGS += -DELEMENTARY_BUILD +endif + +pkgdir = $(libdir)/elementary/modules/gengrid_focus_hook/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la + +module_la_SOURCES = gengrid_focus_hook.c + +module_la_LIBADD = @ELEMENTARY_LIBS@ $(top_builddir)/src/lib/libelementary.la +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_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 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include <Elementary.h> +#include <Elementary_Cursor.h> +#include "elm_priv.h" +#include "elm_widget_gengrid.h" + +#include <limits.h> + +#define GG_IT(_it) (_it->item) + +#define EINA_INLIST_REVERSE_FOREACH_INSIDE(list, it) \ + for (it = NULL, it = (list ? _EINA_INLIST_CONTAINER(it, list) : NULL); it; \ + it = (EINA_INLIST_GET(it)->prev \ + ? _EINA_INLIST_CONTAINER(it, EINA_INLIST_GET(it)->prev) \ + : NULL)) + +#define EINA_LIST_REVERSE_FOREACH_INSIDE(list, l, data) \ + for (l = list, data = eina_list_data_get(l); l; \ + l = eina_list_prev(l), data = eina_list_data_get(l)) + +#define WEIGHT_MAX ((double)INT_MAX / (double)1000000) + +/** + * Find the first parent of object. + * Parent must be type of elm_gengrid. + * + * @param base + * + * @return + */ +static const Evas_Object * +_find_gengrid_parent_item(const Evas_Object *base) +{ + const Evas_Object *res = NULL; + if (base) + { + const Evas_Object *parent = NULL; + parent = elm_widget_parent_get(base); + + while (parent) + { + if (evas_object_smart_type_check(parent, "elm_gengrid")) + { + res = parent; + break; + } + parent = elm_widget_parent_get(parent); + } + } + return res; +} + +static Eina_Bool +_can_focus(const Evas_Object *obj) +{ + if (obj && elm_object_focus_allow_get(obj) && + elm_widget_can_focus_get(obj)) + return EINA_TRUE; + return EINA_FALSE; +} + + +static Eina_List * +_get_contents(const Evas_Object *obj) +{ + Eina_List *res = NULL; + if (!obj) + return NULL; + + if (evas_object_smart_type_check(obj, "elm_layout")) + { + Evas_Object *edje = elm_layout_edje_get(obj); + if (edje) + { + const Eina_List *l = NULL; + const char *key; + const Eina_List *contents = + elm_widget_stringlist_get( + edje_object_data_get(edje, "contents")); + + EINA_LIST_FOREACH(contents, l, key) + { + if (key) + { + const Evas_Object *child = + edje_object_part_swallow_get(edje, key); + if (child) + { + Eina_List *l1 = NULL; + res = eina_list_append(res, child); + + l1 = _get_contents(child); + if (l1) + { + res = eina_list_merge(res, l1); + } + } + } + } + } + } + return res; +} + +static Eina_List * +_gengrid_item_contents_get(const Elm_Gen_Item *it) +{ + Eina_List *res = NULL; + Eina_List *l = NULL; + Evas_Object *child = NULL; + EINA_LIST_FOREACH(it->content_objs, l, child) + { + if (child) + { + Eina_List *l1 = NULL; + res = eina_list_append(res, child); + + l1 = _get_contents(child); + if (l1) + { + res = eina_list_merge(res, l1); + } + } + } + return res; +} + +static const Evas_Object * +_find_focusable_object(const Elm_Gen_Item *it, + const Evas_Object *base, + Elm_Focus_Direction dir) +{ + const Evas_Object *obj = NULL; + Eina_List *l = NULL; + Eina_List *contents = NULL; + + if (!it) return NULL; + + contents = _gengrid_item_contents_get(it); + + if (contents) + { + if (base) + { + l = eina_list_data_find_list(contents, base); + obj = base; + } + + if (dir == ELM_FOCUS_LEFT || dir == ELM_FOCUS_UP) + { + if (l) + l = eina_list_prev(l); + else + l = eina_list_last(contents); + + while (l) + { + obj = eina_list_data_get(l); + if (_can_focus(obj)) + break; + obj = NULL; + l = eina_list_prev(l); + } + } + else if (dir == ELM_FOCUS_RIGHT || dir == ELM_FOCUS_DOWN) + { + if (l) + l = eina_list_next(l); + else + l = contents; + while (l) + { + obj = eina_list_data_get(l); + if (_can_focus(obj)) + break; + obj = NULL; + l = eina_list_next(l); + } + } + eina_list_free(contents); + } + return obj; +} + + + +static Eina_Bool +_check_item_contains(Elm_Gen_Item *it, const Evas_Object *base) +{ + Eina_Bool res = EINA_FALSE; + Eina_List *contents = NULL; + contents = _gengrid_item_contents_get(it); + + if (contents) + { + const Eina_List *l = NULL; + Evas_Object *content = NULL; + + // loop contents (Evas_Object) of item + EINA_LIST_FOREACH(contents, l, content) + { + if (content == base) + { + res = EINA_TRUE; + break; + } + } + eina_list_free(contents); + } + return res; +} + +static Elm_Gen_Item * +_find_item_for_base(const Evas_Object *obj, + const Evas_Object *base) +{ + ELM_GENGRID_CHECK(obj) EINA_FALSE; + ELM_GENGRID_DATA_GET(obj, sd); + Elm_Gen_Item *res = NULL; + Elm_Gen_Item *it = (Elm_Gen_Item *)(sd->last_selected_item); + + if (it && _check_item_contains(it, base)) + { + res = it; + } + else + { // try find in all + EINA_INLIST_FOREACH(sd->items, it) + { + if (it && _check_item_contains(it, base)) + { + res = it; + break; + } + } + } + return res; +} + +static Eina_Bool +_gengrid_self_focus_item_get( + const Evas_Object *obj, const Evas_Object *base, + // list of Elm_Gen_Items + const Eina_List *items, void *(*list_data_get)(const Eina_List *l), + double degree, Evas_Object **direction, double *weight) +{ + Evas_Coord ox, oy; + Evas_Coord vw, vh; + const Evas_Object *res_obj = NULL; + Elm_Focus_Direction dir = ELM_FOCUS_UP; + + unsigned int items_count = 0; + unsigned int columns = 0, items_visible = 0; + unsigned int items_row = 0, items_col = 0, rows = 0; + int new_position = 0; + int cx = 0; + int cy = 0; + + int focused_pos = 0; + + Elm_Gen_Item *it = NULL; + Elm_Gen_Item *it_res = NULL; + Eina_List *list = NULL; + Eina_List *l = NULL; + + Elm_Gen_Item *focused_item = NULL; + + (void)list_data_get; + + ELM_GENGRID_CHECK(obj) EINA_FALSE; + ELM_GENGRID_DATA_GET(obj, sd); + + if (!direction || !weight || !base || !items) return EINA_FALSE; + + evas_object_geometry_get(sd->pan_obj, &ox, &oy, &vw, &vh); + + focused_item = _find_item_for_base(obj, base); + + if (!focused_item) return EINA_FALSE; + + + if (degree == 0) + dir = ELM_FOCUS_UP; + else if (degree == 90) + dir = ELM_FOCUS_RIGHT; + else if (degree == 180) + dir = ELM_FOCUS_DOWN; + else if (degree == 270) + dir = ELM_FOCUS_LEFT; + else + return EINA_FALSE; + + res_obj = _find_focusable_object(focused_item, base, dir); + if (res_obj && res_obj != base) + { + *direction = (Evas_Object *)res_obj; + *weight = WEIGHT_MAX; + return EINA_TRUE; + } + + focused_pos = focused_item->position - 1; + + items_count = + sd->item_count - eina_list_count(sd->group_items) + sd->items_lost; + if (sd->horizontal) + { + if (sd->item_height > 0) items_visible = vh / sd->item_height; + if (items_visible < 1) items_visible = 1; + + columns = items_count / items_visible; + if (items_count % items_visible) columns++; + + items_row = items_visible; + if (items_row > sd->item_count) items_row = sd->item_count; + + cx = focused_pos / items_row; + cy = focused_pos % items_row; + } + else + { + if (sd->item_width > 0) items_visible = vw / sd->item_width; + if (items_visible < 1) items_visible = 1; + + rows = items_count / items_visible; + if (items_count % items_visible) rows++; + + items_col = items_visible; + if (items_col > sd->item_count) items_col = sd->item_count; + + cy = focused_pos / items_col; + cx = focused_pos % items_col; + } + + + if (dir == ELM_FOCUS_UP) + cy--; + else if (dir == ELM_FOCUS_RIGHT) + cx++; + else if (dir == ELM_FOCUS_DOWN) + cy++; + else if (dir == ELM_FOCUS_LEFT) + cx--; + + if (cx < 0 || cy < 0) return EINA_FALSE; + + if (sd->horizontal) + { + if ((cy > (items_row - 1)) || (cx > (columns - 1))) return EINA_FALSE; + new_position = items_row * cx + cy; + } + else + { + if ((cx > (items_col - 1)) || (cy > (rows - 1))) return EINA_FALSE; + new_position = cx + items_col * cy; + } + + if (new_position > (items_count - 1)) return EINA_FALSE; + + focused_pos++; + new_position++; + + list = eina_list_data_find_list(items, focused_item); + + if (!list) return EINA_FALSE; + + if (new_position > focused_pos) + { + /// New position should be after focused + EINA_LIST_FOREACH(list, l, it) + { + if (it->position == new_position) + { + it_res = it; + break; + } + } + } + else if (new_position < focused_pos) + { + /// New position should be before focused + EINA_LIST_REVERSE_FOREACH_INSIDE(list, l, it) + { + if (it->position == new_position) + { + it_res = it; + break; + } + } + } + else + { + return EINA_FALSE; + } + + if (it_res) + { + res_obj = _find_focusable_object(it_res, base, dir); + *direction = (Evas_Object *)res_obj; + *weight = WEIGHT_MAX; + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_gengrid_focus_list_direction_get( + const Evas_Object *obj, const Evas_Object *base, + // list of Elm_Gen_Items + const Eina_List *items, void *(*list_data_get)(const Eina_List *l), + double degree, Evas_Object **direction, double *weight) +{ + const Eina_List *l = NULL; + Evas_Object *current_best = NULL; + (void)list_data_get; + ELM_GENGRID_CHECK(obj) EINA_FALSE; + if (!direction || !weight || !base || !items) return EINA_FALSE; + + l = items; + current_best = *direction; + + // loop items Elm_Gen_Item + for (; l; l = eina_list_next(l)) + { + Eina_List *contents = NULL; + Elm_Gen_Item *it = list_data_get(l); + contents = _gengrid_item_contents_get(it); + if (contents) + { + const Eina_List *l2 = NULL; + Evas_Object *content = NULL; + + // loop contents (Evas_Object) of item + EINA_LIST_FOREACH(contents, l2, content) + { + // if better element than set new sd->focused and sd->selected + elm_widget_focus_direction_get(content, base, degree, direction, + weight); + } + eina_list_free(contents); + } + } + if (current_best != *direction) + return EINA_TRUE; + else + return EINA_FALSE; +} + +EAPI void +gen_focus_direction(Eo *obj, void *_pd, va_list *list) +{ + Eina_List *items = NULL; + const Evas_Object *parent = NULL; + + void *(*list_data_get)(const Eina_List * list); + Eina_List *(*list_free)(Eina_List * list); + + Elm_Gengrid_Smart_Data *sd = _pd; + + Evas_Object *base = va_arg(*list, Evas_Object *); + double degree = va_arg(*list, double); + Evas_Object **direction = va_arg(*list, Evas_Object **); + double *weight = va_arg(*list, double *); + Eina_Bool *ret = va_arg(*list, Eina_Bool *); + + if (!sd) + { + *ret = EINA_FALSE; + return; + } + + + *ret = EINA_FALSE; + list_data_get = NULL; + + Eina_Bool (*list_direction_get)( + const Evas_Object * obj, const Evas_Object * base, + const Eina_List * items, void * (*list_data_get)(const Eina_List * l), + double degree, Evas_Object * *direction, double * weight); + + list_direction_get = NULL; + list_free = NULL; + parent = _find_gengrid_parent_item(base); + + /// If focused is subobject of this gengrid then we selected next + /// in direction + if (obj == parent) + { + items = elm_gengrid_realized_items_get(obj); + list_data_get = NULL; + list_direction_get = _gengrid_self_focus_item_get; + list_free = eina_list_free; + } + + if (!items) + { + items = (Eina_List *)(elm_object_focus_custom_chain_get(obj)); + list_data_get = eina_list_data_get; + list_direction_get = elm_widget_focus_list_direction_get; + list_free = NULL; + } + + if (!items) + { + items = elm_gengrid_realized_items_get(obj); + list_data_get = eina_list_data_get; + list_direction_get = _gengrid_focus_list_direction_get; + list_free = eina_list_free; + } + + if (!items) + { + *ret = EINA_FALSE; + return; + } + + *ret = list_direction_get(obj, base, items, list_data_get, degree, direction, + weight); + + if (list_free) list_free(items); +} + +// module api funcs needed +EAPI int +elm_modapi_init(void *m) +{ + (void) m; + return 1; // succeed always +} + +EAPI int +elm_modapi_shutdown(void *m) +{ + (void) m; + return 1; // succeed always +} |