diff --git a/src/lib/elementary/efl_ui_box.c b/src/lib/elementary/efl_ui_box.c new file mode 100644 index 0000000000..fa3792bf42 --- /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 0000000000..4cc7e8ed7b --- /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 0000000000..d51eca2d4a --- /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 0000000000..38f9a8e0fd --- /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 +#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