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
This commit is contained in:
Jean-Philippe Andre 2016-04-12 14:10:05 +09:00
parent 57e64ee65b
commit b18a993dc0
4 changed files with 852 additions and 0 deletions

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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