2016-06-08 04:40:50 -07:00
|
|
|
#define EFL_GFX_SIZE_HINT_PROTECTED
|
|
|
|
|
2016-04-11 22:10:05 -07:00
|
|
|
#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 max[2];
|
|
|
|
int pad[4];
|
|
|
|
int want[2];
|
|
|
|
int id;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
Efl.Ui.Box: Implement way to override layout function
So, since we don't have function pointers, all the solutions
to reimplementing the layout function are quite convoluted:
1. use events
2. reimplement layout func
3. use an extra object
4. use a generic class (non instanciated)
Promises don't apply here (layout will run multiple times).
Problems:
1. Multiple event callbacks will be called, resulting in
potential performance impact, extra events, etc...
Also, there is no way to define standard implementations
that would be provided by the framework.
2. Reimplementation of a function requires extra EO work
(create an EO class, etc...), doesn't allow on-the-fly
change of the layout method.
3. Probably the best solution is to have an object implementing
the layout. But this means creating an extra object along
with the container.
4. To avoid the extra object, use a class, and reimplement
a @class function. This unfortunately requires extra
EO work.
Solution 4. has been selected, but it's not very nice...
2016-04-12 00:20:54 -07:00
|
|
|
_efl_ui_box_custom_layout(Efl_Ui_Box *ui_box, Evas_Object_Box_Data *bd)
|
2016-04-11 22:10:05 -07:00
|
|
|
{
|
2016-08-15 06:44:41 -07:00
|
|
|
Efl_Ui_Box_Data *pd = efl_data_scope_get(ui_box, EFL_UI_BOX_CLASS);
|
2016-04-11 22:10:05 -07:00
|
|
|
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;
|
2017-08-09 06:36:29 -07:00
|
|
|
Eina_Bool horiz = efl_ui_dir_is_horizontal(pd->dir, EINA_FALSE);
|
|
|
|
Eina_Bool zeroweight = EINA_FALSE;
|
2016-04-11 22:10:05 -07:00
|
|
|
int id = 0, count, boxl = 0, boxr = 0, boxt = 0, boxb = 0;
|
2016-05-15 07:56:59 -07:00
|
|
|
int length, want, pad, extra = 0, rounding = 0;
|
2016-04-15 01:06:14 -07:00
|
|
|
double cur_pos = 0, weight[2] = { 0, 0 }, scale;
|
2016-04-11 22:10:05 -07:00
|
|
|
double box_align[2];
|
2016-04-15 01:06:14 -07:00
|
|
|
Eina_Bool box_fill[2] = { EINA_FALSE, EINA_FALSE };
|
2016-04-11 22:10:05 -07:00
|
|
|
|
|
|
|
evas_object_geometry_get(ui_box, &boxx, &boxy, &boxw, &boxh);
|
2016-06-08 04:40:50 -07:00
|
|
|
efl_gfx_size_hint_margin_get(ui_box, &boxl, &boxr, &boxt, &boxb);
|
2016-04-11 22:10:05 -07:00
|
|
|
scale = evas_object_scale_get(ui_box);
|
|
|
|
|
|
|
|
// Box align: used if "item has max size and fill" or "no item has a weight"
|
2016-04-15 01:06:14 -07:00
|
|
|
// Note: cells always expand on the orthogonal direction
|
|
|
|
box_align[0] = pd->align.h;
|
|
|
|
box_align[1] = pd->align.v;
|
|
|
|
if (box_align[0] < 0)
|
|
|
|
{
|
|
|
|
box_fill[0] = EINA_TRUE;
|
|
|
|
box_align[0] = 0.5;
|
|
|
|
}
|
|
|
|
if (box_align[1] < 0)
|
|
|
|
{
|
|
|
|
box_fill[1] = EINA_TRUE;
|
|
|
|
box_align[1] = 0.5;
|
|
|
|
}
|
2016-04-11 22:10:05 -07:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-06-08 04:40:50 -07:00
|
|
|
efl_gfx_size_hint_weight_get(o, &item->weight[0], &item->weight[1]);
|
|
|
|
efl_gfx_size_hint_align_get(o, &item->align[0], &item->align[1]);
|
|
|
|
efl_gfx_size_hint_margin_get(o, &item->pad[0], &item->pad[1], &item->pad[2], &item->pad[3]);
|
|
|
|
efl_gfx_size_hint_max_get(o, &item->max[0], &item->max[1]);
|
|
|
|
efl_gfx_size_hint_combined_min_get(o, &item->want[0], &item->want[1]);
|
|
|
|
|
2016-04-11 22:10:05 -07:00
|
|
|
if (item->weight[0] < 0) item->weight[0] = 0;
|
|
|
|
if (item->weight[1] < 0) item->weight[1] = 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-06-08 04:40:50 -07:00
|
|
|
if (item->want[0] < 0) item->want[0] = 0;
|
|
|
|
if (item->want[1] < 0) item->want[1] = 0;
|
2016-04-11 22:10:05 -07:00
|
|
|
|
|
|
|
if (item->max[0] <= 0) item->max[0] = INT_MAX;
|
|
|
|
if (item->max[1] <= 0) item->max[1] = INT_MAX;
|
2016-06-08 04:40:50 -07:00
|
|
|
if (item->max[0] < item->want[0]) item->max[0] = item->want[0];
|
|
|
|
if (item->max[1] < item->want[1]) item->max[1] = item->want[1];
|
2016-04-11 22:10:05 -07:00
|
|
|
|
2016-06-08 04:40:50 -07:00
|
|
|
item->want[0] += item->pad[0] + item->pad[1];
|
|
|
|
item->want[1] += item->pad[2] + item->pad[3];
|
2016-04-11 22:10:05 -07:00
|
|
|
|
2016-04-15 01:06:14 -07:00
|
|
|
weight[0] += item->weight[0];
|
|
|
|
weight[1] += item->weight[1];
|
2016-04-11 22:10:05 -07:00
|
|
|
if (horiz)
|
|
|
|
{
|
|
|
|
wantw += item->want[0];
|
|
|
|
if (item->want[1] > wanth)
|
|
|
|
wanth = item->want[1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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;
|
2016-04-15 01:06:14 -07:00
|
|
|
boxx += boxl;
|
|
|
|
boxy += boxt;
|
2016-04-11 22:10:05 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2016-05-15 07:56:59 -07:00
|
|
|
if (extra < 0) extra = 0;
|
2016-04-11 22:10:05 -07:00
|
|
|
|
2017-01-06 09:57:46 -08:00
|
|
|
if (EINA_DBL_EQ(weight[!horiz], 0))
|
2016-04-11 22:10:05 -07:00
|
|
|
{
|
2016-04-15 01:06:14 -07:00
|
|
|
if (box_fill[!horiz])
|
2016-04-11 22:10:05 -07:00
|
|
|
{
|
|
|
|
// box is filled, set all weights to be equal
|
|
|
|
zeroweight = EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// move bounding box according to box align
|
2016-04-15 01:06:14 -07:00
|
|
|
cur_pos = extra * box_align[!horiz];
|
2016-04-11 22:10:05 -07:00
|
|
|
}
|
2016-04-15 01:06:14 -07:00
|
|
|
weight[!horiz] = count;
|
2016-04-11 22:10:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2016-04-15 01:06:14 -07:00
|
|
|
cx = boxx + cur_pos;
|
|
|
|
cy = boxy;
|
|
|
|
cw = item->want[0] + rounding + (zeroweight ? 1.0 : item->weight[0]) * extra / weight[0];
|
2016-04-11 22:10:05 -07:00
|
|
|
ch = boxh;
|
|
|
|
cur_pos += cw + pad;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-15 01:06:14 -07:00
|
|
|
cx = boxx;
|
|
|
|
cy = boxy + cur_pos;
|
2016-04-11 22:10:05 -07:00
|
|
|
cw = boxw;
|
2016-04-15 01:06:14 -07:00
|
|
|
ch = item->want[1] + rounding + (zeroweight ? 1.0 : item->weight[1]) * extra / weight[1];
|
2016-04-11 22:10:05 -07:00
|
|
|
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
|
|
|
|
{
|
2017-08-16 15:56:23 -07:00
|
|
|
if (horiz && item->weight[0] > 0)
|
|
|
|
w = cw - item->pad[0] - item->pad[1];
|
|
|
|
else
|
|
|
|
w = item->want[0] - item->pad[0] - item->pad[1];
|
2016-04-11 22:10:05 -07:00
|
|
|
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
|
|
|
|
{
|
2017-08-16 15:56:23 -07:00
|
|
|
if (!horiz && item->weight[1] > 0)
|
|
|
|
h = ch - item->pad[2] - item->pad[3];
|
|
|
|
else
|
|
|
|
h = item->want[1] - item->pad[2] - item->pad[3];
|
2016-04-11 22:10:05 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|