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',

-- 


Reply via email to