jaehyun pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=3118bfc34bb97b01a0cdb0caf674aaf3fc20565c
commit 3118bfc34bb97b01a0cdb0caf674aaf3fc20565c Author: Yeongjong Lee <[email protected]> Date: Fri Feb 22 19:47:47 2019 +0900 efl_ui_relative_layout: introduce new relative container Summary: Efl.Ui.Relative_Layout is a container which allows you to position and size with relation to each other. it is possible to position and size using relation like edje even though you don't know a edc script. Position and size can be changed dynamically using widget APIs. @feature ref T5487 Test Plan: make check examples elementary_test -to 'efl.ui.relative_layout' Reviewers: cedric, Hermet, Jaehyun_Cho, zmike, bu5hm4n, jpeg, segfaultxavi Reviewed By: Jaehyun_Cho, segfaultxavi Subscribers: segfaultxavi, kimcinoo Tags: #efl Maniphest Tasks: T5487 Differential Revision: https://phab.enlightenment.org/D7524 --- src/Makefile_Elementary.am | 7 +- src/bin/elementary/meson.build | 1 + src/bin/elementary/test.c | 3 + src/bin/elementary/test_ui_relative_layout.c | 319 ++++++++++++ src/examples/elementary.mk | 8 +- src/examples/elementary/.gitignore | 2 + .../elementary/efl_ui_relative_layout_example_01.c | 51 ++ .../elementary/efl_ui_relative_layout_example_02.c | 45 ++ src/lib/elementary/Efl_Ui.h | 1 + src/lib/elementary/Elementary.h | 1 + src/lib/elementary/efl_ui_relative_layout.c | 552 +++++++++++++++++++++ src/lib/elementary/efl_ui_relative_layout.eo | 79 +++ .../elementary/efl_ui_relative_layout_private.h | 90 ++++ src/lib/elementary/meson.build | 5 +- src/tests/elementary/efl_ui_suite.c | 1 + src/tests/elementary/efl_ui_suite.h | 1 + src/tests/elementary/efl_ui_test_relative_layout.c | 300 +++++++++++ src/tests/elementary/meson.build | 1 + 18 files changed, 1463 insertions(+), 4 deletions(-) diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index 5a2ddedea8..1529dcd203 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -133,6 +133,7 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_text_part.eo \ lib/elementary/efl_ui_caching_factory.eo \ lib/elementary/efl_ui_widget_factory.eo \ + lib/elementary/efl_ui_relative_layout.eo \ $(NULL) # More public files -- FIXME @@ -455,7 +456,8 @@ includesunstable_HEADERS = \ lib/elementary/efl_page_indicator_icon.h \ lib/elementary/efl_ui_tab_pager_private.h \ lib/elementary/efl_ui_tab_bar_private.h \ - lib/elementary/efl_ui_tab_page_private.h + lib/elementary/efl_ui_tab_page_private.h \ + lib/elementary/efl_ui_relative_layout_private.h includesunstabledir = $(includedir)/elementary-@VMAJ@ nodist_includesunstable_HEADERS = \ @@ -893,6 +895,7 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/efl_ui_homogeneous_model.c \ lib/elementary/efl_ui_exact_model.c \ lib/elementary/efl_ui_average_model.c \ + lib/elementary/efl_ui_relative_layout.c \ $(NULL) @@ -1111,6 +1114,7 @@ bin/elementary/test_gesture_framework.c \ bin/elementary/test_ui_tab_pager.c \ bin/elementary/test_ui_pager.c \ bin/elementary/test_ui_pager_scroll.c \ +bin/elementary/test_ui_relative_layout.c \ bin/elementary/test.h bin_elementary_elementary_test_LDADD = @USE_ELEMENTARY_LIBS@ @@ -1620,6 +1624,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_relative_layout.c \ tests/elementary/efl_ui_test_grid.c \ tests/elementary/efl_ui_test_image.c \ tests/elementary/efl_ui_test_image_zoomable.c \ diff --git a/src/bin/elementary/meson.build b/src/bin/elementary/meson.build index 81e6309be3..a3a570a25c 100644 --- a/src/bin/elementary/meson.build +++ b/src/bin/elementary/meson.build @@ -155,6 +155,7 @@ elementary_test_src = [ 'test_win_indicator.c', 'test_gesture_framework.c', 'test_ui_tab_pager.c', + 'test_ui_relative_layout.c', 'test.h' ] diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index 15fcc8fa5c..fa2bb740b5 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -377,6 +377,8 @@ void test_ui_tab_pager(void *data, Evas_Object *obj, void *event_info); void test_ui_pager(void *data, Evas_Object *obj, void *event_info); void test_ui_pager_scroll(void *data, Evas_Object *obj, void *event_info); +void test_ui_relative_layout(void *data, Evas_Object *obj, void *event_info); + static void _list_udpate(void); static Evas_Object *win, *tbx, *entry; // TODO: refactoring @@ -842,6 +844,7 @@ add_tests: ADD_TEST_EO(NULL, "Containers", "Efl.Ui.Table", test_ui_table); ADD_TEST_EO(NULL, "Containers", "Efl.Ui.Table (Linear API)", test_ui_table_linear); ADD_TEST_EO(NULL, "Containers", "Efl.Ui.Table_Static", test_ui_table_static); + ADD_TEST_EO(NULL, "Containers", "Efl.Ui.Relative_Layout", test_ui_relative_layout); //------------------------------// ADD_TEST_EO(NULL, "Events", "Event Refeed", test_events); diff --git a/src/bin/elementary/test_ui_relative_layout.c b/src/bin/elementary/test_ui_relative_layout.c new file mode 100644 index 0000000000..9cb8b168c7 --- /dev/null +++ b/src/bin/elementary/test_ui_relative_layout.c @@ -0,0 +1,319 @@ +#include "test.h" +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Elementary.h> + +static Eo *layout, *btn1, *btn2, *btn3; + +typedef enum { + LEFT, + RIGHT, + TOP, + BOTTOM +} Options; + +static void +_btn_clicked_to_cb(void *data, const Efl_Event *event) +{ + Eo *to, *btn, *obj = event->object; + Options opt = (Options)data; + double relative; + + btn = efl_key_wref_get(obj, "btn"); + to = efl_key_wref_get(obj, "to"); + + do + { + if (to == layout) + to = btn1; + else if (to == btn1) + to = btn2; + else if (to == btn2) + to = btn3; + else if (to == btn3) + to = layout; + } + while (btn == to); + efl_key_wref_set(obj, "to", to); + + switch (opt) + { + case LEFT: + efl_ui_relative_layout_relation_left_get(layout, btn, NULL, &relative); + efl_ui_relative_layout_relation_left_set(layout, btn, to, relative); + break; + case RIGHT: + efl_ui_relative_layout_relation_right_get(layout, btn, NULL, &relative); + efl_ui_relative_layout_relation_right_set(layout, btn, to, relative); + break; + case TOP: + efl_ui_relative_layout_relation_top_get(layout, btn, NULL, &relative); + efl_ui_relative_layout_relation_top_set(layout, btn, to, relative); + break; + case BOTTOM: + efl_ui_relative_layout_relation_bottom_get(layout, btn, NULL, &relative); + efl_ui_relative_layout_relation_bottom_set(layout, btn, to, relative); + break; + } + efl_text_set(obj, ((to == layout) ? "parent" : (char *)efl_text_get(to))); + efl_pack_layout_request(layout); +} + +static void +_slider_changed_relative_cb(void *data, const Efl_Event *event) +{ + Options opt = (Options)data; + Eo *btn, *slider = event->object; + double val; + + btn = efl_key_wref_get(slider, "btn"); + val = efl_ui_range_value_get(slider); + + switch (opt) + { + case LEFT: + efl_ui_relative_layout_relation_left_set(layout, btn, NULL, val); + break; + case RIGHT: + efl_ui_relative_layout_relation_right_set(layout, btn, NULL, val); + break; + case TOP: + efl_ui_relative_layout_relation_top_set(layout, btn, NULL, val); + break; + case BOTTOM: + efl_ui_relative_layout_relation_bottom_set(layout, btn, NULL, val); + break; + } + efl_pack_layout_request(layout); +} + +static void +_slider_changed_align_cb(void *data, const Efl_Event *event) +{ + char opt = (char)(uintptr_t)data; + Eo *btn, *slider = event->object; + double val, x, y; + + btn = efl_key_wref_get(slider, "btn"); + val = efl_ui_range_value_get(slider); + + efl_gfx_hint_align_get(btn, &x, &y); + if (opt == 'x') + efl_gfx_hint_align_set(btn, val, y); + else if (opt == 'y') + efl_gfx_hint_align_set(btn, x, val); + + efl_pack_layout_request(layout); +} + +static void +_setter_add(Eo *vbox, Eo *btn, Options option) +{ + Eo *to, *hbox; + char *text, *btn_text; + double relative; + + switch (option) + { + case LEFT: + text = "left"; + efl_ui_relative_layout_relation_left_get(layout, btn, &to, &relative); + break; + case RIGHT: + text = "right"; + efl_ui_relative_layout_relation_right_get(layout, btn, &to, &relative); + break; + case TOP: + text = "top"; + efl_ui_relative_layout_relation_top_get(layout, btn, &to, &relative); + break; + case BOTTOM: + text = "bottom"; + efl_ui_relative_layout_relation_bottom_get(layout, btn, &to, &relative); + break; + } + btn_text = ((to == layout) ? "parent" : (char *)efl_text_get(to)); + + hbox = efl_add(EFL_UI_BOX_CLASS, vbox, + efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL), + efl_pack_padding_set(efl_added, 2, 2, EINA_TRUE), + efl_pack(vbox, efl_added)); + + efl_add(EFL_UI_TEXT_CLASS, hbox, + efl_text_set(efl_added, text), + efl_text_interactive_editable_set(efl_added, EINA_FALSE), + efl_text_valign_set(efl_added, 0.5), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(40, 0)), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_BUTTON_CLASS, hbox, + efl_text_set(efl_added, btn_text), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(60, 0)), + efl_key_wref_set(efl_added, "to", to), + efl_key_wref_set(efl_added, "btn", btn), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _btn_clicked_to_cb, (void *)option), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_SLIDER_CLASS, hbox, + efl_ui_range_min_max_set(efl_added, 0.0, 1.0), + efl_ui_range_step_set(efl_added, 0.1), + efl_ui_range_value_set(efl_added, relative), + efl_key_wref_set(efl_added, "btn", btn), + efl_event_callback_add(efl_added, EFL_UI_SLIDER_EVENT_CHANGED, _slider_changed_relative_cb, (void *)option), + efl_pack(hbox, efl_added)); +} + +static void +_button_frame_add(Eo *box, Eo *btn) +{ + Eo *f, *vbox, *hbox; + double align_x, align_y; + + f = efl_add(EFL_UI_FRAME_CLASS, box, + efl_text_set(efl_added, efl_text_get(btn)), + efl_gfx_hint_weight_set(efl_added, EFL_GFX_HINT_EXPAND, 0), + efl_pack(box, efl_added)); + + vbox = efl_add(EFL_UI_BOX_CLASS, f, + efl_ui_direction_set(efl_added, EFL_UI_DIR_VERTICAL), + efl_pack_padding_set(efl_added, 2, 2, EINA_TRUE), + efl_gfx_hint_margin_set(efl_added, 2, 2, 2, 2), + efl_content_set(f, efl_added)); + + hbox = efl_add(EFL_UI_BOX_CLASS, vbox, + efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL), + efl_pack_padding_set(efl_added, 2, 2, EINA_TRUE), + efl_pack(vbox, efl_added)); + + efl_add(EFL_CANVAS_RECTANGLE_CLASS, hbox, + efl_gfx_color_set(efl_added, 0, 0, 0, 0), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(40, 0)), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_TEXT_CLASS, hbox, + efl_text_set(efl_added, "to"), + efl_text_interactive_editable_set(efl_added, EINA_FALSE), + efl_text_halign_set(efl_added, 0.5), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(60, 0)), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_TEXT_CLASS, hbox, + efl_text_set(efl_added, "relative"), + efl_text_halign_set(efl_added, 0.5), + efl_text_interactive_editable_set(efl_added, EINA_FALSE), + efl_pack(hbox, efl_added)); + + _setter_add(vbox, btn, LEFT); + _setter_add(vbox, btn, RIGHT); + _setter_add(vbox, btn, TOP); + _setter_add(vbox, btn, BOTTOM); + + /* align setter */ + efl_gfx_hint_align_get(btn, &align_x, &align_y); + + hbox = efl_add(EFL_UI_BOX_CLASS, vbox, + efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL), + efl_pack_padding_set(efl_added, 2, 2, EINA_TRUE), + efl_pack(vbox, efl_added)); + + efl_add(EFL_UI_TEXT_CLASS, hbox, + efl_text_set(efl_added, "align_x"), + efl_text_interactive_editable_set(efl_added, EINA_FALSE), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(40, 0)), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_SLIDER_CLASS, hbox, + efl_ui_range_min_max_set(efl_added, 0.0, 1.0), + efl_ui_range_step_set(efl_added, 0.1), + efl_ui_range_value_set(efl_added, align_x), + efl_key_wref_set(efl_added, "btn", btn), + efl_event_callback_add(efl_added, EFL_UI_SLIDER_EVENT_CHANGED, _slider_changed_align_cb, (void *)'x'), + efl_pack(hbox, efl_added)); + + hbox = efl_add(EFL_UI_BOX_CLASS, vbox, + efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL), + efl_pack_padding_set(efl_added, 2, 2, EINA_TRUE), + efl_pack(vbox, efl_added)); + + efl_add(EFL_UI_TEXT_CLASS, hbox, + efl_text_set(efl_added, "align_y"), + efl_text_interactive_editable_set(efl_added, EINA_FALSE), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(40, 0)), + efl_gfx_hint_weight_set(efl_added, 0, EFL_GFX_HINT_EXPAND), + efl_pack(hbox, efl_added)); + + efl_add(EFL_UI_SLIDER_CLASS, hbox, + efl_ui_range_min_max_set(efl_added, 0.0, 1.0), + efl_ui_range_step_set(efl_added, 0.1), + efl_ui_range_value_set(efl_added, align_y), + efl_key_wref_set(efl_added, "btn", btn), + efl_event_callback_add(efl_added, EFL_UI_SLIDER_EVENT_CHANGED, _slider_changed_align_cb, (void *)'y'), + efl_pack(hbox, efl_added)); +} + +void +test_ui_relative_layout(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eo *win, *vbox, *f, *hbox; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Relative_Layout"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + vbox = efl_add(EFL_UI_BOX_CLASS, win, + efl_ui_direction_set(efl_added, EFL_UI_DIR_VERTICAL), + efl_pack_padding_set(efl_added, 10, 10, EINA_TRUE), + efl_gfx_hint_margin_set(efl_added, 5, 5, 5, 5), + efl_content_set(win, efl_added)); + + /* controls */ + f = efl_add(EFL_UI_FRAME_CLASS, vbox, + efl_text_set(efl_added, "Controls"), + efl_gfx_hint_weight_set(efl_added, EFL_GFX_HINT_EXPAND, 0), + efl_pack(vbox, efl_added)); + + hbox = efl_add(EFL_UI_BOX_CLASS, f, + efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL), + efl_pack_padding_set(efl_added, 10, 0, EINA_TRUE), + efl_content_set(f, efl_added)); + + /* contents */ + f = efl_add(EFL_UI_FRAME_CLASS, vbox, + efl_text_set(efl_added, "Contents"), + efl_pack(vbox, efl_added)); + + layout = efl_add(EFL_UI_RELATIVE_LAYOUT_CLASS, f, + efl_content_set(f, efl_added)); + + btn1 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "button1"), + efl_gfx_hint_align_set(efl_added, 0.0, 0.0), + efl_ui_relative_layout_relation_right_set(layout, efl_added, layout, 0.0), + efl_ui_relative_layout_relation_bottom_set(layout, efl_added, layout, 0.0)); + + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "button2"), + efl_gfx_hint_align_set(efl_added, 0.5, 0.0), + efl_ui_relative_layout_relation_left_set(layout, efl_added, btn1, 1.0), + efl_ui_relative_layout_relation_bottom_set(layout, efl_added, layout, 0.0)); + + btn3 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "button3"), + efl_ui_relative_layout_relation_left_set(layout, efl_added, btn2, 0.0), + efl_ui_relative_layout_relation_top_set(layout, efl_added, btn2, 1.0)); + + _button_frame_add(hbox, btn1); + _button_frame_add(hbox, btn2); + _button_frame_add(hbox, btn3); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(600, 400)); + efl_gfx_entity_visible_set(win, EINA_TRUE); +} diff --git a/src/examples/elementary.mk b/src/examples/elementary.mk index ac8fe37c41..dcae89bb90 100644 --- a/src/examples/elementary.mk +++ b/src/examples/elementary.mk @@ -125,7 +125,9 @@ elementary/efl_ui_list_view_example_2.c \ elementary/efl_ui_list_view_example_3.c \ elementary/efl_canvas_layout_text.c \ elementary/efl_ui_theme_example_01.c \ -elementary/efl_ui_theme_example_02.c +elementary/efl_ui_theme_example_02.c \ +elementary/efl_ui_relative_layout_example_01.c \ +elementary/efl_ui_relative_layout_example_02.c ELM_SRCS += \ elementary/bg_cxx_example_01.cc \ @@ -344,7 +346,9 @@ elementary/efl_ui_list_view_example_2 \ elementary/efl_ui_list_view_example_3 \ elementary/efl_canvas_layout_text \ elementary/efl_ui_theme_example_01 \ -elementary/efl_ui_theme_example_02 +elementary/efl_ui_theme_example_02 \ +elementary/efl_ui_relative_layout_example_01 \ +elementary/efl_ui_relative_layout_example_02 #benchmark3d #sphere-hunter diff --git a/src/examples/elementary/.gitignore b/src/examples/elementary/.gitignore index 11544b23ee..06e20555aa 100644 --- a/src/examples/elementary/.gitignore +++ b/src/examples/elementary/.gitignore @@ -169,3 +169,5 @@ /efl_ui_list_view_example_3 /efl_ui_theme_example_01 /efl_ui_theme_example_02 +/efl_ui_relative_layout_example_01 +/efl_ui_relative_layout_example_02 diff --git a/src/examples/elementary/efl_ui_relative_layout_example_01.c b/src/examples/elementary/efl_ui_relative_layout_example_01.c new file mode 100644 index 0000000000..36ebd3f545 --- /dev/null +++ b/src/examples/elementary/efl_ui_relative_layout_example_01.c @@ -0,0 +1,51 @@ +// gcc -o efl_ui_relative_layout_example_01 efl_ui_relative_layout_example_01.c `pkg-config --cflags --libs elementary` + +#ifdef HAVE_CONFIG_H +#include "elementary_config.h" +#else +#define EFL_BETA_API_SUPPORT 1 +#define EFL_EO_API_SUPPORT 1 +#endif + +#include <Elementary.h> +#include <Efl.h> + +EAPI_MAIN int +elm_main(int argc, char **argv) +{ + Eo *win, *layout, *btn1, *btn2, *btn3; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Relative_Layout"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + layout = efl_add(EFL_UI_RELATIVE_LAYOUT_CLASS, win, + efl_content_set(win, efl_added)); + + btn1 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "btn1"), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(100, 100)), + efl_gfx_hint_align_set(efl_added, 0, 0), + efl_gfx_hint_margin_set(efl_added, 10, 30, 20, 40), + efl_ui_relative_layout_relation_right_set(layout, efl_added, layout, 0.0), + efl_ui_relative_layout_relation_bottom_set(layout, efl_added, layout, 0.0)); + + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "btn2"), + efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(0, 200)), + efl_gfx_hint_align_set(efl_added, 0.5, 0), + efl_ui_relative_layout_relation_left_set(layout, efl_added, btn1, 1.0), + efl_ui_relative_layout_relation_bottom_set(layout, efl_added, layout, 0.0)); + + btn3 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "btn3"), + efl_ui_relative_layout_relation_left_set(layout, efl_added, btn2, 0.0), + efl_ui_relative_layout_relation_top_set(layout, efl_added, btn2, 1.0)); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 300)); + + elm_run(); + return 0; +} +ELM_MAIN() diff --git a/src/examples/elementary/efl_ui_relative_layout_example_02.c b/src/examples/elementary/efl_ui_relative_layout_example_02.c new file mode 100644 index 0000000000..4a8d46a810 --- /dev/null +++ b/src/examples/elementary/efl_ui_relative_layout_example_02.c @@ -0,0 +1,45 @@ +// gcc -o efl_ui_relative_layout_example_02 efl_ui_relative_layout_example_02.c `pkg-config --cflags --libs elementary` + +#ifdef HAVE_CONFIG_H +#include "elementary_config.h" +#else +#define EFL_BETA_API_SUPPORT 1 +#define EFL_EO_API_SUPPORT 1 +#endif + +#include <Elementary.h> +#include <Efl.h> + +EAPI_MAIN int +elm_main(int argc, char **argv) +{ + Eo *win, *layout, *btn1, *btn2; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Relative_Layout"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + layout = efl_add(EFL_UI_RELATIVE_LAYOUT_CLASS, win, + efl_content_set(win, efl_added)); + + btn1 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "btn1"), + efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(100, 100))); + + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_text_set(efl_added, "btn2"), + efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(0, 100))); + + efl_ui_relative_layout_relation_right_set(layout, btn1, btn2, 0.0); + efl_ui_relative_layout_relation_bottom_set(layout, btn1, btn2, 0.0); + + efl_ui_relative_layout_relation_left_set(layout, btn2, btn1, 1.0); + efl_ui_relative_layout_relation_top_set(layout, btn2, btn1, 1.0); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 300)); + + elm_run(); + return 0; +} +ELM_MAIN() diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index 54b816a6fe..515ee48c06 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -188,6 +188,7 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel); # include <efl_ui_win.eo.h> # include <efl_ui_win_inlined.eo.h> # include <efl_ui_win_socket.eo.h> +# include <efl_ui_relative_layout.eo.h> /* FIXME: Efl.Ui.Text must not use elm_general.h */ # warning Efl.Ui.Text is not available yet without Elementary.h diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 5bb8374e3a..8e54b4a710 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -360,6 +360,7 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel); # include <efl_ui_navigation_bar_part_back_button.eo.h> # include <efl_ui_navigation_layout.eo.h> # include <efl_ui_stack.eo.h> +# include <efl_ui_relative_layout.eo.h> # ifndef _EFL_UI_PAGER_EO_CLASS_TYPE # define _EFL_UI_PAGER_EO_CLASS_TYPE diff --git a/src/lib/elementary/efl_ui_relative_layout.c b/src/lib/elementary/efl_ui_relative_layout.c new file mode 100644 index 0000000000..c5651fa793 --- /dev/null +++ b/src/lib/elementary/efl_ui_relative_layout.c @@ -0,0 +1,552 @@ +#include "efl_ui_relative_layout_private.h" + +#define MY_CLASS EFL_UI_RELATIVE_LAYOUT_CLASS +#define MY_CLASS_NAME "Efl.Ui.Relative_Layout" + +#define LEFT 0 +#define RIGHT 1 +#define TOP 2 +#define BOTTOM 3 + +#define START (axis ? TOP : LEFT) +#define END (axis ? BOTTOM : RIGHT) + +static void _child_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis); + +static int +_chain_sort_cb(const void *l1, const void *l2) +{ + Efl_Ui_Relative_Layout_Calc *calc1, *calc2; + + calc1 = EINA_INLIST_CONTAINER_GET(l1, Efl_Ui_Relative_Layout_Calc); + calc2 = EINA_INLIST_CONTAINER_GET(l2, Efl_Ui_Relative_Layout_Calc); + + return calc2->comp_factor <= calc1->comp_factor ? -1 : 1; +} + +static Efl_Ui_Relative_Layout_Child * +_efl_ui_relative_layout_register(Efl_Ui_Relative_Layout_Data *pd, Eo *child) +{ + Efl_Ui_Relative_Layout_Child *rc; + + rc = calloc(1, sizeof(Efl_Ui_Relative_Layout_Child)); + if (!rc) return NULL; + + rc->obj = child; + rc->layout = pd->obj; + rc->rel[LEFT].to = rc->layout; + rc->rel[LEFT].relative = 0.0; + rc->rel[RIGHT].to = rc->layout; + rc->rel[RIGHT].relative = 1.0; + rc->rel[TOP].to = rc->layout; + rc->rel[TOP].relative = 0.0; + rc->rel[BOTTOM].to = rc->layout; + rc->rel[BOTTOM].relative = 1.0; + + if (pd->obj == child) + { + rc->calc.state[0] = RELATIVE_CALC_DONE; + rc->calc.state[1] = RELATIVE_CALC_DONE; + rc->calc.chain_state[0] = RELATIVE_CALC_DONE; + rc->calc.chain_state[1] = RELATIVE_CALC_DONE; + } + else + { + efl_ui_widget_sub_object_add(pd->obj, child); + efl_canvas_group_member_add(pd->obj, child); + efl_canvas_group_change(pd->obj); + } + + eina_hash_add(pd->children, &child, rc); + + return rc; +} + +static Efl_Ui_Relative_Layout_Child * +_relative_child_get(Efl_Ui_Relative_Layout_Data *pd, Eo *child) +{ + Efl_Ui_Relative_Layout_Child *rc; + + rc = eina_hash_find(pd->children, &child); + if (!rc) + rc = _efl_ui_relative_layout_register(pd, child); + + return rc; +} + +static Efl_Ui_Relative_Layout_Child * +_relative_child_find(const Eina_Hash *children, Eo *target) +{ + Efl_Ui_Relative_Layout_Child *child; + + child = eina_hash_find(children, &target); + if (!child) + ERR("target(%p(%s)) is not registered", target, efl_class_name_get(target)); + + return child; +} + +static void +_child_aspect_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) +{ + Efl_Ui_Relative_Layout_Calc *calc = &child->calc; + int temph; + + if ((calc->aspect[0] <= 0) || (calc->aspect[1] <= 0)) + { + ERR("Invalid aspect parameter for obj(%p), aspect(%d, %d) ", + child->obj, calc->aspect[0], calc->aspect[1]); + return; + } + + switch (calc->aspect_type) + { + case EFL_GFX_HINT_ASPECT_HORIZONTAL: + if (axis) _child_calc(child, !axis); + calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0]; + break; + case EFL_GFX_HINT_ASPECT_VERTICAL: + if (!axis) _child_calc(child, !axis); + calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1]; + break; + case EFL_GFX_HINT_ASPECT_BOTH: + if (calc->state[!axis] != RELATIVE_CALC_ON) + _child_calc(child, !axis); + temph = calc->want[axis].length * calc->aspect[!axis] / calc->aspect[axis]; + if (temph > calc->want[!axis].length) + { + temph = calc->want[!axis].length; + calc->want[axis].length = temph * calc->aspect[axis] / calc->aspect[!axis]; + } + else + calc->want[!axis].length = temph; + break; + default: + if (calc->state[!axis] != RELATIVE_CALC_ON) + _child_calc(child, !axis); + temph = calc->want[axis].length * calc->aspect[!axis] / calc->aspect[axis]; + if (temph < calc->want[!axis].length) + { + temph = calc->want[!axis].length; + calc->want[axis].length = temph * calc->aspect[axis] / calc->aspect[!axis]; + } + else + calc->want[!axis].length = temph; + } + + //calculate max size + if (calc->want[0].length > calc->max[0]) + { + calc->want[0].length = calc->max[0]; + calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0]; + } + if (calc->want[1].length > calc->max[1]) + { + calc->want[1].length = calc->max[1]; + calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1]; + } + //calculate min size + if (calc->want[0].length < calc->min[0]) + { + calc->want[0].length = calc->min[0]; + calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0]; + } + if (calc->want[1].length < calc->min[1]) + { + calc->want[1].length = calc->min[1]; + calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1]; + } + + //calculate align + calc->want[!axis].position = + calc->space[!axis].position + + (calc->space[!axis].length - calc->want[!axis].length) * calc->align[!axis]; +} + +static Eina_Bool +_child_chain_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) +{ + Efl_Ui_Relative_Layout_Child *head, *tail, *o; + Efl_Gfx_Hint_Aspect aspect_type; + int space, min_sum = 0; + double weight_sum = 0, cur_pos; + Eina_Inlist *chain = NULL; + + if (child->calc.chain_state[axis] == RELATIVE_CALC_DONE) + return EINA_TRUE; + + if ((child != child->calc.to[START]->calc.to[END]) && + (child != child->calc.to[END]->calc.to[START])) + return EINA_FALSE; + + // find head + head = child; + while (head == head->calc.to[START]->calc.to[END]) + head = head->calc.to[START]; + + //calculate weight_sum + aspect_type = !axis ? EFL_GFX_HINT_ASPECT_VERTICAL : EFL_GFX_HINT_ASPECT_HORIZONTAL; + o = head; + do + { + if ((o->calc.aspect[0] > 0) && (o->calc.aspect[1] > 0) && + (o->calc.aspect_type == aspect_type)) + { + _child_calc(o, !axis); + if (o->calc.want[axis].length > o->calc.min[axis]) + o->calc.min[axis] = o->calc.want[axis].length; + } + else if ((o->calc.aspect[0] <= 0) ^ (o->calc.aspect[1] <= 0)) + { + ERR("Invalid aspect parameter for obj(%p), aspect(%d, %d) ", + o->obj, o->calc.aspect[0], o->calc.aspect[1]); + } + + o->calc.space[axis].length = o->calc.min[axis] + + o->calc.margin[START] + o->calc.margin[END]; + min_sum += o->calc.space[axis].length; + weight_sum += o->calc.weight[axis]; + + tail = o; + o = o->calc.to[END]; + } + while (o->calc.to[START] == tail); + + _child_calc(head->calc.to[START], axis); + _child_calc(tail->calc.to[END], axis); + + cur_pos = head->calc.to[START]->calc.want[axis].position + + (head->calc.to[START]->calc.want[axis].length * head->rel[START].relative); + space = tail->calc.to[END]->calc.want[axis].position + + (tail->calc.to[END]->calc.want[axis].length * tail->rel[END].relative) - cur_pos; + + if ((space <= min_sum) || EINA_DBL_EQ(weight_sum, 0.0)) + cur_pos += (space - min_sum) * head->calc.align[axis]; + else + { + Efl_Ui_Relative_Layout_Calc *calc; + double weight_len, orig_space = space, orig_weight = weight_sum; + + // Calculate compare factor + for (o = head; o != tail->calc.to[END]; o = o->calc.to[END]) + { + double denom; + + calc = &o->calc; + denom = (calc->weight[axis] * orig_space) - (orig_weight * calc->min[axis]); + if (denom > 0) + { + calc->comp_factor = (calc->weight[axis] * orig_space) / denom; + chain = eina_inlist_sorted_insert(chain, EINA_INLIST_GET(calc), + _chain_sort_cb); + } + else + { + space -= calc->space[axis].length; + weight_sum -= calc->weight[axis]; + } + } + + EINA_INLIST_FOREACH(chain, calc) + { + weight_len = (space * calc->weight[axis]) / weight_sum; + + if (calc->space[axis].length < weight_len) + calc->space[axis].length = weight_len; + else + { + weight_sum -= calc->weight[axis]; + space -= calc->space[axis].length; + } + } + } + + for (o = head; o != tail->calc.to[END]; o = o->calc.to[END]) + { + o->calc.space[axis].position = cur_pos + o->calc.margin[START] + 0.5; + cur_pos += o->calc.space[axis].length; + o->calc.space[axis].length -= o->calc.margin[START] + o->calc.margin[END]; + o->calc.chain_state[axis] = RELATIVE_CALC_DONE; + } + + return EINA_TRUE; +} + +static void +_child_calc(Efl_Ui_Relative_Layout_Child *child, Eina_Bool axis) +{ + Efl_Ui_Relative_Layout_Calc *calc = &child->calc; + + if (calc->state[axis] == RELATIVE_CALC_DONE) + return; + + if (calc->state[axis] == RELATIVE_CALC_ON) + { + ERR("%c-axis circular dependency when calculating part \"%s\"(%p).", + axis ? 'Y' : 'X', efl_class_name_get(child->obj), child->obj); + return; + } + + calc->state[axis] = RELATIVE_CALC_ON; + + if (!_child_chain_calc(child, axis)) + { + _child_calc(calc->to[START], axis); + _child_calc(calc->to[END], axis); + + calc->space[axis].position = calc->to[START]->calc.want[axis].position + + (calc->to[START]->calc.want[axis].length * child->rel[START].relative) + + calc->margin[START]; + calc->space[axis].length = calc->to[END]->calc.want[axis].position + + (calc->to[END]->calc.want[axis].length * child->rel[END].relative) + - calc->margin[END] - calc->space[axis].position; + } + + if (calc->fill[axis] && (calc->weight[axis] > 0)) + calc->want[axis].length = calc->space[axis].length; + + if (!calc->aspect[0] && !calc->aspect[1]) + { + if (calc->want[axis].length > calc->max[axis]) + calc->want[axis].length = calc->max[axis]; + + if (calc->want[axis].length < calc->min[axis]) + calc->want[axis].length = calc->min[axis]; + } + else + { + _child_aspect_calc(child, axis); + } + + //calculate align + calc->want[axis].position = + calc->space[axis].position + + (calc->space[axis].length - calc->want[axis].length) * calc->align[axis]; + + child->calc.state[axis] = RELATIVE_CALC_DONE; +} + +static void +_hash_free_cb(void *data) +{ + Efl_Ui_Relative_Layout_Child *child = data; + + free(child); +} + +static Eina_Bool +_hash_free_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, + void *data, void *fdata EINA_UNUSED) +{ + Efl_Ui_Relative_Layout_Child *child = data; + + _elm_widget_sub_object_redirect_to_top(child->layout, child->obj); + _hash_free_cb(child); + + return EINA_TRUE; +} + +static Eina_Bool +_hash_child_calc_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, + void *data, void *fdata EINA_UNUSED) +{ + Efl_Ui_Relative_Layout_Child *child = data; + Eina_Rect want; + + if (child->obj == child->layout) + return EINA_TRUE; + + _child_calc(child, 0); + _child_calc(child, 1); + + want.x = child->calc.want[0].position; + want.w = child->calc.want[0].length; + want.y = child->calc.want[1].position; + want.h = child->calc.want[1].length; + + efl_gfx_entity_geometry_set(child->obj, want); + return EINA_TRUE; +} + + +static Eina_Bool +_hash_child_init_foreach_cb(const Eina_Hash *hash, const void *key EINA_UNUSED, + void *data, void *fdata EINA_UNUSED) +{ + Eina_Size2D max, min, aspect; + Efl_Ui_Relative_Layout_Child *child = data; + Efl_Ui_Relative_Layout_Calc *calc = &(child->calc); + + calc->to[LEFT] = _relative_child_find(hash, child->rel[LEFT].to); + if (!calc->to[LEFT]) calc->to[LEFT] = eina_hash_find(hash, &child->layout); + calc->to[RIGHT] = _relative_child_find(hash, child->rel[RIGHT].to); + if (!calc->to[RIGHT]) calc->to[RIGHT] = eina_hash_find(hash, &child->layout); + calc->to[TOP] = _relative_child_find(hash, child->rel[TOP].to); + if (!calc->to[TOP]) calc->to[TOP] = eina_hash_find(hash, &child->layout); + calc->to[BOTTOM] = _relative_child_find(hash, child->rel[BOTTOM].to); + if (!calc->to[BOTTOM]) calc->to[BOTTOM] = eina_hash_find(hash, &child->layout); + + if (child->obj == child->layout) + { + Eina_Rect want = efl_gfx_entity_geometry_get(child->obj); + calc->want[0].position = want.x; + calc->want[0].length = want.w; + calc->want[1].position = want.y; + calc->want[1].length = want.h; + calc->state[0] = RELATIVE_CALC_DONE; + calc->state[1] = RELATIVE_CALC_DONE; + calc->chain_state[0] = RELATIVE_CALC_DONE; + calc->chain_state[1] = RELATIVE_CALC_DONE; + return EINA_TRUE; + } + + calc->state[0] = RELATIVE_CALC_NONE; + calc->state[1] = RELATIVE_CALC_NONE; + calc->chain_state[0] = RELATIVE_CALC_NONE; + calc->chain_state[1] = RELATIVE_CALC_NONE; + + efl_gfx_hint_weight_get(child->obj, &calc->weight[0], &calc->weight[1]); + efl_gfx_hint_align_get(child->obj, &calc->align[0], &calc->align[1]); + efl_gfx_hint_fill_get(child->obj, &calc->fill[0], &calc->fill[1]); + efl_gfx_hint_aspect_get(child->obj, &calc->aspect_type, &aspect); + calc->aspect[0] = aspect.w; + calc->aspect[1] = aspect.h; + efl_gfx_hint_margin_get(child->obj, &calc->margin[LEFT], &calc->margin[RIGHT], + &calc->margin[TOP], &calc->margin[BOTTOM]); + max = efl_gfx_hint_size_max_get(child->obj); + min = efl_gfx_hint_size_combined_min_get(child->obj); + calc->max[0] = max.w; + calc->max[1] = max.h; + calc->min[0] = min.w; + calc->min[1] = min.h; + + calc->want[0].position = 0; + calc->want[0].length = 0; + calc->want[1].position = 0; + calc->want[1].length = 0; + calc->space[0].position = 0; + calc->space[0].length = 0; + calc->space[1].position = 0; + calc->space[1].length = 0; + + if (calc->weight[0] < 0) calc->weight[0] = 0; + if (calc->weight[1] < 0) calc->weight[1] = 0; + + if (calc->align[0] < 0) calc->align[0] = 0; + if (calc->align[1] < 0) calc->align[1] = 0; + if (calc->align[0] > 1) calc->align[0] = 1; + if (calc->align[1] > 1) calc->align[1] = 1; + + if (calc->max[0] < 0) calc->max[0] = INT_MAX; + if (calc->max[1] < 0) calc->max[1] = INT_MAX; + if (calc->aspect[0] < 0) calc->aspect[0] = 0; + if (calc->aspect[1] < 0) calc->aspect[1] = 0; + + return EINA_TRUE; +} + +static void +_on_size_hints_changed(void *data EINA_UNUSED, Evas *e EINA_UNUSED, + Evas_Object *obj, void *event_info EINA_UNUSED) +{ + efl_pack_layout_request(obj); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Relative_Layout_Data *pd) +{ + eina_hash_foreach(pd->children, _hash_child_init_foreach_cb, NULL); + eina_hash_foreach(pd->children, _hash_child_calc_foreach_cb, NULL); + + efl_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_pack_layout_layout_request(Eo *obj, Efl_Ui_Relative_Layout_Data *pd EINA_UNUSED) +{ + efl_canvas_group_need_recalculate_set(obj, EINA_TRUE); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Relative_Layout_Data *pd EINA_UNUSED) +{ + efl_pack_layout_update(obj); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Relative_Layout_Data *pd EINA_UNUSED, Eina_Size2D sz) +{ + efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz); + efl_canvas_group_change(obj); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Relative_Layout_Data *pd EINA_UNUSED, Eina_Position2D pos) +{ + efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos); + efl_canvas_group_change(obj); +} + +EOLIAN static void +_efl_ui_relative_layout_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Relative_Layout_Data *pd EINA_UNUSED) +{ + evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_size_hints_changed, NULL); + efl_canvas_group_add(efl_super(obj, MY_CLASS)); + elm_widget_sub_object_parent_add(obj); + + elm_widget_highlight_ignore_set(obj, EINA_TRUE); +} + +EOLIAN static Eo * +_efl_ui_relative_layout_efl_object_constructor(Eo *obj, Efl_Ui_Relative_Layout_Data *pd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + efl_canvas_object_type_set(obj, MY_CLASS_NAME); + efl_access_object_access_type_set(obj, EFL_ACCESS_TYPE_SKIPPED); + efl_access_object_role_set(obj, EFL_ACCESS_ROLE_FILLER); + + pd->obj = obj; + pd->children = eina_hash_pointer_new(_hash_free_cb); + _efl_ui_relative_layout_register(pd, obj); + + return obj; +} + +EOLIAN static void +_efl_ui_relative_layout_efl_object_destructor(Eo *obj, Efl_Ui_Relative_Layout_Data *pd) +{ + eina_hash_free(pd->children); + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_relative_layout_unregister(Eo *obj, Efl_Ui_Relative_Layout_Data *pd, Efl_Object *child) +{ + _elm_widget_sub_object_redirect_to_top(obj, child); + if (!eina_hash_del_by_key(pd->children, &child)) + ERR("child(%p(%s)) is not registered", child, efl_class_name_get(child)); +} + +EOLIAN static void +_efl_ui_relative_layout_unregister_all(Eo *obj EINA_UNUSED, Efl_Ui_Relative_Layout_Data *pd) +{ + eina_hash_foreach(pd->children, _hash_free_foreach_cb, NULL); +} + +EOLIAN static Eina_Iterator * +_efl_ui_relative_layout_children_iterate(Eo *obj EINA_UNUSED, Efl_Ui_Relative_Layout_Data *pd) +{ + return eina_hash_iterator_data_new(pd->children); +} + +EFL_UI_RELATIVE_LAYOUT_RELATION_SET_GET(left, LEFT); +EFL_UI_RELATIVE_LAYOUT_RELATION_SET_GET(right, RIGHT); +EFL_UI_RELATIVE_LAYOUT_RELATION_SET_GET(top, TOP); +EFL_UI_RELATIVE_LAYOUT_RELATION_SET_GET(bottom, BOTTOM); + +/* Internal EO APIs and hidden overrides */ + +#define EFL_UI_RELATIVE_LAYOUT_EXTRA_OPS \ + EFL_CANVAS_GROUP_ADD_OPS(efl_ui_relative_layout) + +#include "efl_ui_relative_layout.eo.c" diff --git a/src/lib/elementary/efl_ui_relative_layout.eo b/src/lib/elementary/efl_ui_relative_layout.eo new file mode 100644 index 0000000000..967f23d623 --- /dev/null +++ b/src/lib/elementary/efl_ui_relative_layout.eo @@ -0,0 +1,79 @@ +class Efl.Ui.Relative_Layout extends Efl.Ui.Widget implements Efl.Pack_Layout +{ + [[The relative layout class. + + A relative layout calculates the size and position of all the children + based on their relationship to each other.]] + methods { + @property relation_left { + [[Specifies the left side edge of the child relative to the target. + By default, target is parent and relative is 0.0.]] + keys { + child: Efl.Object; [[The child to specify relation.]] + } + values { + target: Efl.Object; [[The relative target.]] + relative: double; [[The ratio between left and right of the target, + ranging from 0.0 to 1.0.]] + } + } + @property relation_right { + [[Specifies the right side edge of the child relative to the target. + By default, target is parent and relative is 1.0.]] + keys { + child: Efl.Object; [[The child to specify relation.]] + } + values { + target: Efl.Object; [[The relative target.]] + relative: double; [[The ratio between left and right of the target, + ranging from 0.0 to 1.0.]] + } + } + @property relation_top { + [[Specifies the top side edge of the child relative to the target. + By default, target is parent and relative is 0.0.]] + keys { + child: Efl.Object; [[The child to specify relation.]] + } + values { + target: Efl.Object; [[The relative target.]] + relative: double; [[The ratio between top and bottom of the target, + ranging from 0.0 to 1.0.]] + } + } + @property relation_bottom { + [[Specifies the bottom side edge of the child relative to the target. + By default, target is parent and relative is 1.0.]] + keys { + child: Efl.Object; [[The child to specify relation.]] + } + values { + target: Efl.Object; [[The relative target.]] + relative: double; [[The ratio between top and bottom of the target, + ranging from 0.0 to 1.0.]] + } + } + unregister { + [[Remove all relations of the child.]] + params { + @in child: Efl.Object; [[The child to unregister]] + } + } + unregister_all { + [[Remove all relations from the registered children. ]] + } + children_iterate { + [[Begin iterating over this object's children.]] + return: iterator<Efl.Object> @owned @warn_unused; [[Iterator to object children.]] + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + Efl.Canvas.Group.group_calculate; + Efl.Gfx.Entity.position { set; } + Efl.Gfx.Entity.size { set; } + Efl.Pack_Layout.layout_update; + Efl.Pack_Layout.layout_request; + } +} diff --git a/src/lib/elementary/efl_ui_relative_layout_private.h b/src/lib/elementary/efl_ui_relative_layout_private.h new file mode 100644 index 0000000000..b7410efc49 --- /dev/null +++ b/src/lib/elementary/efl_ui_relative_layout_private.h @@ -0,0 +1,90 @@ +#ifndef EFL_UI_RELATIVE_LAYOUT_PRIVATE_H +#define EFL_UI_RELATIVE_LAYOUT_PRIVATE_H + +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#define EFL_PACK_LAYOUT_PROTECTED + +#include <Elementary.h> +#include "elm_priv.h" + +typedef enum _Efl_Ui_Relative_Layout_Calc_State +{ + RELATIVE_CALC_NONE, + RELATIVE_CALC_DONE, + RELATIVE_CALC_ON +} Efl_Ui_Relative_Layout_Calc_State; + +typedef struct _Efl_Ui_Relative_Layout_Data Efl_Ui_Relative_Layout_Data; +typedef struct _Efl_Ui_Relative_Layout_Child Efl_Ui_Relative_Layout_Child; +typedef struct _Efl_Ui_Relative_Layout_Calc Efl_Ui_Relative_Layout_Calc; +typedef struct _Efl_Ui_Relative_Layout_Relation Efl_Ui_Relative_Layout_Relation; + +struct _Efl_Ui_Relative_Layout_Calc +{ + EINA_INLIST; + + int max[2]; + int min[2]; + int aspect[2]; + int margin[4]; + Efl_Gfx_Hint_Aspect aspect_type; + Eina_Bool fill[2]; + double weight[2]; + double align[2]; + double comp_factor; + + struct { + int position; + double length; + } space[2], want[2]; + + Efl_Ui_Relative_Layout_Calc_State state[2]; + Efl_Ui_Relative_Layout_Calc_State chain_state[2]; + Efl_Ui_Relative_Layout_Child *to[4]; +}; + +struct _Efl_Ui_Relative_Layout_Data +{ + Eo *obj; + Eina_Hash *children; +}; + +struct _Efl_Ui_Relative_Layout_Relation +{ + Efl_Object *to; + double relative; +}; + +struct _Efl_Ui_Relative_Layout_Child +{ + Eo *obj; + Eo *layout; + Efl_Ui_Relative_Layout_Relation rel[4]; + Efl_Ui_Relative_Layout_Calc calc; +}; + +#define EFL_UI_RELATIVE_LAYOUT_RELATION_SET_GET(direction, DIRECTION) \ + EOLIAN static void \ + _efl_ui_relative_layout_relation_ ## direction ## _set(Eo *obj EINA_UNUSED, Efl_Ui_Relative_Layout_Data *pd, Eo *child, Eo *target, double relative) \ + { \ + Efl_Ui_Relative_Layout_Child *rc; \ + rc = _relative_child_get(pd, child); \ + if (target) rc->rel[DIRECTION].to = target; \ + if (relative < 0) relative = 0; \ + else if (relative > 1) relative = 1; \ + rc->rel[DIRECTION].relative = relative; \ + } \ + \ + EOLIAN static void \ + _efl_ui_relative_layout_relation_ ## direction ## _get(const Eo *obj EINA_UNUSED, Efl_Ui_Relative_Layout_Data *pd, Eo *child, Eo **target, double *relative) \ + { \ + Efl_Ui_Relative_Layout_Child *rc; \ + rc = _relative_child_get(pd, child); \ + if (target) *target = rc->rel[DIRECTION].to; \ + if (relative) *relative = rc->rel[DIRECTION].relative; \ + } + +#endif diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 21a4ab16d5..1db7752473 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -276,6 +276,7 @@ pub_eo_files = [ 'efl_ui_text_part.eo', 'efl_ui_caching_factory.eo', 'efl_ui_widget_factory.eo', + 'efl_ui_relative_layout.eo', ] foreach eo_file : pub_eo_files @@ -480,7 +481,8 @@ elementary_headers_unstable = [ 'efl_page_indicator_icon.h', 'efl_ui_tab_pager_private.h', 'efl_ui_tab_bar_private.h', - 'efl_ui_tab_page_private.h' + 'efl_ui_tab_page_private.h', + 'efl_ui_relative_layout_private.h' ] elementary_pub_headers = [ @@ -912,6 +914,7 @@ elementary_src = [ 'efl_ui_homogeneous_model.c', 'efl_ui_exact_model.c', 'efl_ui_average_model.c' + 'efl_ui_relative_layout.c' ] elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl] diff --git a/src/tests/elementary/efl_ui_suite.c b/src/tests/elementary/efl_ui_suite.c index 5cc88df007..16f7ad3fe4 100644 --- a/src/tests/elementary/efl_ui_suite.c +++ b/src/tests/elementary/efl_ui_suite.c @@ -14,6 +14,7 @@ static const Efl_Test_Case etc[] = { { "efl_ui_focus_sub", efl_ui_test_focus_sub}, { "efl_ui_box", efl_ui_test_box}, { "efl_ui_grid", efl_ui_test_grid}, + { "efl_ui_relative_layout", efl_ui_test_relative_layout}, { "efl_ui_image", efl_ui_test_image}, { "efl_ui_image_zoomable", efl_ui_test_image_zoomable}, { "efl_ui_layout", efl_ui_test_layout}, diff --git a/src/tests/elementary/efl_ui_suite.h b/src/tests/elementary/efl_ui_suite.h index b65cbe5bfb..c337323823 100644 --- a/src/tests/elementary/efl_ui_suite.h +++ b/src/tests/elementary/efl_ui_suite.h @@ -21,6 +21,7 @@ void efl_ui_test_box(TCase *tc); void efl_ui_test_grid(TCase *tc); +void efl_ui_test_relative_layout(TCase *tc); void efl_ui_test_atspi(TCase *tc); void efl_ui_test_image_zoomable(TCase *tc); void efl_ui_test_layout(TCase *tc); diff --git a/src/tests/elementary/efl_ui_test_relative_layout.c b/src/tests/elementary/efl_ui_test_relative_layout.c new file mode 100644 index 0000000000..0471154338 --- /dev/null +++ b/src/tests/elementary/efl_ui_test_relative_layout.c @@ -0,0 +1,300 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include <Elementary.h> +#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.3, (200 - 70) * 0.7, 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.7, 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.7, 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, 200), + EINA_RECT((200 - 70) * 0.3, -7, 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.3, (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, 200), + EINA_RECT((200 - 70) * 0.3, -7, 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.7, 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, 200), + EINA_RECT((200 - 70) * 0.3, -7, 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.3, (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, 200), + EINA_RECT((200 - 70) * 0.3, -7, 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.7, 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_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.8, (300 - 140) * 0.2 + 70, 70, 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 - 140) * 0.7, 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_NONE, EINA_SIZE2D(0, 0), EINA_FALSE, EINA_FALSE, + EINA_SIZE2D(150, 300), EINA_SIZE2D(150, 300), + EINA_RECT((150 - 70) * 0.8, (300 - 140) * 0.7 + 70, 70, 70), "[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 btn2]" } + }, + { + { 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 btn2]" } + }, + { + { 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, -28, 150, 70), "[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, 42, 150, 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(0, 142, 150, 70), "[1/1/1 weight_s btn2]" } + }, +}; + +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_max_set(btn, hint->max); + efl_gfx_hint_size_min_set(btn, hint->min); + efl_gfx_hint_margin_set(btn, hint->marginl, hint->marginr, hint->margint, + hint->marginb); + 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_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 = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC)); + + layout = efl_add(EFL_UI_RELATIVE_LAYOUT_CLASS, win, + efl_gfx_entity_size_set(efl_added, EINA_SIZE2D(200, 200))); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(200, 200)); +} + +static void +layout_teardown() +{ + if (win) + { + efl_del(win); + win = NULL; + } +} + +EFL_START_TEST (efl_ui_relative_layout_class_check) +{ + const char *class; + + class = efl_class_name_get(layout); + + ck_assert(class != NULL); + ck_assert(!strcmp(class, "Efl.Ui.Relative_Layout")); +} +EFL_END_TEST + +EFL_START_TEST (efl_ui_relative_layout_layout_update) +{ + int i, max_index = (sizeof(hints) / sizeof(Hint)); + + Eo *btn = efl_add(EFL_UI_BUTTON_CLASS, layout, + efl_ui_relative_layout_relation_left_set(layout, efl_added, NULL, 0.0)); + + 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_relative_layout_layout_update_chain) +{ + int i, max_index2, max_index3; + Eo *btn, *btn2, *btn3; + + btn = efl_add(EFL_UI_BUTTON_CLASS, layout); + btn2 = efl_add(EFL_UI_BUTTON_CLASS, layout); + + max_index2 = ((sizeof(hints2) / sizeof(Hint)) / 2); + max_index3 = ((sizeof(hints3) / sizeof(Hint)) / 3); + + efl_ui_relative_layout_relation_bottom_set(layout, btn, btn2, 0.0); + efl_ui_relative_layout_relation_top_set(layout, btn2, btn, 1.0); + + 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_ui_relative_layout_relation_bottom_set(layout, btn2, btn3, 0.0); + efl_ui_relative_layout_relation_top_set(layout, btn3, btn2, 1.0); + + 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)); + } +} +EFL_END_TEST + +void efl_ui_test_relative_layout(TCase *tc) +{ + tcase_add_checked_fixture(tc, layout_setup, layout_teardown); + tcase_add_test(tc, efl_ui_relative_layout_class_check); + tcase_add_test(tc, efl_ui_relative_layout_layout_update); + tcase_add_test(tc, efl_ui_relative_layout_layout_update_chain); +} diff --git a/src/tests/elementary/meson.build b/src/tests/elementary/meson.build index 091d1540ef..f9e6a0eec2 100644 --- a/src/tests/elementary/meson.build +++ b/src/tests/elementary/meson.build @@ -124,6 +124,7 @@ efl_ui_suite_src = [ 'efl_ui_test_focus_sub.c', 'efl_ui_test_box.c', 'efl_ui_test_grid.c', + 'efl_ui_test_relative_layout.c', 'efl_ui_test_image.c', 'efl_ui_test_image_zoomable.c', 'efl_ui_test_layout.c', --
