summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinYong Park <j4939.park@samsung.com>2017-09-20 19:36:39 +0900
committerJaehyun Cho <jae_hyun.cho@samsung.com>2017-11-28 17:15:42 +0900
commitc8c7ac8aae0574ad0c6ad56f284c119dfd2709df (patch)
tree01f79ccba9a0e1974308360cb326e7af2faba06c
parenta7082df12b9d72880e308be4c81152de596ee028 (diff)
downloadefl-c8c7ac8aae0574ad0c6ad56f284c119dfd2709df.tar.gz
efl_ui_popup_anchor: add Efl.Ui.Popup.Anchor class
Summary: Add initial code for Efl.Ui.Popup.Anchor class. It supports adding anchor object to popup. Test Plan: 1. run elementary_test -to efluipopupanchor Reviewers: Jaehyun_Cho, thiepha, herb, jpeg, cedric, woohyun Reviewed By: Jaehyun_Cho Differential Revision: https://phab.enlightenment.org/D5126
-rw-r--r--data/elementary/objects/test.edc78
-rw-r--r--src/Makefile_Elementary.am3
-rw-r--r--src/bin/elementary/test.c2
-rw-r--r--src/bin/elementary/test_popup.c116
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/efl_ui_popup_anchor.c357
-rw-r--r--src/lib/elementary/efl_ui_popup_anchor.eo40
-rw-r--r--src/lib/elementary/efl_ui_popup_anchor_private.h18
8 files changed, 615 insertions, 0 deletions
diff --git a/data/elementary/objects/test.edc b/data/elementary/objects/test.edc
index 834bea4e27..6574ab3adf 100644
--- a/data/elementary/objects/test.edc
+++ b/data/elementary/objects/test.edc
@@ -933,4 +933,82 @@ collections {
}
}
}
+ group { "efl_ui_popup_anchor_layout";
+ parts {
+ spacer { "base";
+ desc { "default";
+ }
+ }
+ swallow { "anchor1";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.15 0.25;
+ rel2.relative: 0.15 0.25;
+ fixed: 1 1;
+ min: 50 50;
+ }
+ }
+ swallow { "anchor2";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.75 0.15;
+ rel2.relative: 0.75 0.15;
+ fixed: 1 1;
+ min: 50 50;
+ }
+ }
+ swallow { "anchor3";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.25 0.85;
+ rel2.relative: 0.25 0.85;
+ fixed: 1 1;
+ min: 50 50;
+ }
+ }
+ swallow { "anchor4";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.85 0.75;
+ rel2.relative: 0.85 0.75;
+ fixed: 1 1;
+ min: 50 50;
+ }
+ }
+ swallow { "anchor5";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.45 0.35;
+ rel2.relative: 0.45 0.35;
+ fixed: 1 1;
+ min: 50 50;
+ }
+ }
+ swallow { "anchor6";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel2.relative: 0.0 0.0;
+ rel1.offset: 150 300;
+ rel2.offset: 200 350;
+ fixed: 1 1;
+ }
+ }
+ swallow { "anchor_none";
+ scale;
+ desc { "default";
+ rel.to: "base";
+ rel1.relative: 0.60 0.45;
+ rel2.relative: 0.60 0.45;
+ fixed: 1 1;
+ min: 70 50;
+ }
+ }
+ }
+ }
}
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index cbee49167e..f62e9f2d9d 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -39,6 +39,7 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_popup_alert_scroll_part.eo \
lib/elementary/efl_ui_popup_alert_text.eo \
lib/elementary/efl_ui_popup_alert_text_part.eo \
+ lib/elementary/efl_ui_popup_anchor.eo \
lib/elementary/efl_ui_text_editable.eo \
lib/elementary/efl_ui_text_async.eo \
lib/elementary/efl_ui_textpath.eo \
@@ -295,6 +296,7 @@ includesunstable_HEADERS = \
lib/elementary/efl_ui_popup_alert_private.h \
lib/elementary/efl_ui_popup_alert_scroll_private.h \
lib/elementary/efl_ui_popup_alert_text_private.h \
+ lib/elementary/efl_ui_popup_anchor_private.h \
lib/elementary/elm_widget_index.h \
lib/elementary/elm_widget_inwin.h \
lib/elementary/elm_widget_label.h \
@@ -708,6 +710,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_popup_alert.c \
lib/elementary/efl_ui_popup_alert_scroll.c \
lib/elementary/efl_ui_popup_alert_text.c \
+ lib/elementary/efl_ui_popup_anchor.c \
lib/elementary/efl_ui_grid.c \
lib/elementary/efl_ui_grid_static.c \
lib/elementary/efl_ui_grid_private.h \
diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index f5666e52ff..ae576feec8 100644
--- a/src/bin/elementary/test.c
+++ b/src/bin/elementary/test.c
@@ -278,6 +278,7 @@ void test_efl_ui_popup(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_popup_alert(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_popup_alert_scroll(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_popup_alert_text(void *data, Evas_Object *obj, void *event_info);
+void test_efl_ui_popup_anchor(void *data, Evas_Object *obj, void *event_info);
void test_dayselector(void *data, Evas_Object *obj, void *event_info);
void test_image(void *data, Evas_Object *obj, void *event_info);
void test_image_scale_type(void *data, Evas_Object *obj, void *event_info);
@@ -1050,6 +1051,7 @@ add_tests:
ADD_TEST(NULL, "Popups", "Efl UI Popup Alert", test_efl_ui_popup_alert);
ADD_TEST(NULL, "Popups", "Efl UI Popup Alert Scroll", test_efl_ui_popup_alert_scroll);
ADD_TEST(NULL, "Popups", "Efl UI Popup Alert Text", test_efl_ui_popup_alert_text);
+ ADD_TEST(NULL, "Popups", "Efl UI Popup Anchor", test_efl_ui_popup_anchor);
//------------------------------//
ADD_TEST(NULL, "Times & Dates", "Calendar", test_calendar);
diff --git a/src/bin/elementary/test_popup.c b/src/bin/elementary/test_popup.c
index 2bb6edea45..701cd178b5 100644
--- a/src/bin/elementary/test_popup.c
+++ b/src/bin/elementary/test_popup.c
@@ -1,6 +1,8 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
+
+#define EFL_UI_POPUP_ANCHOR_BETA
#include <Elementary.h>
#define POPUP_POINT_MAX 8
@@ -1205,3 +1207,117 @@ test_efl_ui_popup_alert_text(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSE
efl_event_callback_add(efl_ui_popup, EFL_UI_POPUP_ALERT_EVENT_CLICKED, efl_ui_popup_alert_clicked_cb, NULL);
}
+
+static void
+_anchor_set_cb(void *data, Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ efl_ui_popup_anchor_set(data, obj);
+}
+
+static void
+_anchor_unset_cb(void *data, Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ efl_ui_popup_anchor_set(data, NULL);
+}
+
+void
+test_efl_ui_popup_anchor(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Evas_Object *win, *layout, *tbl, *btn;
+ char buf[PATH_MAX];
+
+ win = elm_win_util_standard_add("Efl UI AnchorPopup", "Efl UI AnchorPopup");
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ evas_object_resize(win, 500, 500);
+ evas_object_show(win);
+
+ layout = elm_layout_add(win);
+ snprintf(buf, sizeof(buf), "%s/objects/test.edj", elm_app_data_dir_get());
+ elm_layout_file_set(layout, buf, "efl_ui_popup_anchor_layout");
+ evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_win_resize_object_add(win, layout);
+ evas_object_show(layout);
+
+ Evas_Object *efl_ui_popup= efl_add(EFL_UI_POPUP_ANCHOR_CLASS, win);
+
+ efl_ui_popup_bg_repeat_events_set(efl_ui_popup, EINA_TRUE);
+
+ //Default align priority order is top, left, right, bottom, center.
+ efl_ui_popup_anchor_align_priority_set(efl_ui_popup, EFL_UI_POPUP_ALIGN_TOP,
+ EFL_UI_POPUP_ALIGN_BOTTOM,
+ EFL_UI_POPUP_ALIGN_LEFT,
+ EFL_UI_POPUP_ALIGN_RIGHT,
+ EFL_UI_POPUP_ALIGN_CENTER);
+
+ evas_object_move(efl_ui_popup, 80, 80);
+ evas_object_resize(efl_ui_popup, 160, 120);
+ evas_object_show(efl_ui_popup);
+
+ for (int i = 0; i < 6; i++)
+ {
+ btn = elm_button_add(win);
+ elm_object_text_set(btn, "anchor");
+ evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_smart_callback_add(btn, "clicked", _anchor_set_cb, efl_ui_popup);
+
+ snprintf(buf, sizeof(buf), "anchor%d", i+1);
+ elm_object_part_content_set(layout, buf, btn);
+ }
+
+ btn = elm_button_add(win);
+ elm_object_text_set(btn, "anchor none");
+ evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_smart_callback_add(btn, "clicked", _anchor_unset_cb, efl_ui_popup);
+ elm_object_part_content_set(layout, "anchor_none", btn);
+
+ tbl = elm_table_add(efl_ui_popup);
+ evas_object_size_hint_weight_set(tbl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(tbl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Center Align");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _center_align_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 0, 0, 1, 1);
+ evas_object_show(btn);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Left Align");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _left_align_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 1, 0, 1, 1);
+ evas_object_show(btn);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Right Align");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _right_align_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 2, 0, 1, 1);
+ evas_object_show(btn);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Top Align");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _top_align_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 0, 1, 1, 1);
+ evas_object_show(btn);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Bottom Align");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _bottom_align_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 1, 1, 1, 1);
+ evas_object_show(btn);
+
+ btn = elm_button_add(efl_ui_popup);
+ elm_object_text_set(btn, "Position Set");
+ evas_object_size_hint_min_set(btn, 70, 35);
+ evas_object_smart_callback_add(btn, "clicked", _position_set_cb, efl_ui_popup);
+ elm_table_pack(tbl, btn, 2, 1, 1, 1);
+ evas_object_show(btn);
+
+ efl_content_set(efl_ui_popup, tbl);
+}
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 6ea73c2de1..66b3c8fd14 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -305,6 +305,7 @@ EAPI extern Elm_Version *elm_version;
# include <efl_ui_popup_alert.eo.h>
# include <efl_ui_popup_alert_scroll.eo.h>
# include <efl_ui_popup_alert_text.eo.h>
+# include <efl_ui_popup_anchor.eo.h>
# include <efl_ui_text_editable.eo.h>
# include <efl_ui_text_async.eo.h>
# include <efl_ui_clock.eo.h>
diff --git a/src/lib/elementary/efl_ui_popup_anchor.c b/src/lib/elementary/efl_ui_popup_anchor.c
new file mode 100644
index 0000000000..8ec41bc991
--- /dev/null
+++ b/src/lib/elementary/efl_ui_popup_anchor.c
@@ -0,0 +1,357 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define EFL_UI_POPUP_PROTECTED
+#define EFL_UI_POPUP_ANCHOR_BETA
+
+#include <Elementary.h>
+
+#include "elm_priv.h"
+#include "efl_ui_popup_anchor_private.h"
+
+#define MY_CLASS EFL_UI_POPUP_ANCHOR_CLASS
+#define MY_CLASS_NAME "Efl.Ui.Popup.Anchor"
+
+static void
+_anchor_calc(Evas_Object *obj)
+{
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ EFL_UI_POPUP_ANCHOR_DATA_GET(obj, sd);
+
+ Evas_Coord_Rectangle anchor_geom = {0, 0, 0, 0};
+ Evas_Coord_Size popup_size = {0, 0};
+ Evas_Coord_Size parent_size = {0, 0};
+ Eina_Position2D pos = {0, 0};
+
+ Evas_Object *parent = efl_ui_popup_parent_window_get(obj);
+
+ evas_object_geometry_get(sd->anchor, &anchor_geom.x, &anchor_geom.y, &anchor_geom.w, &anchor_geom.h);
+ evas_object_geometry_get(obj, NULL, NULL, &popup_size.w, &popup_size.h);
+ evas_object_geometry_get(parent, NULL, NULL, &parent_size.w, &parent_size.h);
+
+ sd->used_align = EFL_UI_POPUP_ALIGN_NONE;
+
+ /* 1. Find align which display popup.
+ It enables to shifting popup from exact position.
+ LEFT, RIGHT - shift only y position within anchor object's height
+ TOP, BOTTOM - shift only x position within anchor object's width
+ CENTER - shift both x, y position within anchor object's area
+ */
+
+ for (int idx = 0; idx < 6; idx++)
+ {
+ Efl_Ui_Popup_Align cur_align;
+
+ if (idx == 0)
+ cur_align = sd->align;
+ else
+ cur_align = sd->priority[idx - 1];
+
+ if (cur_align == EFL_UI_POPUP_ALIGN_NONE)
+ continue;
+
+ switch(cur_align)
+ {
+ case EFL_UI_POPUP_ALIGN_TOP:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = (anchor_geom.y - popup_size.h);
+
+ if ((pos.y < 0) ||
+ ((pos.y + popup_size.h) > parent_size.h) ||
+ (popup_size.w > parent_size.w))
+ continue;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_LEFT:
+ pos.x = (anchor_geom.x - popup_size.w);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+
+ if ((pos.x < 0) ||
+ ((pos.x + popup_size.w) > parent_size.w) ||
+ (popup_size.h > parent_size.h))
+ continue;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_RIGHT:
+ pos.x = (anchor_geom.x + anchor_geom.w);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+
+ if ((pos.x < 0) ||
+ ((pos.x + popup_size.w) > parent_size.w) ||
+ (popup_size.h > parent_size.h))
+ continue;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_BOTTOM:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = (anchor_geom.y + anchor_geom.h);
+
+ if ((pos.y < 0) ||
+ ((pos.y + popup_size.h) > parent_size.h) ||
+ (popup_size.w > parent_size.w))
+ continue;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_CENTER:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+
+ if (popup_size.w > parent_size.w || popup_size.h > parent_size.h)
+ continue;
+ break;
+
+ default:
+ continue;
+ }
+
+ if ((cur_align == EFL_UI_POPUP_ALIGN_TOP) ||
+ (cur_align == EFL_UI_POPUP_ALIGN_BOTTOM) ||
+ (cur_align == EFL_UI_POPUP_ALIGN_CENTER))
+ {
+ if (pos.x < 0)
+ pos.x = 0;
+ if ((pos.x + popup_size.w) > parent_size.w)
+ pos.x = parent_size.w - popup_size.w;
+
+ if ((pos.x > (anchor_geom.x + anchor_geom.w)) ||
+ ((pos.x + popup_size.w) < anchor_geom.x))
+ continue;
+ }
+
+ if ((cur_align == EFL_UI_POPUP_ALIGN_LEFT) ||
+ (cur_align == EFL_UI_POPUP_ALIGN_RIGHT) ||
+ (cur_align == EFL_UI_POPUP_ALIGN_CENTER))
+ {
+ if (pos.y < 0)
+ pos.y = 0;
+ if ((pos.y + popup_size.h) > parent_size.h)
+ pos.y = parent_size.h - popup_size.h;
+
+ if ((pos.y > (anchor_geom.y + anchor_geom.h)) ||
+ ((pos.y + popup_size.h) < anchor_geom.y))
+ continue;
+ }
+
+ sd->used_align = cur_align;
+ goto end;
+ }
+
+ /* 2. Move popup to fit first valid align although entire popup can't display */
+
+ for (int idx = 0; idx < 6; idx++)
+ {
+ Efl_Ui_Popup_Align cur_align;
+
+ if (idx == 0)
+ cur_align = sd->align;
+ else
+ cur_align = sd->priority[idx - 1];
+
+ if (cur_align == EFL_UI_POPUP_ALIGN_NONE)
+ continue;
+
+ switch(cur_align)
+ {
+ case EFL_UI_POPUP_ALIGN_TOP:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = (anchor_geom.y - popup_size.h);
+ sd->used_align = cur_align;
+ goto end;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_LEFT:
+ pos.x = (anchor_geom.x - popup_size.w);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+ sd->used_align = cur_align;
+ goto end;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_RIGHT:
+ pos.x = (anchor_geom.x + anchor_geom.w);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+ sd->used_align = cur_align;
+ goto end;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_BOTTOM:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = (anchor_geom.y + anchor_geom.h);
+ sd->used_align = cur_align;
+ goto end;
+ break;
+
+ case EFL_UI_POPUP_ALIGN_CENTER:
+ pos.x = anchor_geom.x + ((anchor_geom.w - popup_size.w) / 2);
+ pos.y = anchor_geom.y + ((anchor_geom.h - popup_size.h) / 2);
+ sd->used_align = cur_align;
+ goto end;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+end:
+ if (sd->used_align != EFL_UI_POPUP_ALIGN_NONE)
+ efl_gfx_position_set(efl_super(obj, EFL_UI_POPUP_CLASS), pos);
+}
+
+static void
+_anchor_geom_cb(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+ _anchor_calc(data);
+}
+
+static void
+_anchor_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+ EFL_UI_POPUP_ANCHOR_DATA_GET(data, sd);
+
+ efl_event_callback_del(efl_ui_popup_parent_window_get(data), EFL_GFX_EVENT_RESIZE, _anchor_geom_cb, data);
+
+ sd->anchor = NULL;
+ efl_ui_popup_align_set(efl_super(data, MY_CLASS), sd->align);
+}
+
+static void
+_anchor_detach(Evas_Object *obj)
+{
+ EFL_UI_POPUP_ANCHOR_DATA_GET(obj, sd);
+
+ if (sd->anchor == NULL) return;
+
+ efl_event_callback_del(efl_ui_popup_parent_window_get(obj), EFL_GFX_EVENT_RESIZE, _anchor_geom_cb, obj);
+ efl_event_callback_del(sd->anchor, EFL_GFX_EVENT_RESIZE, _anchor_geom_cb, obj);
+ efl_event_callback_del(sd->anchor, EFL_GFX_EVENT_MOVE, _anchor_geom_cb, obj);
+ efl_event_callback_del(sd->anchor, EFL_EVENT_DEL, _anchor_del_cb, obj);
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_anchor_set(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd, Evas_Object *anchor)
+{
+ _anchor_detach(obj);
+ pd->anchor = anchor;
+
+ if (anchor == NULL)
+ efl_ui_popup_align_set(efl_super(obj, MY_CLASS), pd->align);
+ else
+ {
+ efl_ui_popup_align_set(efl_super(obj, MY_CLASS), EFL_UI_POPUP_ALIGN_NONE);
+
+ _anchor_calc(obj);
+
+ efl_event_callback_add(efl_ui_popup_parent_window_get(obj), EFL_GFX_EVENT_RESIZE, _anchor_geom_cb, obj);
+ efl_event_callback_add(anchor, EFL_GFX_EVENT_RESIZE, _anchor_geom_cb, obj);
+ efl_event_callback_add(anchor, EFL_GFX_EVENT_MOVE, _anchor_geom_cb, obj);
+ efl_event_callback_add(anchor, EFL_EVENT_DEL, _anchor_del_cb, obj);
+ }
+}
+
+EOLIAN static Efl_Object *
+_efl_ui_popup_anchor_anchor_get(Eo *obj EINA_UNUSED, Efl_Ui_Popup_Anchor_Data *pd)
+{
+ return pd->anchor;
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_align_priority_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Popup_Anchor_Data *pd,
+ Efl_Ui_Popup_Align first,
+ Efl_Ui_Popup_Align second,
+ Efl_Ui_Popup_Align third,
+ Efl_Ui_Popup_Align fourth,
+ Efl_Ui_Popup_Align fifth)
+{
+ pd->priority[0] = first;
+ pd->priority[1] = second;
+ pd->priority[2] = third;
+ pd->priority[3] = fourth;
+ pd->priority[4] = fifth;
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_align_priority_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Popup_Anchor_Data *pd,
+ Efl_Ui_Popup_Align *first,
+ Efl_Ui_Popup_Align *second,
+ Efl_Ui_Popup_Align *third,
+ Efl_Ui_Popup_Align *fourth,
+ Efl_Ui_Popup_Align *fifth)
+{
+ if (first) *first = pd->priority[0];
+ if (second) *second = pd->priority[1];
+ if (third) *third = pd->priority[2];
+ if (fourth) *fourth = pd->priority[3];
+ if (fifth) *fifth = pd->priority[4];
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_efl_gfx_position_set(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd EINA_UNUSED, Eina_Position2D pos)
+{
+ _anchor_detach(obj);
+
+ pd->anchor = NULL;
+ pd->align = EFL_UI_POPUP_ALIGN_NONE;
+
+ efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd EINA_UNUSED)
+{
+ elm_layout_sizing_eval(efl_super(obj, MY_CLASS));
+
+ if (pd->anchor != NULL)
+ _anchor_calc(obj);
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_efl_ui_popup_align_set(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd, Efl_Ui_Popup_Align type)
+{
+ pd->align = type;
+ if (pd->anchor == NULL)
+ efl_ui_popup_align_set(efl_super(obj, MY_CLASS), type);
+ else
+ _anchor_calc(obj);
+}
+
+EOLIAN static Efl_Ui_Popup_Align
+_efl_ui_popup_anchor_efl_ui_popup_align_get(Eo *obj EINA_UNUSED, Efl_Ui_Popup_Anchor_Data *pd)
+{
+ return pd->align;
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd EINA_UNUSED)
+{
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ efl_canvas_group_add(efl_super(obj, MY_CLASS));
+ elm_widget_sub_object_parent_add(obj);
+
+ pd->priority[0] = EFL_UI_POPUP_ALIGN_TOP;
+ pd->priority[1] = EFL_UI_POPUP_ALIGN_LEFT;
+ pd->priority[2] = EFL_UI_POPUP_ALIGN_RIGHT;
+ pd->priority[3] = EFL_UI_POPUP_ALIGN_BOTTOM;
+ pd->priority[4] = EFL_UI_POPUP_ALIGN_CENTER;
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Popup_Anchor_Data *pd EINA_UNUSED)
+{
+ efl_canvas_group_del(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static void
+_efl_ui_popup_anchor_class_constructor(Efl_Class *klass)
+{
+ evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
+}
+
+#define EFL_UI_POPUP_ANCHOR_EXTRA_OPS \
+ EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_popup_anchor), \
+ ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_popup_anchor)
+
+#include "efl_ui_popup_anchor.eo.c"
diff --git a/src/lib/elementary/efl_ui_popup_anchor.eo b/src/lib/elementary/efl_ui_popup_anchor.eo
new file mode 100644
index 0000000000..1dc422dba0
--- /dev/null
+++ b/src/lib/elementary/efl_ui_popup_anchor.eo
@@ -0,0 +1,40 @@
+class Efl.Ui.Popup.Anchor(Efl.Ui.Popup)
+{
+ methods {
+ @property anchor {
+ set {
+ [[Set anchor popup follows the anchor object.
+ If anchor object is moved or parent window is resized, the anchor popup moves to the new position.
+ If anchor object is set NULL, the anchor popup stop to following anchor object.
+ When the popup is moved by using gfx_position_set, anchor is set NULL.
+ ]]
+ }
+ get {
+ [[Returns the anchor object which the popup is following.]]
+ }
+ values {
+ anchor: Efl.Canvas.Object; [[The object which popup is following.]]
+ }
+ }
+ @property align_priority @beta {
+ set {
+ [[Set the align priority of a popup.]]
+ }
+ get {
+ [[Get the align priority of a popup.]]
+ }
+ values {
+ first: Efl.Ui.Popup.Align;
+ second: Efl.Ui.Popup.Align;
+ third: Efl.Ui.Popup.Align;
+ fourth: Efl.Ui.Popup.Align;
+ fifth: Efl.Ui.Popup.Align;
+ }
+ }
+ }
+ implements {
+ class.constructor;
+ Efl.Gfx.position { set; }
+ Efl.Ui.Popup.align { set; get; }
+ }
+}
diff --git a/src/lib/elementary/efl_ui_popup_anchor_private.h b/src/lib/elementary/efl_ui_popup_anchor_private.h
new file mode 100644
index 0000000000..e99094c591
--- /dev/null
+++ b/src/lib/elementary/efl_ui_popup_anchor_private.h
@@ -0,0 +1,18 @@
+#ifndef EFL_UI_POPUP_ANCHOR_H
+#define EFL_UI_POPUP_ANCHOR_H
+
+#include "Elementary.h"
+
+typedef struct _Efl_Ui_Popup_Anchor_Data Efl_Ui_Popup_Anchor_Data;
+struct _Efl_Ui_Popup_Anchor_Data
+{
+ Evas_Object *anchor;
+ Efl_Ui_Popup_Align align;
+ Efl_Ui_Popup_Align priority[5];
+ Efl_Ui_Popup_Align used_align;
+};
+
+#define EFL_UI_POPUP_ANCHOR_DATA_GET(o, sd) \
+ Efl_Ui_Popup_Anchor_Data * sd = efl_data_scope_get(o, EFL_UI_POPUP_ANCHOR_CLASS)
+
+#endif