jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=b18a993dc0a1f9aa762dbafcce63155fb73d7d7b

commit b18a993dc0a1f9aa762dbafcce63155fb73d7d7b
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Tue Apr 12 14:10:05 2016 +0900

    Efl.Ui.Box: Add implementation of a simple box
    
    This should be the only linear packing container.
    This replaces: evas box and elm box.
    
    Edje box needs to be kept around for compatibility,
    but it stays an EDC object only (for apps).
    
    Lots of things are still to be fleshed out in this
    box implementation:
    - Simplify smart object / elm widget code
    - Maybe stop using evas object box altogether
    - Implement other layout strategies
    
    @feature
---
 src/lib/elementary/efl_ui_box.c         | 511 ++++++++++++++++++++++++++++++++
 src/lib/elementary/efl_ui_box.eo        |  39 +++
 src/lib/elementary/efl_ui_box_layout.c  | 254 ++++++++++++++++
 src/lib/elementary/efl_ui_box_private.h |  48 +++
 4 files changed, 852 insertions(+)

diff --git a/src/lib/elementary/efl_ui_box.c b/src/lib/elementary/efl_ui_box.c
new file mode 100644
index 0000000..fa3792b
--- /dev/null
+++ b/src/lib/elementary/efl_ui_box.c
@@ -0,0 +1,511 @@
+#include "efl_ui_box_private.h"
+
+/* COPIED FROM ELM_BOX
+ * - removed transition stuff (TODO: add back - needs clean API first)
+ */
+
+static const char SIG_CHILD_ADDED[] = "child,added";
+static const char SIG_CHILD_REMOVED[] = "child,removed";
+static const Evas_Smart_Cb_Description _smart_callbacks[] = {
+   {SIG_CHILD_ADDED, ""},
+   {SIG_CHILD_REMOVED, ""},
+   {NULL, NULL}
+};
+
+static void *
+_efl_ui_box_list_data_get(const Eina_List *list)
+{
+   Evas_Object_Box_Option *opt = eina_list_data_get(list);
+   return opt->obj;
+}
+
+static Eina_Bool
+_child_added_cb_proxy(void *data, const Eo_Event *event)
+{
+   Evas_Object *box = data;
+   Evas_Object_Box_Option *opt = event->info;
+   eo_event_callback_call(box, EFL_PACK_EVENT_CHILD_ADDED, opt->obj);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_child_removed_cb_proxy(void *data, const Eo_Event *event)
+{
+   Evas_Object *box = data;
+   Evas_Object *child = event->info;
+   eo_event_callback_call(box, EFL_PACK_EVENT_CHILD_REMOVED, child);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, 
Efl_Ui_Box_Data *_pd EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_elm_widget_focus_next(Eo *obj, Efl_Ui_Box_Data *_pd EINA_UNUSED, 
Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
+{
+   const Eina_List *items;
+   void *(*list_data_get)(const Eina_List *list);
+
+   /* Focus chain */
+   /* TODO: Change this to use other chain */
+   if ((items = elm_widget_focus_custom_chain_get(obj)))
+     list_data_get = eina_list_data_get;
+   else
+     {
+        ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+        Evas_Object_Box_Data *bd =
+          evas_object_smart_data_get(wd->resize_obj);
+
+        items = bd->children;
+        list_data_get = _efl_ui_box_list_data_get;
+
+        if (!items) return EINA_FALSE;
+     }
+
+   return elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next, 
next_item);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, 
Efl_Ui_Box_Data *_pd EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_elm_widget_focus_direction(Eo *obj EINA_UNUSED, Efl_Ui_Box_Data 
*_pd EINA_UNUSED, const Evas_Object *base, double degree, Evas_Object 
**direction, Elm_Object_Item **direction_item, double *weight)
+{
+   const Eina_List *items;
+   void *(*list_data_get)(const Eina_List *list);
+
+   if ((items = elm_widget_focus_custom_chain_get(obj)))
+     list_data_get = eina_list_data_get;
+   else
+     {
+        ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+        Evas_Object_Box_Data *bd =
+          evas_object_smart_data_get(wd->resize_obj);
+
+        items = bd->children;
+        list_data_get = _efl_ui_box_list_data_get;
+
+        if (!items) return EINA_FALSE;
+     }
+   return elm_widget_focus_list_direction_get
+            (obj, base, items, list_data_get, degree, direction, 
direction_item, weight);
+}
+
+static void
+_sizing_eval(Evas_Object *obj, Efl_Ui_Box_Data *sd)
+{
+   Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
+   Evas_Coord w, h;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   if (sd->delete_me)
+     return;
+
+   evas_object_size_hint_min_get(wd->resize_obj, &minw, &minh);
+   evas_object_size_hint_max_get(wd->resize_obj, &maxw, &maxh);
+   evas_object_size_hint_min_set(obj, minw, minh);
+   evas_object_size_hint_max_set(obj, maxw, maxh);
+
+   evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+   if (w < minw) w = minw;
+   if (h < minh) h = minh;
+   if ((maxw >= 0) && (w > maxw)) w = maxw;
+   if ((maxh >= 0) && (h > maxh)) h = maxh;
+   evas_object_resize(obj, w, h);
+}
+
+static void
+_on_size_hints_changed(void *data, Evas *e EINA_UNUSED,
+                       Evas_Object *resizeobj, void *event_info EINA_UNUSED)
+{
+   Efl_Ui_Box *obj = data;
+   Efl_Ui_Box_Data *pd = eo_data_scope_get(obj, EFL_UI_BOX_CLASS);
+
+   if (obj == resizeobj)
+     efl_pack_layout_request(obj);
+   else
+     _sizing_eval(data, pd);
+}
+
+EOLIAN static void
+_efl_ui_box_evas_object_smart_calculate(Eo *obj, Efl_Ui_Box_Data *pd)
+{
+   if (pd->recalc) return;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   evas_object_smart_need_recalculate_set(wd->resize_obj, EINA_TRUE);
+   pd->recalc = EINA_TRUE;
+   evas_object_smart_calculate(wd->resize_obj);
+   pd->recalc = EINA_FALSE;
+}
+
+EOLIAN static void
+_efl_ui_box_evas_object_smart_add(Eo *obj, Efl_Ui_Box_Data *_pd EINA_UNUSED)
+{
+   Evas *e = evas_object_evas_get(obj);
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   elm_widget_resize_object_set(obj, evas_object_box_add(e), EINA_TRUE);
+   evas_object_box_layout_set(wd->resize_obj, _efl_ui_box_custom_layout, obj, 
NULL);
+
+   evas_object_event_callback_add(wd->resize_obj, 
EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_size_hints_changed, obj);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, 
_on_size_hints_changed, obj);
+
+   evas_obj_smart_add(eo_super(obj, MY_CLASS));
+   elm_widget_sub_object_parent_add(obj);
+
+   eo_event_callback_add(wd->resize_obj, EFL_PACK_EVENT_CHILD_ADDED, 
_child_added_cb_proxy, obj);
+   eo_event_callback_add(wd->resize_obj, EFL_PACK_EVENT_CHILD_REMOVED, 
_child_removed_cb_proxy, obj);
+
+   elm_widget_can_focus_set(obj, EINA_FALSE);
+   elm_widget_highlight_ignore_set(obj, EINA_TRUE);
+
+   // new defaults: fill - no expand
+   evas_object_size_hint_align_set(obj, -1, -1);
+}
+
+EOLIAN static void
+_efl_ui_box_evas_object_smart_del(Eo *obj, Efl_Ui_Box_Data *sd)
+{
+   Eina_List *l;
+   Evas_Object *child;
+
+   sd->delete_me = EINA_TRUE;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   evas_object_event_callback_del_full
+     (wd->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+     _on_size_hints_changed, obj);
+
+   /* let's make our box object the *last* to be processed, since it
+    * may (smart) parent other sub objects here */
+   EINA_LIST_FOREACH (wd->subobjs, l, child)
+     {
+        if (child == wd->resize_obj)
+          {
+             wd->subobjs =
+               eina_list_demote_list(wd->subobjs, l);
+             break;
+          }
+     }
+
+   evas_obj_smart_del(eo_super(obj, MY_CLASS));
+}
+
+EAPI Evas_Object *
+efl_ui_box_add(Evas_Object *parent)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+   Evas_Object *obj = eo_add(MY_CLASS, parent);
+   return obj;
+}
+
+EOLIAN static Eo *
+_efl_ui_box_eo_base_constructor(Eo *obj, Efl_Ui_Box_Data *pd)
+{
+   elm_interface_atspi_accessible_type_set(obj, ELM_ATSPI_TYPE_SKIPPED);
+   obj = eo_constructor(eo_super(obj, MY_CLASS));
+   evas_obj_type_set(obj, MY_CLASS_NAME);
+   evas_obj_smart_callbacks_descriptions_set(obj, _smart_callbacks);
+   elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_FILLER);
+
+   pd->orient = EFL_ORIENT_RIGHT;
+
+   return obj;
+}
+
+/* CLEAN API BELOW */
+
+EOLIAN static int
+_efl_ui_box_efl_pack_contents_count(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED)
+{
+   Evas_Object_Box_Data *bd;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, 0);
+
+   bd = evas_object_smart_data_get(wd->resize_obj);
+   return bd ? eina_list_count(bd->children) : 0;
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_clear(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED)
+{
+   /* EINA_TRUE means to delete objects as well */
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   evas_object_box_remove_all(wd->resize_obj, EINA_TRUE);
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_unpack_all(Eo *obj, Efl_Ui_Box_Data *pd)
+{
+   Evas_Object_Box_Data *bd;
+   Evas_Object_Box_Option *opt;
+   Eina_List *l;
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   /* set this to block _sizing_eval() calls */
+   pd->delete_me = EINA_TRUE;
+   bd = evas_object_smart_data_get(wd->resize_obj);
+   EINA_LIST_FOREACH (bd->children, l, opt)
+     elm_widget_sub_object_del(obj, opt->obj);
+   pd->delete_me = EINA_FALSE;
+
+   /* EINA_FALSE means do not delete objects */
+   evas_object_box_remove_all(wd->resize_obj, EINA_FALSE);
+   /* update size hints */
+   _sizing_eval(obj, pd);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_efl_pack_unpack(Eo *obj, Efl_Ui_Box_Data *pd, Efl_Pack_Item 
*subobj)
+{
+   Eina_Bool ret = EINA_FALSE;
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+
+   if (evas_object_box_remove(wd->resize_obj, subobj))
+     {
+        ret = elm_widget_sub_object_del(obj, subobj);
+        _sizing_eval(obj, pd);
+     }
+
+   return ret;
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_pack(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED, 
Efl_Pack_Item *subobj)
+{
+   efl_pack_end(obj, subobj);
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_linear_pack_end(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED, 
Efl_Pack_Item *subobj)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   elm_widget_sub_object_add(obj, subobj);
+   evas_object_box_append(wd->resize_obj, subobj);
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_linear_pack_begin(Eo *obj, Efl_Ui_Box_Data *_pd 
EINA_UNUSED, Efl_Pack_Item *subobj)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   elm_widget_sub_object_add(obj, subobj);
+   evas_object_box_prepend(wd->resize_obj, subobj);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_efl_pack_linear_pack_before(Eo *obj, Efl_Ui_Box_Data *_pd 
EINA_UNUSED, Efl_Pack_Item *subobj, const Efl_Pack_Item *existing)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+
+   if (!elm_widget_sub_object_add(obj, subobj))
+     return EINA_FALSE;
+
+   if (!evas_object_box_insert_before(wd->resize_obj, subobj, existing))
+     {
+        elm_obj_widget_sub_object_del(obj, subobj);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_box_efl_pack_linear_pack_after(Eo *obj, Efl_Ui_Box_Data *_pd 
EINA_UNUSED, Efl_Pack_Item *subobj, const Efl_Pack_Item *existing)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+
+   if (!elm_widget_sub_object_add(obj, subobj))
+     return EINA_FALSE;
+
+   if (!evas_object_box_insert_after(wd->resize_obj, subobj, existing))
+     {
+        elm_obj_widget_sub_object_del(obj, subobj);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static inline Efl_Pack_Item *
+_box_item(Evas_Object_Box_Option *opt)
+{
+   return opt ? opt->obj : NULL;
+}
+
+EOLIAN static Efl_Pack_Item *
+_efl_ui_box_efl_pack_linear_child_at_get(Eo *obj, Efl_Ui_Box_Data *pd 
EINA_UNUSED, int index)
+{
+   Evas_Object_Box_Data *bd;
+   int cnt;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
+   bd = evas_object_smart_data_get(wd->resize_obj);
+   if (!bd || !bd->children) return NULL;
+
+   if (!index)
+     return _box_item(eina_list_data_get(bd->children));
+   else if (index == -1)
+     return _box_item(eina_list_last_data_get(bd->children));
+
+   cnt = eina_list_count(bd->children);
+   if (!cnt) return NULL;
+
+   if (index >= cnt)
+     return _box_item(eina_list_last_data_get(bd->children));
+   else if (index <= (-cnt))
+     return _box_item(eina_list_data_get(bd->children));
+
+   // this should loop only once
+   while (index < 0)
+     index += cnt;
+
+   return _box_item(eina_list_nth(bd->children, index));
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_linear_child_at_set(Eo *obj, Efl_Ui_Box_Data *pd 
EINA_UNUSED, int index, Efl_Pack_Item *subobj)
+{
+   if (!index)
+     efl_pack_begin(obj, subobj);
+   else if (index == -1)
+     efl_pack_end(obj, subobj);
+   else
+     {
+        Efl_Pack_Item *other = efl_pack_child_at_get(obj, index);
+        if (!other)
+          efl_pack_end(obj, subobj);
+        else
+          efl_pack_after(obj, subobj, other);
+     }
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_layout_update(Eo *obj, Efl_Ui_Box_Data *pd)
+{
+   _sizing_eval(obj, pd);
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_layout_request(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED)
+{
+   evas_object_smart_need_recalculate_set(obj, EINA_TRUE);
+}
+
+static Eina_Bool
+_box_item_iterator_next(Box_Item_Iterator *it, void **data)
+{
+   Efl_Pack_Item *sub;
+
+   if (!eina_iterator_next(it->real_iterator, (void **) &sub))
+     return EINA_FALSE;
+
+   if (data) *data = sub;
+   return EINA_TRUE;
+}
+
+static Elm_Layout *
+_box_item_iterator_get_container(Box_Item_Iterator *it)
+{
+   return it->object;
+}
+
+static void
+_box_item_iterator_free(Box_Item_Iterator *it)
+{
+   eina_iterator_free(it->real_iterator);
+   eina_list_free(it->list);
+   free(it);
+}
+
+EOLIAN static Eina_Iterator *
+_efl_ui_box_efl_pack_contents_iterate(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED)
+{
+   Box_Item_Iterator *it;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
+
+   it = calloc(1, sizeof(*it));
+   if (!it) return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->list = evas_object_box_children_get(wd->resize_obj);
+   it->real_iterator = eina_list_iterator_new(it->list);
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_box_item_iterator_next);
+   it->iterator.get_container = 
FUNC_ITERATOR_GET_CONTAINER(_box_item_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_box_item_iterator_free);
+   it->object = obj;
+
+   return &it->iterator;
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_linear_direction_set(Eo *obj, Efl_Ui_Box_Data *pd, 
Efl_Orient dir)
+{
+   switch (dir)
+     {
+      //case EFL_ORIENT_UP:
+      case EFL_ORIENT_DOWN:
+        pd->orient = EFL_ORIENT_DOWN;
+        break;
+
+      case EFL_ORIENT_RIGHT:
+      //case EFL_ORIENT_LEFT:
+      default:
+        pd->orient = EFL_ORIENT_RIGHT;
+        break;
+     }
+
+   efl_pack_layout_request(obj);
+}
+
+EOLIAN static Efl_Orient
+_efl_ui_box_efl_pack_linear_direction_get(Eo *obj EINA_UNUSED, Efl_Ui_Box_Data 
*pd)
+{
+   return pd->orient;
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_padding_set(Eo *obj, Efl_Ui_Box_Data *pd, double h, 
double v, Eina_Bool scalable)
+{
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   if (h < 0) h = 0;
+   if (v < 0) v = 0;
+   pd->pad.h = h;
+   pd->pad.v = v;
+   pd->pad.scalable = !!scalable;
+   if (pd->pad.scalable)
+     {
+        double scale = elm_object_scale_get(obj);
+        evas_object_box_padding_set(wd->resize_obj, h * scale, v * scale);
+     }
+   else
+     evas_object_box_padding_set(wd->resize_obj, h, v);
+}
+
+EOLIAN static void
+_efl_ui_box_efl_pack_padding_get(Eo *obj, Efl_Ui_Box_Data *pd, double *h, 
double *v, Eina_Bool *scalable)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   if (scalable) *scalable = pd->pad.scalable;
+   if (h) *h = pd->pad.h;
+   if (v) *v = pd->pad.v;
+}
+
+#include "efl_ui_box.eo.c"
diff --git a/src/lib/elementary/efl_ui_box.eo b/src/lib/elementary/efl_ui_box.eo
new file mode 100644
index 0000000..4cc7e8e
--- /dev/null
+++ b/src/lib/elementary/efl_ui_box.eo
@@ -0,0 +1,39 @@
+class Efl.Ui.Box (Elm.Widget, Efl.Pack_Linear)
+{
+   legacy_prefix: null;
+   implements {
+      Eo.Base.constructor;
+
+      // smart obj
+      Evas.Object_Smart.add;
+      Evas.Object_Smart.del;
+      Evas.Object_Smart.calculate;
+
+      // Focus
+      Elm.Widget.focus_direction;
+      Elm.Widget.focus_next_manager_is;
+      Elm.Widget.focus_direction_manager_is;
+      Elm.Widget.focus_next;
+
+      Efl.Pack.contents_iterate;
+      Efl.Pack.contents_count;
+      Efl.Pack.clear;
+      Efl.Pack.unpack_all;
+      Efl.Pack.unpack;
+      Efl.Pack.pack;
+      Efl.Pack.padding.get;
+      Efl.Pack.padding.set;
+      Efl.Pack.layout_update;
+      Efl.Pack.layout_request;
+      Efl.Pack_Linear.pack_begin;
+      Efl.Pack_Linear.pack_end;
+      Efl.Pack_Linear.pack_before;
+      Efl.Pack_Linear.pack_after;
+      Efl.Pack_Linear.child_at.get;
+      Efl.Pack_Linear.child_at.set;
+      //Efl.Pack_Linear.child_index.get;
+      //Efl.Pack_Linear.child_index.set;
+      Efl.Pack_Linear.direction.set;
+      Efl.Pack_Linear.direction.get;
+   }
+}
diff --git a/src/lib/elementary/efl_ui_box_layout.c 
b/src/lib/elementary/efl_ui_box_layout.c
new file mode 100644
index 0000000..d51eca2
--- /dev/null
+++ b/src/lib/elementary/efl_ui_box_layout.c
@@ -0,0 +1,254 @@
+#include "efl_ui_box_private.h"
+
+// FIXME: Aspect support is not implemented
+// FIXME: handle RTL? just invert the horizontal order?
+
+typedef struct _Item_Calc Item_Calc;
+
+struct _Item_Calc
+{
+   Evas_Object *obj;
+   double weight[2];
+   double align[2];
+   int min[2];
+   int req[2];
+   int max[2];
+   int pad[4];
+   int want[2];
+   int id;
+};
+
+void
+_efl_ui_box_custom_layout(Evas_Object *evas_box EINA_UNUSED,
+                          Evas_Object_Box_Data *bd, void *data)
+{
+   Efl_Ui_Box *ui_box = data;
+   Efl_Ui_Box_Data *pd = eo_data_scope_get(ui_box, EFL_UI_BOX_CLASS);
+   Evas_Object_Box_Option *opt;
+   Evas_Object *o;
+   Eina_List *li;
+   int wantw = 0, wanth = 0; // requested size
+   int boxx, boxy, boxw, boxh;
+   Item_Calc *items, *item;
+   Eina_Bool horiz = _horiz(pd->orient), zeroweight = EINA_FALSE;
+   int id = 0, count, boxl = 0, boxr = 0, boxt = 0, boxb = 0;
+   int length, want, deficit = 0, pad, extra = 0, rounding = 0;
+   double cur_pos = 0, weight = 0, scale;
+   double box_align[2];
+
+   evas_object_geometry_get(ui_box, &boxx, &boxy, &boxw, &boxh);
+   evas_object_size_hint_padding_get(ui_box, &boxl, &boxr, &boxt, &boxb);
+   scale = evas_object_scale_get(ui_box);
+
+   // Box align: used if "item has max size and fill" or "no item has a weight"
+   //box_align[0] = bd->align.h;
+   //box_align[1] = bd->align.v;
+   evas_object_size_hint_align_get(ui_box, &box_align[0], &box_align[1]);
+
+   count = eina_list_count(bd->children);
+   if (!count)
+     {
+        evas_object_size_hint_min_set(ui_box, 0, 0);
+        return;
+     }
+
+   items = alloca(count * sizeof(*items));
+#ifdef DEBUG
+   memset(items, 0, count * sizeof(*items));
+#endif
+
+   // scan all items, get their properties, calculate total weight & min size
+   EINA_LIST_FOREACH(bd->children, li, opt)
+     {
+        item = &items[id];
+        o = item->obj = opt->obj;
+
+        evas_object_size_hint_weight_get(o, &item->weight[0], 
&item->weight[1]);
+        if (item->weight[0] < 0) item->weight[0] = 0;
+        if (item->weight[1] < 0) item->weight[1] = 0;
+
+        evas_object_size_hint_align_get(o, &item->align[0], &item->align[1]);
+        if (item->align[0] < 0) item->align[0] = -1;
+        if (item->align[1] < 0) item->align[1] = -1;
+        if (item->align[0] > 1) item->align[0] = 1;
+        if (item->align[1] > 1) item->align[1] = 1;
+
+        evas_object_size_hint_padding_get(o, &item->pad[0], &item->pad[1], 
&item->pad[2], &item->pad[3]);
+        evas_object_size_hint_min_get(o, &item->min[0], &item->min[1]);
+        if (item->min[0] < 0) item->min[0] = 0;
+        if (item->min[1] < 0) item->min[1] = 0;
+
+        evas_object_size_hint_max_get(o, &item->max[0], &item->max[1]);
+        if (item->max[0] <= 0) item->max[0] = INT_MAX;
+        if (item->max[1] <= 0) item->max[1] = INT_MAX;
+        if (item->max[0] < item->min[0]) item->max[0] = item->min[0];
+        if (item->max[1] < item->min[1]) item->max[1] = item->min[1];
+
+        evas_object_size_hint_request_get(o, &item->req[0], &item->req[1]);
+        if (item->req[0] < 0) item->req[0] = 0;
+        if (item->req[1] < 0) item->req[1] = 0;
+
+        item->want[0] = MAX(item->req[0], item->min[0]) + item->pad[0] + 
item->pad[1];
+        item->want[1] = MAX(item->req[1], item->min[1]) + item->pad[2] + 
item->pad[3];
+
+        if (horiz)
+          {
+             weight += item->weight[0];
+             wantw += item->want[0];
+             if (item->want[1] > wanth)
+               wanth = item->want[1];
+          }
+        else
+          {
+             weight += item->weight[1];
+             wanth += item->want[1];
+             if (item->want[0] > wantw)
+               wantw = item->want[0];
+          }
+
+        item->id = id++;
+     }
+
+   // box outer margin
+   boxw -= boxl + boxr;
+   boxh -= boxt + boxb;
+
+   // total space & available space
+   if (horiz)
+     {
+        length = boxw;
+        want = wantw;
+        pad = pd->pad.scalable ? (pd->pad.h * scale) : pd->pad.h;
+     }
+   else
+     {
+        length = boxh;
+        want = wanth;
+        pad = pd->pad.scalable ? (pd->pad.v * scale) : pd->pad.v;
+     }
+
+   // padding can not be squeezed (note: could make it an option)
+   length -= pad * (count - 1);
+
+   // available space. if <0 we overflow
+   extra = length - want;
+
+   if (horiz)
+     {
+        evas_object_size_hint_min_set(ui_box,
+                                      wantw + boxl + boxr + pad * (count - 1),
+                                      wanth + boxt + boxb);
+     }
+   else
+     {
+        evas_object_size_hint_min_set(ui_box,
+                                      wantw + boxl + boxr,
+                                      wanth + pad * (count - 1) + boxt + boxb);
+     }
+
+   if (extra < 0)
+     {
+        // note: deficit unused
+        deficit = (-extra);
+        extra = 0;
+     }
+
+   if (!weight)
+     {
+        double balign = box_align[!horiz];
+        if (balign < 0)
+          {
+             // box is filled, set all weights to be equal
+             zeroweight = EINA_TRUE;
+          }
+        else
+          {
+             // move bounding box according to box align
+             cur_pos = extra * balign;
+          }
+        weight = count;
+     }
+
+   // reset box_align to 0.5 if filled (only used by items with max size)
+   if (box_align[0] < 0) box_align[0] = 0.5;
+   if (box_align[1] < 0) box_align[1] = 0.5;
+
+   for (id = 0; id < count; id++)
+     {
+        double cx, cy, cw, ch, x, y, w, h;
+        item = &items[id];
+
+        // extra rounding up (compensate cumulative error)
+        if ((item->id == (count - 1)) && (cur_pos - floor(cur_pos) >= 0.5))
+          rounding = 1;
+
+        if (horiz)
+          {
+             cx = boxx + boxl + cur_pos;
+             cy = boxy + boxt;
+             cw = item->want[0] + rounding + (zeroweight ? 1.0 : 
item->weight[0]) * extra / weight;
+             ch = boxh;
+             cur_pos += cw + pad;
+          }
+        else
+          {
+             cx = boxx + boxl;
+             cy = boxy + boxt + cur_pos;
+             cw = boxw;
+             ch = item->want[1] + rounding + (zeroweight ? 1.0 : 
item->weight[1]) * extra / weight;
+             cur_pos += ch + pad;
+          }
+
+        // horizontally
+        if (item->max[0] < INT_MAX)
+          {
+             w = MIN(MAX(item->want[0] - item->pad[0] - item->pad[1], 
item->max[0]), cw);
+             if (item->align[0] < 0)
+               {
+                  // bad case: fill+max are not good together
+                  x = cx + ((cw - w) * box_align[0]) + item->pad[0];
+               }
+             else
+               x = cx + ((cw - w) * item->align[0]) + item->pad[0];
+          }
+        else if (item->align[0] < 0)
+          {
+             // fill x
+             w = cw - item->pad[0] - item->pad[1];
+             x = cx + item->pad[0];
+          }
+        else
+          {
+             w = item->want[0] - item->pad[0] - item->pad[1];
+             x = cx + ((cw - w) * item->align[0]) + item->pad[0];
+          }
+
+        // vertically
+        if (item->max[1] < INT_MAX)
+          {
+             h = MIN(MAX(item->want[1] - item->pad[2] - item->pad[3], 
item->max[1]), ch);
+             if (item->align[1] < 0)
+               {
+                  // bad case: fill+max are not good together
+                  y = cy + ((ch - h) * box_align[1]) + item->pad[2];
+               }
+             else
+               y = cy + ((ch - h) * item->align[1]) + item->pad[2];
+          }
+        else if (item->align[1] < 0)
+          {
+             // fill y
+             h = ch - item->pad[2] - item->pad[3];
+             y = cy + item->pad[2];
+          }
+        else
+          {
+             h = item->want[1] - item->pad[2] - item->pad[3];
+             y = cy + ((ch - h) * item->align[1]) + item->pad[2];
+          }
+
+        //DBG("[%2d/%2d] cell: %.0f,%.0f %.0fx%.0f item: %.0f,%.0f %.0fx%.0f",
+        //    id, count, cx, cy, cw, ch, x, y, w, h);
+        evas_object_geometry_set(item->obj, x, y, w, h);
+     }
+}
diff --git a/src/lib/elementary/efl_ui_box_private.h 
b/src/lib/elementary/efl_ui_box_private.h
new file mode 100644
index 0000000..38f9a8e
--- /dev/null
+++ b/src/lib/elementary/efl_ui_box_private.h
@@ -0,0 +1,48 @@
+#ifndef EFL_UI_BOX_PRIVATE_H
+#define EFL_UI_BOX_PRIVATE_H
+
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define EFL_PACK_PROTECTED
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_BOX_CLASS
+#define MY_CLASS_NAME "Efl.Ui.Box"
+
+void _efl_ui_box_custom_layout(Evas_Object *evas_box, Evas_Object_Box_Data 
*priv, void *data);
+
+typedef struct _Efl_Ui_Box_Data Efl_Ui_Box_Data;
+typedef struct _Box_Item_Iterator Box_Item_Iterator;
+
+struct _Efl_Ui_Box_Data
+{
+   Efl_Orient orient;
+   Eina_Bool homogeneous : 1;
+   Eina_Bool delete_me : 1;
+   Eina_Bool recalc : 1;
+
+   struct {
+      double h, v;
+      Eina_Bool scalable: 1;
+   } pad;
+};
+
+struct _Box_Item_Iterator
+{
+   Eina_List     *list;
+   Eina_Iterator  iterator;
+   Eina_Iterator *real_iterator;
+   Efl_Ui_Box    *object;
+};
+
+static inline Eina_Bool
+_horiz(Efl_Orient dir)
+{
+   return dir % 180 == EFL_ORIENT_RIGHT;
+}
+
+#endif

-- 


Reply via email to