lib/elementary/els_cursor.c \
lib/elementary/els_tooltip.c \
lib/elementary/elu_ews_wm.c \
+ lib/elementary/efl_ui_container_layout.c \
+ lib/elementary/efl_ui_container_layout.h \
lib/elementary/efl_ui_box.c \
lib/elementary/efl_ui_box_flow.c \
lib/elementary/efl_ui_box_stack.c \
lib/elementary/efl_ui_anchor_popup.c \
lib/elementary/efl_ui_table.c \
lib/elementary/efl_ui_table_static.c \
+ lib/elementary/efl_ui_table_layout.c \
lib/elementary/efl_ui_table_private.h \
lib/elementary/efl_ui_text.c \
lib/elementary/efl_ui_text_factory_images.c \
{
case NONE:
efl_gfx_hint_align_set(table, 0.5, 0.5);
- for (int i = 0; i < 7; i++)
+ for (int i = 1; i < 7; i++)
efl_gfx_hint_weight_set(objects[i], 0, 0);
break;
case NONE_BUT_FILL:
efl_gfx_hint_fill_set(table, EINA_TRUE, EINA_TRUE);
- for (int i = 0; i < 7; i++)
+ for (int i = 1; i < 7; i++)
efl_gfx_hint_weight_set(objects[i], 0, 0);
break;
case EQUAL:
efl_gfx_hint_align_set(table, 0.5, 0.5);
- for (int i = 0; i < 7; i++)
+ for (int i = 1; i < 7; i++)
efl_gfx_hint_weight_set(objects[i], 1, 1);
break;
case ONE:
efl_gfx_hint_align_set(table, 0.5, 0.5);
- for (int i = 0; i < 6; i++)
+ for (int i = 1; i < 7; i++)
efl_gfx_hint_weight_set(objects[i], 0, 0);
- efl_gfx_hint_weight_set(objects[6], 1, 1);
+ efl_gfx_hint_weight_set(objects[2], 1, 1);
break;
case TWO:
efl_gfx_hint_align_set(table, 0.5, 0.5);
- for (int i = 0; i < 5; i++)
+ for (int i = 1; i < 7; i++)
efl_gfx_hint_weight_set(objects[i], 0, 0);
- efl_gfx_hint_weight_set(objects[5], 1, 1);
- efl_gfx_hint_weight_set(objects[6], 1, 1);
+ efl_gfx_hint_weight_set(objects[2], 1, 1);
+ efl_gfx_hint_weight_set(objects[3], 1, 1);
break;
case CUSTOM:
efl_object_override(table, &custom_layout_ops);
}
static void
-btnmargins_slider_cb(void *data, const Efl_Event *event)
+btnmargins_slider_cb(void *data EINA_UNUSED, const Efl_Event *event)
{
int val = elm_slider_value_get(event->object);
for (int i = 1; i < 7; i++)
- efl_gfx_hint_margin_set(data, val, val, val, val);
+ efl_gfx_hint_margin_set(objects[i], val, val, val, val);
}
static void
efl_event_callback_add(o, EFL_UI_SLIDER_EVENT_CHANGED, padding_slider_cb, table);
elm_slider_min_max_set(o, 0, 40);
elm_slider_inverted_set(o, 1);
- elm_slider_value_set(o, 10);
+ elm_slider_value_set(o, 0);
efl_pack(bx, o);
efl_gfx_entity_visible_set(o, 1);
efl_event_callback_add(o, EFL_UI_SLIDER_EVENT_CHANGED, margin_slider_cb, table);
elm_slider_min_max_set(o, 0, 40);
elm_slider_inverted_set(o, 1);
- elm_slider_value_set(o, 10);
+ elm_slider_value_set(o, 0);
efl_pack(bx, o);
efl_gfx_entity_visible_set(o, 1);
efl_event_callback_add(o, EFL_UI_SLIDER_EVENT_CHANGED, btnmargins_slider_cb, table);
elm_slider_min_max_set(o, 0, 40);
elm_slider_inverted_set(o, 1);
- elm_slider_value_set(o, 10);
+ elm_slider_value_set(o, 0);
efl_pack(bx, o);
efl_gfx_entity_visible_set(o, 1);
#define EFL_GFX_HINT_PROTECTED
#include "efl_ui_box_private.h"
+#include "efl_ui_container_layout.h"
// FIXME: handle RTL? just invert the horizontal order?
EINA_INLIST;
Evas_Object *obj;
- double weight[2];
- double align[2];
- double space[2];
- double comp_factor;
- Eina_Bool fill[2];
- Eina_Size2D max, min, aspect;
- int pad[4];
- Efl_Gfx_Hint_Aspect aspect_type;
- int id;
+ double weight_factor;
+ Efl_Ui_Container_Item_Hints hints[2]; /* 0 is x-axis, 1 is y-axis */
};
static int
-weight_sort_cb(const void *l1, const void *l2)
+_weight_sort_cb(const void *l1, const void *l2)
{
Item_Calc *it1, *it2;
it1 = EINA_INLIST_CONTAINER_GET(l1, Item_Calc);
it2 = EINA_INLIST_CONTAINER_GET(l2, Item_Calc);
- return it2->comp_factor <= it1->comp_factor ? -1 : 1;
-}
-
-static inline void
-_min_max_calc(Item_Calc *item, int *cw, int *ch, Eina_Bool aspect_check)
-{
- int w = *cw, h = *ch;
-
- if (aspect_check)
- {
- w = h * item->aspect.w / item->aspect.h;
- if (w > *cw)
- {
- w = *cw;
- h = w * item->aspect.h / item->aspect.w;
- }
- }
-
- if (w > item->max.w)
- {
- w = item->max.w;
- if (aspect_check) h = w * item->aspect.h / item->aspect.w;
- }
- if (h > item->max.h)
- {
- h = item->max.h;
- if (aspect_check) w = h * item->aspect.w / item->aspect.h;
- }
- if (w < item->min.w)
- {
- w = item->min.w;
- if (aspect_check) h = w * item->aspect.h / item->aspect.w;
- }
- if (h < item->min.h)
- {
- h = item->min.h;
- if (aspect_check) w = h * item->aspect.w / item->aspect.h;
- }
- *cw = w;
- *ch = h;
+ return it2->weight_factor <= it1->weight_factor ? -1 : 1;
}
void
{
Efl_Ui_Box_Data *pd = efl_data_scope_get(ui_box, EFL_UI_BOX_CLASS);
Evas_Object_Box_Option *opt;
- Evas_Object *o;
Eina_List *li;
Eina_Inlist *inlist = NULL;
- int wantw = 0, wanth = 0; // requested size
- Eina_Rect boxs;
Item_Calc *items, *item;
- Eina_Bool horiz = efl_ui_dir_is_horizontal(pd->dir, EINA_FALSE);
- int id = 0, count, boxl = 0, boxr = 0, boxt = 0, boxb = 0;
- int length, want, pad;
- double cur_pos, weight[2] = { 0, 0 }, scale, mmin = 0;
- double box_align[2];
- Eina_Bool box_fill[2] = { EINA_FALSE, EINA_FALSE };
-
- boxs = efl_gfx_entity_geometry_get(ui_box);
- efl_gfx_hint_margin_get(ui_box, &boxl, &boxr, &boxt, &boxb);
- scale = efl_gfx_entity_scale_get(ui_box);
-
- // Box align: used if "item has max size and fill" or "no item has a weight"
- // 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;
- }
+ Efl_Ui_Container_Item_Hints *hints, *hint;
+ Eina_Bool axis = !efl_ui_dir_is_horizontal(pd->dir, EINA_FALSE);
+ Eina_Bool r_axis = !axis;
+ int want[2] = { 0, 0 };
+ int count, i = 0;
+ double cur_pos, mmin = 0, weight_sum = 0;
+ Efl_Ui_Container_Layout_Calc box_calc[2]; /* 0 is x-axis, 1 is y-axis */
+
count = eina_list_count(bd->children);
if (!count)
return;
}
+ _efl_ui_container_layout_init(ui_box, box_calc);
+
items = alloca(count * sizeof(*items));
#ifdef DEBUG
memset(items, 0, count * sizeof(*items));
#endif
- // box outer margin
- boxs.w -= boxl + boxr;
- boxs.h -= boxt + boxb;
- boxs.x += boxl;
- boxs.y += boxt;
-
// 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;
-
- efl_gfx_hint_weight_get(o, &item->weight[0], &item->weight[1]);
- efl_gfx_hint_align_get(o, &item->align[0], &item->align[1]);
- efl_gfx_hint_margin_get(o, &item->pad[0], &item->pad[1], &item->pad[2], &item->pad[3]);
- efl_gfx_hint_fill_get(o, &item->fill[0], &item->fill[1]);
- item->max = efl_gfx_hint_size_max_get(o);
- item->min = efl_gfx_hint_size_combined_min_get(o);
- efl_gfx_hint_aspect_get(o, &item->aspect_type, &item->aspect);
-
- if (horiz && (box_fill[0] || pd->homogeneous)) item->weight[0] = 1;
- else if (item->weight[0] < 0) item->weight[0] = 0;
- if (!horiz && (box_fill[1] || pd->homogeneous)) item->weight[1] = 1;
- else if (item->weight[1] < 0) item->weight[1] = 0;
-
- if (EINA_DBL_EQ(item->align[0], -1))
- {
- item->align[0] = 0.5;
- item->fill[0] = EINA_TRUE;
- }
- else if (item->align[0] < 0) item->align[0] = 0;
- else if (item->align[0] > 1) item->align[0] = 1;
- if (EINA_DBL_EQ(item->align[1], -1))
- {
- item->align[1] = 0.5;
- item->fill[1] = EINA_TRUE;
- }
- else if (item->align[1] < 0) item->align[1] = 0;
- else if (item->align[1] > 1) item->align[1] = 1;
+ item = &items[i++];
+ item->obj = opt->obj;
+ hints = item->hints;
- if (item->min.w < 0) item->min.w = 0;
- if (item->min.h < 0) item->min.h = 0;
+ _efl_ui_container_layout_item_init(item->obj, hints);
- if (item->max.w < 0) item->max.w = INT_MAX;
- if (item->max.h < 0) item->max.h = INT_MAX;
+ if (pd->homogeneous || box_calc[0].fill)
+ hints[0].weight = 1;
+ else if (hints[0].weight < 0)
+ hints[0].weight = 0;
- weight[0] += item->weight[0];
- weight[1] += item->weight[1];
+ if (pd->homogeneous || box_calc[1].fill)
+ hints[1].weight = 1;
+ else if (hints[1].weight < 0)
+ hints[1].weight = 0;
- if ((item->aspect.w <= 0) || (item->aspect.h <= 0))
- {
- if ((item->aspect.w <= 0) ^ (item->aspect.h <= 0))
- {
- ERR("Invalid aspect parameter for obj: %p", item->obj);
- item->aspect.w = item->aspect.h = 0;
- item->aspect_type = EFL_GFX_HINT_ASPECT_NONE;
- }
- }
- else
- {
- _min_max_calc(item, &item->min.w, &item->min.h, EINA_TRUE);
- }
+ weight_sum += hints[axis].weight;
- item->space[0] = item->min.w + item->pad[0] + item->pad[1];
- item->space[1] = item->min.h + item->pad[2] + item->pad[3];
+ if (hints[r_axis].space > want[r_axis])
+ want[r_axis] = hints[r_axis].space;
- if (horiz)
+ if (pd->homogeneous)
{
- if (item->space[1] > wanth)
- wanth = item->space[1];
- if (pd->homogeneous)
- {
- if (item->space[0] > mmin)
- mmin = item->space[0];
- }
- else
- {
- wantw += item->space[0];
- }
+ if (hints[axis].space > mmin)
+ mmin = hints[axis].space;
}
else
{
- if (item->space[0] > wantw)
- wantw = item->space[0];
- if (pd->homogeneous)
- {
- if (item->space[1] > mmin)
- mmin = item->space[1];
- }
- else
- {
- wanth += item->space[1];
- }
+ want[axis] += hints[axis].space;
}
-
- item->id = id++;
}
// total space & available space
- if (horiz)
- {
- if (pd->homogeneous)
- wantw = mmin * count;
- want = wantw;
- length = boxs.w;
- pad = pd->pad.scalable ? (pd->pad.h * scale) : pd->pad.h;
- if (boxs.h < wanth)
- boxs.h = wanth;
- }
- else
- {
- if (pd->homogeneous)
- wanth = mmin * count;
- want = wanth;
- length = boxs.h;
- pad = pd->pad.scalable ? (pd->pad.v * scale) : pd->pad.v;
- if (boxs.w < wantw)
- boxs.w = wantw;
- }
+ if (pd->homogeneous)
+ want[axis] = mmin * count;
+
+ if (box_calc[r_axis].size < want[r_axis])
+ box_calc[r_axis].size = want[r_axis];
// padding can not be squeezed (note: could make it an option)
- length -= pad * (count - 1);
- cur_pos = horiz ? boxs.x : boxs.y;
+ box_calc[axis].size -= (box_calc[axis].pad * (count - 1));
+ box_calc[r_axis].pad = 0;
+ cur_pos = box_calc[axis].pos;
- // calculate weight length
- if (!pd->homogeneous && (length > want) && (weight[!horiz] > 0))
+ // calculate weight size
+ if (!pd->homogeneous && (box_calc[axis].size > want[axis]) && (weight_sum > 0))
{
- int orig_length = length;
- double orig_weight = weight[!horiz];
+ int orig_size, calc_size;
+ double orig_weight = weight_sum;
+
+ calc_size = orig_size = box_calc[axis].size;
- for (id = 0; id < count; id++)
+ for (i = 0; i < count; i++)
{
double denom;
- item = &items[id];
+ hint = &items[i].hints[axis];
- denom = (item->weight[!horiz] * orig_length) -
- (orig_weight * item->space[!horiz]);
+ denom = (hint->weight * orig_size) - (orig_weight * hint->space);
if (denom > 0)
{
- item->comp_factor = (item->weight[!horiz] * orig_length) / denom;
- inlist = eina_inlist_sorted_insert(inlist, EINA_INLIST_GET(item),
- weight_sort_cb);
+ items[i].weight_factor = (hint->weight * orig_size) / denom;
+ inlist = eina_inlist_sorted_insert(inlist, EINA_INLIST_GET(&items[i]),
+ _weight_sort_cb);
+
}
else
{
- length -= item->space[!horiz];
- weight[!horiz] -= item->weight[!horiz];
+ calc_size -= hint->space;
+ weight_sum -= hint->weight;
}
}
EINA_INLIST_FOREACH(inlist, item)
{
double weight_len;
+ hint = &item->hints[axis];
- weight_len = (length * item->weight[!horiz]) / weight[!horiz];
- if (item->space[!horiz] < weight_len)
+ weight_len = (calc_size * hint->weight) / weight_sum;
+ if (hint->space < weight_len)
{
- item->space[!horiz] = weight_len;
+ hint->space = weight_len;
}
else
{
- weight[!horiz] -= item->weight[!horiz];
- length -= item->space[!horiz];
+ weight_sum -= hint->weight;
+ calc_size -= hint->space;
}
}
}
// calculate item geometry
{
- int x, y, w, h, sw, sh;
+ int item_size[2], item_pos[2], sw, sh;
- if (length > want)
+ if (box_calc[axis].size > want[axis])
{
if (pd->homogeneous)
- mmin = (double)length / count;
- else if (EINA_DBL_EQ(weight[!horiz], 0))
- cur_pos += (length - want) * box_align[!horiz];
+ mmin = (double)box_calc[axis].size / count;
+ else if (EINA_DBL_EQ(weight_sum, 0))
+ cur_pos += (box_calc[axis].size - want[axis]) * box_calc[axis].align;
}
- for (id = 0; id < count; id++)
+ for (i = 0; i < count; i++)
{
- item = &items[id];
+ hints = items[i].hints;
+
if (pd->homogeneous)
- item->space[!horiz] = mmin;
- item->space[horiz] = horiz ? boxs.h : boxs.w;
- sw = item->space[0] - item->pad[0] - item->pad[1];
- sh = item->space[1] - item->pad[2] - item->pad[3];
+ hints[axis].space = mmin;
+ hints[r_axis].space = box_calc[r_axis].size;
+ sw = hints[0].space - (hints[0].margin[0] + hints[0].margin[1]);
+ sh = hints[1].space - (hints[1].margin[0] + hints[1].margin[1]);
- if ((item->weight[0] > 0) && item->fill[0])
- w = sw;
- else
- w = 0;
+ item_size[0] = ((hints[0].weight > 0) && hints[0].fill) ? sw : 0;
+ item_size[1] = ((hints[1].weight > 0) && hints[1].fill) ? sh : 0;
- if ((item->weight[1] > 0) && item->fill[1])
- h = sh;
- else
- h = 0;
+ _efl_ui_container_layout_min_max_calc(hints, &item_size[0], &item_size[1],
+ (hints[0].aspect > 0) && (hints[1].aspect > 0));
- _min_max_calc(item, &w, &h, (item->aspect.w > 0) &&
- (item->aspect.h > 0));
- if (horiz)
- {
- x = cur_pos + 0.5;
- y = boxs.y;
- }
- else
- {
- x = boxs.x;
- y = cur_pos + 0.5;
- }
- x += item->pad[0] + ((sw - w) * item->align[0]);
- y += item->pad[2] + ((sh - h) * item->align[1]);
+ item_pos[axis] = cur_pos + 0.5;
+ item_pos[r_axis] = box_calc[r_axis].pos;
+
+ item_pos[0] += (hints[0].margin[0] +
+ ((sw - item_size[0]) * hints[0].align));
+ item_pos[1] += (hints[1].margin[0] +
+ ((sh - item_size[1]) * hints[1].align));
- cur_pos += item->space[!horiz] + pad;
+ cur_pos += hints[axis].space + box_calc[axis].pad;
- efl_gfx_entity_geometry_set(item->obj, EINA_RECT(x, y, w, h));
+ efl_gfx_entity_geometry_set(items[i].obj,
+ EINA_RECT(item_pos[0], item_pos[1],
+ item_size[0], item_size[1]));
}
}
+ want[0] += (box_calc[0].margin[0] + box_calc[0].margin[1]) +
+ (box_calc[0].pad * (count - 1));
+ want[1] += (box_calc[1].margin[0] + box_calc[1].margin[1]) +
+ (box_calc[1].pad * (count - 1));
- if (horiz)
- {
- efl_gfx_hint_size_min_set(ui_box, EINA_SIZE2D(
- wantw + boxl + boxr + pad * (count - 1),
- wanth + boxt + boxb));
- }
- else
- {
- efl_gfx_hint_size_min_set(ui_box, EINA_SIZE2D(
- wantw + boxl + boxr,
- wanth + pad * (count - 1) + boxt + boxb));
- }
+ efl_gfx_hint_size_min_set(ui_box, EINA_SIZE2D(want[0], want[1]));
}
--- /dev/null
+#include "efl_ui_container_layout.h"
+
+void
+_efl_ui_container_layout_min_max_calc(Efl_Ui_Container_Item_Hints *item, int *cw, int *ch, Eina_Bool aspect_check)
+{
+ int w = *cw, h = *ch;
+ Eina_Size2D aspect = { item[0].aspect, item[1].aspect };
+
+ if (aspect_check)
+ {
+ w = h * aspect.w / aspect.h;
+ if (w > *cw)
+ {
+ w = *cw;
+ h = w * aspect.h / aspect.w;
+ }
+ }
+
+ if (w > item[0].max)
+ {
+ w = item[0].max;
+ if (aspect_check) h = w * aspect.h / aspect.w;
+ }
+ if (h > item[1].max)
+ {
+ h = item[1].max;
+ if (aspect_check) w = h * aspect.w / aspect.h;
+ }
+ if (w < item[0].min)
+ {
+ w = item[0].min;
+ if (aspect_check) h = w * aspect.h / aspect.w;
+ }
+ if (h < item[1].min)
+ {
+ h = item[1].min;
+ if (aspect_check) w = h * aspect.w / aspect.h;
+ }
+ *cw = w;
+ *ch = h;
+}
+
+void
+_efl_ui_container_layout_item_init(Eo* o, Efl_Ui_Container_Item_Hints *item)
+{
+ Eina_Size2D max;
+ Eina_Size2D min;
+ Eina_Size2D aspect;
+ Efl_Gfx_Hint_Aspect aspect_type;
+
+ efl_gfx_hint_weight_get(o, &item[0].weight, &item[1].weight);
+ efl_gfx_hint_align_get(o, &item[0].align, &item[1].align);
+ efl_gfx_hint_margin_get(o, &item[0].margin[0], &item[0].margin[1],
+ &item[1].margin[0], &item[1].margin[1]);
+ efl_gfx_hint_fill_get(o, &item[0].fill, &item[1].fill);
+ max = efl_gfx_hint_size_max_get(o);
+ min = efl_gfx_hint_size_combined_min_get(o);
+ efl_gfx_hint_aspect_get(o, &aspect_type, &aspect);
+ item[0].aspect = aspect.w;
+ item[1].aspect = aspect.h;
+ item[0].aspect_type = aspect_type;
+ item[1].aspect_type = aspect_type;
+
+ if (EINA_DBL_EQ(item[0].align, -1))
+ {
+ item[0].align = 0.5;
+ item[0].fill = EINA_TRUE;
+ }
+ else if (item[0].align < 0) item[0].align = 0;
+ else if (item[0].align > 1) item[0].align = 1;
+ if (EINA_DBL_EQ(item[1].align, -1))
+ {
+ item[1].align = 0.5;
+ item[1].fill = EINA_TRUE;
+ }
+ else if (item[1].align < 0) item[1].align = 0;
+ else if (item[1].align > 1) item[1].align = 1;
+
+ if (min.w < 0) min.w = 0;
+ if (min.h < 0) min.h = 0;
+
+ if (max.w < 0) max.w = INT_MAX;
+ if (max.h < 0) max.h = INT_MAX;
+
+ item[0].max = max.w;
+ item[1].max = max.h;
+ item[0].min = min.w;
+ item[1].min = min.h;
+
+ if ((item[0].aspect <= 0) || (item[1].aspect_type <= 0))
+ {
+ if ((item[0].aspect <= 0) ^ (item[1].aspect_type <= 0))
+ {
+ ERR("Invalid aspect parameter for obj(%p)", o);
+ item[0].aspect = item[1].aspect_type = 0;
+ item[0].aspect_type = item[1].aspect_type = EFL_GFX_HINT_ASPECT_NONE;
+ }
+ }
+ else
+ {
+ _efl_ui_container_layout_min_max_calc(item, &item[0].min, &item[1].min,
+ EINA_TRUE);
+ }
+
+
+ item[0].space = item[0].min + item[0].margin[0] + item[0].margin[1];
+ item[1].space = item[1].min + item[1].margin[0] + item[1].margin[1];
+}
+
+void
+_efl_ui_container_layout_init(Eo* obj, Efl_Ui_Container_Layout_Calc *calc)
+{
+ Eina_Rect geom;
+ Eina_Bool pad_scalable;
+
+ geom = efl_gfx_entity_geometry_get(obj);
+ efl_gfx_hint_margin_get(obj, &calc[0].margin[0], &calc[0].margin[1],
+ &calc[1].margin[0], &calc[1].margin[1]);
+ calc[0].scale = calc[1].scale = efl_gfx_entity_scale_get(obj);
+
+ efl_pack_padding_get(obj, &calc[0].pad, &calc[1].pad, &pad_scalable);
+ calc[0].pad = pad_scalable ? (calc[0].pad * calc[0].scale) : calc[0].pad;
+ calc[1].pad = pad_scalable ? (calc[1].pad * calc[1].scale) : calc[1].pad;
+
+ // pack align is used if "no item has a weight"
+ efl_pack_align_get(obj, &calc[0].align, &calc[1].align);
+ if (calc[0].align < 0)
+ {
+ calc[0].fill = EINA_TRUE;
+ calc[0].align = 0.5;
+ }
+ else if (calc[0].align > 1)
+ {
+ calc[0].align = 1;
+ }
+ else
+ {
+ calc[0].fill = EINA_FALSE;
+ }
+
+ if (calc[1].align < 0)
+ {
+ calc[1].fill = EINA_TRUE;
+ calc[1].align = 0.5;
+ }
+ else if (calc[1].align > 1)
+ {
+ calc[1].align = 1;
+ }
+ else
+ {
+ calc[1].fill = EINA_FALSE;
+ }
+ calc[0].pos = geom.x + calc[0].margin[0];
+ calc[1].pos = geom.y + calc[1].margin[0];
+ calc[0].size = geom.w - calc[0].margin[0] - calc[0].margin[1];
+ calc[1].size = geom.h - calc[1].margin[0] - calc[1].margin[1];
+}
--- /dev/null
+#ifndef _EFL_UI_CONTAINER_HELPER_H_
+#define _EFL_UI_CONTAINER_HELPER_H_
+
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+typedef struct _Efl_Ui_Container_Item_Hints Efl_Ui_Container_Item_Hints;
+typedef struct _Efl_Ui_Container_Layout_Calc Efl_Ui_Container_Layout_Calc;
+
+struct _Efl_Ui_Container_Item_Hints
+{
+ int max;
+ int min;
+ int aspect;
+ int margin[2]; // start, end
+ Efl_Gfx_Hint_Aspect aspect_type;
+ double weight;
+ double align;
+ double space;
+ Eina_Bool fill;
+};
+
+struct _Efl_Ui_Container_Layout_Calc
+{
+ int pos;
+ int size;
+ int margin[2];
+ double align;
+ double scale;
+ double pad;
+ Eina_Bool fill : 1;
+};
+
+void _efl_ui_container_layout_min_max_calc(Efl_Ui_Container_Item_Hints *item, int *cw, int *ch, Eina_Bool aspect_check);
+void _efl_ui_container_layout_item_init(Eo* o, Efl_Ui_Container_Item_Hints *item);
+void _efl_ui_container_layout_init(Eo* obj, Efl_Ui_Container_Layout_Calc *calc);
+
+#endif
{
Efl_Ui_Table_Data *pd = efl_data_scope_get(data, MY_CLASS);
- _sizing_eval(data, pd);
+ if (table == data)
+ efl_pack_layout_request(data);
+ else
+ _sizing_eval(data, pd);
+}
+
+static void
+_efl_ui_table_size_hints_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
+{
+ efl_pack_layout_request(ev->object);
}
/* Custom table class: overrides smart_calculate. */
EOLIAN static void
_efl_ui_table_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Table_Data *pd)
{
- ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
-
- _sizing_eval(obj, pd);
- efl_canvas_group_calculate(efl_super(wd->resize_obj, CUSTOM_TABLE_CLASS));
+ _efl_ui_table_custom_layout(obj, pd);
}
EOLIAN void
evas_object_event_callback_add
(table, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _table_size_hints_changed, obj);
+ efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED,
+ _efl_ui_table_size_hints_changed_cb, NULL);
efl_canvas_group_add(efl_super(obj, MY_CLASS));
evas_object_event_callback_del_full
(wd->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
_table_size_hints_changed, obj);
+ efl_event_callback_del(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED,
+ _efl_ui_table_size_hints_changed_cb, NULL);
/* let's make our table object the *last* to be processed, since it
* may (smart) parent other sub objects here */
pd->last_row = -1;
pd->req_cols = 0;
pd->req_rows = 0;
+ pd->align.h = 0.5;
+ pd->align.v = 0.5;
return obj;
}
if (v) *v = pd->pad.v;
}
+EOLIAN static void
+_efl_ui_table_efl_pack_pack_align_set(Eo *obj, Efl_Ui_Table_Data *pd, double h, double v)
+{
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ if (h < 0) h = -1;
+ if (v < 0) v = -1;
+ if (h > 1) h = 1;
+ if (v > 1) v = 1;
+ pd->align.h = h;
+ pd->align.v = v;
+
+ efl_pack_layout_request(obj);
+}
+
+EOLIAN static void
+_efl_ui_table_efl_pack_pack_align_get(const Eo *obj EINA_UNUSED, Efl_Ui_Table_Data *pd, double *h, double *v)
+{
+ if (h) *h = pd->align.h;
+ if (v) *v = pd->align.v;
+}
+
static void
_subobj_del_cb(void *data, const Efl_Event *event)
{
Efl.Pack.unpack;
Efl.Pack.pack;
Efl.Pack.pack_padding { get; set; }
+ Efl.Pack.pack_align { get; set; }
Efl.Pack_Table.pack_table;
Efl.Pack_Table.table_content_get;
Efl.Pack_Table.table_contents_get;
--- /dev/null
+#include "efl_ui_table_private.h"
+#include "efl_ui_container_layout.h"
+
+typedef struct _Item_Calc Item_Calc;
+typedef struct _Cell_Calc Cell_Calc;
+typedef struct _Table_Calc Table_Calc;
+
+struct _Item_Calc
+{
+ Evas_Object *obj;
+ int cell_span[2];
+ int cell_index[2];
+ Efl_Ui_Container_Item_Hints hints[2]; /* 0 is x-axis, 1 is y-axis */
+};
+
+struct _Cell_Calc
+{
+ EINA_INLIST;
+
+ int index;
+ int next;
+ double acc;
+ double space;
+ double weight;
+ double weight_factor;
+ Eina_Bool occupied : 1;
+};
+
+struct _Table_Calc
+{
+ /* 0 is x-axis, 1 is y-axis */
+
+ int rows;
+ int cols;
+ int want[2];
+ double weight_sum[2];
+ Cell_Calc *cell_calc[2];
+ Efl_Ui_Container_Layout_Calc layout_calc[2];
+};
+
+static int
+_weight_sort_cb(const void *l1, const void *l2)
+{
+ Cell_Calc *cc1, *cc2;
+
+ cc1 = EINA_INLIST_CONTAINER_GET(l1, Cell_Calc);
+ cc2 = EINA_INLIST_CONTAINER_GET(l2, Cell_Calc);
+
+ return cc2->weight_factor <= cc1->weight_factor ? -1 : 1;
+}
+
+static void
+_cell_weight_calc(Table_Calc *table_calc, Eina_Bool axis)
+{
+ int i, count, layout_size, calc_size;
+ double denom, weight_sum, calc_weight;
+ Eina_Inlist *inlist = NULL;
+ Cell_Calc *cell_calc, *cc;
+
+ layout_size = calc_size = table_calc->layout_calc[axis].size;
+ weight_sum = calc_weight = table_calc->weight_sum[axis];
+ cell_calc = table_calc->cell_calc[axis];
+ count = axis ? table_calc->rows : table_calc->cols;
+
+ for (i = 0; i < count; i = cell_calc[i].next)
+ {
+ denom = (cell_calc[i].weight * layout_size) -
+ (weight_sum * cell_calc[i].space);
+ if (denom > 0)
+ {
+ cell_calc[i].weight_factor = (cell_calc[i].weight * layout_size) / denom;
+ inlist = eina_inlist_sorted_insert(inlist,
+ EINA_INLIST_GET(&cell_calc[i]),
+ _weight_sort_cb);
+ }
+ else
+ {
+ calc_size -= cell_calc[i].space;
+ calc_weight -= cell_calc[i].weight;
+ }
+ }
+
+ EINA_INLIST_FOREACH(inlist, cc)
+ {
+ double weight_len;
+
+ weight_len = (calc_size * cc->weight) / calc_weight;
+ if (cc->space < weight_len)
+ {
+ cc->space = weight_len;
+ }
+ else
+ {
+ calc_size -= cc->space;
+ calc_weight -= cc->weight;
+ }
+ }
+}
+
+static void
+_efl_ui_table_regular_cell_init(Table_Calc *table_calc, Eina_Bool axis)
+{
+ int i, index = 0, acc, want = 0, count;
+ double weight_sum = 0;
+ Cell_Calc *prev_cell = NULL, *cell_calc;
+ Efl_Ui_Container_Layout_Calc *layout_calc;
+
+ layout_calc = &(table_calc->layout_calc[axis]);
+ cell_calc = table_calc->cell_calc[axis];
+ count = axis ? table_calc->rows : table_calc->cols;
+
+ for (i = 0; i < count; i++)
+ {
+ if (!cell_calc[i].occupied) continue;
+
+ cell_calc[i].index = index++;
+ want += cell_calc[i].space;
+ weight_sum += cell_calc[i].weight;
+
+ if (prev_cell)
+ prev_cell->next = i;
+
+ prev_cell = &cell_calc[i];
+ }
+ if (prev_cell)
+ prev_cell->next = count;
+
+ table_calc->want[axis] = want;
+ table_calc->weight_sum[axis] = weight_sum;
+ table_calc->layout_calc[axis].size -= (table_calc->layout_calc[axis].pad
+ * (index - 1));
+
+ if ((layout_calc->size > want) && (weight_sum > 0))
+ _cell_weight_calc(table_calc, axis);
+ if (EINA_DBL_EQ(weight_sum, 0.0))
+ layout_calc->pos += (layout_calc->size - want) * layout_calc->align;
+
+ for (i = 0, acc = 0; i < count; acc += cell_calc[i].space, i = cell_calc[i].next)
+ cell_calc[i].acc = acc;
+}
+
+static inline int
+_efl_ui_table_regular_item_pos_get(Table_Calc *table_calc, Item_Calc *item, Eina_Bool axis)
+{
+ return 0.5 + table_calc->layout_calc[axis].pos
+ + table_calc->cell_calc[axis][item->cell_index[axis]].acc
+ + (table_calc->cell_calc[axis][item->cell_index[axis]].index *
+ table_calc->layout_calc[axis].pad);
+}
+
+static inline int
+_efl_ui_table_regular_item_size_get(Table_Calc *table_calc, Item_Calc *item, Eina_Bool axis)
+{
+ int start, end;
+
+ start = item->cell_index[axis];
+ end = start + item->cell_span[axis] - 1;
+
+ return table_calc->cell_calc[axis][end].acc
+ - table_calc->cell_calc[axis][start].acc
+ + table_calc->cell_calc[axis][end].space
+ + ((item->cell_span[axis] - 1) * table_calc->layout_calc[axis].pad)
+ - item->hints[axis].margin[0] - item->hints[axis].margin[1];
+}
+
+void
+_efl_ui_table_custom_layout(Efl_Ui_Table *ui_table, Efl_Ui_Table_Data *pd)
+{
+ Table_Item *ti;
+ Item_Calc *items, *item;
+ Efl_Ui_Container_Item_Hints *hints;
+ int i = 0, rows, cols;
+
+ Table_Calc table_calc;
+
+ if (!pd->count)
+ {
+ efl_gfx_hint_size_min_set(ui_table, EINA_SIZE2D(0, 0));
+ return;
+ }
+
+ _efl_ui_container_layout_init(ui_table, table_calc.layout_calc);
+
+ table_calc.want[0] = table_calc.want[1] = 0;
+ table_calc.weight_sum[0] = table_calc.weight_sum[1] = 0;
+
+ efl_pack_table_size_get(ui_table, &cols, &rows);
+
+ table_calc.cell_calc[0] = alloca(cols * sizeof(Cell_Calc));
+ table_calc.cell_calc[1] = alloca(rows * sizeof(Cell_Calc));
+
+ memset(table_calc.cell_calc[0], 0, cols * sizeof(Cell_Calc));
+ memset(table_calc.cell_calc[1], 0, rows * sizeof(Cell_Calc));
+
+ items = alloca(pd->count * sizeof(*items));
+#ifdef DEBUG
+ memset(items, 0, pd->count * sizeof(*items));
+#endif
+
+ table_calc.cols = cols;
+ table_calc.rows = rows;
+ // scan all items, get their properties, calculate total weight & min size
+ EINA_INLIST_FOREACH(pd->items, ti)
+ {
+ if (((ti->col + ti->col_span) > cols) ||
+ ((ti->row + ti->row_span) > rows))
+ {
+ efl_gfx_entity_visible_set(ti->object, EINA_FALSE);
+ continue;
+ }
+
+ item = &items[i++];
+ item->obj = ti->object;
+ hints = item->hints;
+
+ _efl_ui_container_layout_item_init(item->obj, hints);
+
+ if (table_calc.layout_calc[0].fill)
+ hints[0].weight = 1;
+ else if (hints[0].weight < 0)
+ hints[0].weight = 0;
+
+ if (table_calc.layout_calc[1].fill)
+ hints[1].weight = 1;
+ else if (hints[1].weight < 0)
+ hints[1].weight = 0;
+
+ item->cell_index[0] = ti->col;
+ item->cell_index[1] = ti->row;
+ item->cell_span[0] = ti->col_span;
+ item->cell_span[1] = ti->row_span;
+
+ if (ti->col_span == 1)
+ {
+ table_calc.cell_calc[0][ti->col].occupied = EINA_TRUE;
+
+ if (table_calc.cell_calc[0][ti->col].space < hints[0].space)
+ table_calc.cell_calc[0][ti->col].space = hints[0].space;
+ if (table_calc.cell_calc[0][ti->col].weight < hints[0].weight)
+ table_calc.cell_calc[0][ti->col].weight = hints[0].weight;
+ }
+
+ if (ti->row_span == 1)
+ {
+ table_calc.cell_calc[1][ti->row].occupied = EINA_TRUE;
+
+ if (table_calc.cell_calc[1][ti->row].space < hints[1].space)
+ table_calc.cell_calc[1][ti->row].space = hints[1].space;
+ if (table_calc.cell_calc[1][ti->row].weight < hints[1].weight)
+ table_calc.cell_calc[1][ti->row].weight = hints[1].weight;
+ }
+ }
+
+ _efl_ui_table_regular_cell_init(&table_calc, 0);
+ _efl_ui_table_regular_cell_init(&table_calc, 1);
+
+ for (i = 0; i < pd->count; i++)
+ {
+ Eina_Rect space, item_geom;
+ item = &items[i];
+ hints = items[i].hints;
+
+ space.x = _efl_ui_table_regular_item_pos_get(&table_calc, item, 0);
+ space.y = _efl_ui_table_regular_item_pos_get(&table_calc, item, 1);
+ space.w = _efl_ui_table_regular_item_size_get(&table_calc, item, 0);
+ space.h = _efl_ui_table_regular_item_size_get(&table_calc, item, 1);
+
+ item_geom.w = hints[0].fill ? space.w : hints[0].min;
+ item_geom.h = hints[1].fill ? space.h : hints[1].min;
+
+ _efl_ui_container_layout_min_max_calc(hints, &item_geom.w, &item_geom.h,
+ (hints[0].aspect > 0) && (hints[1].aspect > 0));
+
+ item_geom.x = space.x + ((space.w - item_geom.w) * hints[0].align)
+ + hints[0].margin[0];
+ item_geom.y = space.y + ((space.h - item_geom.h) * hints[1].align)
+ + hints[1].margin[0];
+
+ efl_gfx_entity_geometry_set(item->obj, item_geom);
+ }
+
+ table_calc.want[0] += table_calc.layout_calc[0].margin[0]
+ + table_calc.layout_calc[0].margin[1]
+ + (table_calc.layout_calc[0].pad *
+ table_calc.cell_calc[0][cols - 1].index);
+
+ table_calc.want[1] += table_calc.layout_calc[1].margin[0]
+ + table_calc.layout_calc[1].margin[1]
+ + (table_calc.layout_calc[1].pad *
+ table_calc.cell_calc[1][rows - 1].index);
+
+ efl_gfx_hint_size_min_set(ui_table, EINA_SIZE2D(table_calc.want[0],
+ table_calc.want[1]));
+}
typedef struct _Table_Item_Iterator Table_Item_Iterator;
typedef struct _Table_Item Table_Item;
+void _efl_ui_table_custom_layout(Efl_Ui_Table *ui_table, Efl_Ui_Table_Data *pd);
+
#define TABLE_ITEM_KEY "__table_item"
struct _Table_Item
double h, v;
Eina_Bool scalable: 1;
} pad;
+ struct {
+ double h, v;
+ } align;
Eina_Bool linear_recalc : 1;
};
'els_cursor.c',
'els_tooltip.c',
'elu_ews_wm.c',
+ 'efl_ui_container_layout.c',
+ 'efl_ui_container_layout.h',
'efl_ui_box.c',
'efl_ui_box_flow.c',
'efl_ui_box_stack.c',
'efl_ui_anchor_popup.c',
'efl_ui_table.c',
'efl_ui_table_static.c',
+ 'efl_ui_table_layout.c',
'efl_ui_table_private.h',
'efl_ui_text.c',
'efl_ui_text_factory_images.c',