diff options
author | Larry Lira <larry@expertisesolutions.com.br> | 2018-10-31 09:39:57 -0300 |
---|---|---|
committer | Larry Lira <larry@expertisesolutions.com.br> | 2018-12-19 15:48:32 -0200 |
commit | b66b31f236b398a6b62b197a2d1e4aa4f82c00aa (patch) | |
tree | af40828fcdb2530d81dfe65eead8ffc4bb224903 | |
parent | 7a5fbd1db6db445047fea036403be664ce55a59e (diff) | |
download | efl-devs/larrylira/viewtree.tar.gz |
Efl.Ui.Tree_View: added new MVVM asynchronous widgetdevs/larrylira/viewtree
Summary:
new classes added:
Efl.Ui.Tree_View
Efl.Ui.Tree_View_Layouter
Efl.Ui.Tree_View_Segarray
Efl.Ui.Tree_Factory
added view_tree_example_1 in elementary example
Reviewers: felipealmeida
Subscribers: cedric, #reviewers, vitor.sousa, #committers
Tags: #efl
Differential Revision: https://phab.enlightenment.org/D7242
24 files changed, 3211 insertions, 13 deletions
diff --git a/data/elementary/themes/edc/efl/list.edc b/data/elementary/themes/edc/efl/list.edc index ca3c5b47ff..a551f1c7aa 100644 --- a/data/elementary/themes/edc/efl/list.edc +++ b/data/elementary/themes/edc/efl/list.edc @@ -6,6 +6,10 @@ group { "efl/list_view"; inherit: "efl/list"; } +group { "efl/tree_view"; + inherit: "efl/list"; +} + group { "efl/list_item"; data.item: "selectraise" "on"; data.item: "focusraise" "on"; diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index 0c75466680..ff5d6fbcf3 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -82,6 +82,14 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_list_view_pan.eo \ lib/elementary/efl_ui_list_view_seg_array.eo \ lib/elementary/efl_ui_list_view_relayout.eo \ + lib/elementary/efl_ui_tree_view.eo \ + lib/elementary/efl_ui_tree_view_model.eo \ + lib/elementary/efl_ui_tree_view_pan.eo \ + lib/elementary/efl_ui_tree_view_seg_array.eo \ + lib/elementary/efl_ui_tree_view_seg_array_depth_model.eo \ + lib/elementary/efl_ui_tree_view_relayout.eo \ + lib/elementary/efl_ui_tree_view_layouter.eo \ + lib/elementary/efl_ui_tree_factory.eo \ lib/elementary/efl_ui_item.eo \ lib/elementary/efl_ui_list_item.eo \ lib/elementary/efl_ui_list_default_item_part_icon.eo \ @@ -425,6 +433,7 @@ includesunstable_HEADERS = \ lib/elementary/efl_ui_grid_private.h \ lib/elementary/efl_ui_list_view_private.h \ lib/elementary/efl_ui_list_view_seg_array.h \ + lib/elementary/efl_ui_tree_view_private.h \ lib/elementary/elm_widget_web.h \ lib/elementary/efl_ui_clock.h \ lib/elementary/elm_code.h \ @@ -655,6 +664,7 @@ includesub_HEADERS = \ lib/elementary/efl_ui_video.h \ lib/elementary/efl_ui_video_eo.h \ lib/elementary/efl_ui_video_legacy.h \ + lib/elementary/efl_ui_tree_view_seg_array.h \ lib/elementary/elm_view_list.h \ lib/elementary/elm_view_form.h \ lib/elementary/elm_web.h \ @@ -858,6 +868,11 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/efl_ui_list_view.c \ lib/elementary/efl_ui_list_view_precise_layouter.c \ lib/elementary/efl_ui_list_view_seg_array.c \ + lib/elementary/efl_ui_tree_factory.c \ + lib/elementary/efl_ui_tree_view.c \ + lib/elementary/efl_ui_tree_view_layouter.c \ + lib/elementary/efl_ui_tree_view_seg_array.c \ + lib/elementary/efl_ui_tree_view_seg_array_depth_model.c \ lib/elementary/efl_ui_layout_factory.c \ lib/elementary/efl_ui_scroller.c \ lib/elementary/efl_ui_scroll_manager.c \ diff --git a/src/examples/elementary.mk b/src/examples/elementary.mk index 0d817258dc..a83795b4bc 100644 --- a/src/examples/elementary.mk +++ b/src/examples/elementary.mk @@ -125,7 +125,8 @@ elementary/efl_ui_list_view_example_2.c \ elementary/efl_ui_list_view_example_3.c \ elementary/efl_canvas_layout_text.c \ elementary/efl_ui_theme_example_01.c \ -elementary/efl_ui_theme_example_02.c +elementary/efl_ui_theme_example_02.c \ +elementary/view_tree_example_1.c ELM_SRCS += \ elementary/bg_cxx_example_01.cc \ @@ -344,7 +345,8 @@ elementary/efl_ui_list_view_example_2 \ elementary/efl_ui_list_view_example_3 \ elementary/efl_canvas_layout_text \ elementary/efl_ui_theme_example_01 \ -elementary/efl_ui_theme_example_02 +elementary/efl_ui_theme_example_02 \ +elementary/view_tree_example_1 #benchmark3d #sphere-hunter diff --git a/src/examples/elementary/.gitignore b/src/examples/elementary/.gitignore index 54d71c14a0..213241b859 100644 --- a/src/examples/elementary/.gitignore +++ b/src/examples/elementary/.gitignore @@ -63,6 +63,7 @@ /list_example_02 /list_example_03 /efl_ui_list_example_1 +/view_tree_example_1 /efl_ui_view_list_example_1 /efl_ui_view_list_example_2 /efl_ui_view_list_example_3 diff --git a/src/examples/elementary/efl_ui_list_view_example_1.c b/src/examples/elementary/efl_ui_list_view_example_1.c index dc300264aa..3decb4ae5c 100644 --- a/src/examples/elementary/efl_ui_list_view_example_1.c +++ b/src/examples/elementary/efl_ui_list_view_example_1.c @@ -22,7 +22,7 @@ const char *styles[] = { char edj_path[PATH_MAX]; static void -_realized_cb(void *data EINA_UNUSED, const Efl_Event *event) +_realized_cb(void *data, const Efl_Event *event) { Efl_Ui_List_View_Item_Event *ie = event->info; if (!ie->layout) return; @@ -69,7 +69,7 @@ _make_model(Evas_Object *win) } EAPI_MAIN int -elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +elm_main(int argc, char **argv) { Efl_Ui_Factory *factory; Evas_Object *win, *li; diff --git a/src/examples/elementary/efl_ui_list_view_example_2.c b/src/examples/elementary/efl_ui_list_view_example_2.c index ca56f37d33..c624cade19 100644 --- a/src/examples/elementary/efl_ui_list_view_example_2.c +++ b/src/examples/elementary/efl_ui_list_view_example_2.c @@ -15,7 +15,7 @@ #define EFL_MODEL_TEST_FILENAME_PATH "/tmp" EAPI_MAIN int -elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +elm_main(int argc, char **argv) { Efl_Ui_Layout_Factory *factory; Efl_Ui_Image_Factory *imgf; diff --git a/src/examples/elementary/efl_ui_list_view_example_3.c b/src/examples/elementary/efl_ui_list_view_example_3.c index eaf5dc975a..46d5ca5813 100644 --- a/src/examples/elementary/efl_ui_list_view_example_3.c +++ b/src/examples/elementary/efl_ui_list_view_example_3.c @@ -66,7 +66,7 @@ _focused(void *data, const Efl_Event *event) } static void -_bt_add_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_add_clicked(void *data, Evas_Object *obj, void *event_info) { Priv_Data *priv = (Priv_Data*)data; Eina_Value vtext, value; @@ -90,7 +90,7 @@ _bt_add_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_ } static void -_bt_del_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_del_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Priv_Data *priv = (Priv_Data*)data; Eo *child = NULL; @@ -110,35 +110,35 @@ _bt_del_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_ } static void -_bt_none_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_none_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *li = data; efl_ui_list_view_select_mode_set(li, ELM_OBJECT_SELECT_MODE_NONE); } static void -_bt_donly_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_donly_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *li = data; efl_ui_list_view_select_mode_set(li, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY); } static void -_bt_default_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_default_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *li = data; efl_ui_list_view_select_mode_set(li, ELM_OBJECT_SELECT_MODE_DEFAULT); } static void -_bt_set_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_set_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Priv_Data *priv = data; efl_ui_view_model_set(priv->list2, priv->model); } static void -_bt_unset_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +_bt_unset_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *li = data; efl_ui_view_model_set(li, NULL); @@ -201,7 +201,7 @@ _make_model() } EAPI_MAIN int -elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +elm_main(int argc, char **argv) { Priv_Data *priv; Evas_Object *win, *bx, *vbx, *bt; diff --git a/src/examples/elementary/view_tree_example_1.c b/src/examples/elementary/view_tree_example_1.c new file mode 100644 index 0000000000..fe39a6d81e --- /dev/null +++ b/src/examples/elementary/view_tree_example_1.c @@ -0,0 +1,129 @@ +// gcc -o tree_view_example_1 tree_view_example_1.c `pkg-config --cflags --libs elementary` + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EFL_BETA_API_SUPPORT 1 +# define EFL_EO_API_SUPPORT 1 +#endif + +#include <Elementary.h> +#include <Efl.h> +#include <Eio.h> +#include <stdio.h> +#include <time.h> + +#define NUM_ITEMS 20 + +static void +_realized_cb(void *data EINA_UNUSED, const Efl_Event *event) +{ + char *depth, *name; + Eina_Value *vd, *vn; + Efl_Ui_Tree_View_Item_Event *ie = event->info; + if (!ie->child) return; + + vd = efl_model_property_get(ie->child, "depth"); + vn = efl_model_property_get(ie->child, "name"); + depth = eina_value_to_string(vd); + name = eina_value_to_string(vn); + eina_value_free(vd); + eina_value_free(vn); + + printf("realize item=%s depth=%s\n", name, depth); + free(name); + free(depth); +} + +static Efl_Model* +_child_add(Efl_Model_Item *parent, Eina_Value *value, const char *msg) +{ + Efl_Model_Item *model; + + model = efl_model_child_add(parent); + if (model) + { + eina_value_set(value, msg); + efl_model_property_set(model, "name", value); + } + + return model; +} + +static void +_children_add(Efl_Model_Item *parent, Eina_Value *value, int n, const char *msg) +{ + char msgbuf[256]; + char buff[256]; + int i; + + if (!parent) return; + snprintf(msgbuf, sizeof(msgbuf), " %s - %%i", msg); + + for (i = 0; i < n; ++i) + { + snprintf(buff, sizeof(buff), msgbuf, i); + _children_add(_child_add(parent, value, buff), value, i, buff); + } +} + +static Efl_Model* +_make_model(Evas_Object *win) +{ + Efl_Model_Item *root, *child; + Eina_Value vtext; + unsigned int i; + + srand(time(NULL)); + eina_value_setup(&vtext, EINA_VALUE_TYPE_STRING); + root = efl_add(EFL_MODEL_ITEM_CLASS, win); + char buf[256]; + + for (i = 0; i < (NUM_ITEMS); ++i) + { + snprintf(buf, sizeof(buf), "Item # %i", i); + child = _child_add(root, &vtext, buf); + snprintf(buf, sizeof(buf), "|-> Item # %i", i); + _children_add(child, &vtext, 5, buf); + } + + eina_value_flush(&vtext); + return root; +} + +EAPI_MAIN int +elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + Efl_Ui_Layout_Factory *factory; + Evas_Object *win; + Eo *model, *tree; + + win = elm_win_util_standard_add("viewtree", "ViewTree"); + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + elm_win_autodel_set(win, EINA_TRUE); + + model = _make_model(win); + factory = efl_add(EFL_UI_TREE_FACTORY_CLASS, win, + efl_ui_layout_factory_theme_config(efl_added, "list_item", NULL, "default")); + efl_ui_model_connect(factory, "efl.text", "name"); + + tree = efl_add(EFL_UI_TREE_VIEW_CLASS, win); + efl_ui_tree_view_layout_factory_set(tree, factory); + efl_ui_view_model_set(tree, model); + + evas_object_size_hint_weight_set(tree, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(tree, EVAS_HINT_FILL, EVAS_HINT_FILL); + efl_event_callback_add(tree, EFL_UI_TREE_VIEW_EVENT_ITEM_REALIZED, _realized_cb, NULL); + + elm_win_resize_object_add(win, tree); + + //showall + evas_object_show(tree); + evas_object_resize(win, 320, 320); + evas_object_show(win); + + elm_run(); + return 0; +} +ELM_MAIN() diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 9bd33c4feb..a6e5f50ce3 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -327,6 +327,7 @@ typedef Eo Efl_Ui_Focus_Manager; # include <efl_ui_slider.eo.h> # include <efl_ui_slider_interval.eo.h> # include <efl_ui_layout_factory.eo.h> +# include <efl_ui_tree_factory.eo.h> # include <efl_ui_item.eo.h> # include <efl_ui_list_item.eo.h> # include <efl_ui_list_default_item_part_icon.eo.h> @@ -346,6 +347,14 @@ typedef Eo Efl_Ui_Focus_Manager; # include <efl_ui_list_view_relayout.eo.h> # include <efl_ui_list_view.eo.h> # include <efl_ui_list_view_pan.eo.h> +# include <efl_ui_tree_view_seg_array.h> +# include <efl_ui_tree_view_seg_array.eo.h> +# include <efl_ui_tree_view_seg_array_depth_model.eo.h> +# include <efl_ui_tree_view_model.eo.h> +# include <efl_ui_tree_view_relayout.eo.h> +# include <efl_ui_tree_view_layouter.eo.h> +# include <efl_ui_tree_view.eo.h> +# include <efl_ui_tree_view_pan.eo.h> # include <efl_ui_pan.eo.h> # include <efl_ui_scroll_manager.eo.h> # include <efl_ui_scroller.eo.h> diff --git a/src/lib/elementary/efl_ui_tree_factory.c b/src/lib/elementary/efl_ui_tree_factory.c new file mode 100644 index 0000000000..3ab9cb78c8 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_factory.c @@ -0,0 +1,169 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Elementary.h> +#include "elm_priv.h" + +#define MY_CLASS EFL_UI_TREE_FACTORY_CLASS +#define MY_CLASS_NAME "Efl.Ui.Tree_Factory" + +typedef struct _Efl_Ui_Tree_Factory_Data +{ + Eina_Hash *connects; + Eina_Hash *factory_connects; + Eina_Stringshare *klass; + Eina_Stringshare *group; + Eina_Stringshare *def_style; + Eina_Stringshare *exp_style; +} Efl_Ui_Tree_Factory_Data; + +static Eina_Bool +_model_connect(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata) +{ + Eo *layout = fdata; + Eina_Stringshare *name = key; + Eina_Stringshare *property = data; + + efl_ui_model_connect(layout, name, property); + return EINA_TRUE; +} + +static Eina_Bool +_factory_model_connect(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata) +{ + Eo *layout = fdata; + Eina_Stringshare *name = key; + Efl_Ui_Factory *factory = data; + + efl_ui_factory_model_connect(layout, name, factory); + return EINA_TRUE; +} + +EOLIAN static Eo * +_efl_ui_tree_factory_efl_object_constructor(Eo *obj, Efl_Ui_Tree_Factory_Data *pd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + pd->connects = eina_hash_stringshared_new(EINA_FREE_CB(eina_stringshare_del)); + pd->factory_connects = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); + + return obj; +} + +EOLIAN static void +_efl_ui_tree_factory_efl_object_destructor(Eo *obj, Efl_Ui_Tree_Factory_Data *pd) +{ + eina_stringshare_del(pd->klass); + eina_stringshare_del(pd->group); + eina_stringshare_del(pd->def_style); + eina_stringshare_del(pd->exp_style); + + eina_hash_free(pd->connects); + eina_hash_free(pd->factory_connects); + + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eina_Future * +_efl_ui_tree_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Tree_Factory_Data *pd + , Efl_Model *model, Efl_Gfx_Entity *parent) +{ + Eina_Value r; + Efl_Gfx_Entity *layout; + Efl_Ui_Tree_Factory_Item_Event evt; + EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); + + Eina_Stringshare *style = pd->def_style; + evt.model = model; + evt.expandable = EINA_FALSE; + efl_event_callback_call(obj, EFL_UI_TREE_FACTORY_EVENT_ITEM_CREATE, &evt); + + if (pd->exp_style && (evt.expandable || efl_model_children_count_get(model))) + style = pd->exp_style; + + layout = efl_add(EFL_UI_LAYOUT_CLASS, parent, + efl_ui_view_model_set(efl_added, model), + efl_ui_layout_theme_set(efl_added, pd->klass, pd->group, style)); + + eina_hash_foreach(pd->connects, _model_connect, layout); + eina_hash_foreach(pd->factory_connects, _factory_model_connect, layout); + + evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, 0); + evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + + r = eina_value_object_init(layout); + + return eina_future_resolved(efl_loop_future_scheduler_get(obj), r); +} + +EOLIAN static void +_efl_ui_tree_factory_efl_ui_factory_release(Eo *obj EINA_UNUSED, Efl_Ui_Tree_Factory_Data *pd EINA_UNUSED, Efl_Gfx_Entity *layout) +{ + efl_ui_view_model_set(layout, NULL); + efl_del(layout); +} + +EOLIAN static void +_efl_ui_tree_factory_efl_ui_factory_model_connect(Eo *obj EINA_UNUSED, Efl_Ui_Tree_Factory_Data *pd + , const char *name, Efl_Ui_Factory *factory) +{ + Eina_Stringshare *ss_name; + Efl_Ui_Factory *f_old; + ss_name = eina_stringshare_add(name); + + if (factory == NULL) + { + eina_hash_del(pd->factory_connects, ss_name, NULL); + eina_stringshare_del(ss_name); + return; + } + + f_old = eina_hash_set(pd->factory_connects, ss_name, efl_ref(factory)); + if (f_old) + { + efl_unref(f_old); + eina_stringshare_del(ss_name); + } +} + +EOLIAN static void +_efl_ui_tree_factory_efl_ui_model_connect_connect(Eo *obj EINA_UNUSED, Efl_Ui_Tree_Factory_Data *pd + , const char *name, const char *property) +{ + Eina_Stringshare *ss_name, *ss_prop, *ss_old; + ss_name = eina_stringshare_add(name); + + if (property == NULL) + { + eina_hash_del(pd->connects, ss_name, NULL); + eina_stringshare_del(ss_name); + return; + } + + ss_prop = eina_stringshare_add(property); + ss_old = eina_hash_set(pd->connects, ss_name, ss_prop); + if (ss_old) + { + eina_stringshare_del(ss_old); + eina_stringshare_del(ss_name); + } +} + + +EOLIAN static void +_efl_ui_tree_factory_efl_ui_layout_factory_theme_config(Eo *obj EINA_UNUSED, Efl_Ui_Tree_Factory_Data *pd + , const char *klass, const char *group, const char *style) +{ + eina_stringshare_replace(&pd->klass, klass); + eina_stringshare_replace(&pd->group, group); + eina_stringshare_replace(&pd->def_style, style); +} + +EOLIAN static void +_efl_ui_tree_factory_expandable_style_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_Factory_Data *pd, const char *style) +{ + eina_stringshare_replace(&pd->exp_style, style); +} + +#include "efl_ui_tree_factory.eo.c" diff --git a/src/lib/elementary/efl_ui_tree_factory.eo b/src/lib/elementary/efl_ui_tree_factory.eo new file mode 100644 index 0000000000..9bb9a38fb8 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_factory.eo @@ -0,0 +1,33 @@ +import elm_general; + +struct Efl.Ui.Tree_Factory_Item_Event +{ + model: Efl.Model; + expandable: bool; +} + +class Efl.Ui.Tree_Factory (Efl.Ui.Layout_Factory) +{ + [[Efl Ui Tree Factory class]] + methods { + @property expandable_style { + [[Style used to expandable itens]] + set {} + values { + style: string; [[The style to use.]] + } + } + } + events { + item,create : Efl.Ui.Tree_Factory_Item_Event; + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + Efl.Ui.Factory.create; + Efl.Ui.Factory.release; + Efl.Ui.Factory.model_connect; + Efl.Ui.Model.Connect.connect; + Efl.Ui.Layout_Factory.theme_config; + } +} diff --git a/src/lib/elementary/efl_ui_tree_view.c b/src/lib/elementary/efl_ui_tree_view.c new file mode 100644 index 0000000000..ea66461cb4 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view.c @@ -0,0 +1,1159 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#define EFL_ACCESS_OBJECT_PROTECTED +#define EFL_ACCESS_SELECTION_PROTECTED +#define EFL_UI_SCROLL_MANAGER_PROTECTED +#define EFL_UI_SCROLLBAR_PROTECTED +#define EFL_UI_SCROLLBAR_BETA +#define EFL_UI_FOCUS_COMPOSITION_PROTECTED +#define EFL_UI_WIDGET_FOCUS_MANAGER_PROTECTED + +#include <Elementary.h> +#include "elm_priv.h" +#include "efl_ui_tree_view_private.h" + +#define MY_CLASS EFL_UI_TREE_VIEW_CLASS +#define MY_CLASS_NAME "Efl.Ui.Tree_View" + +#define MY_PAN_CLASS EFL_UI_TREE_VIEW_PAN_CLASS + +#define SELECTED_PROP "selected" + +static Eina_Bool _key_action_move(Evas_Object *obj, const char *params); +static Eina_Bool _key_action_select(Evas_Object *obj, const char *params); +static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params); + +static const Elm_Action key_actions[] = { + {"move", _key_action_move}, + {"select", _key_action_select}, + {"escape", _key_action_escape}, + {NULL, NULL} +}; + +typedef struct _Tree_View_Slice_Callback_Data +{ + Efl_Ui_Tree_View_Data *private; + Efl_Ui_Tree_View_Item *parent_item; + Eina_Future *future; + int first; +} Tree_View_Slice_Callback_Data; + +static Eina_Bool +_key_action_move(Evas_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_key_action_select(Evas_Object *obj, const char *params EINA_UNUSED) +{ + Efl_Ui_Focus_Object *focused = efl_ui_focus_manager_focus_get(obj); + + if (!focused) return EINA_FALSE; + +//TODO expanded actions + return EINA_FALSE; +} + +static Eina_Bool +_key_action_escape(Evas_Object *obj, const char *params EINA_UNUSED) +{ + efl_ui_focus_manager_reset_history(obj); + return EINA_TRUE; +} + +void _efl_ui_tree_view_item_select_set(Efl_Ui_Tree_View_Item*, Eina_Bool); +static void _layout(Efl_Ui_Tree_View_Data* pd); + +EOLIAN static void +_efl_ui_tree_view_pan_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd) +{ + evas_object_smart_changed(psd->wobj); +} + +EOLIAN static void +_efl_ui_tree_view_pan_efl_ui_pan_pan_position_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd, Eina_Position2D pos) +{ + if ((pos.x == psd->gmt.x) && (pos.y == psd->gmt.y)) return; + + psd->gmt.x = pos.x; + psd->gmt.y = pos.y; + + efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL); + evas_object_smart_changed(psd->wobj); +} + +EOLIAN static Eina_Position2D +_efl_ui_tree_view_pan_efl_ui_pan_pan_position_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd) +{ + return psd->gmt.pos; +} + +EOLIAN static Eina_Position2D +_efl_ui_tree_view_pan_efl_ui_pan_pan_position_max_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd) +{ + EFL_UI_TREE_VIEW_DATA_GET(psd->wobj, pd); + Eina_Rect vgmt = {}; + Eina_Size2D min = {}; + + vgmt = efl_ui_scrollable_viewport_geometry_get(pd->scrl_mgr); + min = efl_ui_tree_view_model_min_size_get(psd->wobj); + + min.w = min.w - vgmt.w; + if (min.w < 0) min.w = 0; + min.h = min.h - vgmt.h; + if (min.h < 0) min.h = 0; + + return EINA_POSITION2D(min.w, min.h); +} + +EOLIAN static Eina_Position2D +_efl_ui_tree_view_pan_efl_ui_pan_pan_position_min_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd EINA_UNUSED) +{ + return EINA_POSITION2D(0, 0); +} + +EOLIAN static Eina_Size2D +_efl_ui_tree_view_pan_efl_ui_pan_content_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Pan_Data *psd) +{ + return efl_ui_tree_view_model_min_size_get(psd->wobj); +} + +EOLIAN static void +_efl_ui_tree_view_pan_efl_object_destructor(Eo *obj, Efl_Ui_Tree_View_Pan_Data *psd EINA_UNUSED) +{ + efl_destructor(efl_super(obj, MY_PAN_CLASS)); +} + +#include "efl_ui_tree_view_pan.eo.c" + +EOLIAN static void +_efl_ui_tree_view_efl_ui_scrollable_interactive_content_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *psd, Eina_Position2D pos) +{ + efl_ui_scrollable_content_pos_set(psd->scrl_mgr, pos); +} + +EOLIAN static Eina_Position2D +_efl_ui_tree_view_efl_ui_scrollable_interactive_content_pos_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *psd) +{ + return efl_ui_scrollable_content_pos_get(psd->scrl_mgr); +} + +EOLIAN static Eina_Size2D +_efl_ui_tree_view_efl_ui_scrollable_interactive_content_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *psd) +{ + return efl_ui_scrollable_content_size_get(psd->scrl_mgr); +} + +EOLIAN static Eina_Rect +_efl_ui_tree_view_efl_ui_scrollable_interactive_viewport_geometry_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *psd) +{ + return efl_ui_scrollable_viewport_geometry_get(psd->scrl_mgr); +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_scrollable_interactive_scroll(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *psd, Eina_Rect rect, Eina_Bool animation) +{ + efl_ui_scrollable_scroll(psd->scrl_mgr, rect, animation); +} + +static Eina_Bool +_efl_model_properties_has(Efl_Model *model, Eina_Stringshare *propfind) +{ + Eina_Iterator *properties; + const char *property; + Eina_Bool ret = EINA_FALSE; + + EINA_SAFETY_ON_NULL_RETURN_VAL(model, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(propfind, EINA_FALSE); + + properties = efl_model_properties_get(model); + + EINA_ITERATOR_FOREACH(properties, property) + { + if (property == propfind || + !strcmp(property, propfind)) + { + ret = EINA_TRUE; + break; + } + } + eina_iterator_free(properties); + + return ret; +} + +static void +_list_element_focused(void *data EINA_UNUSED, const Efl_Event *ev) +{ + Eina_Rect geom; + Eina_Position2D pos; + Efl_Ui_Focus_Object *focused = efl_ui_focus_manager_focus_get(ev->object); + + if (!focused) return; + + EFL_UI_TREE_VIEW_DATA_GET(ev->object, pd); + geom = efl_ui_focus_object_focus_geometry_get(focused); + pos = efl_ui_scrollable_content_pos_get(pd->scrl_mgr); + + geom.x += pos.x; + geom.y += pos.y; + efl_ui_scrollable_scroll(ev->object, geom, EINA_TRUE); +} + +static void +_on_item_mouse_up(void *data, Evas *evas EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info) +{ + Evas_Event_Mouse_Down *ev = event_info; + Efl_Ui_Tree_View_Item *item = data; + + if (ev->button != 1) return; + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; + + _efl_ui_tree_view_item_select_set(item, EINA_TRUE); +} + +EOLIAN static void +_efl_ui_tree_view_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Tree_View_Data *pd, Eina_Position2D pos) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y)) + return; + + efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos); + evas_object_smart_changed(pd->obj); +} + +EOLIAN static void +_efl_ui_tree_view_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Tree_View_Data *pd, Eina_Size2D size) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, size.w, size.h)) + return; + + efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), size); + + evas_object_smart_changed(pd->obj); +} + +EOLIAN static void +_efl_ui_tree_view_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + _layout(pd); +} + +EOLIAN static void +_efl_ui_tree_view_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Tree_View_Data *pd EINA_UNUSED, Evas_Object *member) +{ + efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member); +} + +//Scrollable Implement +static void +_efl_ui_tree_view_bar_read_and_update(Eo *obj) +{ + EFL_UI_TREE_VIEW_DATA_GET(obj, pd); + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + double vx, vy; + + edje_object_part_drag_value_get + (wd->resize_obj, "efl.dragable.vbar", NULL, &vy); + edje_object_part_drag_value_get + (wd->resize_obj, "efl.dragable.hbar", &vx, NULL); + + efl_ui_scrollbar_bar_position_set(pd->scrl_mgr, vx, vy); + + efl_canvas_group_change(pd->pan_obj); +} + +static void +_efl_ui_tree_view_reload_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + EFL_UI_TREE_VIEW_DATA_GET(data, pd); + + efl_ui_scrollbar_bar_visibility_update(pd->scrl_mgr); +} + +static void +_efl_ui_tree_view_vbar_drag_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + _efl_ui_tree_view_bar_read_and_update(data); + + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type); +} + +static void +_efl_ui_tree_view_vbar_press_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type); +} + +static void +_efl_ui_tree_view_vbar_unpress_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type); +} + +static void +_efl_ui_tree_view_edje_drag_start_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + EFL_UI_TREE_VIEW_DATA_GET(data, pd); + + _efl_ui_tree_view_bar_read_and_update(data); + + pd->scrl_freeze = efl_ui_scrollable_scroll_freeze_get(pd->scrl_mgr); + efl_ui_scrollable_scroll_freeze_set(pd->scrl_mgr, EINA_TRUE); + efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_START, NULL); +} + +static void +_efl_ui_tree_view_edje_drag_stop_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + EFL_UI_TREE_VIEW_DATA_GET(data, pd); + + _efl_ui_tree_view_bar_read_and_update(data); + + efl_ui_scrollable_scroll_freeze_set(pd->scrl_mgr, pd->scrl_freeze); + efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL); +} + +static void +_efl_ui_tree_view_edje_drag_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + _efl_ui_tree_view_bar_read_and_update(data); +} + +static void +_efl_ui_tree_view_hbar_drag_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + _efl_ui_tree_view_bar_read_and_update(data); + + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type); +} + +static void +_efl_ui_tree_view_hbar_press_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type); +} + +static void +_efl_ui_tree_view_hbar_unpress_cb(void *data, + Evas_Object *obj EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL; + efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type); +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_scrollbar_bar_mode_set(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd, + Efl_Ui_Scrollbar_Mode hmode, + Efl_Ui_Scrollbar_Mode vmode) +{ + efl_ui_scrollbar_bar_mode_set(pd->scrl_mgr, hmode, vmode); +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_scrollbar_bar_mode_get(Eo const *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd, + Efl_Ui_Scrollbar_Mode *hmode, + Efl_Ui_Scrollbar_Mode *vmode) +{ + efl_ui_scrollbar_bar_mode_get(pd->scrl_mgr, hmode, vmode); +} + +static void +_efl_ui_tree_view_bar_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + Eo *obj = data; + EFL_UI_TREE_VIEW_DATA_GET(obj, pd); + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + double width = 0.0, height = 0.0; + + efl_ui_scrollbar_bar_size_get(pd->scrl_mgr, &width, &height); + + edje_object_part_drag_size_set(wd->resize_obj, "efl.dragable.hbar", width, 1.0); + edje_object_part_drag_size_set(wd->resize_obj, "efl.dragable.vbar", 1.0, height); +} + +static void +_efl_ui_tree_view_bar_pos_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + Eo *obj = data; + EFL_UI_TREE_VIEW_DATA_GET(obj, pd); + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + double posx = 0.0, posy = 0.0; + + efl_ui_scrollbar_bar_position_get(pd->scrl_mgr, &posx, &posy); + + edje_object_part_drag_value_set(wd->resize_obj, "efl.dragable.hbar", posx, 0.0); + edje_object_part_drag_value_set(wd->resize_obj, "efl.dragable.vbar", 0.0, posy); +} + +static void +_efl_ui_tree_view_bar_show_cb(void *data, const Efl_Event *event) +{ + Eo *obj = data; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info); + + if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL) + edje_object_signal_emit(wd->resize_obj, "efl,action,show,hbar", "efl"); + else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL) + edje_object_signal_emit(wd->resize_obj, "efl,action,show,vbar", "efl"); +} + +static void +_efl_ui_tree_view_bar_hide_cb(void *data, const Efl_Event *event) +{ + Eo *obj = data; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info); + + if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL) + edje_object_signal_emit(wd->resize_obj, "efl,action,hide,hbar", "efl"); + else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL) + edje_object_signal_emit(wd->resize_obj, "efl,action,hide,vbar", "efl"); +} + +EOLIAN static Eina_Bool +_efl_ui_tree_view_efl_layout_signal_signal_callback_add(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *sd EINA_UNUSED, + const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); + return efl_layout_signal_callback_add(wd->resize_obj, emission, source, func_cb, data); +} + +EOLIAN static Eina_Bool +_efl_ui_tree_view_efl_layout_signal_signal_callback_del(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *sd EINA_UNUSED, + const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); + return efl_layout_signal_callback_del(wd->resize_obj, emission, source, func_cb, data); +} + +static void +_efl_ui_tree_view_edje_object_attach(Eo *obj) +{ + efl_layout_signal_callback_add + (obj, "reload", "efl", + _efl_ui_tree_view_reload_cb, obj); + //Vertical bar + efl_layout_signal_callback_add + (obj, "drag", "efl.dragable.vbar", + _efl_ui_tree_view_vbar_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,set", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,start", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_start_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,stop", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_stop_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,step", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,page", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "efl,vbar,press", "efl", + _efl_ui_tree_view_vbar_press_cb, obj); + efl_layout_signal_callback_add + (obj, "efl,vbar,unpress", "efl", + _efl_ui_tree_view_vbar_unpress_cb, obj); + + //Horizontal bar + efl_layout_signal_callback_add + (obj, "drag", "efl.dragable.hbar", + _efl_ui_tree_view_hbar_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,set", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,start", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_start_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,stop", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_stop_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,step", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "drag,page", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_add + (obj, "efl,hbar,press", "efl", + _efl_ui_tree_view_hbar_press_cb, obj); + efl_layout_signal_callback_add + (obj, "efl,hbar,unpress", "efl", + _efl_ui_tree_view_hbar_unpress_cb, obj); +} + +static void +_efl_ui_tree_view_edje_object_detach(Evas_Object *obj) +{ + efl_layout_signal_callback_del + (obj, "reload", "efl", _efl_ui_tree_view_reload_cb, obj); + //Vertical bar + efl_layout_signal_callback_del + (obj, "drag", "efl.dragable.vbar", + _efl_ui_tree_view_vbar_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,set", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,start", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_start_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,stop", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_stop_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,step", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,page", "efl.dragable.vbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "efl,vbar,press", "efl", + _efl_ui_tree_view_vbar_press_cb, obj); + efl_layout_signal_callback_del + (obj, "efl,vbar,unpress", "efl", + _efl_ui_tree_view_vbar_unpress_cb, obj); + + //Horizontal bar + efl_layout_signal_callback_del + (obj, "drag", "efl.dragable.hbar", + _efl_ui_tree_view_hbar_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,set", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,start", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_start_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,stop", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_stop_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,step", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "drag,page", "efl.dragable.hbar", + _efl_ui_tree_view_edje_drag_cb, obj); + efl_layout_signal_callback_del + (obj, "efl,hbar,press", "efl", + _efl_ui_tree_view_hbar_press_cb, obj); + efl_layout_signal_callback_del + (obj, "efl,hbar,unpress", "efl", + _efl_ui_tree_view_hbar_unpress_cb, obj); +} + +EOLIAN static void +_efl_ui_tree_view_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + Efl_Ui_Tree_View_Pan_Data *pan_data; + Eina_Size2D min = {}; + Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable; + Evas_Object *o; + + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + efl_canvas_group_add(efl_super(obj, MY_CLASS)); + elm_widget_sub_object_parent_add(obj); + + elm_widget_can_focus_set(obj, EINA_TRUE); + + if (!elm_layout_theme_set(obj, "tree_view", "base", elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + + pd->pan_obj = efl_add(MY_PAN_CLASS, obj); + pd->scrl_mgr = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj, + efl_ui_mirrored_set(efl_added, efl_ui_mirrored_get(obj)), + efl_ui_scroll_manager_pan_set(efl_added, pd->pan_obj)); + pan_data = efl_data_scope_get(pd->pan_obj, MY_PAN_CLASS); + pan_data->wobj = obj; + + efl_ui_scrollable_bounce_enabled_set(pd->scrl_mgr, bounce, bounce); + + edje_object_part_swallow(wd->resize_obj, "efl.content", pd->pan_obj); + edje_object_freeze(wd->resize_obj); + o = (Evas_Object *)edje_object_part_object_get(wd->resize_obj, "efl.dragable.vbar"); + edje_object_thaw(wd->resize_obj); + efl_gfx_stack_raise((Eo *)o); + + efl_gfx_entity_visible_set(pd->pan_obj, EINA_TRUE); + + efl_access_object_access_type_set(obj, EFL_ACCESS_TYPE_DISABLED); + + edje_object_size_min_calc(wd->resize_obj, &min.w, &min.h); + efl_gfx_size_hint_restricted_min_set(obj, min); + + efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED, + _efl_ui_tree_view_bar_size_changed_cb, obj); + efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED, + _efl_ui_tree_view_bar_pos_changed_cb, obj); + efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW, + _efl_ui_tree_view_bar_show_cb, obj); + efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE, + _efl_ui_tree_view_bar_hide_cb, obj); + + _efl_ui_tree_view_edje_object_attach(obj); + + elm_layout_sizing_eval(obj); +} + +EOLIAN static void +_efl_ui_tree_view_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + efl_ui_tree_view_relayout_model_set(pd->layouter, NULL); + ELM_SAFE_FREE(pd->pan_obj, efl_del); + efl_canvas_group_del(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Efl_Ui_Focus_Manager* +_efl_ui_tree_view_efl_ui_widget_focus_manager_focus_manager_create(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root) +{ + if (!pd->manager) + pd->manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj, + efl_ui_focus_manager_root_set(efl_added, root)); + + return pd->manager; +} + +EOLIAN static Eo * +_efl_ui_tree_view_efl_object_finalize(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + + if (!pd->factory) + { + pd->factory = efl_new(EFL_UI_LAYOUT_FACTORY_CLASS); + efl_ui_layout_factory_theme_config(pd->factory, "list_item", NULL, "default"); + } + + if(!pd->layouter) + { + pd->layouter = efl_new(EFL_UI_TREE_VIEW_LAYOUTER_CLASS); + if (pd->model) + efl_ui_tree_view_relayout_model_set(pd->layouter, pd->model); + } + return obj; +} + +EOLIAN static Eo * +_efl_ui_tree_view_efl_object_constructor(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + pd->obj = obj; + efl_canvas_object_type_set(obj, MY_CLASS_NAME); + efl_access_object_role_set(obj, EFL_ACCESS_ROLE_LIST); + + pd->segarray = efl_new(EFL_UI_TREE_VIEW_SEG_ARRAY_CLASS, + efl_ui_tree_view_seg_array_setup(efl_added, 32)); + + efl_ui_focus_composition_custom_manager_set(obj, obj); + efl_ui_focus_composition_logical_mode_set(obj, EINA_TRUE); + + efl_event_callback_add(obj, EFL_UI_FOCUS_MANAGER_EVENT_FOCUS_CHANGED, + _list_element_focused, NULL); + return obj; +} + +EOLIAN static void +_efl_ui_tree_view_efl_object_destructor(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + efl_event_callback_del(obj, EFL_UI_FOCUS_MANAGER_EVENT_FOCUS_CHANGED, + _list_element_focused, NULL); + + _efl_ui_tree_view_edje_object_detach(obj); + efl_ui_tree_view_seg_array_flush(pd->segarray); + + efl_replace(&pd->model, NULL); + efl_replace(&pd->layouter, NULL); + efl_replace(&pd->factory, NULL); + efl_replace(&pd->segarray, NULL); + + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_tree_view_layout_factory_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd, Efl_Ui_Factory *factory) +{ + if (pd->factory == factory) + return; + + efl_replace(&pd->factory, factory); +} + +EOLIAN static Efl_Ui_Factory * +_efl_ui_tree_view_layout_factory_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return pd->factory; +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_view_model_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd, Efl_Model *model) +{ + if (pd->model == model) + return; + + if (pd->model) + { + if (pd->layouter) + efl_ui_tree_view_relayout_model_set(pd->layouter, NULL); + efl_ui_tree_view_seg_array_flush(pd->segarray); + } + + efl_replace(&pd->model, model); + + if (pd->model && pd->layouter) + efl_ui_tree_view_relayout_model_set(pd->layouter, pd->model); + + evas_object_smart_changed(pd->obj); +} + +EOLIAN static Efl_Model * +_efl_ui_tree_view_efl_ui_view_model_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return pd->model; +} + +EOLIAN int +_efl_ui_tree_view_efl_access_selection_selected_children_count_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return eina_list_count(pd->selected_items); +} + +EOLIAN Eo* +_efl_ui_tree_view_efl_access_selection_selected_child_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd, int child_index) +{ + if(child_index < (int) eina_list_count(pd->selected_items)) + { + Efl_Ui_Tree_View_Item* items = eina_list_nth(pd->selected_items, child_index); + return items[child_index].layout; + } + else + return NULL; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_child_select(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd EINA_UNUSED, int child_index EINA_UNUSED) +{ + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_selected_child_deselect(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd EINA_UNUSED, int child_index EINA_UNUSED) +{ + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_is_child_selected(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd EINA_UNUSED, int child_index EINA_UNUSED) +{ + return EINA_FALSE; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_all_children_select(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd EINA_UNUSED) +{ + return EINA_TRUE; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_access_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd EINA_UNUSED) +{ + return EINA_TRUE; +} + +EOLIAN Eina_Bool +_efl_ui_tree_view_efl_access_selection_child_deselect(Eo *obj EINA_UNUSED, + Efl_Ui_Tree_View_Data *pd EINA_UNUSED, int child_index EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Value +_expand_children_slice_then(void * data, Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +{ + Efl_Ui_Tree_View_Data *pd; + Efl_Model *children; + Tree_View_Slice_Callback_Data *slice = data; + unsigned int i, len; + + if (!slice || eina_value_type_get(&v) == EINA_VALUE_TYPE_ERROR) + goto on_error; + + pd = slice->private; + if (eina_value_type_get(&v) == EINA_VALUE_TYPE_OBJECT) + { + children = eina_value_object_get(&v); + efl_ui_tree_view_seg_array_insert(pd->segarray, slice->parent_item, 0, children); + } + else if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ARRAY) + { + EINA_VALUE_ARRAY_FOREACH(&v, len, i, children) + { + unsigned int idx = 0 + i; + efl_ui_tree_view_seg_array_insert(pd->segarray, slice->parent_item, idx, children); + } + } + else + { + ERR ("_expand_children_slice_then"); + } + slice->future = NULL; + + efl_ui_tree_view_relayout_layout_do(pd->layouter, pd->obj, pd->segarray_first, pd->segarray); + on_error: + free(slice); + return v; +} + +void +_efl_ui_tree_view_item_select_set(Efl_Ui_Tree_View_Item *item, Eina_Bool selected) +{ + Eina_Stringshare *sprop; + assert(item != NULL); + assert(item->model != NULL); + + selected = !!selected; + + sprop = eina_stringshare_add(SELECTED_PROP); + + if (_efl_model_properties_has(item->model, sprop)) + { + Eina_Value v; + eina_value_setup(&v, EINA_VALUE_TYPE_UCHAR); + eina_value_set(&v, selected); + efl_model_property_set(item->model, sprop, &v); + eina_value_flush(&v); + } + eina_stringshare_del(sprop); +} + +EOLIAN static void +_efl_ui_tree_view_relayout_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd, Efl_Ui_Tree_View_Relayout *layouter) +{ + if (pd->layouter == layouter) + return; + + efl_replace(&pd->layouter, layouter); + + if (pd->model && pd->layouter) + efl_ui_tree_view_relayout_model_set(pd->layouter, pd->model); +} + +EOLIAN static Efl_Ui_Tree_View_Relayout * +_efl_ui_tree_view_relayout_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return pd->layouter; +} + +EOLIAN static void +_efl_ui_tree_view_show_root_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd, Eina_Bool showroot) +{ + pd->show_root = showroot; +} + +EOLIAN static Eina_Bool +_efl_ui_tree_view_show_root_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return pd->show_root; +} + +static void +_layout(Efl_Ui_Tree_View_Data *pd) +{ + if (!pd->model) + return; + + efl_ui_tree_view_relayout_layout_do(pd->layouter, pd->obj, pd->segarray_first, pd->segarray); +} + +static Eina_Value +_children_slice_then(void * data, Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +{ + Efl_Ui_Tree_View_Data *pd = data; + Efl_Model *children; + unsigned int i, len; + + if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ERROR) + goto on_error; + + if (eina_value_type_get(&v) == EINA_VALUE_TYPE_OBJECT) + { + children = eina_value_object_get(&v); + efl_ui_tree_view_seg_array_insert(pd->segarray, NULL, pd->slice.start, children); + } + else if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ARRAY) + { + EINA_VALUE_ARRAY_FOREACH(&v, len, i, children) + { + unsigned int idx = pd->slice.start + i; + + efl_ui_tree_view_seg_array_insert(pd->segarray, NULL, idx, children); + } + } + + pd->segarray_first = pd->slice.start; + pd->slice.start = pd->slice.count = 0; + pd->slice.future = NULL; + + efl_ui_tree_view_relayout_layout_do(pd->layouter, pd->obj, pd->segarray_first, pd->segarray); + on_error: + return v; +} + +/* EFL UI TREE MODEL INTERFACE */ +EOLIAN static Eina_Size2D +_efl_ui_tree_view_efl_ui_tree_view_model_min_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return pd->min; +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_tree_view_model_min_size_set(Eo *obj, Efl_Ui_Tree_View_Data *pd, Eina_Size2D min) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + pd->min.w = min.w; + pd->min.h = min.h; + + evas_object_size_hint_min_set(wd->resize_obj, pd->min.w, pd->min.h); + efl_event_callback_call(pd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL); +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_focus_composition_prepare(Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + Eina_List *order = efl_ui_tree_view_relayout_elements_get(pd->layouter); + efl_ui_focus_composition_elements_set(obj, order); +} + +EOLIAN Eina_List* +_efl_ui_tree_view_efl_access_object_access_children_get(const Eo *obj, Efl_Ui_Tree_View_Data *pd) +{ + Eina_List *ret = NULL, *ret2 = NULL; + + ret = efl_ui_tree_view_relayout_elements_get(pd->layouter); + ret2 = efl_access_object_access_children_get(efl_super(obj, EFL_UI_TREE_VIEW_CLASS)); + + return eina_list_merge(ret, ret2); +} + +EOLIAN static Eina_Bool +_efl_ui_tree_view_efl_ui_widget_focus_state_apply(Eo *obj, Efl_Ui_Tree_View_Data *pd EINA_UNUSED, Efl_Ui_Widget_Focus_State current_state, Efl_Ui_Widget_Focus_State *configured_state, Efl_Ui_Widget *redirect EINA_UNUSED) +{ + return efl_ui_widget_focus_state_apply(efl_super(obj, MY_CLASS), current_state, configured_state, obj); +} + +typedef struct _Efl_Ui_Tree_View_Layout_Item_Tracking Efl_Ui_Tree_View_Layout_Item_Tracking; +struct _Efl_Ui_Tree_View_Layout_Item_Tracking +{ + Efl_Ui_Tree_View_Item *item; + Eo *obj; + Efl_Ui_Tree_View_Data *pd; +}; + +static Eina_Value +_content_created(void *data, const Eina_Value value) +{ + Efl_Ui_Tree_View_Item_Event evt; + Efl_Ui_Tree_View_Layout_Item_Tracking *tracking = data; + Efl_Ui_Tree_View_Item *item = tracking->item; + Efl_Ui_Tree_View_Data *pd = tracking->pd; + Eo *obj = tracking->obj; + + eina_value_pget(&value, &item->layout); + + evas_object_smart_member_add(item->layout, pd->pan_obj); + evas_object_event_callback_add(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item); + + if (_elm_config->atspi_mode) + { + efl_access_added(item->layout); + efl_access_children_changed_added_signal_emit(obj, item->layout); + } + + evt.child = item->model; + evt.layout = item->layout; + evt.index = EFL_UI_TREE_VIEW_SEG_ARRAY_POS_GET(item); + efl_event_callback_call(obj, EFL_UI_TREE_VIEW_EVENT_ITEM_REALIZED, &evt); + + item->layout_request = NULL; + efl_ui_tree_view_relayout_content_created(pd->layouter, item); + + efl_ui_focus_composition_dirty(obj); + evas_object_show(item->layout); + + return value; +} + +static void +_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED) +{ + Efl_Ui_Tree_View_Layout_Item_Tracking *tracking = data; + + tracking->item->layout_request = NULL; + free(tracking); +} + +EOLIAN static Efl_Ui_Tree_View_Item * +_efl_ui_tree_view_efl_ui_tree_view_model_realize(Eo *obj, Efl_Ui_Tree_View_Data *pd, Efl_Ui_Tree_View_Item *item) +{ + + Efl_Ui_Tree_View_Layout_Item_Tracking *tracking; + EINA_SAFETY_ON_NULL_RETURN_VAL(item->model, item); + + if (item->layout_request) eina_future_cancel(item->layout_request); + + tracking = calloc(1, sizeof (Efl_Ui_Tree_View_Layout_Item_Tracking)); + if (!tracking) return item; + + tracking->item = item; + tracking->obj = obj; + tracking->pd = pd; + + item->layout_request = efl_ui_factory_create(pd->factory, item->model, obj); + item->layout_request = efl_future_then(obj, item->layout_request); + item->layout_request = eina_future_then_from_desc(item->layout_request, + eina_future_cb_easy(.success = _content_created, + .success_type = EINA_VALUE_TYPE_OBJECT, + .data = tracking, + .free = _clean_request)); + return item; +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_tree_view_model_unrealize(Eo *obj, Efl_Ui_Tree_View_Data *pd, Efl_Ui_Tree_View_Item *item) +{ + Efl_Ui_Tree_View_Item_Event evt; + EINA_SAFETY_ON_NULL_RETURN(item); + + if (!item->layout) + return; + + // First check if the item has been fully realized + if (item->layout_request) + { + eina_future_cancel(item->layout_request); + return ; + } + + evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item); + if (elm_object_focus_allow_get(item->layout)) + { + if (efl_ui_focus_object_focus_get(item->layout)) + efl_ui_focus_object_focus_set(item->layout, EINA_FALSE); + efl_ui_focus_manager_calc_unregister(obj, item->layout); + } + evas_object_hide(item->layout); + evas_object_move(item->layout, -9999, -9999); + + evt.child = item->model; + evt.layout = item->layout; + evt.index = EFL_UI_TREE_VIEW_SEG_ARRAY_POS_GET(item); + efl_event_callback_call(obj, EFL_UI_TREE_VIEW_EVENT_ITEM_UNREALIZED, &evt); + + efl_ui_factory_release(pd->factory, item->layout); + evas_object_smart_member_del(item->layout); + item->layout = NULL; +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_tree_view_model_expand(Eo *obj, Efl_Ui_Tree_View_Data *pd, Efl_Ui_Tree_View_Item *item, int first, int count) +{ + Tree_View_Slice_Callback_Data *slice; + Eina_Future *f; + + if (item->expanded) return; + + item->expanded = EINA_TRUE; + slice = calloc(1, sizeof(Tree_View_Slice_Callback_Data)); + slice->private = pd; + slice->parent_item = item; + slice->first = first; + f = efl_model_children_slice_get(item->model, first, count); + f = eina_future_then(f, _expand_children_slice_then, slice); + slice->future = efl_future_then(obj, f); +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_tree_view_model_contract(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd EINA_UNUSED, Efl_Ui_Tree_View_Item *item EINA_UNUSED) +{ + //TODO +} + +EOLIAN static void +_efl_ui_tree_view_efl_ui_tree_view_model_load_range_set(Eo* obj, Efl_Ui_Tree_View_Data* pd, int first, int count) +{ + if (pd->slice.future) return ; //FIXME: why ignore a new range set? + + pd->slice.start = first; + pd->slice.count = count; + + if (efl_model_children_count_get(pd->model)) + { + Eina_Future *f = efl_model_children_slice_get(pd->model, first, count); + f = eina_future_then(f, _children_slice_then, pd); + pd->slice.future = efl_future_then(obj, f); + } +} + +EOLIAN static int +_efl_ui_tree_view_efl_ui_tree_view_model_model_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Data *pd) +{ + return efl_model_children_count_get(pd->model); +} + +ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_tree_view, Efl_Ui_Tree_View_Data) + +/* Internal EO APIs and hidden overrides */ + +#define EFL_UI_TREE_VIEW_EXTRA_OPS \ + EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_tree_view) + +#include "efl_ui_tree_view.eo.c" +#include "efl_ui_tree_view_relayout.eo.c" +#include "efl_ui_tree_view_model.eo.c" diff --git a/src/lib/elementary/efl_ui_tree_view.eo b/src/lib/elementary/efl_ui_tree_view.eo new file mode 100644 index 0000000000..065932d4ad --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view.eo @@ -0,0 +1,96 @@ +import elm_general; + +struct Efl.Ui.Tree_View_Item_Event +{ + layout: Efl.Ui.Layout; + child: Efl.Model; + index: int; [[index of the item in thee layout]] + depth: int; [[depth of the item in tree layout]] +} + +class Efl.Ui.Tree_View (Efl.Ui.Layout, Efl.Ui.View, Efl.Ui.Scrollable_Interactive, Efl.Ui.Scrollbar, + Efl.Access.Widget.Action, Efl.Access.Selection, Efl.Ui.Focus.Composition, Efl.Ui.Focus.Manager_Sub, + Efl.Ui.Clickable, Efl.Ui.Selectable, Efl.Ui.Tree_View_Model, Efl.Ui.Widget_Focus_Manager) +{ + methods { + @property relayout { + get {} + set {} + values { + object: Efl.Ui.Tree_View_Relayout; + } + } + @property layout_factory { + [[Treeview layout factory set.]] + set {} + get {} + values { + factory: Efl.Ui.Factory; [[The factory.]] + } + } + @property show_root { + get { + [[Get if root is visible.]] + } + set { + [[Enable/Disable root visiblity.]] + } + values { + show: bool; [[Default is Disabled.]] + } + } + } + events { + item,realized : Efl.Ui.Tree_View_Item_Event; + item,unrealized : Efl.Ui.Tree_View_Item_Event; + item,focused : Efl.Ui.Tree_View_Item_Event; + item,unfocused : Efl.Ui.Tree_View_Item_Event; + item,selected : Efl.Ui.Tree_View_Item_Event; + item,unselected : Efl.Ui.Tree_View_Item_Event; + item,expanded : Efl.Ui.Tree_View_Item_Event; + item,unexpanded : Efl.Ui.Tree_View_Item_Event; + } + + implements { + Efl.Object.constructor; + Efl.Object.finalize; + Efl.Object.destructor; + Efl.Gfx.Entity.position { set; } + Efl.Gfx.Entity.size { set; } + // Smart obj + Efl.Canvas.Group.group_member_add; + Efl.Canvas.Group.group_calculate; + + Efl.Ui.Tree_View_Model.load_range { set;} + Efl.Ui.Tree_View_Model.realize; + Efl.Ui.Tree_View_Model.unrealize; + Efl.Ui.Tree_View_Model.expand; + Efl.Ui.Tree_View_Model.contract; + Efl.Ui.Tree_View_Model.model_size { get; } + Efl.Ui.Tree_View_Model.min_size { get; set; } + + // Widget + Efl.Ui.Widget_Focus_Manager.focus_manager_create; + Efl.Ui.Widget.widget_event; + Efl.Ui.Widget.focus_state_apply; + Efl.Ui.Focus.Composition.prepare; + Efl.Ui.View.model { get; set; } + + Efl.Ui.Scrollable_Interactive.viewport_geometry { get; } + Efl.Ui.Scrollable_Interactive.content_pos { get; set; } + Efl.Ui.Scrollable_Interactive.content_size { get; } + Efl.Ui.Scrollable_Interactive.scroll; + Efl.Ui.Scrollbar.bar_mode { get; set; } + Efl.Layout.Signal.signal_callback_add; + Efl.Layout.Signal.signal_callback_del; + Efl.Access.Object.access_children { get; } + Efl.Access.Selection.selected_children_count { get; } + Efl.Access.Selection.selected_child { get; } + Efl.Access.Selection.selected_child_deselect; + Efl.Access.Selection.child_select; + Efl.Access.Selection.child_deselect; + Efl.Access.Selection.is_child_selected; + Efl.Access.Selection.all_children_select; + Efl.Access.Selection.access_selection_clear; + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_layouter.c b/src/lib/elementary/efl_ui_tree_view_layouter.c new file mode 100644 index 0000000000..e97b0f1a5f --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_layouter.c @@ -0,0 +1,722 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Elementary.h> + +#include <assert.h> + +#include "elm_priv.h" +#include "efl_ui_tree_view_seg_array.h" + +#define MY_CLASS EFL_UI_TREE_VIEW_LAYOUTER_CLASS + +typedef struct _Efl_Ui_Tree_View_Layouter_Data +{ + Efl_Ui_Tree_View_Seg_Array *segarray; + Efl_Ui_Tree_View_Model *modeler; + Ecore_Job *calc_job; + Efl_Model* model; + Eina_Size2D min; + int count_total; + int count_segarray; + + Eina_Bool initialized : 1; + Eina_Bool recalc : 1; + Eina_Bool resize : 1; +} Efl_Ui_Tree_View_Layouter_Data; + +typedef struct _Efl_Ui_Tree_View_Layouter_Node_Data +{ + Eina_Size2D min; + Eina_Size2D size; + Eina_Bool realized : 1; + Eina_Bool expanded : 1; +} Efl_Ui_Tree_View_Layouter_Node_Data; + +typedef struct _Efl_Ui_Tree_View_Layouter_Callback_Data +{ + Efl_Ui_Tree_View_Layouter_Data *pd; + Efl_Ui_Tree_View_Item *item; +} Efl_Ui_Tree_View_Layouter_Callback_Data; + +typedef struct _Request Request; +struct _Request +{ + Efl_Ui_Tree_View_Layouter_Data *pd; + unsigned int index; +}; + +typedef struct _Draw_Data +{ + Eina_Rect vgmt; + Eina_Position2D spos; + int extra; + int rounding; + double cur_pos; +} Draw_Data; + +#include "efl_ui_tree_view_layouter.eo.h" + +static void +_item_size_calc(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Item* item) +{ + int boxx, boxy, boxw, boxh, boxl, boxr, boxt, boxb, pad[4]; + double align[2]; + Eina_Size2D max; + + efl_gfx_size_hint_margin_get(item->layout, &pad[0], &pad[1], &pad[2], &pad[3]); + evas_object_geometry_get(pd->modeler, &boxx, &boxy, &boxw, &boxh); + efl_gfx_size_hint_margin_get(pd->modeler, &boxl, &boxr, &boxt, &boxb); + efl_gfx_size_hint_align_get(item->layout, &align[0], &align[1]); + max = efl_gfx_size_hint_max_get(item->layout); + + // box outer margin + boxw -= boxl + boxr; + boxh -= boxt + boxb; + boxx += boxl; + boxy += boxt; + + if (align[0] < 0) align[0] = -1; + if (align[1] < 0) align[1] = -1; + if (align[0] > 1) align[0] = 1; + if (align[1] > 1) align[1] = 1; + + if (max.w <= 0) max.w = INT_MAX; + if (max.h <= 0) max.h = INT_MAX; + if (max.w < item->min.w) max.w = item->min.w; + if (max.h < item->min.h) max.h = item->min.h; + + // horizontally + if (max.w < INT_MAX) + { + item->size.w = MIN(MAX(item->min.w - pad[0] - pad[1], max.w), boxw); + item->pos.x = boxx + pad[0]; + } + else if (align[0] < 0) + { + // fill x + item->size.w = boxw - pad[0] - pad[1]; + item->pos.x = boxx + pad[0]; + } + else + { + item->size.w = item->min.w - pad[0] - pad[1]; + item->pos.x = boxx + ((boxw - item->size.w) * align[0]) + pad[0]; + } + + // vertically + if (max.h < INT_MAX) + { + item->size.h = MIN(MAX(item->min.h - pad[2] - pad[3], max.h), boxh); + item->pos.y = boxy + pad[2]; + } + else if (align[1] < 0) + { + // fill y + item->size.h = item->min.h - pad[2] - pad[3]; + item->pos.y = boxy + pad[2]; + } + else + { + item->size.h = item->min.h - pad[2] - pad[3]; + item->pos.y = boxy + ((item->min.h - item->size.h) * align[1]) + pad[2]; + } +} + +static void +_node_size_fix(Efl_Ui_Tree_View_Item* item, int sizediff) +{ + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata; + Efl_Ui_Tree_View_Seg_Array_Node *node; + Efl_Ui_Tree_View_Item *parent; + + if (!item || !item->parent) + return; + + parent = item->parent; + node = parent->tree_node; + if (node && node->layout_data) + { + nodedata = node->layout_data; + nodedata->min.h += sizediff; + } + + parent->children_min.h += sizediff; + if (parent->children_min.h < 0) parent->children_min.h = 0; + + _node_size_fix(parent, sizediff); +} + +static void +_item_min_calc(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Item* item + , Eina_Size2D min, Efl_Ui_Tree_View_Seg_Array_Node *itemnode + , Efl_Ui_Tree_View_Seg_Array *segarray) +{ + EINA_SAFETY_ON_NULL_RETURN(pd); + EINA_SAFETY_ON_NULL_RETURN(item); + EINA_SAFETY_ON_NULL_RETURN(itemnode); + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = itemnode->layout_data; + Efl_Ui_Tree_View_Item *litem; + int i, pad[4]; + + efl_gfx_size_hint_margin_get(item->layout, &pad[0], &pad[1], &pad[2], &pad[3]); + min.w += pad[0] + pad[1]; + min.h += pad[2] + pad[3]; + + if (item->min.h == min.h && item->min.w == min.w) + return; + + pd->min.h += min.h - item->min.h; + nodedata->min.h += min.h - item->min.h; + + if (nodedata->min.w <= min.w) + nodedata->min.w = min.w; + else if (nodedata->min.w == item->min.w) + { + nodedata->min.w = 0; + for (i = 0; i != itemnode->length; ++i) + { + litem = (Efl_Ui_Tree_View_Item *)itemnode->pointers[i]; + if (nodedata->min.w < litem->min.w) + nodedata->min.w = litem->min.w; + if (item->min.w == litem->min.w) + break; + } + } + + if (pd->min.w <= min.w) + pd->min.w = min.w; + else if (pd->min.w == item->min.w) + { + Efl_Ui_Tree_View_Seg_Array_Node *node2; + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(segarray); + pd->min.w = min.w; + + EINA_ACCESSOR_FOREACH(nodes, i, node2) + { + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata2 = node2->layout_data; + if (pd->min.w < nodedata2->min.w) + pd->min.w = nodedata2->min.w; + + if (item->min.w == nodedata2->min.w) + break; + } + eina_accessor_free(nodes); + } + + _node_size_fix(item, (min.h - item->min.h)); + + item->min.w = min.w; + item->min.h = min.h; + _item_size_calc(pd, item); +} + +static void +_on_item_size_hint_change(void *data, Evas *e EINA_UNUSED, + Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Efl_Ui_Tree_View_Layouter_Callback_Data *cb_data = data; + EINA_SAFETY_ON_NULL_RETURN(cb_data); + Efl_Ui_Tree_View_Layouter_Data *pd = cb_data->pd; + EINA_SAFETY_ON_NULL_RETURN(pd); + Efl_Ui_Tree_View_Item *item = cb_data->item;; + EINA_SAFETY_ON_NULL_RETURN(item); + Efl_Ui_Tree_View_Seg_Array_Node *node = item->tree_node; + EINA_SAFETY_ON_NULL_RETURN(node); + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = node->layout_data; + EINA_SAFETY_ON_NULL_RETURN(nodedata); + + Eina_Size2D min = efl_gfx_size_hint_combined_min_get(obj); + if (item->parent) + { + Efl_Ui_Tree_View_Item *parent = item->parent; + _item_min_calc(pd, item, min, node, parent->segarray); + } + else + _item_min_calc(pd, item, min, node, pd->segarray); + + if (!nodedata->realized) + free(evas_object_event_callback_del(item->layout, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_item_size_hint_change)); +} + +static Eina_Value +_children_get(void *data, Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +{ + Efl_Model *children; + unsigned int i, len; + Request *r = data; + + if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ERROR) + goto on_error; + + if (eina_value_type_get(&v) == EINA_VALUE_TYPE_OBJECT) + { + children = eina_value_object_get(&v); + efl_ui_tree_view_seg_array_insert(r->pd->segarray, NULL, r->index, children); + } + else if (eina_value_type_get(&v) == EINA_VALUE_TYPE_ARRAY) + { + EINA_VALUE_ARRAY_FOREACH(&v, len, i, children) + { + unsigned int idx = r->index + i; + efl_ui_tree_view_seg_array_insert(r->pd->segarray, NULL, idx, children); + } + } + + r->pd->recalc = EINA_TRUE; + evas_object_smart_changed(r->pd->modeler); + + on_error: + free(r); + return v; +} + +static void +_on_modeler_resize(void *data, Evas *e EINA_UNUSED, + Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Efl_Ui_Tree_View_Layouter_Data *pd = data; + pd->resize = EINA_TRUE; +} + +static void +_child_added_cb(void *data, const Efl_Event *event) +{ + Efl_Model_Children_Event* evt = event->info; + Efl_Ui_Tree_View_Layouter_Data *pd = data; + Eina_Future *f; + Request *r; + + r = calloc(1, sizeof (Request)); + if (!r) return; + + r->index = evt->index; + r->pd = pd; + + f = efl_model_children_slice_get(pd->model, evt->index, 1); + f = eina_future_then(f, _children_get, r); +} + +static void +_node_realize(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Seg_Array_Node *node) +{ + Efl_Ui_Tree_View_Item* item; + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = node->layout_data; + int i; + + EINA_SAFETY_ON_NULL_RETURN(nodedata); + if (nodedata->realized) + return; + + nodedata->realized = EINA_TRUE; + + for (i = 0; i != node->length; ++i) + { + item = (Efl_Ui_Tree_View_Item *)node->pointers[i]; + efl_ui_tree_view_model_realize(pd->modeler, item); + } +} + +void +_node_unrealize(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Seg_Array_Node *node, Eina_Bool is_free) +{ + Efl_Ui_Tree_View_Seg_Array_Node *s_node; + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata; + Efl_Ui_Tree_View_Item* item; + int i, j; + + EINA_SAFETY_ON_NULL_RETURN(node); + EINA_SAFETY_ON_NULL_RETURN(node->layout_data); + + nodedata = node->layout_data; + if (!nodedata->realized) + return; + + nodedata->realized = EINA_FALSE; + for (i = 0; i != node->length; ++i) + { + item = (Efl_Ui_Tree_View_Item *)node->pointers[i]; + if (item->expanded && item->segarray) + { + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(item->segarray); + EINA_ACCESSOR_FOREACH(nodes, j, s_node) + { + _node_unrealize(pd, s_node, is_free); + } + eina_accessor_free(nodes); + } + + if (item->layout) + { + free(evas_object_event_callback_del(item->layout, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_item_size_hint_change)); + efl_ui_tree_view_model_unrealize(pd->modeler, item); + } + } + + if (is_free) + { + free(node->layout_data); + node->layout_data = NULL; + } +} + +static void +_child_count_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + Efl_Ui_Tree_View_Layouter_Data *pd = data; + pd->count_total = efl_model_children_count_get(pd->model); + if (pd->count_total) + efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, _child_count_changed_cb, pd); +} + +static Eina_Bool +_initilize(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Model *modeler) +{ + if (pd->initialized) + return EINA_TRUE; + + efl_replace(&pd->modeler, modeler); + + if (!pd->model || !pd->modeler) + return EINA_FALSE; + + pd->recalc = EINA_TRUE; + pd->initialized = EINA_TRUE; + + efl_ui_tree_view_model_load_range_set(pd->modeler, 0, pd->count_total); // load all + efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, pd); + + evas_object_event_callback_add(pd->modeler, EVAS_CALLBACK_RESIZE, _on_modeler_resize, pd); + pd->min.w = 0; + pd->min.h = 0; + + return EINA_TRUE; +} + +static void +_finalize(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd) +{ + Efl_Ui_Tree_View_Seg_Array_Node* node; + int i; + + if (pd->segarray) + { + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(pd->segarray); + EINA_ACCESSOR_FOREACH(nodes, i, node) + { + _node_unrealize(pd, node, EINA_TRUE); + } + eina_accessor_free(nodes); + } + + if (pd->model) + { + efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, pd); + pd->count_total = 0; + } + + if (pd->modeler) + { + evas_object_event_callback_del_full(pd->modeler, EVAS_CALLBACK_RESIZE, _on_modeler_resize, pd); + efl_ui_tree_view_model_min_size_set(pd->modeler, pd->min); + } + + pd->min.w = 0; + pd->min.h = 0; + efl_replace(&pd->modeler, NULL); + efl_replace(&pd->segarray, NULL); + pd->initialized = EINA_FALSE; + pd->recalc = EINA_TRUE; +} + +static void +_calc_range(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Seg_Array *segarray, Evas_Coord cur_pos) +{ + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata; + Efl_Ui_Tree_View_Seg_Array_Node *node; + Eina_Position2D spos; + Evas_Coord ny; + Eina_Rect vgmt; + int i; + + vgmt = efl_ui_scrollable_viewport_geometry_get(pd->modeler); + spos = efl_ui_scrollable_content_pos_get(pd->modeler); + ny = spos.y - (vgmt.h / 2); + if (ny < 0) spos.y = 0; + else spos.y = ny; + vgmt.h *= 2; + + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(segarray); + EINA_ACCESSOR_FOREACH(nodes, i, node) + { + nodedata = node->layout_data; + if (!nodedata || !nodedata->min.h) + continue; + + if ((cur_pos > spos.y || nodedata->min.h + cur_pos > spos.y) && (cur_pos < (spos.y + vgmt.h) || nodedata->min.h + cur_pos < spos.y + vgmt.h)) + _node_realize(pd, node); + else + _node_unrealize(pd, node, EINA_FALSE); + + cur_pos += nodedata->min.h; + } + eina_accessor_free(nodes); +} + +static void +_calc_size_segarray(Efl_Ui_Tree_View_Layouter_Data* pd, Efl_Ui_Tree_View_Seg_Array *segarray) +{ + EINA_SAFETY_ON_NULL_RETURN(pd); + EINA_SAFETY_ON_NULL_RETURN(segarray); + Efl_Ui_Tree_View_Seg_Array_Node *node; + Efl_Ui_Tree_View_Item *item; + int i, j = 0, count; + + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(segarray); + while (eina_accessor_data_get(nodes, j, (void **)&node)) + { + ++j; + if (!node->layout_data) + node->layout_data = calloc(1, sizeof(Efl_Ui_Tree_View_Layouter_Node_Data)); + + if (j == 1) + { + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = node->layout_data; + nodedata->realized = EINA_TRUE; + } + + for (i = 0; i != node->length; ++i) + { + item = (Efl_Ui_Tree_View_Item *)node->pointers[i]; + EINA_SAFETY_ON_NULL_RETURN(item); + + // cache size of new items + if ((item->min.w == 0) && (item->min.h == 0) && !item->layout) + efl_ui_tree_view_model_realize(pd->modeler, item); + + count = efl_model_children_count_get(item->model); + if (count && !item->expanded) + { + efl_ui_tree_view_model_expand(pd->modeler, item, 0, count); + } + else if (item->expanded && item->segarray) + { + _calc_size_segarray (pd, item->segarray); + } + } + } + eina_accessor_free(nodes); +} + +static void +_calc_size_job(void *data) +{ + Efl_Ui_Tree_View_Layouter_Data *pd; + Eo *obj = data; + /* double start_time = ecore_time_get(); */ + + EINA_SAFETY_ON_NULL_RETURN(data); + pd = efl_data_scope_get(obj, MY_CLASS); + if (EINA_UNLIKELY(!pd)) return; + + _calc_size_segarray(pd, pd->segarray); + + pd->calc_job = NULL; + pd->recalc = EINA_FALSE; + + evas_object_smart_changed(pd->modeler); +} + +EOLIAN static Efl_Object * +_efl_ui_tree_view_layouter_efl_object_constructor(Eo *obj, Efl_Ui_Tree_View_Layouter_Data *pd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + pd->initialized = EINA_FALSE; + + return obj; +} + +EOLIAN static void +_efl_ui_tree_view_layouter_efl_ui_tree_view_relayout_content_created(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Item *item) +{ + Efl_Ui_Tree_View_Layouter_Callback_Data *cb_data; + EINA_SAFETY_ON_NULL_RETURN(item); + EINA_SAFETY_ON_NULL_RETURN(item->layout); + Efl_Ui_Tree_View_Seg_Array_Node *node = item->tree_node; + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = node->layout_data; + + Eina_Size2D min = efl_gfx_size_hint_combined_min_get(item->layout); + _item_min_calc(pd, item, min, node, pd->segarray); + + if (min.w && min.h && !nodedata->realized) + { + efl_ui_tree_view_model_unrealize(pd->modeler, item); + return; + } + + cb_data = calloc(1, sizeof(Efl_Ui_Tree_View_Layouter_Callback_Data)); + cb_data->pd = pd; + cb_data->item = item; + evas_object_event_callback_add(item->layout, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_item_size_hint_change, cb_data); + + _item_size_calc(pd, item); +} + +EOLIAN static Eina_List * +_efl_ui_tree_view_layouter_efl_ui_tree_view_relayout_elements_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd) +{ + Eina_List *elements_order = NULL; + Efl_Ui_Tree_View_Item* item; + Efl_Ui_Tree_View_Seg_Array_Node *items_node; + int i, j; + + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(pd->segarray); + EINA_ACCESSOR_FOREACH(nodes, i, items_node) + { + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = items_node->layout_data; + if (!nodedata || !nodedata->realized) + continue; + + for (j = 0; j != items_node->length; ++j) + { + item = (Efl_Ui_Tree_View_Item *)items_node->pointers[j]; + if (item->layout) + elements_order = eina_list_append(elements_order, item->layout); + } + } + eina_accessor_free(nodes); + return elements_order; +} + +EOLIAN static void +_efl_ui_tree_view_layouter_efl_ui_tree_view_relayout_model_set(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Model *model) +{ + _finalize(obj, pd); + + efl_replace(&pd->model, model); + if (pd->model) + { + pd->count_total = efl_model_children_count_get(pd->model); + if (pd->count_total && pd->modeler) + efl_ui_tree_view_model_load_range_set(pd->modeler, 0, pd->count_total); // load all + else + efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILDREN_COUNT_CHANGED, _child_count_changed_cb, pd); + } +} + +static void +_node_draw(Efl_Ui_Tree_View_Layouter_Data *pd, Efl_Ui_Tree_View_Seg_Array *segarray, Draw_Data *drawdata) +{ + Efl_Ui_Tree_View_Seg_Array_Node *items_node; + Efl_Ui_Tree_View_Item* item; + int i, j; + + _calc_range(pd, segarray, drawdata->cur_pos); + + Eina_Accessor *nodes = efl_ui_tree_view_seg_array_node_accessor_get(segarray); + EINA_SAFETY_ON_NULL_RETURN(nodes); + EINA_ACCESSOR_FOREACH(nodes, i, items_node) + { + Efl_Ui_Tree_View_Layouter_Node_Data *nodedata = items_node->layout_data; + if (!nodedata) continue; + + if (nodedata->realized) + for (j = 0; j != items_node->length;++j) + { + double x, y, w, h; + double weight_x, weight_y; + item = (Efl_Ui_Tree_View_Item *)items_node->pointers[j]; + EINA_SAFETY_ON_NULL_RETURN(item); + + if (item->layout) + { + if (pd->resize) + _item_size_calc(pd, item); + + efl_gfx_size_hint_weight_get(item->layout, &weight_x, &weight_y); + // extra rounding up (compensate cumulative error) + if ((i == (pd->count_total - 1)) && (drawdata->cur_pos - floor(drawdata->cur_pos) >= 0.5)) + drawdata->rounding = 1; + + x = item->pos.x; + y = item->pos.y + drawdata->cur_pos; + w = item->size.w; + h = item->size.h + drawdata->rounding + weight_y * drawdata->extra; + drawdata->cur_pos += h; + + if (w < pd->min.w) w = pd->min.w; + if (w > drawdata->vgmt.w) w = drawdata->vgmt.w; + + evas_object_geometry_set(item->layout, (x + 0 - drawdata->spos.x), (y + 0 - drawdata->spos.y), w, h); + } + else + { + drawdata->cur_pos += item->size.h; + } + + if (item->expanded && item->segarray) + _node_draw(pd, item->segarray, drawdata); + } + else + drawdata->cur_pos += nodedata->min.h; + } + eina_accessor_free(nodes); +} + +static void +_efl_ui_tree_view_relayout_layout_do(Efl_Ui_Tree_View_Layouter_Data *pd) +{ + int boxx, boxy, boxw, boxh; + int boxl = 0, boxr = 0, boxt = 0, boxb = 0; + Draw_Data drawdata; + memset(&drawdata, 0, sizeof(drawdata)); + + evas_object_geometry_get(pd->modeler, &boxx, &boxy, &boxw, &boxh); + efl_gfx_size_hint_margin_get(pd->modeler, &boxl, &boxr, &boxt, &boxb); + + // box outer margin + boxw -= boxl + boxr; + boxh -= boxt + boxb; + boxx += boxl; + boxy += boxt; + + drawdata.extra = boxh - pd->min.h; + if (drawdata.extra < 0) drawdata.extra = 0; + + efl_ui_tree_view_model_min_size_set(pd->modeler, pd->min); + drawdata.vgmt = efl_ui_scrollable_viewport_geometry_get(pd->modeler); + drawdata.spos = efl_ui_scrollable_content_pos_get(pd->modeler); + + _node_draw(pd, pd->segarray, &drawdata); + pd->resize = EINA_FALSE; +} + +EOLIAN static void +_efl_ui_tree_view_layouter_efl_ui_tree_view_relayout_layout_do + (Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Layouter_Data *pd + , Efl_Ui_Tree_View_Model *modeler, int first EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array *segarray) +{ + int count; + + if (!_initilize(obj, pd, modeler)) + return; + + efl_replace(&pd->segarray, segarray); + if (!pd->segarray) + return; + + count = efl_ui_tree_view_seg_array_count(pd->segarray); + + if ((pd->recalc && count > 0) || pd->count_segarray != count) + { + // cache size of new items + pd->count_segarray = count; + ecore_job_del(pd->calc_job); + pd->calc_job = ecore_job_add(_calc_size_job, obj); + return; + } + _efl_ui_tree_view_relayout_layout_do(pd); +} + +#include "efl_ui_tree_view_layouter.eo.c" diff --git a/src/lib/elementary/efl_ui_tree_view_layouter.eo b/src/lib/elementary/efl_ui_tree_view_layouter.eo new file mode 100644 index 0000000000..5826ec37a8 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_layouter.eo @@ -0,0 +1,10 @@ +class Efl.Ui.Tree_View_Layouter (Efl.Object, Efl.Ui.Tree_View_Relayout) +{ + implements { + Efl.Object.constructor; + Efl.Ui.Tree_View_Relayout.layout_do; + Efl.Ui.Tree_View_Relayout.content_created; + Efl.Ui.Tree_View_Relayout.model { set; } + Efl.Ui.Tree_View_Relayout.elements { get; } + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_model.eo b/src/lib/elementary/efl_ui_tree_view_model.eo new file mode 100644 index 0000000000..be2fe0acd3 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_model.eo @@ -0,0 +1,70 @@ +struct Efl.Ui.Tree_View_Item { + layout: Efl.Ui.Layout; + layout_request: future<Efl.Ui.Layout>; + model: Efl.Model; + linearized_offset: int; [[model index]] + shallow_offset: int; + depth: int; + children_count: int; [[ Number of indirect children ]] + children_min: Eina.Size2D; + children_size: Eina.Size2D; + parent: void_ptr; [[Efl.Ui.Tree_View_Item parent]] + tree_node: void_ptr; + segarray: Efl.Ui.Tree_View_Seg_Array; + expanded: bool; + min: Eina.Size2D; + size: Eina.Size2D; + pos: Eina.Position2D; +} + +struct @extern Efl.Ui.Tree_View_Seg_Array_Node; [[ ]] + +interface Efl.Ui.Tree_View_Model (Efl.Ui.Direction, Efl.Gfx.Entity, Efl.Ui.Scrollable_Interactive) +{ + methods { + @property load_range { + set {} + values { + first: int; + count: int; + } + } + realize { + params { + item: ptr(Efl.Ui.Tree_View_Item); + } + return: ptr(Efl.Ui.Tree_View_Item); + } + unrealize { + params { + item: ptr(Efl.Ui.Tree_View_Item); + } + } + expand { + params { + item: ptr(Efl.Ui.Tree_View_Item); + first: int; + count: int; + } + } + contract { + params { + item: ptr(Efl.Ui.Tree_View_Item); + } + } + @property model_size { + get {} + values { + s: int; + } + } + @property min_size { + [[Minimal content size.]] + set {} + get {} + values { + min: Eina.Size2D; + } + } + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_pan.eo b/src/lib/elementary/efl_ui_tree_view_pan.eo new file mode 100644 index 0000000000..823d89f0e9 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_pan.eo @@ -0,0 +1,12 @@ +class Efl.Ui.Tree_View_Pan (Efl.Ui.Pan) +{ + [[Elementary Efl_Ui_Tree_View pan class]] + implements { + Efl.Object.destructor; + Efl.Ui.Pan.content_size { get; } + Efl.Ui.Pan.pan_position { get; set; } + Efl.Ui.Pan.pan_position_min { get; } + Efl.Ui.Pan.pan_position_max { get; } + Efl.Canvas.Group.group_calculate; + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_private.h b/src/lib/elementary/efl_ui_tree_view_private.h new file mode 100644 index 0000000000..bb99f1253f --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_private.h @@ -0,0 +1,73 @@ +#ifndef EFL_UI_TREE_VIEW_PRIVATE_H +#define EFL_UI_TREE_VIEW_PRIVATE_H + +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Elementary.h> +#include "elm_priv.h" + +#include "efl_ui_tree_view.eo.h" +#include "efl_ui_tree_view_layouter.eo.h" + +#include <assert.h> + +typedef struct _Efl_Ui_Tree_View_Data Efl_Ui_Tree_View_Data; +#include "efl_ui_tree_view_seg_array.h" + +struct _Efl_Ui_Tree_View_Data +{ + Eo *obj; + Eo *scrl_mgr; + Efl_Ui_Tree_View_Pan *pan_obj; + Efl_Model *model; + + struct { + Eina_Future *future; + + int start; + int count; + } slice; + + Efl_Ui_Layout_Factory *factory; + Eina_List *selected_items; + Efl_Ui_Focus_Manager *manager; + Efl_Ui_Tree_View_Relayout *layouter; + Efl_Ui_Tree_View_Seg_Array *segarray; + int segarray_first; + + Eina_Size2D min; + Eina_Bool scrl_freeze : 1; + Eina_Bool show_root: 1; +}; + +typedef struct _Efl_Ui_Tree_View_Pan_Data Efl_Ui_Tree_View_Pan_Data; +struct _Efl_Ui_Tree_View_Pan_Data +{ + Eo *wobj; + Eina_Rect gmt; +}; + +#define EFL_UI_TREE_VIEW_DATA_GET(o, ptr) \ + Efl_Ui_Tree_View_Data * ptr = efl_data_scope_get(o, EFL_UI_TREE_VIEW_CLASS) + +#define EFL_UI_TREE_VIEW_DATA_GET_OR_RETURN(o, ptr) \ + EFL_UI_TREE_VIEW_DATA_GET(o, ptr); \ + if (EINA_UNLIKELY(!ptr)) \ + { \ + ERR("No widget data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return; \ + } + +#define EFL_UI_TREE_VIEW_DATA_GET_OR_RETURN_VAL(o, ptr, val) \ + EFL_UI_TREE_VIEW_DATA_GET(o, ptr); \ + if (EINA_UNLIKELY(!ptr)) \ + { \ + ERR("No widget data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return val; \ + } + +#endif diff --git a/src/lib/elementary/efl_ui_tree_view_relayout.eo b/src/lib/elementary/efl_ui_tree_view_relayout.eo new file mode 100644 index 0000000000..28b520f296 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_relayout.eo @@ -0,0 +1,30 @@ +interface Efl.Ui.Tree_View_Relayout (Efl.Interface) +{ + methods { + layout_do { + params { + modeler: Efl.Ui.Tree_View_Model; + first: int; + children: Efl.Ui.Tree_View_Seg_Array; + } + } + content_created { + params { + item: ptr(Efl.Ui.Tree_View_Item); + } + } + @property model { + [[Model that is/will be ]] + set {} + values { + model: Efl.Model; [[Efl model]] + } + } + @property elements { + get {} + values { + elements: list<Efl.Gfx.Entity>; [[The order to use]] + } + } + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_seg_array.c b/src/lib/elementary/efl_ui_tree_view_seg_array.c new file mode 100644 index 0000000000..674c59c5a9 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_seg_array.c @@ -0,0 +1,474 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Efl.h> +#include <assert.h> + +#include <Elementary.h> +#include "elm_priv.h" + +#define MY_CLASS EFL_UI_TREE_VIEW_SEG_ARRAY_CLASS +#define MY_CLASS_NAME "Efl.Ui.Tree_View_Seg_Array" + +#include "efl_ui_tree_view_seg_array.h" + +static int _shallow_search_lookup_cb(Eina_Rbtree const* rbtree, const void* key, int length EINA_UNUSED, void* data EINA_UNUSED) +{ + Efl_Ui_Tree_View_Seg_Array_Node const* node = (void const*)rbtree; + int index = *(int*)key; + if (index < node->shallow_first_index) + { + return 1; + } + else if (index < node->shallow_first_index + node->length) + { + return 0; + } + else + { + return -1; + } +} + +static Eina_Rbtree_Direction _shallow_rbtree_compare(Efl_Ui_Tree_View_Seg_Array_Node const* left, + Efl_Ui_Tree_View_Seg_Array_Node const* right, void* data EINA_UNUSED) +{ + if (left->shallow_first_index < right->shallow_first_index) + return EINA_RBTREE_LEFT; + else + return EINA_RBTREE_RIGHT; +} + +static void +_free_node(Efl_Ui_Tree_View_Seg_Array_Node* node, void* data EINA_UNUSED) +{ + int i = 0; + + while (i < node->length) + { + Efl_Ui_Tree_View_Item* item = node->pointers[i]; + if (item->segarray) + { + efl_ui_tree_view_seg_array_flush(item->segarray); + efl_unref(item->segarray); + } + efl_unref(item->model); + free(item); + ++i; + } + + free(node); +} + +static Efl_Ui_Tree_View_Seg_Array_Node* +_alloc_node(Efl_Ui_Tree_View_Seg_Array_Data* pd, int shallow_first_index, int linearized_first_index) +{ + Efl_Ui_Tree_View_Seg_Array_Node* node; + node = calloc(1, sizeof(Efl_Ui_Tree_View_Seg_Array_Node) + pd->step_size*sizeof(Efl_Ui_Tree_View_Item*)); + node->linearized_first_index = linearized_first_index; + node->shallow_first_index = shallow_first_index; + node->max = pd->step_size; + node->pd = pd; + pd->root = (void*)eina_rbtree_inline_insert(EINA_RBTREE_GET(pd->root), EINA_RBTREE_GET(node), + EINA_RBTREE_CMP_NODE_CB(&_shallow_rbtree_compare), NULL); + pd->node_count++; + return node; +} + +EOLIAN static void +_efl_ui_tree_view_seg_array_flush(Eo* obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data *pd) +{ + if (pd->root) + eina_rbtree_delete(EINA_RBTREE_GET(pd->root), EINA_RBTREE_FREE_CB(_free_node), NULL); + + pd->root = NULL; + pd->node_count = 0; + pd->count = 0; +} + +static Efl_Ui_Tree_View_Item* _create_item_partial(Efl_Model* model, Efl_Ui_Tree_View_Item* parent) +{ + Eina_Value *v; + Efl_Ui_Tree_View_Item* item; + + item = calloc(1, sizeof(Efl_Ui_Tree_View_Item)); + item->parent = parent; + item->depth = 1; + + if (parent) + item->depth += parent->depth; + + v = eina_value_uint_new(item->depth); + item->model = efl_new(EFL_UI_TREE_VIEW_SEG_ARRAY_DEPTH_MODEL_CLASS, + efl_ui_view_model_set(efl_added, model), + efl_model_property_set(efl_added, "depth", v)); + eina_value_free(v); + + return item; +} + +EOLIAN static Efl_Ui_Tree_View_Item* +_efl_ui_tree_view_seg_array_remove(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data *pd EINA_UNUSED, int index EINA_UNUSED) +{ + return NULL; +} + +static void +_efl_ui_tree_view_seg_array_insert_at_node(Efl_Ui_Tree_View_Seg_Array_Data* pd, int shallow_index, Efl_Ui_Tree_View_Item* item, Efl_Ui_Tree_View_Seg_Array_Node* node) +{ + Efl_Ui_Tree_View_Seg_Array_Node* before_node; + int shallow_index_pred, pos = 0; + Eina_Iterator* iterator; + + assert (item->shallow_offset == 0); + assert (item->linearized_offset == 0); + + if (node && node->length != node->max && (shallow_index - node->shallow_first_index) <= node->length) + { + assert(node->length != node->max); + + pos = shallow_index - node->shallow_first_index; + item->tree_node = node; + item->shallow_offset = pos; + + assert(pos == node->length); + if (pos < node->length) + memmove(&node->pointers[pos], &node->pointers[pos+1], sizeof(node->pointers[pos])*(node->length - pos)); + + node->pointers[pos] = item; + if (pos) + item->linearized_offset = node->pointers[pos-1]->linearized_offset + node->pointers[pos-1]->children_count + 1; + + node->length++; + } + else + { + node = _alloc_node(pd, shallow_index, 0u); + node->pointers[0] = item; + node->length++; + item->shallow_offset = 0; + item->tree_node = node; + + shallow_index_pred = shallow_index ? shallow_index - 1 : 0; + + before_node = (void*)eina_rbtree_inline_lookup(EINA_RBTREE_GET(pd->root), + &shallow_index_pred, sizeof(shallow_index_pred), + &_shallow_search_lookup_cb, NULL); + if (before_node == node) + { + node->linearized_first_index = 0u; + assert (node->shallow_first_index == 0); + } + else + { + assert (node->shallow_first_index > before_node->shallow_first_index); + assert (node->shallow_first_index == before_node->shallow_first_index + + before_node->pointers[before_node->length-1]->shallow_offset + 1); + node->linearized_first_index = before_node->linearized_first_index; + if (before_node->length) + node->linearized_first_index += before_node->pointers[before_node->length-1]->linearized_offset + + before_node->pointers[before_node->length-1]->children_count + 1; + } + } + + int i = node->linearized_first_index; + iterator = eina_rbtree_iterator_infix((void*)pd->root); + while (eina_iterator_next(iterator, (void**)&node)) + if (node->linearized_first_index > i) + { + node->shallow_first_index++; + node->linearized_first_index++; + } + eina_iterator_free(iterator); + pd->count++; +} + +EOLIAN static void +_efl_ui_tree_view_seg_array_fix_offset (Efl_Ui_Tree_View_Item* current) +{ + Efl_Ui_Tree_View_Seg_Array_Node *node; + Efl_Ui_Tree_View_Item* item; + Eina_Iterator* iterator; + int i; + EINA_SAFETY_ON_NULL_RETURN(current); + + // need to fix size + current->children_count++; + node = current->tree_node; + + EINA_SAFETY_ON_NULL_RETURN(node); + EINA_SAFETY_ON_NULL_RETURN(node->pd); + + i = current->shallow_offset + 1; + while (i < node->length) + { + item = node->pointers[i]; + item->linearized_offset++; + i++; + } + + i = node->linearized_first_index; + iterator = eina_rbtree_iterator_infix((void*)node->pd->root); + while (eina_iterator_next(iterator, (void**)&node)) + if (node->linearized_first_index > i) + node->linearized_first_index++; + + eina_iterator_free(iterator); + if (current->parent) + _efl_ui_tree_view_seg_array_fix_offset(current->parent); +} + +EOLIAN static void +_efl_ui_tree_view_seg_array_insert(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data* pd, Efl_Ui_Tree_View_Item* parent, int shallow_index, Efl_Model* model) +{ + Efl_Ui_Tree_View_Seg_Array_Node *next, *node = NULL; + Efl_Ui_Tree_View_Seg_Array_Data* priv = pd; + Efl_Ui_Tree_View_Item* item; + Eina_Iterator* iterator; + + item = _create_item_partial(model, parent); + + if (parent) + { + if (!parent->segarray) + parent->segarray = efl_new(EFL_UI_TREE_VIEW_SEG_ARRAY_CLASS, + efl_ui_tree_view_seg_array_setup(efl_added, pd->step_size)); + + _efl_ui_tree_view_seg_array_fix_offset (parent); + pd->count++; + priv = efl_data_scope_get(parent->segarray, EFL_UI_TREE_VIEW_SEG_ARRAY_CLASS); + } + + iterator = eina_rbtree_iterator_infix((void*)priv->root); + while (eina_iterator_next(iterator, (void**)&next)) + { + if (next->shallow_first_index > shallow_index) + break; + node = next; + } + eina_iterator_free(iterator); + + _efl_ui_tree_view_seg_array_insert_at_node(priv, shallow_index, item, node); +} + +EOLIAN static int +_efl_ui_tree_view_seg_array_count(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data* pd) +{ + return pd->count; +} + +typedef struct _Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow +{ + Eina_Accessor vtable; + Efl_Ui_Tree_View_Seg_Array_Data* segarray; +} Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow; + +static Eina_Bool +_efl_ui_tree_view_seg_array_accessor_shallow_get_at(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc, + int idx, void** data) +{ + Efl_Ui_Tree_View_Seg_Array_Node* node; + node = (void*)eina_rbtree_inline_lookup(EINA_RBTREE_GET(acc->segarray->root), + &idx, sizeof(idx), &_shallow_search_lookup_cb, NULL); + if (node && (node->shallow_first_index <= idx && node->shallow_first_index + node->length > idx)) + { + int i = idx - node->shallow_first_index; + Efl_Ui_Tree_View_Item* item = node->pointers[i]; + *data = item; + return EINA_TRUE; + } + return EINA_FALSE; +} + +EOLIAN static void +_efl_ui_tree_view_seg_array_setup(Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data *pd, int size) +{ + pd->step_size = size; +} + +EOLIAN static Eo * +_efl_ui_tree_view_seg_array_efl_object_constructor(Eo *obj, Efl_Ui_Tree_View_Seg_Array_Data *pd EINA_UNUSED) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + return obj; +} + +EOLIAN static void +_efl_ui_tree_view_seg_array_efl_object_destructor(Eo *obj, Efl_Ui_Tree_View_Seg_Array_Data *pd) +{ + if (pd->root) + eina_rbtree_delete(EINA_RBTREE_GET(pd->root), EINA_RBTREE_FREE_CB(_free_node), NULL); + + pd->root = NULL; + efl_destructor(efl_super(obj, MY_CLASS)); +} + +static void* +_efl_ui_tree_view_seg_array_accessor_shallow_get_container(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc EINA_UNUSED) +{ + return NULL; +} + +static void +_efl_ui_tree_view_seg_array_accessor_shallow_free(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc EINA_UNUSED) +{ + free(acc); +} + +static Eina_Bool +_efl_ui_tree_view_seg_array_accessor_shallow_lock(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_efl_ui_tree_view_seg_array_accessor_shallow_unlock(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Accessor* +_efl_ui_tree_view_seg_array_accessor_shallow_clone(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc EINA_UNUSED) +{ + return &acc->vtable; +} + +static void +_efl_ui_tree_view_seg_array_accessor_shallow_setup(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc, Efl_Ui_Tree_View_Seg_Array_Data* segarray) +{ + EINA_MAGIC_SET(&acc->vtable, EINA_MAGIC_ACCESSOR); + acc->vtable.version = EINA_ACCESSOR_VERSION; + acc->vtable.get_at = FUNC_ACCESSOR_GET_AT(_efl_ui_tree_view_seg_array_accessor_shallow_get_at); + acc->vtable.get_container = FUNC_ACCESSOR_GET_CONTAINER(_efl_ui_tree_view_seg_array_accessor_shallow_get_container); + acc->vtable.free = FUNC_ACCESSOR_FREE(_efl_ui_tree_view_seg_array_accessor_shallow_free); + acc->vtable.lock = FUNC_ACCESSOR_LOCK(_efl_ui_tree_view_seg_array_accessor_shallow_lock); + acc->vtable.unlock = FUNC_ACCESSOR_LOCK(_efl_ui_tree_view_seg_array_accessor_shallow_unlock); + acc->vtable.clone = FUNC_ACCESSOR_CLONE(_efl_ui_tree_view_seg_array_accessor_shallow_clone); + acc->segarray = segarray; +} + +EOLIAN static Eina_Accessor* +_efl_ui_tree_view_seg_array_shallow_accessor_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data* pd) +{ + Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow* acc = calloc(1, sizeof(Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow)); + _efl_ui_tree_view_seg_array_accessor_shallow_setup(acc, pd); + return &acc->vtable; +} + +EOLIAN static Eina_Accessor* +_efl_ui_tree_view_seg_array_linearized_accessor_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data* pd EINA_UNUSED) +{ + return efl_ui_tree_view_seg_array_shallow_accessor_get (obj); +} + +typedef struct _Efl_Ui_Tree_View_Segarray_Node_Accessor +{ + Eina_Accessor vtable; + Efl_Ui_Tree_View_Seg_Array_Data* segarray; + Eina_Iterator* pre_iterator; + Efl_Ui_Tree_View_Seg_Array_Node* current_node; + int current_index; +} Efl_Ui_Tree_View_Segarray_Node_Accessor; + +static Eina_Bool +_efl_ui_tree_view_seg_array_node_accessor_get_at(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc, + int idx, void** data) +{ + if (idx == acc->current_index && acc->current_node) + { + (*data) = acc->current_node; + } + else + { + if (acc->current_index >= idx || !acc->current_node) + { + eina_iterator_free(acc->pre_iterator); + acc->pre_iterator = NULL; + acc->current_node = NULL; + acc->current_index = -1; + } + + if (!acc->pre_iterator) + acc->pre_iterator = eina_rbtree_iterator_infix((void*)acc->segarray->root); + + for (;acc->current_index != idx;++acc->current_index) + { + if (!eina_iterator_next(acc->pre_iterator, (void**)&acc->current_node)) + { + --acc->current_index; + return EINA_FALSE; + } + } + + (*data) = acc->current_node; + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void* +_efl_ui_tree_view_seg_array_node_accessor_get_container(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc EINA_UNUSED) +{ + return NULL; +} + +static void +_efl_ui_tree_view_seg_array_node_accessor_free(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc EINA_UNUSED) +{ + if (acc->pre_iterator) + eina_iterator_free(acc->pre_iterator); + free(acc); +} + +static Eina_Bool +_efl_ui_tree_view_seg_array_node_accessor_lock(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_efl_ui_tree_view_seg_array_node_accessor_unlock(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Accessor* +_efl_ui_tree_view_seg_array_node_accessor_clone(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc EINA_UNUSED) +{ + return &acc->vtable; +} + +static void +_efl_ui_tree_view_seg_array_node_accessor_setup(Efl_Ui_Tree_View_Segarray_Node_Accessor* acc, Efl_Ui_Tree_View_Seg_Array_Data* segarray) +{ + EINA_MAGIC_SET(&acc->vtable, EINA_MAGIC_ACCESSOR); + acc->vtable.version = EINA_ACCESSOR_VERSION; + acc->vtable.get_at = FUNC_ACCESSOR_GET_AT(_efl_ui_tree_view_seg_array_node_accessor_get_at); + acc->vtable.get_container = FUNC_ACCESSOR_GET_CONTAINER(_efl_ui_tree_view_seg_array_node_accessor_get_container); + acc->vtable.free = FUNC_ACCESSOR_FREE(_efl_ui_tree_view_seg_array_node_accessor_free); + acc->vtable.lock = FUNC_ACCESSOR_LOCK(_efl_ui_tree_view_seg_array_node_accessor_lock); + acc->vtable.unlock = FUNC_ACCESSOR_LOCK(_efl_ui_tree_view_seg_array_node_accessor_unlock); + acc->vtable.clone = FUNC_ACCESSOR_CLONE(_efl_ui_tree_view_seg_array_node_accessor_clone); + acc->segarray = segarray; + acc->pre_iterator = NULL; + acc->current_index = -1; + acc->current_node = NULL; +} + +EOLIAN static Eina_Accessor* +_efl_ui_tree_view_seg_array_node_accessor_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tree_View_Seg_Array_Data* pd) +{ + Efl_Ui_Tree_View_Segarray_Node_Accessor* acc = calloc(1, sizeof(Efl_Ui_Tree_View_Segarray_Node_Accessor)); + _efl_ui_tree_view_seg_array_node_accessor_setup(acc, pd); + return &acc->vtable; +} + +int efl_ui_tree_view_item_index_get(Efl_Ui_Tree_View_Item* item) +{ + Efl_Ui_Tree_View_Seg_Array_Node* node = item->tree_node; + return item->shallow_offset + node->shallow_first_index; +} + +#include "efl_ui_tree_view_seg_array.eo.c" diff --git a/src/lib/elementary/efl_ui_tree_view_seg_array.eo b/src/lib/elementary/efl_ui_tree_view_seg_array.eo new file mode 100644 index 0000000000..81873c5a8c --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_seg_array.eo @@ -0,0 +1,63 @@ +import efl_ui_tree_view_model; + +class Efl.Ui.Tree_View_Seg_Array (Efl.Object) +{ + methods { + @property shallow_accessor { + get { + [[ Get a Seg_Array List items accessor ]] + } + values { + acc: accessor<ptr(Efl.Ui.Tree_View_Item)>; + } + } + @property linearized_accessor { + get { + [[ Get a Seg_Array List items accessor ]] + } + values { + acc: accessor<ptr(Efl.Ui.Tree_View_Item)>; + } + } + @property node_accessor { + get { + [[ Get a Seg_Array node accessor ]] + } + values { + acc: accessor<ptr(Efl.Ui.Tree_View_Seg_Array_Node)>; + } + } + count { + [[ Get the number of items in Seg_Array tree ]] + return: int; + } + setup { + [[ Configure a step of Seg_Array tree, this is the max node size ]] + params { + @in initial_step_size: int; + } + } + flush { + [[ flush the Seg_Array tree ]] + } + insert { + [[ Insert a new model in Seg_Array tree at index position ]] + params { + @in parent: ptr(Efl.Ui.Tree_View_Item); + @in index: int; + @in model: Efl.Model; + } + } + remove { + [[ Remove the item at index position in Seg_Array tree ]] + params { + @in index: int; + } + return: ptr(Efl.Ui.Tree_View_Item) @owned; + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + } +} diff --git a/src/lib/elementary/efl_ui_tree_view_seg_array.h b/src/lib/elementary/efl_ui_tree_view_seg_array.h new file mode 100644 index 0000000000..e3abb054e0 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_seg_array.h @@ -0,0 +1,38 @@ +#ifndef EFL_UI_TREE_SEG_ARRAY_H +#define EFL_UI_TREE_SEG_ARRAY_H + +#include <Elementary.h> + +typedef struct _Efl_Ui_Tree_View_Item Efl_Ui_Tree_View_Item; +typedef struct _Efl_Ui_Tree_View_Seg_Array_Node Efl_Ui_Tree_View_Seg_Array_Node; + +typedef struct _Efl_Ui_Tree_View_Seg_Array_Data +{ + Efl_Ui_Tree_View_Seg_Array_Node *root; + + int step_size; + int node_count; + int count; +} Efl_Ui_Tree_View_Seg_Array_Data; + +struct _Efl_Ui_Tree_View_Seg_Array_Node +{ + EINA_RBTREE; + + int length; + int max; + int linearized_first_index, shallow_first_index; + + void* layout_data; + Efl_Ui_Tree_View_Seg_Array_Data *pd; + Efl_Ui_Tree_View_Item* pointers[0]; +}; + + +#define EFL_UI_TREE_VIEW_SEG_ARRAY_POS_GET(_item) \ + _item->shallow_offset + ((Efl_Ui_Tree_View_Seg_Array_Node*)_item->tree_node)->shallow_first_index + +#define EFL_UI_TREE_VIEW_SEG_ARRAY_LINEAR_POS_GET(_item) \ + _item->linearized_offset + ((Efl_Ui_Tree_View_Seg_Array_Node*)_item->tree_node)->linearized_first_index + +#endif diff --git a/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.c b/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.c new file mode 100644 index 0000000000..49209a1e48 --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.c @@ -0,0 +1,78 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include "Eina.h" +#include <Efl.h> +#include <Ecore.h> +#include "Eo.h" +#include <assert.h> + +#define MY_CLASS EFL_UI_TREE_VIEW_SEG_ARRAY_DEPTH_MODEL_CLASS +#define MY_CLASS_NAME "Efl.Ui.Tree_View_Seg_Array_Depth_Model" + +#include "efl_ui_tree_view_seg_array_depth_model.eo.h" +#include "efl_model_accessor_view_private.h" +#include "efl_model_composite_private.h" + +typedef struct _Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data +{ + unsigned int depth; + Eina_Bool readonly; + +} Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data; + +EOLIAN static Efl_Object * +_efl_ui_tree_view_seg_array_depth_model_efl_object_constructor(Eo *obj, Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data *pd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + pd->readonly = EINA_FALSE; + + return obj; +} + +EOLIAN static Efl_Object * +_efl_ui_tree_view_seg_array_depth_model_efl_object_finalize(Eo *obj, Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data *pd) +{ + pd->readonly = EINA_TRUE; + + return obj; +} + +EOLIAN static Eina_Value * +_efl_ui_tree_view_seg_array_depth_model_efl_model_property_get(const Eo *obj, + Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data *pd, + const char *property) +{ + if (strcmp("depth", property)) + return efl_model_property_get(efl_super(obj, MY_CLASS), property); + + return eina_value_uint_new(pd->depth); +} + +EOLIAN static Eina_Future * +_efl_ui_tree_view_seg_array_depth_model_efl_model_property_set(Eo *obj, + Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data *pd, + const char *property, Eina_Value *value) +{ + if (strcmp("depth", property)) + return efl_model_property_set(efl_super(obj, MY_CLASS), property, value); + + if (!pd->readonly && eina_value_uint_get(value, &pd->depth)) + return efl_loop_future_resolved(obj, eina_value_uint_init(pd->depth)); + else + return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_READ_ONLY); +} + +static Eina_Iterator * +_efl_ui_tree_view_seg_array_depth_model_efl_model_properties_get(const Eo *obj, + Efl_Ui_Tree_View_Seg_Array_Depth_Model_Data *pd EINA_UNUSED) +{ + EFL_MODEL_COMPOSITE_PROPERTIES_SUPER(props, + obj, MY_CLASS, + NULL, + "depth"); + return props; +} + +#include "efl_ui_tree_view_seg_array_depth_model.eo.c" diff --git a/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.eo b/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.eo new file mode 100644 index 0000000000..e01ae1773b --- /dev/null +++ b/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.eo @@ -0,0 +1,11 @@ +import efl_ui_tree_view_model; + +class Efl.Ui.Tree_View_Seg_Array_Depth_Model (Efl.Model_Composite) +{ + implements { + Efl.Object.constructor; + Efl.Object.finalize; + Efl.Model.properties { get; } + Efl.Model.property { get; set; } + } +} |