From fbc7c31b33270a4d617bead2cf3baec61cc64b62 Mon Sep 17 00:00:00 2001 From: Yeongjong Lee Date: Fri, 8 Mar 2019 08:22:08 -0500 Subject: [PATCH] ui.box_flow: refactor layout_update Summary: This patch remove evas_box function from Efl.Ui.Box_Flow and add unit test. Depends on D8214 Test Plan: 1. make check 2. `elementary_test -to 'efl.ui.box'` with 'flow' checkbox. Reviewers: zmike, Jaehyun_Cho Reviewed By: zmike Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8219 --- src/Makefile_Elementary.am | 1 + src/bin/elementary/test_ui_box.c | 18 +- src/lib/elementary/efl_ui_box_flow.c | 384 +++++++++++++++--- src/lib/elementary/efl_ui_box_flow.eo | 18 - src/tests/elementary/efl_ui_suite.c | 1 + src/tests/elementary/efl_ui_suite.h | 1 + src/tests/elementary/efl_ui_test_box_flow.c | 416 ++++++++++++++++++++ src/tests/elementary/meson.build | 1 + 8 files changed, 754 insertions(+), 86 deletions(-) create mode 100644 src/tests/elementary/efl_ui_test_box_flow.c diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index 002d3f27ba..e29471912b 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -1922,6 +1922,7 @@ tests_elementary_efl_ui_suite_SOURCES = \ tests/elementary/efl_ui_test_focus.c \ tests/elementary/efl_ui_test_focus_sub.c \ tests/elementary/efl_ui_test_box.c \ + tests/elementary/efl_ui_test_box_flow.c \ tests/elementary/efl_ui_test_table.c \ tests/elementary/efl_ui_test_relative_layout.c \ tests/elementary/efl_ui_test_grid.c \ diff --git a/src/bin/elementary/test_ui_box.c b/src/bin/elementary/test_ui_box.c index c5b9db8d56..0021be5603 100644 --- a/src/bin/elementary/test_ui_box.c +++ b/src/bin/elementary/test_ui_box.c @@ -179,15 +179,7 @@ homo_check_cb(void *data, const Efl_Event *event) { Eina_Bool chk = elm_check_selected_get(event->object); Eo *box = efl_key_wref_get(data, "box"); - efl_ui_box_flow_homogenous_set(box, chk); -} - -static void -max_size_check_cb(void *data, const Efl_Event *event) -{ - Eina_Bool chk = elm_check_selected_get(event->object); - Eo *box = efl_key_wref_get(data, "box"); - efl_ui_box_flow_max_size_set(box, chk); + efl_ui_box_homogeneous_set(box, chk); } static void @@ -358,14 +350,6 @@ test_ui_box(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_in efl_pack(bx, o); efl_gfx_entity_visible_set(o, 1); - o = elm_check_add(win); - elm_check_selected_set(o, 0); - elm_object_text_set(o, "Homogenous + Max"); - efl_event_callback_add(o, EFL_UI_CHECK_EVENT_CHANGED, max_size_check_cb, win); - efl_gfx_hint_align_set(o, 0, 0); - efl_pack(bx, o); - efl_gfx_entity_visible_set(o, 1); - o = elm_check_add(win); elm_check_selected_set(o, 0); elm_object_text_set(o, "Custom layout"); diff --git a/src/lib/elementary/efl_ui_box_flow.c b/src/lib/elementary/efl_ui_box_flow.c index a93ccc9e49..38bcb7d626 100644 --- a/src/lib/elementary/efl_ui_box_flow.c +++ b/src/lib/elementary/efl_ui_box_flow.c @@ -1,4 +1,5 @@ #include "efl_ui_box_private.h" +#include "efl_ui_container_layout.h" #define MY_CLASS EFL_UI_BOX_FLOW_CLASS @@ -6,75 +7,356 @@ typedef struct _Efl_Ui_Box_Flow_Data Efl_Ui_Box_Flow_Data; struct _Efl_Ui_Box_Flow_Data { - Eina_Bool homogenous; - Eina_Bool max_size; }; -EOLIAN static void -_efl_ui_box_flow_box_flow_homogenous_set(Eo *obj EINA_UNUSED, Efl_Ui_Box_Flow_Data *pd, Eina_Bool val) +typedef struct _Item_Calc Item_Calc; +typedef struct _Row_Calc Row_Calc; + +struct _Item_Calc { - pd->homogenous = val; + EINA_INLIST; + + Evas_Object *obj; + Row_Calc *row; + double weight_factor; + Efl_Ui_Container_Item_Hints hints[2]; /* 0 is x-axis, 1 is y-axis */ +}; + +struct _Row_Calc +{ + EINA_INLIST; + + Evas_Object *obj; + int item_count; + int min_sum; + int hgsize; + double weight_sum; + double cross_weight; + double cross_space; + double cur_pos; + double weight_factor; + Efl_Ui_Container_Item_Hints hint; +}; + +static int +_item_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->weight_factor <= it1->weight_factor ? -1 : 1; } -EOLIAN static Eina_Bool -_efl_ui_box_flow_box_flow_homogenous_get(const Eo *obj EINA_UNUSED, Efl_Ui_Box_Flow_Data *pd) +static int +_row_weight_sort_cb(const void *l1, const void *l2) { - return pd->homogenous; + Row_Calc *it1, *it2; + + it1 = EINA_INLIST_CONTAINER_GET(l1, Row_Calc); + it2 = EINA_INLIST_CONTAINER_GET(l2, Row_Calc); + + return it2->weight_factor <= it1->weight_factor ? -1 : 1; } EOLIAN static void -_efl_ui_box_flow_box_flow_max_size_set(Eo *obj EINA_UNUSED, Efl_Ui_Box_Flow_Data *pd, Eina_Bool val) +_efl_ui_box_flow_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Box_Flow_Data *pd EINA_UNUSED) { - pd->max_size = val; -} - -EOLIAN static Eina_Bool -_efl_ui_box_flow_box_flow_max_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Box_Flow_Data *pd) -{ - return pd->max_size; -} - -EOLIAN static void -_efl_ui_box_flow_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Box_Flow_Data *pd) -{ - void (*func)(Evas_Box *obj, Evas_Object_Box_Data *priv, void *data); Evas_Object_Box_Data *bd; - Eina_Bool homo = EINA_FALSE, maxsize = EINA_FALSE; - EINA_SAFETY_ON_FALSE_RETURN(efl_isa(obj, EFL_UI_BOX_CLASS)); ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); bd = efl_data_scope_get(wd->resize_obj, EVAS_BOX_CLASS); + Efl_Ui_Box_Data *bcd = efl_data_scope_get(obj, EFL_UI_BOX_CLASS); + Evas_Object_Box_Option *opt; + Eina_List *li; + Eina_Inlist *inlist = NULL; + Item_Calc *items, *item; + Row_Calc *rows, *row; + Efl_Ui_Container_Item_Hints *hints, *hint; + Eina_Bool axis = !efl_ui_dir_is_horizontal(bcd->dir, EINA_FALSE); + Eina_Bool c_axis = !axis; + int want[2] = { 0, 0 }; + int rc = 0, count, i = 0, id, item_last = 0; + double cur_pos, cross_weight_sum = 0, cross_min_sum = 0, min_sum = 0; + Efl_Ui_Container_Layout_Calc box_calc[2]; /* 0 is x-axis, 1 is y-axis */ - homo = pd->homogenous; - maxsize = pd->max_size; - - // This makes it horizontal by default, as opposed to the standard box. - if (efl_ui_dir_is_horizontal(efl_ui_direction_get(obj), EINA_TRUE)) + count = eina_list_count(bd->children); + if (!count) { - if (homo) - { - if (maxsize) - func = evas_object_box_layout_homogeneous_max_size_horizontal; - else - func = evas_object_box_layout_homogeneous_horizontal; - } - else - func = evas_object_box_layout_flow_horizontal; - } - else - { - if (homo) - { - if (maxsize) - func = evas_object_box_layout_homogeneous_max_size_vertical; - else - func = evas_object_box_layout_homogeneous_vertical; - } - else - func = evas_object_box_layout_flow_vertical; + efl_gfx_hint_size_min_set(obj, EINA_SIZE2D(0, 0)); + return; } - func(wd->resize_obj, bd, NULL); + _efl_ui_container_layout_init(obj, box_calc); + + items = alloca(count * sizeof(*items)); + rows = alloca(count * sizeof(*rows)); + memset(rows, 0, count * sizeof(*rows)); + +#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[i++]; + item->obj = opt->obj; + hints = item->hints; + + _efl_ui_container_layout_item_init(item->obj, hints); + + if ((bcd->homogeneous && !axis) || box_calc[0].fill) + hints[0].weight = 1; + else if (hints[0].weight < 0) + hints[0].weight = 0; + + if ((bcd->homogeneous && axis) || box_calc[1].fill) + hints[1].weight = 1; + else if (hints[1].weight < 0) + hints[1].weight = 0; + + if (want[axis] < hints[axis].space) + want[axis] = hints[axis].space; + + if (bcd->homogeneous) + continue; + + if (i == 1) + { + min_sum = hints[axis].space; + } + else if (box_calc[axis].size < (min_sum + hints[axis].space + box_calc[axis].pad)) + { + min_sum = hints[axis].space; + rc++; + } + else + { + min_sum += (hints[axis].space + box_calc[axis].pad); + } + + row = &rows[rc]; + item->row = row; + + if (row->cross_weight < hints[c_axis].weight) + row->cross_weight = hints[c_axis].weight; + if (row->cross_space < hints[c_axis].space) + row->cross_space = hints[c_axis].space; + row->weight_sum += hints[axis].weight; + row->min_sum += hints[axis].space; + row->item_count++; + } + + // initialize homogeneous properties + if (bcd->homogeneous) + { + min_sum = 0; + for (i = 0; i < count; i++) + { + item = &items[i]; + hints = items[i].hints; + + if (i == 0) + { + min_sum = want[axis]; + } + else if (box_calc[axis].size < (min_sum + want[axis] + box_calc[axis].pad)) + { + min_sum = want[axis]; + rc++; + } + else + { + min_sum += (want[axis] + box_calc[axis].pad); + } + + row = &rows[rc]; + item->row = row; + + if (row->cross_weight < hints[c_axis].weight) + row->cross_weight = hints[c_axis].weight; + if (row->cross_space < hints[c_axis].space) + row->cross_space = hints[c_axis].space; + row->item_count++; + } + } + + // calculate item space of each row + for (id = 0, i = 0; id <= rc; id++) + { + int box_size; + + row = &rows[id]; + row->cur_pos = box_calc[axis].pos; + + box_size = box_calc[axis].size - + (box_calc[axis].pad * (row->item_count - 1)); + row->hgsize = box_size / row->item_count; + + cross_min_sum += row->cross_space; + cross_weight_sum += row->cross_weight; + + if (bcd->homogeneous) + continue; + + if (row->weight_sum > 0) + { + int calc_size; + double orig_weight = row->weight_sum; + + calc_size = box_size; + inlist = NULL; + + item_last += row->item_count; + for (; i < item_last; i++) + { + double denom; + hint = &items[i].hints[axis]; + + denom = (hint->weight * box_size) - (orig_weight * hint->space); + if (denom > 0) + { + items[i].weight_factor = (hint->weight * box_size) / denom; + inlist = eina_inlist_sorted_insert(inlist, EINA_INLIST_GET(&items[i]), + _item_weight_sort_cb); + + } + else + { + calc_size -= hint->space; + row->weight_sum -= hint->weight; + } + } + + EINA_INLIST_FOREACH(inlist, item) + { + double weight_len; + hint = &item->hints[axis]; + + weight_len = (calc_size * hint->weight) / row->weight_sum; + if (hint->space < weight_len) + { + hint->space = weight_len; + } + else + { + row->weight_sum -= hint->weight; + calc_size -= hint->space; + } + } + } + else if (EINA_DBL_EQ(row->weight_sum, 0)) + { + row->cur_pos += (box_size - row->min_sum) * box_calc[axis].align; + } + } + + // calculate row space + box_calc[c_axis].size -= (box_calc[c_axis].pad * rc); + cur_pos = box_calc[c_axis].pos; + if ((box_calc[c_axis].size > cross_min_sum)) + { + if (cross_weight_sum > 0) + { + int orig_size, calc_size; + double orig_weight = cross_weight_sum; + + calc_size = orig_size = box_calc[c_axis].size; + inlist = NULL; + + for (i = 0; i <= rc; i++) + { + double denom; + row = &rows[i]; + + denom = (row->cross_weight * orig_size) - + (orig_weight * row->cross_space); + if (denom > 0) + { + row->weight_factor = (row->cross_weight * orig_size) / denom; + inlist = eina_inlist_sorted_insert(inlist, EINA_INLIST_GET(row), + _row_weight_sort_cb); + + } + else + { + calc_size -= row->cross_space; + cross_weight_sum -= row->cross_weight; + } + } + + EINA_INLIST_FOREACH(inlist, row) + { + double weight_len; + + weight_len = (calc_size * row->cross_weight) / cross_weight_sum; + if (row->cross_space < weight_len) + { + row->cross_space = weight_len; + } + else + { + cross_weight_sum -= row->cross_weight; + calc_size -= row->cross_space; + } + } + } + else if (EINA_DBL_EQ(cross_weight_sum, 0)) + { + cur_pos += (box_calc[c_axis].size - cross_min_sum) * box_calc[c_axis].align; + } + } + + // calculate item geometry + int item_size[2], item_pos[2], sw, sh; + + row = NULL; + for (i = 0; i < count; i++) + { + item = &items[i]; + hints = items[i].hints; + + if (row && (row != item->row)) + cur_pos += row->cross_space + box_calc[c_axis].pad; + + row = item->row; + + if (bcd->homogeneous) + hints[axis].space = row->hgsize; + hints[c_axis].space = row->cross_space; + sw = hints[0].space - (hints[0].margin[0] + hints[0].margin[1]); + sh = hints[1].space - (hints[1].margin[0] + hints[1].margin[1]); + + item_size[0] = ((hints[0].weight > 0) && hints[0].fill) ? sw : 0; + item_size[1] = ((hints[1].weight > 0) && hints[1].fill) ? sh : 0; + + _efl_ui_container_layout_min_max_calc(hints, &item_size[0], &item_size[1], + (hints[0].aspect > 0) && (hints[1].aspect > 0)); + + item_pos[axis] = row->cur_pos + 0.5; + item_pos[c_axis] = cur_pos + 0.5; + + 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)); + + row->cur_pos += hints[axis].space + box_calc[axis].pad; + + efl_gfx_entity_geometry_set(items[i].obj, + EINA_RECT(item_pos[0], item_pos[1], + item_size[0], item_size[1])); + } + + want[axis] += (box_calc[axis].margin[0] + box_calc[axis].margin[1]); + want[c_axis] = (box_calc[c_axis].margin[0] + box_calc[c_axis].margin[1]) + + (box_calc[c_axis].pad * rc) + cross_min_sum; + + efl_gfx_hint_size_restricted_min_set(obj, EINA_SIZE2D(want[0], want[1])); + + efl_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL); } #include "efl_ui_box_flow.eo.c" diff --git a/src/lib/elementary/efl_ui_box_flow.eo b/src/lib/elementary/efl_ui_box_flow.eo index 3ba120b6fb..91336525dc 100644 --- a/src/lib/elementary/efl_ui_box_flow.eo +++ b/src/lib/elementary/efl_ui_box_flow.eo @@ -1,24 +1,6 @@ class @beta Efl.Ui.Box_Flow extends Efl.Ui.Box { [[A custom layout engine for @Efl.Ui.Box.]] - methods { - @property box_flow_homogenous { - [[Box flow homogenous property]] - set {} - get {} - values { - val: bool; [[$true if the box flow layout is homogenous, $false otherwise]] - } - } - @property box_flow_max_size { - [[Box flow maximum size property]] - set {} - get {} - values { - val: bool; [[$true if the box flow layout has the maximal size, $false otherwise]] - } - } - } implements { Efl.Pack_Layout.layout_update; } diff --git a/src/tests/elementary/efl_ui_suite.c b/src/tests/elementary/efl_ui_suite.c index aa5de44f60..5783c203ce 100644 --- a/src/tests/elementary/efl_ui_suite.c +++ b/src/tests/elementary/efl_ui_suite.c @@ -13,6 +13,7 @@ static const Efl_Test_Case etc[] = { { "efl_ui_focus", efl_ui_test_focus}, { "efl_ui_focus_sub", efl_ui_test_focus_sub}, { "efl_ui_box", efl_ui_test_box}, + { "efl_ui_box_flow", efl_ui_test_box_flow}, { "efl_ui_table", efl_ui_test_table}, { "efl_ui_grid", efl_ui_test_grid}, { "efl_ui_relative_layout", efl_ui_test_relative_layout}, diff --git a/src/tests/elementary/efl_ui_suite.h b/src/tests/elementary/efl_ui_suite.h index 4f5e529af0..1f393828f4 100644 --- a/src/tests/elementary/efl_ui_suite.h +++ b/src/tests/elementary/efl_ui_suite.h @@ -20,6 +20,7 @@ } void efl_ui_test_box(TCase *tc); +void efl_ui_test_box_flow(TCase *tc); void efl_ui_test_table(TCase *tc); void efl_ui_test_grid(TCase *tc); void efl_ui_test_relative_layout(TCase *tc); diff --git a/src/tests/elementary/efl_ui_test_box_flow.c b/src/tests/elementary/efl_ui_test_box_flow.c new file mode 100644 index 0000000000..52af8f0c15 --- /dev/null +++ b/src/tests/elementary/efl_ui_test_box_flow.c @@ -0,0 +1,416 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include "elm_suite.h" + +#define COORD_EQ(a, b) (!!(abs(a - b) < 2)) +#define GEOMETRY_EQ(a, b) (COORD_EQ(a.x, b.x) && COORD_EQ(a.y, b.y) && \ + COORD_EQ(a.w, b.w) && COORD_EQ(a.h, b.h)) + +typedef struct { + Eina_Size2D max; + Eina_Size2D min; + double weightx; + double weighty; + double alignx; + double aligny; + int marginl; + int marginr; + int margint; + int marginb; + Efl_Gfx_Hint_Aspect mode; + Eina_Size2D aspect; + Eina_Bool fillx; + Eina_Bool filly; + Eina_Size2D layout_size; + Eina_Size2D layout_expected; + Eina_Rect expected; + char testname[1024]; +} Hint; + +static Hint hints[] = { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(0, 0), 1, 1, 0.5, 0.5, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT(0, 0, 200, 200), "[0]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.5, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT(0, 0, 200, 200), "[1]" }, + { EINA_SIZE2D(50, 150), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT((200 - 70) * 0.3, (200 - 150) * 0.7, 70, 150), "[2]" }, + { EINA_SIZE2D(150, -1), EINA_SIZE2D(70, 70), 0, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT((200 - 70) * 0.8, (200 - 70) * 0.2, 70, 70), "[3]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_TRUE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT((200 - 70) * 0.3, (200 - 70) * 0.2, 70, 70), "[4]" }, + { EINA_SIZE2D(150, 150), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_TRUE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 200), + EINA_RECT((200 - 70) * 0.3, (200 - 70) * 0.2, 70, 70), "[5]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 0, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 210), + EINA_RECT((200 - 70) * 0.8, 0, 70, 70 * 3), "[6]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 0, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(300, 300), EINA_SIZE2D(300, 300), + EINA_RECT((300 - 70) * 0.8, (300 - 70 * 3) * 0.7, 70, 70 * 3), "[7]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 210), + EINA_RECT((200 - 70) * 0.3, 0, 70, 70 * 3), "[8]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(300, 300), EINA_SIZE2D(300, 300), + EINA_RECT((300 - 70) * 0.3, (300 - 70 * 3) * 0.2, 70, 70 * 3), "[9]" }, + { EINA_SIZE2D(-1, 150), EINA_SIZE2D(70, 70), 0, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 210), + EINA_RECT((200 - 70) * 0.8, 0, 70, 70 * 3), "[10]" }, + { EINA_SIZE2D(-1, 150), EINA_SIZE2D(70, 70), 0, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(300, 300), EINA_SIZE2D(300, 300), + EINA_RECT((300 - 70) * 0.8, (300 - 70 * 3) * 0.7, 70, 70 * 3), "[11]" }, + { EINA_SIZE2D(-1, 150), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(200, 200), EINA_SIZE2D(200, 210), + EINA_RECT((200 - 70) * 0.3, 0, 70, 70 * 3), "[12]" }, + { EINA_SIZE2D(-1, 150), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(300, 300), EINA_SIZE2D(300, 300), + EINA_RECT((300 - 70) * 0.3, (300 - 70 * 3) * 0.2, 70, 70 * 3), "[13]" }, +}; + +static Hint hints2[][2] = { + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.3, (150 - 70) * 0.7, 70, 70), "[1/1 weight btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.8, (150 - 70) * 0.2 + 150, 70, 70), "[1/1 weight btn2]" } + }, + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.3, 0, 70, 70), "[0/1 weight btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_VERTICAL, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - ((300 - 70) / 3)) * 0.8, 70, (300 - 70) / 3, (300 - 70)), "[0/1 weight btn2]" } + }, + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.3, (300 - 280) * 0.2, 70, 70), "[0/0 weight btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 0, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_HORIZONTAL, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.8, (300 - 280) * 0.2 + 70, 70, 70 * 3), "[0/0 weight btn2]" } + }, +}; + +static Hint hints3[][3] = { + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT(0, 0, 150, 100), "[1/1/1 weight_l btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 100), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT(0, 100, 150, 100), "[1/1/1 weight_l btn2]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT(0, 100 + 100, 150, 100), "[1/1/1 weight_l btn3]" } + }, + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 270), EINA_SIZE2D(150, 270), + EINA_RECT(0, 0, 150, 85), "[1/1/1 weight_m btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 100), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 270), EINA_SIZE2D(150, 270), + EINA_RECT(0, 85, 150, 100), "[1/1/1 weight_m btn2]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 270), EINA_SIZE2D(150, 270), + EINA_RECT(0, 100 + 85, 150, 85), "[1/1/1 weight_m btn3]" } + }, + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.3, 0.7, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 200), EINA_SIZE2D(150, 200), + EINA_RECT(0, 0, 75, 100), "[1/1/1 weight_s btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 100), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 200), EINA_SIZE2D(150, 200), + EINA_RECT(0, 100, 75, 100), "[1/1/1 weight_s btn2]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(70, 70), 1, 1, 0.8, 0.2, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_NONE, EINA_SIZE2D(0, 0), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(150, 200), EINA_SIZE2D(150, 200), + EINA_RECT(75, 0, 75, 200), "[1/1/1 weight_s btn3]" } + }, + { + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(0, 0), 1, 1, 0.5, 0.5, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(300, 900), EINA_SIZE2D(300, 900), + EINA_RECT(100, 0, 100, 300), "[aspect resize btn]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(0, 0), 1, 1, 0.5, 0.5, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(300, 900), EINA_SIZE2D(300, 900), + EINA_RECT(100, 300, 100, 300), "[aspect resize btn2]" }, + { EINA_SIZE2D(-1, -1), EINA_SIZE2D(0, 0), 1, 1, 0.5, 0.5, 0, 0, 0, 0, + EFL_GFX_HINT_ASPECT_BOTH, EINA_SIZE2D(1, 3), EINA_TRUE, EINA_TRUE, + EINA_SIZE2D(300, 900), EINA_SIZE2D(300, 900), + EINA_RECT(100, 300 + 300, 100, 300), "[aspect resize btn3]" } + }, +}; + +static Eo *win, *layout; + +static void +btn_hint_set(Eo *btn, Hint *hint) +{ + efl_gfx_entity_size_set(layout, hint->layout_size); + efl_gfx_hint_size_min_set(layout, hint->layout_size); + efl_gfx_hint_size_max_set(btn, hint->max); + efl_gfx_hint_size_min_set(btn, hint->min); + efl_gfx_hint_weight_set(btn, hint->weightx, hint->weighty); + efl_gfx_hint_align_set(btn, hint->alignx, hint->aligny); + efl_gfx_hint_fill_set(btn, hint->fillx, hint->filly); + efl_gfx_hint_aspect_set(btn, hint->mode, hint->aspect); + efl_canvas_group_calculate(layout); +} + +static void +btn_geom_assert(Hint *hint, Eina_Rect btn_geom) +{ + Eina_Size2D layout_size, layout_min; + + layout_size = efl_gfx_entity_size_get(layout); + layout_min = efl_gfx_hint_size_combined_min_get(layout); + layout_size.w = layout_size.w > layout_min.w ? layout_size.w : layout_min.w; + layout_size.h = layout_size.h > layout_min.h ? layout_size.h : layout_min.h; + + ck_assert_msg(GEOMETRY_EQ(btn_geom, hint->expected), + "Case %s failed... button geometry: (%d, %d, %d, %d) expected geometry: (%d, %d, %d, %d)", + hint->testname, btn_geom.x, btn_geom.y, btn_geom.w, btn_geom.h, + hint->expected.x, hint->expected.y, hint->expected.w, hint->expected.h); + ck_assert_msg(COORD_EQ(layout_size.w, hint->layout_expected.w) && + COORD_EQ(layout_size.h, hint->layout_expected.h), + "Case %s failed... layout size: (%d, %d) expected size: (%d, %d)", + hint->testname, layout_size.w, layout_size.h, + hint->layout_expected.w, hint->layout_expected.h); +} + +static void +layout_setup() +{ + win = win_add(); + + layout = efl_add(EFL_UI_BOX_FLOW_CLASS, win, + efl_pack_align_set(efl_added, 0.8, 0.2), + efl_ui_direction_set(efl_added, EFL_UI_DIR_VERTICAL)); +} + +static void +layout_teardown() +{ + if (win) + { + efl_del(win); + win = NULL; + } +} + +EFL_START_TEST (efl_ui_box_flow_class_check) +{ + const char *class; + + class = efl_class_name_get(layout); + + ck_assert(class != NULL); + ck_assert(!strcmp(class, "Efl.Ui.Box_Flow")); +} +EFL_END_TEST + +EFL_START_TEST (efl_ui_box_flow_layout_update) +{ + int i, max_index = (sizeof(hints) / sizeof(Hint)); + + Eo *btn = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_pack_end(layout, efl_added)); + + for (i = 0; i < max_index; i++) + { + btn_hint_set(btn, &hints[i]); + btn_geom_assert(&hints[i], efl_gfx_entity_geometry_get(btn)); + } +} +EFL_END_TEST + +EFL_START_TEST (efl_ui_box_flow_layout_update_pack) +{ + int i, max_index2, max_index3; + Eo *btn, *btn2, *btn3; + + max_index2 = ((sizeof(hints2) / sizeof(Hint)) / 2); + max_index3 = ((sizeof(hints3) / sizeof(Hint)) / 3); + + btn = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_pack_end(layout, efl_added)); + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_pack_end(layout, efl_added)); + + for (i = 0; i < max_index2; i++) + { + btn_hint_set(btn, &hints2[i][0]); + btn_hint_set(btn2, &hints2[i][1]); + btn_geom_assert(&hints2[i][0], efl_gfx_entity_geometry_get(btn)); + btn_geom_assert(&hints2[i][1], efl_gfx_entity_geometry_get(btn2)); + } + + btn3 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_pack_end(layout, efl_added)); + + for (i = 0; i < max_index3; i++) + { + btn_hint_set(btn, &hints3[i][0]); + btn_hint_set(btn2, &hints3[i][1]); + btn_hint_set(btn3, &hints3[i][2]); + btn_geom_assert(&hints3[i][0], efl_gfx_entity_geometry_get(btn)); + btn_geom_assert(&hints3[i][1], efl_gfx_entity_geometry_get(btn2)); + btn_geom_assert(&hints3[i][2], efl_gfx_entity_geometry_get(btn3)); + } + + // aspect resize test + hints3[3][0].layout_expected = hints3[3][0].layout_size = EINA_SIZE2D(150, 450); + hints3[3][1].layout_expected = hints3[3][1].layout_size = EINA_SIZE2D(150, 450); + hints3[3][2].layout_expected = hints3[3][2].layout_size = EINA_SIZE2D(150, 450); + hints3[3][0].expected = EINA_RECT(50, 0, 50, 150); + hints3[3][1].expected = EINA_RECT(50, 150, 50, 150); + hints3[3][2].expected = EINA_RECT(50, 300, 50, 150); + + btn_hint_set(btn, &hints3[3][0]); + btn_hint_set(btn2, &hints3[3][1]); + btn_hint_set(btn3, &hints3[3][2]); + btn_geom_assert(&hints3[3][0], efl_gfx_entity_geometry_get(btn)); + btn_geom_assert(&hints3[3][1], efl_gfx_entity_geometry_get(btn2)); + btn_geom_assert(&hints3[3][2], efl_gfx_entity_geometry_get(btn3)); + + efl_ui_direction_set(layout, EFL_UI_DIR_HORIZONTAL); + hints3[3][0].layout_expected = hints3[3][0].layout_size = EINA_SIZE2D(300, 900); + hints3[3][1].layout_expected = hints3[3][1].layout_size = EINA_SIZE2D(300, 900); + hints3[3][2].layout_expected = hints3[3][2].layout_size = EINA_SIZE2D(300, 900); + hints3[3][0].expected = EINA_RECT(0, 300, 100, 300); + hints3[3][1].expected = EINA_RECT(100, 300, 100, 300); + hints3[3][2].expected = EINA_RECT(200, 300, 100, 300); + + btn_hint_set(btn, &hints3[3][0]); + btn_hint_set(btn2, &hints3[3][1]); + btn_hint_set(btn3, &hints3[3][2]); + btn_geom_assert(&hints3[3][0], efl_gfx_entity_geometry_get(btn)); + btn_geom_assert(&hints3[3][1], efl_gfx_entity_geometry_get(btn2)); + btn_geom_assert(&hints3[3][2], efl_gfx_entity_geometry_get(btn3)); + + hints3[3][0].layout_expected = hints3[3][0].layout_size = EINA_SIZE2D(150, 450); + hints3[3][1].layout_expected = hints3[3][1].layout_size = EINA_SIZE2D(150, 450); + hints3[3][2].layout_expected = hints3[3][2].layout_size = EINA_SIZE2D(150, 450); + hints3[3][0].expected = EINA_RECT(0, 150, 50, 150); + hints3[3][1].expected = EINA_RECT(50, 150, 50, 150); + hints3[3][2].expected = EINA_RECT(100, 150, 50, 150); + + btn_hint_set(btn, &hints3[3][0]); + btn_hint_set(btn2, &hints3[3][1]); + btn_hint_set(btn3, &hints3[3][2]); + btn_geom_assert(&hints3[3][0], efl_gfx_entity_geometry_get(btn)); + btn_geom_assert(&hints3[3][1], efl_gfx_entity_geometry_get(btn2)); + btn_geom_assert(&hints3[3][2], efl_gfx_entity_geometry_get(btn3)); +} +EFL_END_TEST + +EFL_START_TEST (efl_ui_box_flow_size) +{ +#define USERMIN_CHECK(a, b) \ + efl_canvas_group_calculate(layout); \ + user_min = efl_gfx_hint_size_min_get(layout); \ + ck_assert_msg(COORD_EQ(user_min.w, (a)) && COORD_EQ(user_min.h, (b)), \ + "Case box_size failed... user_min: (%d, %d) expected user_min: (%d, %d)", \ + user_min.w, user_min.h, (a), (b)); + +#define MIN_CHECK(a, b) \ + efl_canvas_group_calculate(layout); \ + min = efl_gfx_hint_size_combined_min_get(layout); \ + ck_assert_msg(COORD_EQ(min.w, (a)) && COORD_EQ(min.h, (b)), \ + "Case box_size failed... min: (%d, %d) expected min: (%d, %d)", \ + min.w, min.h, (a), (b)); + + Eo *btn, *btn2, *btn3; + Eina_Size2D min, user_min; + + btn = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(100, 100)), + efl_pack_end(layout, efl_added)); + + USERMIN_CHECK(0, 0); + MIN_CHECK(100, 100); + + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(100, 100)), + efl_pack_end(layout, efl_added)); + btn3 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(100, 100)), + efl_pack_end(layout, efl_added)); + USERMIN_CHECK(0, 0); + MIN_CHECK(300, 100); + + efl_pack_unpack(layout, btn2); + USERMIN_CHECK(0, 0); + MIN_CHECK(200, 100); + + efl_pack_unpack(layout, btn3); + USERMIN_CHECK(0, 0); + MIN_CHECK(100, 100); + + efl_pack_unpack(layout, btn); + USERMIN_CHECK(0, 0); + MIN_CHECK(0, 0); + + efl_pack_end(layout, btn); + efl_gfx_hint_size_min_set(layout, EINA_SIZE2D(200, 200)); + USERMIN_CHECK(200, 200); + MIN_CHECK(200, 200); + + efl_pack_end(layout, btn2); + efl_pack_end(layout, btn3); + USERMIN_CHECK(200, 200); + MIN_CHECK(300, 200); + +#undef USERMIN_ASSERT +#undef MIN_ASSERT +} +EFL_END_TEST + +void efl_ui_test_box_flow(TCase *tc) +{ + tcase_add_checked_fixture(tc, layout_setup, layout_teardown); + tcase_add_test(tc, efl_ui_box_flow_class_check); + tcase_add_test(tc, efl_ui_box_flow_layout_update); + tcase_add_test(tc, efl_ui_box_flow_layout_update_pack); + tcase_add_test(tc, efl_ui_box_flow_size); +} diff --git a/src/tests/elementary/meson.build b/src/tests/elementary/meson.build index eaffab6d6b..8ff6298917 100644 --- a/src/tests/elementary/meson.build +++ b/src/tests/elementary/meson.build @@ -123,6 +123,7 @@ efl_ui_suite_src = [ 'efl_ui_test_focus.c', 'efl_ui_test_focus_sub.c', 'efl_ui_test_box.c', + 'efl_ui_test_box_flow.c', 'efl_ui_test_table.c', 'efl_ui_test_grid.c', 'efl_ui_test_relative_layout.c',