aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Lira <larry@expertisesolutions.com.br>2019-01-24 17:07:07 -0200
committerLarry Lira <larry@expertisesolutions.com.br>2019-01-31 20:22:42 -0200
commit7e5dff70813e1f02cbfca5c0d47e1e91b335dc6f (patch)
tree193f3a0dec6c40a7d82b23cfa45f9a59246c133c
parentefl_interfaces: missing interfaces prefix (diff)
downloadefl-devs/larrylira/treeview.tar.gz
Efl.Ui.Tree_View: added new MVVM asynchronous widgetdevs/larrylira/treeview
new classes added: Efl.Ui.Tree_View Efl.Ui.Tree_View_Layouter Efl.Ui.Tree_Factory added tree_view_example_1 in elementary example
-rw-r--r--data/elementary/themes/edc/efl/list.edc4
-rw-r--r--src/Makefile_Elementary.am14
-rw-r--r--src/examples/elementary.mk6
-rw-r--r--src/examples/elementary/.gitignore1
-rw-r--r--src/examples/elementary/tree_view_example_1.c129
-rw-r--r--src/lib/elementary/Elementary.h7
-rw-r--r--src/lib/elementary/efl_ui.eot2
-rw-r--r--src/lib/elementary/efl_ui_tree_factory.c93
-rw-r--r--src/lib/elementary/efl_ui_tree_factory.eo26
-rw-r--r--src/lib/elementary/efl_ui_tree_view.c1158
-rw-r--r--src/lib/elementary/efl_ui_tree_view.eo96
-rw-r--r--src/lib/elementary/efl_ui_tree_view_layouter.c722
-rw-r--r--src/lib/elementary/efl_ui_tree_view_layouter.eo10
-rw-r--r--src/lib/elementary/efl_ui_tree_view_model.eo68
-rw-r--r--src/lib/elementary/efl_ui_tree_view_pan.eo12
-rw-r--r--src/lib/elementary/efl_ui_tree_view_private.h73
-rw-r--r--src/lib/elementary/efl_ui_tree_view_relayout.eo30
-rw-r--r--src/lib/elementary/efl_ui_tree_view_seg_array.c469
-rw-r--r--src/lib/elementary/efl_ui_tree_view_seg_array.h50
-rw-r--r--src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.c79
-rw-r--r--src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.eo11
-rw-r--r--src/lib/elementary/meson.build14
22 files changed, 3072 insertions, 2 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 2ed29dd393..a68dc0a1ec 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -81,6 +81,9 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_list_view.eo \
lib/elementary/efl_ui_list_view_model.eo \
lib/elementary/efl_ui_list_view_pan.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_item.eo \
lib/elementary/efl_ui_list_item.eo \
lib/elementary/efl_ui_list_default_item_part_icon.eo \
@@ -180,6 +183,10 @@ elm_private_eolian_files = \
lib/elementary/efl_ui_homogeneous_model.eo \
lib/elementary/efl_ui_exact_model.eo \
lib/elementary/efl_ui_average_model.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 \
$(NULL)
# Legacy classes - not part of public EO API
@@ -431,6 +438,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 \
@@ -661,6 +669,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 \
@@ -865,7 +874,12 @@ 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_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_tree_factory.c \
lib/elementary/efl_ui_scroller.c \
lib/elementary/efl_ui_scroll_manager.c \
lib/elementary/efl_ui_pan.c \
diff --git a/src/examples/elementary.mk b/src/examples/elementary.mk
index 0d817258dc..604cecd5f0 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/tree_view_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/tree_view_example_1
#benchmark3d
#sphere-hunter
diff --git a/src/examples/elementary/.gitignore b/src/examples/elementary/.gitignore
index 54d71c14a0..1ac5db594b 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
+/tree_view_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/tree_view_example_1.c b/src/examples/elementary/tree_view_example_1.c
new file mode 100644
index 0000000000..aadf601b95
--- /dev/null
+++ b/src/examples/elementary/tree_view_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 10
+
+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_Generic_Model *parent, Eina_Value *value, const char *msg)
+{
+ Efl_Generic_Model *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_Generic_Model *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(Eo *win)
+{
+ Efl_Generic_Model *root, *child;
+ Eina_Value vtext;
+ unsigned int i;
+
+ srand(time(NULL));
+ eina_value_setup(&vtext, EINA_VALUE_TYPE_STRING);
+ root = efl_add(EFL_GENERIC_MODEL_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, 1, 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;
+ Eo *win, *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_LAYOUT_FACTORY_CLASS, win);
+ efl_ui_model_connect(factory, "efl.text", "name");
+ efl_ui_layout_factory_theme_config(factory, "list_item", NULL, "default");
+
+ tree = efl_add(EFL_UI_TREE_VIEW_CLASS, win
+ , efl_ui_tree_view_layout_factory_set(efl_added, factory)
+ , efl_ui_view_model_set(efl_added, 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 5bb8374e3a..8f8a8c815e 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -330,6 +330,7 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel);
# 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>
@@ -348,6 +349,12 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel);
# include <efl_ui_list_view_pan.eo.h>
# include <efl_ui_widget_factory.eo.h>
# include <efl_ui_caching_factory.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.eot b/src/lib/elementary/efl_ui.eot
index ce17980e56..7d3985d0fa 100644
--- a/src/lib/elementary/efl_ui.eot
+++ b/src/lib/elementary/efl_ui.eot
@@ -104,3 +104,5 @@ enum Efl.Ui.Widget_Orientation_Mode
/* Types for A11Y (internal/beta API) */
type @extern Efl.Access.Action_Data: __undefined_type; [[Internal struct for accesssibility.]]
+
+struct Efl_Ui_Tree_View_Seg_Array;
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..b25f6f38f5
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_factory.c
@@ -0,0 +1,93 @@
+#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_Stringshare *exp_style;
+} Efl_Ui_Tree_Factory_Data;
+
+typedef struct _Efl_Ui_Tree_Factory_Request
+{
+ Efl_Ui_Tree_Factory_Data *pd;
+ Efl_Model *model;
+} Efl_Ui_Tree_Factory_Request;
+
+EOLIAN static void
+_efl_ui_tree_factory_efl_object_destructor(Eo *obj, Efl_Ui_Tree_Factory_Data *pd)
+{
+ eina_stringshare_del(pd->exp_style);
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+static Eina_Value
+_efl_ui_tree_factory_connect(Eo *obj, void *data, const Eina_Value value)
+{
+ Efl_Ui_Tree_Factory_Request *r = data;
+ Efl_Ui_Tree_Factory_Data *pd = r->pd;
+ Efl_Model *model = r->model;
+ Efl_Ui_Tree_Factory_Item_Event evt;
+
+ evt.model = model;
+ evt.expandable = EINA_FALSE;
+
+ if (efl_model_children_count_get(model) > 0)
+ evt.expandable = EINA_TRUE;
+
+ efl_event_callback_call(obj, EFL_UI_TREE_FACTORY_EVENT_ITEM_CREATE, &evt);
+
+ if (pd->exp_style && evt.expandable)
+ {
+ Efl_Gfx_Entity *layout;
+ eina_value_pget(&value, &layout);
+ efl_ui_widget_style_set(layout, pd->exp_style);
+ }
+
+ return value;
+}
+
+static void
+_efl_ui_tree_factory_create_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
+{
+ Efl_Ui_Tree_Factory_Request *r = data;
+
+ efl_unref(r->model);
+ free(r);
+}
+
+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)
+{
+ Efl_Ui_Tree_Factory_Request *r;
+ Eina_Future *f;
+
+ r = calloc(1, sizeof (Efl_Ui_Tree_Factory_Request));
+ if (!r) return efl_loop_future_rejected(obj, ENOMEM);
+
+ r->pd = pd;
+ r->model = efl_ref(model);
+
+ f = efl_ui_factory_create(efl_super(obj, MY_CLASS), model, parent);
+
+ return efl_future_then(obj, f,
+ .success_type = EINA_VALUE_TYPE_OBJECT,
+ .success = _efl_ui_tree_factory_connect,
+ .data = r,
+ .free = _efl_ui_tree_factory_create_cleanup);
+}
+
+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..3e3d2c393f
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_factory.eo
@@ -0,0 +1,26 @@
+struct Efl.Ui.Tree_Factory_Item_Event
+{
+ model: Efl.Model;
+ expandable: bool;
+}
+
+class Efl.Ui.Tree_Factory extends 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.destructor;
+ Efl.Ui.Factory.create;
+ }
+}
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..41a9728bf6
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view.c
@@ -0,0 +1,1158 @@
+#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->scrl_mgr = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj,
+ efl_ui_mirrored_set(efl_added, efl_ui_mirrored_get(obj)));
+ efl_composite_attach(obj, pd->scrl_mgr);
+ pd->pan_obj = efl_add(MY_PAN_CLASS, obj);
+ pan_data = efl_data_scope_get(pd->pan_obj, MY_PAN_CLASS);
+ pan_data->wobj = obj;
+
+ efl_ui_scroll_manager_pan_set(pd->scrl_mgr, pd->pan_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);
+ 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_ui_tree_view_seg_array_setup(32);
+
+ efl_event_callback_add(obj, EFL_UI_FOCUS_MANAGER_EVENT_FOCUS_CHANGED, _list_element_focused, NULL);
+
+ efl_ui_focus_composition_custom_manager_set(obj, obj);
+ efl_ui_focus_composition_logical_mode_set(obj, EINA_TRUE);
+
+// pd->style = eina_stringshare_add(elm_widget_style_get(obj));
+
+ //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_ui_tree_view_seg_array_free(pd->segarray);
+
+ 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;
+ Efl_Ui_Tree_View_Data *pd;
+};
+
+static Eina_Value
+_content_created(Eo *obj EINA_UNUSED, 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;
+
+ 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(Eo *obj EINA_UNUSED, 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->pd = pd;
+
+ item->layout_request = efl_ui_view_factory_create_with_event(pd->factory, item->model, obj);
+ item->layout_request = efl_future_then(obj, item->layout_request,
+ .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, NULL);
+ 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, NULL);
+ 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..0c7a9f03cc
--- /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 extends Efl.Ui.Layout implements 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..a8df96bf94
--- /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, NULL);
+}
+
+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);
+ 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;
+
+ 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..a4db60757b
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_layouter.eo
@@ -0,0 +1,10 @@
+class Efl.Ui.Tree_View_Layouter extends Efl.Object implements 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..a39b9977a5
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_model.eo
@@ -0,0 +1,68 @@
+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: ptr(Efl_Ui_Tree_View_Seg_Array);
+ expanded: bool;
+ min: Eina.Size2D;
+ size: Eina.Size2D;
+ pos: Eina.Position2D;
+}
+
+interface Efl.Ui.Tree_View_Model extends Efl.Interface
+{
+ 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..90ef89470c
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_pan.eo
@@ -0,0 +1,12 @@
+class Efl.Ui.Tree_View_Pan extends 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..1188456aa6
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_relayout.eo
@@ -0,0 +1,30 @@
+interface Efl.Ui.Tree_View_Relayout extends Efl.Interface
+{
+ methods {
+ layout_do {
+ params {
+ modeler: Efl.Ui.Tree_View_Model;
+ first: int;
+ children: ptr(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..07c2034d4d
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_seg_array.c
@@ -0,0 +1,469 @@
+#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_free(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* seg_array, 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) + seg_array->step_size*sizeof(Efl_Ui_Tree_View_Item*));
+ node->linearized_first_index = linearized_first_index;
+ node->shallow_first_index = shallow_first_index;
+ node->max = seg_array->step_size;
+ node->seg_array = seg_array;
+ seg_array->root = (void*)eina_rbtree_inline_insert(EINA_RBTREE_GET(seg_array->root), EINA_RBTREE_GET(node),
+ EINA_RBTREE_CMP_NODE_CB(&_shallow_rbtree_compare), NULL);
+ seg_array->node_count++;
+ return node;
+}
+
+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;
+}
+
+static void
+_efl_ui_tree_view_seg_array_insert_at_node(Efl_Ui_Tree_View_Seg_Array* seg_array, 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(seg_array, 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(seg_array->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*)seg_array->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);
+ seg_array->count++;
+}
+
+typedef struct _Efl_Ui_Tree_View_Segarray_Eina_Accessor_Shallow
+{
+ Eina_Accessor vtable;
+ Efl_Ui_Tree_View_Seg_Array* 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;
+}
+
+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* 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;
+}
+
+typedef struct _Efl_Ui_Tree_View_Segarray_Node_Accessor
+{
+ Eina_Accessor vtable;
+ Efl_Ui_Tree_View_Seg_Array* 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* 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;
+}
+
+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;
+}
+
+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->seg_array);
+
+ 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->seg_array->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);
+}
+
+/* External methods */
+
+Efl_Ui_Tree_View_Seg_Array*
+efl_ui_tree_view_seg_array_setup(int size)
+{
+
+ Efl_Ui_Tree_View_Seg_Array *seg_array = calloc(1, sizeof(Efl_Ui_Tree_View_Seg_Array));
+ seg_array->step_size = size;
+
+ return seg_array;
+}
+
+void
+efl_ui_tree_view_seg_array_free(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ if (seg_array->root)
+ eina_rbtree_delete(EINA_RBTREE_GET(seg_array->root), EINA_RBTREE_FREE_CB(_free_node), NULL);
+
+ free(seg_array);
+}
+
+void
+efl_ui_tree_view_seg_array_flush(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ if (seg_array->root)
+ eina_rbtree_delete(EINA_RBTREE_GET(seg_array->root), EINA_RBTREE_FREE_CB(_free_node), NULL);
+
+ seg_array->root = NULL;
+ seg_array->node_count = 0;
+ seg_array->count = 0;
+}
+
+int
+efl_ui_tree_view_seg_array_count(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ return seg_array->count;
+}
+
+void
+efl_ui_tree_view_seg_array_insert(Efl_Ui_Tree_View_Seg_Array *seg_array, 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* priv = seg_array;
+ Efl_Ui_Tree_View_Item* item;
+ Eina_Iterator* iterator;
+
+ item = _create_item_partial(model, parent);
+
+ if (parent)
+ {
+ if (!parent->segarray)
+ parent->segarray = efl_ui_tree_view_seg_array_setup(seg_array->step_size);
+
+ _efl_ui_tree_view_seg_array_fix_offset (parent);
+ seg_array->count++;
+ priv = parent->segarray;
+ }
+
+ 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);
+}
+
+/* TODO */
+Efl_Ui_Tree_View_Item*
+efl_ui_tree_view_seg_array_remove(Efl_Ui_Tree_View_Seg_Array *seg_array EINA_UNUSED, int index EINA_UNUSED)
+{
+ return NULL;
+}
+
+Eina_Accessor*
+efl_ui_tree_view_seg_array_shallow_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ 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, seg_array);
+ return &acc->vtable;
+}
+
+Eina_Accessor*
+efl_ui_tree_view_seg_array_linearized_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ return efl_ui_tree_view_seg_array_shallow_accessor_get(seg_array);
+}
+
+Eina_Accessor*
+efl_ui_tree_view_seg_array_node_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array)
+{
+ 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, seg_array);
+ return &acc->vtable;
+}
+
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..a4169c6481
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_seg_array.h
@@ -0,0 +1,50 @@
+#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
+{
+ Efl_Ui_Tree_View_Seg_Array_Node* root;
+
+ int step_size;
+ int node_count;
+ int count;
+} Efl_Ui_Tree_View_Seg_Array;
+
+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* seg_array;
+ Efl_Ui_Tree_View_Item* pointers[0];
+};
+
+
+Efl_Ui_Tree_View_Seg_Array* efl_ui_tree_view_seg_array_setup(int size);
+void efl_ui_tree_view_seg_array_free(Efl_Ui_Tree_View_Seg_Array *seg_array);
+void efl_ui_tree_view_seg_array_flush(Efl_Ui_Tree_View_Seg_Array *seg_array);
+int efl_ui_tree_view_seg_array_count(Efl_Ui_Tree_View_Seg_Array *seg_array);
+
+void efl_ui_tree_view_seg_array_insert(Efl_Ui_Tree_View_Seg_Array *seg_array, Efl_Ui_Tree_View_Item *parent, int shallow_index, Efl_Model *model);
+Efl_Ui_Tree_View_Item* efl_ui_tree_view_seg_array_remove(Efl_Ui_Tree_View_Seg_Array *seg_array, int index);
+
+Eina_Accessor* efl_ui_tree_view_seg_array_shallow_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array);
+Eina_Accessor* efl_ui_tree_view_seg_array_linearized_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array);
+Eina_Accessor* efl_ui_tree_view_seg_array_node_accessor_get(Efl_Ui_Tree_View_Seg_Array *seg_array);
+
+#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..4b6caceb1c
--- /dev/null
+++ b/src/lib/elementary/efl_ui_tree_view_seg_array_depth_model.c
@@ -0,0 +1,79 @@
+#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_composite_model_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)
+ return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_READ_ONLY);
+
+ eina_value_uint_get(value, &pd->depth);
+ return efl_loop_future_resolved(obj, eina_value_uint_init(pd->depth));
+}
+
+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_COMPOSITE_MODEL_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..203aec7a95
--- /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 extends Efl.Composite_Model
+{
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.finalize;
+ Efl.Model.properties { get; }
+ Efl.Model.property { get; set; }
+ }
+}
diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build
index cb12e6dd95..de36d816db 100644
--- a/src/lib/elementary/meson.build
+++ b/src/lib/elementary/meson.build
@@ -194,6 +194,7 @@ pub_eo_files = [
'efl_ui_focus_util.eo',
'efl_ui_flip_part.eo',
'efl_ui_layout_factory.eo',
+ 'efl_ui_tree_factory.eo',
'efl_ui_layout_part.eo',
'efl_ui_layout_part_box.eo',
'efl_ui_layout_part_content.eo',
@@ -204,6 +205,9 @@ pub_eo_files = [
'efl_ui_list_view.eo',
'efl_ui_list_view_model.eo',
'efl_ui_list_view_pan.eo',
+ 'efl_ui_tree_view.eo',
+ 'efl_ui_tree_view_model.eo',
+ 'efl_ui_tree_view_pan.eo',
'efl_ui_item.eo',
'efl_ui_list_item.eo',
'efl_ui_list_default_item_part_icon.eo',
@@ -341,6 +345,9 @@ priv_eo_files = [
'efl_ui_homogeneous_model.eo',
'efl_ui_exact_model.eo',
'efl_ui_average_model.eo',
+ 'efl_ui_tree_view_seg_array_depth_model.eo',
+ 'efl_ui_tree_view_relayout.eo',
+ 'efl_ui_tree_view_layouter.eo',
]
priv_eo_file_target = []
@@ -456,6 +463,8 @@ elementary_headers_unstable = [
'efl_ui_grid_private.h',
'efl_ui_list_view_private.h',
'efl_ui_list_view_seg_array.h',
+ 'efl_ui_tree_view_private.h',
+ 'efl_ui_tree_view_seg_array.h',
'elm_widget_web.h',
'efl_ui_clock.h',
'elm_code.h',
@@ -887,6 +896,11 @@ elementary_src = [
'efl_ui_list_view_precise_layouter.c',
'efl_ui_list_view_seg_array.c',
'efl_ui_layout_factory.c',
+ 'efl_ui_tree_view.c',
+ 'efl_ui_tree_view_layouter.c',
+ 'efl_ui_tree_view_seg_array.c',
+ 'efl_ui_tree_view_seg_array_depth_model.c',
+ 'efl_ui_tree_factory.c',
'efl_ui_scroller.c',
'efl_ui_scroll_manager.c',
'efl_ui_pan.c',