summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaeun Choi <jaeun12.choi@samsung.com>2014-06-25 23:43:18 +0900
committerJaeun Choi <jaeun12.choi@samsung.com>2014-06-25 23:43:18 +0900
commita47eef78c4f8e41708d54ddea96fe7e7f5511df4 (patch)
tree06825a9f589d564ced6505a07d5f7c519db2ff3a
parentda1b5c8fecff8a3acb86a2be7184c3021bf47584 (diff)
downloadelementary-a47eef78c4f8e41708d54ddea96fe7e7f5511df4.tar.gz
panel: add scrollable feature
This implements scrollable interface in elm_panel so that users can drag open/close panel. Tap & hold on the edge and panel handler will appear. Left scrollable panel is implemented in elementary_test > Panel Scrollable. @feature
-rw-r--r--data/themes/edc/elm/panel.edc381
-rw-r--r--src/bin/test.c2
-rw-r--r--src/bin/test_panel.c73
-rw-r--r--src/lib/elm_panel.c953
-rw-r--r--src/lib/elm_panel.eo29
-rw-r--r--src/lib/elm_panel.h3
-rw-r--r--src/lib/elm_panel_common.h6
-rw-r--r--src/lib/elm_widget_panel.h12
8 files changed, 1432 insertions, 27 deletions
diff --git a/data/themes/edc/elm/panel.edc b/data/themes/edc/elm/panel.edc
index 7dab212da..7a99dbb73 100644
--- a/data/themes/edc/elm/panel.edc
+++ b/data/themes/edc/elm/panel.edc
@@ -1,3 +1,384 @@
+group { name: "elm/scroller/panel/default";
+ data {
+ item: "handler_size" "30";
+ }
+ parts {
+ part { name: "elm.swallow.content";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ }
+ }
+ }
+}
+
+group { name: "elm/scroller/panel/left/default";
+ parts {
+ part { name: "panel_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel2.relative: 0.0 1.0;
+ align: 0.0 0.5;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "event_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1 {
+ relative: 1.0 0.0;
+ to: "panel_area";
+ }
+ rel2 {
+ relative: 1.0 1.0;
+ to: "panel_area";
+ }
+ align: 0.0 0.5;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "access.outline";
+ type: RECT;
+ repeat_events: 1;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 0 0 0 0;
+ }
+ }
+ part { name: "bg";
+ type: RECT;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 64 64 64 255;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "elm.swallow.content";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program { name: "active";
+ signal: "elm,state,content,visible";
+ source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ program { name: "inactive";
+ signal: "elm,state,content,hidden";
+ source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ }
+}
+
+group { name: "elm/scroller/panel/right/default";
+ parts {
+ part { name: "event_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel2.relative: 0.0 1.0;
+ align: 0.0 0.5;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "panel_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1 {
+ relative: 1.0 0.0;
+ to: "event_area";
+ }
+ rel2 {
+ relative: 1.0 1.0;
+ to: "event_area";
+ }
+ align: 0.0 0.5;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "access.outline";
+ type: RECT;
+ repeat_events: 1;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 0 0 0 0;
+ }
+ }
+ part { name: "bg";
+ type: RECT;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 64 64 64 255;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "elm.swallow.content";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program { name: "active";
+ signal: "elm,state,content,visible";
+ source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ program { name: "inactive";
+ signal: "elm,state,content,hidden";
+ source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ }
+}
+
+group { name: "elm/scroller/panel/top/default";
+ parts {
+ part { name: "panel_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel2.relative: 1.0 0.0;
+ align: 0.5 0.0;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "event_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1 {
+ relative: 0.0 1.0;
+ to: "panel_area";
+ }
+ rel2 {
+ relative: 1.0 1.0;
+ to: "panel_area";
+ }
+ align: 0.5 0.0;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "access.outline";
+ type: RECT;
+ repeat_events: 1;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 0 0 0 0;
+ }
+ }
+ part { name: "bg";
+ type: RECT;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 64 64 64 255;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "elm.swallow.content";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program { name: "active";
+ signal: "elm,state,content,visible";
+ source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ program { name: "inactive";
+ signal: "elm,state,content,hidden";
+ source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ }
+}
+
+group { name: "elm/scroller/panel/bottom/default";
+ parts {
+ part { name: "event_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel2.relative: 1.0 0.0;
+ align: 0.5 0.0;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "panel_area";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1 {
+ relative: 0.0 1.0;
+ to: "event_area";
+ }
+ rel2 {
+ relative: 1.0 1.0;
+ to: "event_area";
+ }
+ align: 0.5 0.0;
+ fixed: 1 1;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "access.outline";
+ type: RECT;
+ repeat_events: 1;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 0 0 0 0;
+ }
+ }
+ part { name: "bg";
+ type: RECT;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ color: 64 64 64 255;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "elm.swallow.content";
+ type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.to: "panel_area";
+ rel2.to: "panel_area";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program { name: "active";
+ signal: "elm,state,content,visible";
+ source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ program { name: "inactive";
+ signal: "elm,state,content,hidden";
+ source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "panel_area";
+ target: "event_area";
+ target: "bg";
+ target: "elm.swallow.content";
+ }
+ }
+}
+
group { name: "elm/panel/left/default";
images.image: "bevel_out.png" COMP;
images.image: "shine.png" COMP;
diff --git a/src/bin/test.c b/src/bin/test.c
index ada5c2516..ae3976c19 100644
--- a/src/bin/test.c
+++ b/src/bin/test.c
@@ -158,6 +158,7 @@ void test_slideshow(void *data, Evas_Object *obj, void *event_info);
void test_menu(void *data, Evas_Object *obj, void *event_info);
void test_menu2(void *data, Evas_Object *obj, void *event_info);
void test_panel(void *data, Evas_Object *obj, void *event_info);
+void test_panel2(void *data, Evas_Object *obj, void *event_info);
void test_panes(void *data, Evas_Object *obj, void *event_info);
void test_calendar(void *data, Evas_Object *obj, void *event_info);
void test_calendar2(void *data, Evas_Object *obj, void *event_info);
@@ -785,6 +786,7 @@ add_tests:
//------------------------------//
ADD_TEST(NULL, "Dividers", "Panel", test_panel);
+ ADD_TEST(NULL, "Dividers", "Panel Scrollable", test_panel2);
ADD_TEST(NULL, "Dividers", "Panes", test_panes);
//------------------------------//
diff --git a/src/bin/test_panel.c b/src/bin/test_panel.c
index d0b7f6b3f..7743174ce 100644
--- a/src/bin/test_panel.c
+++ b/src/bin/test_panel.c
@@ -270,3 +270,76 @@ test_panel(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_inf
evas_object_resize(win, 320, 400);
evas_object_show(win);
}
+
+static void
+_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Evas_Object *panel = data;
+ elm_panel_toggle(panel);
+}
+
+void
+test_panel2(void *data EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Evas_Object *win, *box, *table, *panel, *list, *button;
+ int i;
+
+ // Left Panel
+ win = elm_win_util_standard_add("panel", "Left Panel");
+ elm_win_autodel_set(win, EINA_TRUE);
+ evas_object_resize(win, 320, 400);
+ evas_object_show(win);
+
+ // box for button and table
+ box = elm_box_add(win);
+ evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_show(box);
+ elm_win_resize_object_add(win, box);
+
+ // toggle button
+ button = elm_button_add(box);
+ evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0);
+ evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(button);
+ elm_object_text_set(button, "Toggle");
+ elm_box_pack_end(box, button);
+
+ // table for panel and center content
+ table = elm_table_add(win);
+ evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(table);
+ elm_box_pack_end(box, table);
+
+ // center content
+ list = elm_list_add(table);
+ evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(list);
+ for (i = 0; i < 20; i++)
+ elm_list_item_append(list, "center list item", NULL, NULL, NULL, NULL);
+ elm_table_pack(table, list, 0, 0, 1, 1);
+
+ // panel
+ panel = elm_panel_add(table);
+ evas_object_size_hint_weight_set(panel, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(panel, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(panel);
+ elm_table_pack(table, panel, 0, 0, 1, 1);
+
+ elm_panel_scrollable_set(panel, EINA_TRUE);
+ elm_panel_orient_set(panel, ELM_PANEL_ORIENT_LEFT);
+ elm_panel_hidden_set(panel, EINA_TRUE);
+ elm_panel_scrollable_content_size_set(panel, 0.75);
+
+ list = elm_list_add(panel);
+ evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ for (i = 0; i < 7; i++)
+ elm_list_item_append(list, "panel list item", NULL, NULL, NULL, NULL);
+ elm_object_content_set(panel, list);
+
+ evas_object_smart_callback_add(button, "clicked", _clicked_cb, panel);
+}
diff --git a/src/lib/elm_panel.c b/src/lib/elm_panel.c
index 6da13f975..8a48e1e2a 100644
--- a/src/lib/elm_panel.c
+++ b/src/lib/elm_panel.c
@@ -18,7 +18,12 @@
#define MY_CLASS_NAME "Elm_Panel"
#define MY_CLASS_NAME_LEGACY "elm_panel"
+static const char ACCESS_OUTLINE_PART[] = "access.outline";
+
+static const char SIG_SCROLL[] = "scroll";
+
static const Evas_Smart_Cb_Description _smart_callbacks[] = {
+ {SIG_SCROLL, ""},
{SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
{SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
{NULL, NULL}
@@ -68,6 +73,55 @@ _access_state_cb(void *data, Evas_Object *obj EINA_UNUSED)
return NULL;
}
+static Evas_Object *
+_access_object_get(const Evas_Object *obj, const char *part)
+{
+ Evas_Object *po, *ao;
+ ELM_PANEL_DATA_GET(obj, sd);
+
+ po = (Evas_Object *)edje_object_part_object_get
+ (elm_layout_edje_get(sd->scr_ly), part);
+ ao = evas_object_data_get(po, "_part_access_obj");
+
+ return ao;
+}
+
+static void
+_access_activate_cb(void *data,
+ Evas_Object *part_obj EINA_UNUSED,
+ Elm_Object_Item *item EINA_UNUSED)
+{
+ elm_panel_hidden_set(data, EINA_TRUE);
+}
+
+static void
+_access_obj_process(Evas_Object *obj, Eina_Bool is_access)
+{
+ Evas_Object *ao;
+ ELM_PANEL_DATA_GET(obj, sd);
+
+ if (is_access)
+ {
+ ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
+ if (!ao)
+ {
+ ao = _elm_access_edje_object_part_object_register
+ (obj, elm_layout_edje_get(sd->scr_ly), ACCESS_OUTLINE_PART);
+ _elm_access_text_set(_elm_access_info_get(ao),
+ ELM_ACCESS_TYPE, E_("A drawer is open"));
+ _elm_access_text_set(_elm_access_info_get(ao),
+ ELM_ACCESS_CONTEXT_INFO, E_("Double tap to close drawer menu"));
+ _elm_access_activate_callback_set
+ (_elm_access_info_get(ao), _access_activate_cb, obj);
+ }
+ }
+ else
+ {
+ _elm_access_edje_object_part_object_unregister
+ (obj, elm_layout_edje_get(sd->scr_ly), ACCESS_OUTLINE_PART);
+ }
+}
+
static void
_orient_set_do(Evas_Object *obj)
{
@@ -132,6 +186,38 @@ _orient_set_do(Evas_Object *obj)
}
}
+static void
+_scrollable_layout_theme_set(Eo *obj, Elm_Panel_Data *sd)
+{
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/top",
+ elm_widget_style_get(obj)))
+ CRI("Failed to set layout!");
+ break;
+ case ELM_PANEL_ORIENT_BOTTOM:
+ if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/bottom",
+ elm_widget_style_get(obj)))
+ CRI("Failed to set layout!");
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/left",
+ elm_widget_style_get(obj)))
+ CRI("Failed to set layout!");
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/right",
+ elm_widget_style_get(obj)))
+ CRI("Failed to set layout!");
+ break;
+ }
+
+ /* access */
+ if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
+ _access_obj_process(obj, EINA_TRUE);
+}
+
EOLIAN static Eina_Bool
_elm_panel_elm_widget_theme_apply(Eo *obj, Elm_Panel_Data *sd)
{
@@ -147,22 +233,36 @@ _elm_panel_elm_widget_theme_apply(Eo *obj, Elm_Panel_Data *sd)
_mirrored_set(obj, elm_widget_mirrored_get(obj));
- str = edje_object_data_get
- (wd->resize_obj, "focus_highlight");
- if ((str) && (!strcmp(str, "on")))
- elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
+ if (sd->scrollable)
+ {
+ const char *handler_size;
+ elm_widget_theme_object_set(obj, sd->scr_edje, "scroller", "panel",
+ elm_widget_style_get(obj));
+ _scrollable_layout_theme_set(obj, sd);
+
+ handler_size = edje_object_data_get(sd->scr_edje, "handler_size");
+ if (handler_size)
+ sd->handler_size = (int) (elm_object_scale_get(obj)) * (atoi(handler_size));
+ }
else
- elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
+ {
+ str = edje_object_data_get
+ (wd->resize_obj, "focus_highlight");
+ if ((str) && (!strcmp(str, "on")))
+ elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
+ else
+ elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
- _orient_set_do(obj);
+ _orient_set_do(obj);
- evas_object_hide(sd->event);
- elm_coords_finger_size_adjust(1, &minw, 1, &minh);
- evas_object_size_hint_min_set(sd->event, minw, minh);
+ evas_object_hide(sd->event);
+ elm_coords_finger_size_adjust(1, &minw, 1, &minh);
+ evas_object_size_hint_min_set(sd->event, minw, minh);
- if (edje_object_part_exists
- (wd->resize_obj, "elm.swallow.event"))
- elm_layout_content_set(obj, "elm.swallow.event", sd->event);
+ if (edje_object_part_exists
+ (wd->resize_obj, "elm.swallow.event"))
+ elm_layout_content_set(obj, "elm.swallow.event", sd->event);
+ }
elm_layout_sizing_eval(obj);
@@ -179,11 +279,33 @@ EOLIAN static Eina_Bool
_elm_panel_elm_widget_focus_next(Eo *obj, Elm_Panel_Data *sd, Elm_Focus_Direction dir, Evas_Object **next)
{
Evas_Object *cur;
+ Eina_List *items = NULL;
+ Eina_Bool ret = EINA_FALSE;
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
if (!sd->content) return EINA_FALSE;
+ if (sd->scrollable)
+ {
+ if (sd->hidden) return EINA_FALSE;
+
+ if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
+ {
+ Evas_Object *ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
+ if (ao) items = eina_list_append(items, ao);
+ items = eina_list_append(items, sd->content);
+
+ ret = elm_widget_focus_list_next_get
+ (obj, items, eina_list_data_get, dir, next);
+ eina_list_free(items);
+
+ return ret;
+ }
+
+ return elm_widget_focus_next_get(sd->content, dir, next);
+ }
+
cur = sd->content;
/* Try to Focus cycle in subitem */
@@ -213,6 +335,124 @@ _box_layout_cb(Evas_Object *o,
}
static void
+_handler_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+ ELM_PANEL_DATA_GET(obj, sd);
+
+ if (sd->handler_size == 0) return;
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ eo_do(obj, elm_interface_scrollable_region_bring_in
+ (0, (h * sd->content_size_ratio) - sd->handler_size, w, h));
+ break;
+ case ELM_PANEL_ORIENT_BOTTOM:
+ eo_do(obj, elm_interface_scrollable_region_bring_in
+ (0, sd->handler_size, w, h));
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ eo_do(obj, elm_interface_scrollable_region_bring_in
+ ((w * sd->content_size_ratio) - sd->handler_size, 0, w, h));
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ eo_do(obj, elm_interface_scrollable_region_bring_in
+ (sd->handler_size, 0, w, h));
+ break;
+ }
+}
+
+static void
+_drawer_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim)
+{
+ ELM_PANEL_DATA_GET(obj, sd);
+ int x = 0, y = 0;
+
+ if (sd->freeze)
+ {
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_NO_BLOCK));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ case ELM_PANEL_ORIENT_LEFT:
+ break;
+
+ case ELM_PANEL_ORIENT_BOTTOM:
+ y = h * sd->content_size_ratio;
+ break;
+
+ case ELM_PANEL_ORIENT_RIGHT:
+ x = w * sd->content_size_ratio;
+ break;
+ }
+
+ if (anim)
+ eo_do(obj, elm_interface_scrollable_region_bring_in
+ (x, y, w, h));
+ else
+ eo_do(obj, elm_interface_scrollable_content_region_show
+ (x, y, w, h));
+}
+
+static void
+_drawer_close(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim)
+{
+ ELM_PANEL_DATA_GET(obj, sd);
+ int x = 0, y = 0;
+ Eina_Bool horizontal = EINA_FALSE;
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ y = h * sd->content_size_ratio;
+ break;
+
+ case ELM_PANEL_ORIENT_LEFT:
+ x = w * sd->content_size_ratio;
+ horizontal = EINA_TRUE;
+ break;
+
+ case ELM_PANEL_ORIENT_BOTTOM:
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ horizontal = EINA_TRUE;
+ break;
+ }
+
+ if (anim)
+ {
+ if (sd->freeze)
+ {
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_NO_BLOCK));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+ eo_do(obj, elm_interface_scrollable_region_bring_in(x, y, w, h));
+ }
+ else
+ {
+ eo_do(obj, elm_interface_scrollable_content_region_show(x, y, w, h));
+ if (!sd->freeze)
+ {
+ if (horizontal)
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL));
+ else
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL));
+ sd->freeze = EINA_TRUE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
+ }
+ }
+}
+
+static void
_panel_toggle(void *data EINA_UNUSED,
Evas_Object *obj,
const char *emission EINA_UNUSED,
@@ -220,26 +460,382 @@ _panel_toggle(void *data EINA_UNUSED,
{
ELM_PANEL_DATA_GET(obj, sd);
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ int w, h;
- if (sd->hidden)
+ if (sd->scrollable)
{
- elm_layout_signal_emit(obj, "elm,action,show", "elm");
- sd->hidden = EINA_FALSE;
- evas_object_repeat_events_set(obj, EINA_FALSE);
+ if (elm_widget_disabled_get(obj)) return;
+
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+ if (sd->hidden)
+ {
+ sd->hidden = EINA_FALSE;
+ _drawer_open(obj, w, h, EINA_TRUE);
+ }
+ else
+ {
+ sd->hidden = EINA_TRUE;
+ _drawer_close(obj, w, h, EINA_TRUE);
+ }
}
else
{
- elm_layout_signal_emit(obj, "elm,action,hide", "elm");
- sd->hidden = EINA_TRUE;
- evas_object_repeat_events_set(obj, EINA_TRUE);
- if (sd->content && elm_widget_focus_get(sd->content))
+ if (sd->hidden)
+ {
+ elm_layout_signal_emit(obj, "elm,action,show", "elm");
+ sd->hidden = EINA_FALSE;
+ evas_object_repeat_events_set(obj, EINA_FALSE);
+ }
+ else
{
- elm_widget_focused_object_clear(obj);
- elm_widget_focus_steal(obj);
+ elm_layout_signal_emit(obj, "elm,action,hide", "elm");
+ sd->hidden = EINA_TRUE;
+ evas_object_repeat_events_set(obj, EINA_TRUE);
+ if (sd->content && elm_widget_focus_get(sd->content))
+ {
+ elm_widget_focused_object_clear(obj);
+ elm_widget_focus_steal(obj);
+ }
}
+
+ edje_object_message_signal_process(wd->resize_obj);
+ }
+}
+
+static Eina_Bool
+_state_sync(Evas_Object *obj)
+{
+ ELM_PANEL_DATA_GET(obj, sd);
+ Evas_Object *ao;
+ Evas_Coord pos, panel_size, w, h;
+ Eina_Bool open = EINA_FALSE, horizontal = EINA_FALSE;
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ panel_size = h * sd->content_size_ratio;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(NULL, &pos));
+
+ if (pos == 0) open = EINA_TRUE;
+ else if (pos == panel_size) open = EINA_FALSE;
+ else return EINA_FALSE;
+ break;
+
+ case ELM_PANEL_ORIENT_BOTTOM:
+ panel_size = h * sd->content_size_ratio;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(NULL, &pos));
+
+ if (pos == panel_size) open = EINA_TRUE;
+ else if (pos == 0) open = EINA_FALSE;
+ else return EINA_FALSE;
+ break;
+
+ case ELM_PANEL_ORIENT_LEFT:
+ panel_size = w * sd->content_size_ratio;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(&pos, NULL));
+ horizontal = EINA_TRUE;
+
+ if (pos == 0) open = EINA_TRUE;
+ else if (pos == panel_size) open = EINA_FALSE;
+ else return EINA_FALSE;
+ break;
+
+ case ELM_PANEL_ORIENT_RIGHT:
+ panel_size = w * sd->content_size_ratio;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(&pos, NULL));
+ horizontal = EINA_TRUE;
+
+ if (pos == panel_size) open = EINA_TRUE;
+ else if (pos == 0) open = EINA_FALSE;
+ else return EINA_FALSE;
+ break;
+ }
+
+ if (open)
+ {
+ if (sd->hidden) sd->hidden = EINA_FALSE;
+ eo_do(obj, elm_interface_scrollable_single_direction_set
+ (ELM_SCROLLER_SINGLE_DIRECTION_HARD));
+
+ //focus & access
+ elm_object_tree_focus_allow_set(obj, EINA_TRUE);
+ if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
+ {
+ ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
+ evas_object_show(ao);
+ _elm_access_highlight_set(ao);
+ }
+ else
+ elm_object_focus_set(obj, EINA_TRUE);
+ }
+ else
+ {
+ if (!sd->hidden) sd->hidden = EINA_TRUE;
+
+ if (horizontal)
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL));
+ else
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL));
+ sd->freeze = EINA_TRUE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
+
+ eo_do(obj, elm_interface_scrollable_single_direction_set
+ (ELM_SCROLLER_SINGLE_DIRECTION_NONE));
+
+ //focus & access
+ elm_object_tree_focus_allow_set(obj, EINA_FALSE);
+ if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
+ {
+ ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
+ evas_object_hide(ao);
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_timer_cb(void *data)
+{
+ ELM_PANEL_DATA_GET(data, sd);
+ Evas_Object *obj = data;
+ Evas_Coord w, h;
+
+ sd->timer = NULL;
+
+ if (sd->freeze)
+ {
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_NO_BLOCK));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+ _handler_open(obj, w, h);
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_event_mouse_up(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info)
+{
+ ELM_PANEL_DATA_GET(data, sd);
+ Evas_Event_Mouse_Up *ev = event_info;
+ Evas_Coord x, y, up_x, up_y, minw = 0, minh = 0;
+ evas_object_geometry_get(data, &x, &y, NULL, NULL);
+
+ up_x = ev->output.x - x;
+ up_y = ev->output.y - y;
+
+ elm_coords_finger_size_adjust(1, &minw, 1, &minh);
+
+ if ((!sd->hidden) && (up_x == sd->down_x) && (up_y == sd->down_y))
+ elm_panel_hidden_set(data, EINA_TRUE);
+}
+
+static void
+_on_mouse_down(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj,
+ void *event_info)
+{
+ Elm_Panel_Data *sd = data;
+ Evas_Event_Mouse_Down *ev = event_info;
+ Evas_Coord finger_size = elm_config_finger_size_get();
+ Evas_Coord x, y, w, h;
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+ sd->down_x = ev->output.x - x;
+ sd->down_y = ev->output.y - y;
+
+ // if freeze state & mouse down on the edge
+ // then set timer for un-freeze
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ if ((sd->freeze) && (sd->down_y >= 0) && (sd->down_y < finger_size))
+ {
+ ecore_timer_del(sd->timer);
+ sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
+ }
+ break;
+ case ELM_PANEL_ORIENT_BOTTOM:
+ if ((sd->freeze) && (sd->down_y <= h) && (sd->down_y > (h - finger_size)))
+ {
+ ecore_timer_del(sd->timer);
+ sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
+ }
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ if ((sd->freeze) && (sd->down_x >= 0) && (sd->down_x < finger_size))
+ {
+ ecore_timer_del(sd->timer);
+ sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
+ }
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ if ((sd->freeze) && (sd->down_x <= w) && (sd->down_x > (w - finger_size)))
+ {
+ ecore_timer_del(sd->timer);
+ sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
+ }
+ break;
+ }
+}
+
+static void
+_on_mouse_move(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj,
+ void *event_info)
+{
+ Elm_Panel_Data *sd = data;
+ Evas_Event_Mouse_Move *ev = event_info;
+ Evas_Coord x, y, w, h, cur_x, cur_y, finger_size;
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ finger_size = elm_config_finger_size_get();
+
+ cur_x = ev->cur.canvas.x - x;
+ cur_y = ev->cur.canvas.y - y;
+
+ // if mouse down on the edge (it means sd->timer is not null)
+ // and move more than finger size
+ // then un-freeze
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ if (sd->timer && ((cur_y - sd->down_y) > finger_size))
+ {
+ eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+ break;
+ case ELM_PANEL_ORIENT_BOTTOM:
+ if (sd->timer && ((sd->down_y - cur_y) > finger_size))
+ {
+ eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ if (sd->timer && ((cur_x - sd->down_x) > finger_size))
+ {
+ eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ if (sd->timer && ((sd->down_x - cur_x) > finger_size))
+ {
+ eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+ break;
+ }
+
+ if (!sd->freeze && sd->hidden)
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+}
+
+static void
+_on_mouse_up(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj,
+ void *event_info)
+{
+ Elm_Panel_Data *sd = data;
+ Evas_Event_Mouse_Up *ev = event_info;
+ Evas_Coord panel_size, threshold, pos, w, h;
+
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+
+ ELM_SAFE_FREE(sd->timer, ecore_timer_del);
+
+ if (_state_sync(obj)) return;
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ panel_size = h * sd->content_size_ratio;
+ threshold = panel_size / 4;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(NULL, &pos));
+
+ if (sd->hidden)
+ {
+ if (pos < (panel_size - threshold)) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ else
+ {
+ if (pos < threshold) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ break;
+
+ case ELM_PANEL_ORIENT_BOTTOM:
+ panel_size = h * sd->content_size_ratio;
+ threshold = panel_size / 4;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(NULL, &pos));
+
+ if (sd->hidden)
+ {
+ if (pos > threshold) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ else
+ {
+ if (pos > (panel_size - threshold)) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ break;
+
+ case ELM_PANEL_ORIENT_LEFT:
+ panel_size = w * sd->content_size_ratio;
+ threshold = panel_size / 4;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(&pos, NULL));
+
+ if (sd->hidden)
+ {
+ if (pos < (panel_size - threshold)) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ else
+ {
+ if (pos < threshold) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ break;
+
+ case ELM_PANEL_ORIENT_RIGHT:
+ panel_size = w * sd->content_size_ratio;
+ threshold = panel_size / 4;
+ eo_do(obj, elm_interface_scrollable_content_pos_get(&pos, NULL));
+
+ if (sd->hidden)
+ {
+ if (pos > threshold) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ else
+ {
+ if (pos > (panel_size - threshold)) _drawer_open(obj, w, h, EINA_TRUE);
+ else _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ break;
}
- edje_object_message_signal_process(wd->resize_obj);
+ if (!sd->freeze && sd->hidden)
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
static Eina_Bool
@@ -330,6 +926,8 @@ _elm_panel_evas_object_smart_add(Eo *obj, Elm_Panel_Data *priv)
elm_widget_sub_object_parent_add(obj);
elm_widget_can_focus_set(obj, EINA_TRUE);
+ priv->panel_edje = wd->resize_obj;
+
eo_do(obj, elm_obj_widget_theme_apply());
priv->bx = evas_object_box_add(evas_object_evas_get(obj));
@@ -378,6 +976,8 @@ _elm_panel_evas_object_smart_del(Eo *obj, Elm_Panel_Data *sd)
sd->delete_me = EINA_TRUE;
+ ELM_SAFE_FREE(sd->timer, ecore_timer_del);
+
/* let's make our box object the *last* to be processed, since it
* may (smart) parent other sub objects here */
EINA_LIST_FOREACH(wd->subobjs, l, child)
@@ -394,9 +994,63 @@ _elm_panel_evas_object_smart_del(Eo *obj, Elm_Panel_Data *sd)
}
EOLIAN static void
-_elm_panel_elm_widget_access(Eo *obj, Elm_Panel_Data *_pd EINA_UNUSED, Eina_Bool is_access)
+_elm_panel_evas_object_smart_move(Eo *obj, Elm_Panel_Data *sd, Evas_Coord x, Evas_Coord y)
+{
+ eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
+
+ evas_object_move(sd->hit_rect, x, y);
+}
+
+EOLIAN static void
+_elm_panel_evas_object_smart_resize(Eo *obj, Elm_Panel_Data *sd, Evas_Coord w, Evas_Coord h)
+{
+ eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
+
+ if (!sd->scrollable) return;
+
+ evas_object_resize(sd->hit_rect, w, h);
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ case ELM_PANEL_ORIENT_BOTTOM:
+ // vertical
+ evas_object_resize(sd->scr_ly, w, (1 + sd->content_size_ratio) * h);
+ evas_object_size_hint_min_set(sd->scr_panel, w, (sd->content_size_ratio * h));
+ evas_object_size_hint_min_set(sd->scr_event, w, h);
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ case ELM_PANEL_ORIENT_RIGHT:
+ // horizontal
+ evas_object_resize(sd->scr_ly, (1 + sd->content_size_ratio) * w, h);
+ evas_object_size_hint_min_set(sd->scr_panel, (sd->content_size_ratio * w), h);
+ evas_object_size_hint_min_set(sd->scr_event, w, h);
+ break;
+ }
+
+ if (sd->hidden) _drawer_close(obj, w, h, EINA_FALSE);
+ else _drawer_open(obj, w, h, EINA_FALSE);
+}
+
+EOLIAN static void
+_elm_panel_evas_object_smart_member_add(Eo *obj, Elm_Panel_Data *sd, Evas_Object *member)
+{
+ eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(member));
+
+ if (sd->hit_rect) evas_object_raise(sd->hit_rect);
+}
+
+EOLIAN static void
+_elm_panel_elm_widget_access(Eo *obj, Elm_Panel_Data *_pd, Eina_Bool is_access)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ Elm_Panel_Data *sd = _pd;
+
+ if (sd->scrollable)
+ {
+ _access_obj_process(obj, is_access);
+ return;
+ }
if (is_access)
_elm_access_edje_object_part_object_register
@@ -431,7 +1085,8 @@ _elm_panel_orient_set(Eo *obj, Elm_Panel_Data *sd, Elm_Panel_Orient orient)
if (sd->orient == orient) return;
sd->orient = orient;
- _orient_set_do(obj);
+ if (sd->scrollable) _scrollable_layout_theme_set(obj, sd);
+ else _orient_set_do(obj);
elm_layout_sizing_eval(obj);
}
@@ -445,7 +1100,16 @@ _elm_panel_orient_get(Eo *obj EINA_UNUSED, Elm_Panel_Data *sd)
EOLIAN static void
_elm_panel_hidden_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool hidden)
{
- if (sd->hidden == !!hidden) return;
+ if (sd->hidden == !!hidden)
+ {
+ if (sd->scrollable && sd->hidden && !sd->freeze)
+ {
+ Evas_Coord w, h;
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+ _drawer_close(obj, w, h, EINA_TRUE);
+ }
+ return;
+ }
_panel_toggle(NULL, obj, NULL, NULL);
}
@@ -462,6 +1126,243 @@ _elm_panel_toggle(Eo *obj, Elm_Panel_Data *_pd EINA_UNUSED)
_panel_toggle(NULL, obj, NULL, NULL);
}
+EOLIAN static Eina_Bool
+_elm_panel_elm_widget_on_focus_region(Eo *obj,
+ Elm_Panel_Data *sd,
+ Evas_Coord *x,
+ Evas_Coord *y,
+ Evas_Coord *w,
+ Evas_Coord *h)
+{
+ eo_do(obj, elm_interface_scrollable_content_pos_get(x, y));
+ evas_object_geometry_get(obj, NULL, NULL, w, h);
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ case ELM_PANEL_ORIENT_BOTTOM:
+ *h = *h * sd->content_size_ratio;
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ case ELM_PANEL_ORIENT_RIGHT:
+ *w = *w * sd->content_size_ratio;
+ break;
+ }
+ return EINA_TRUE;
+}
+
+static void
+_anim_stop_cb(Evas_Object *obj, void *data EINA_UNUSED)
+{
+ if (elm_widget_disabled_get(obj)) return;
+ _state_sync(obj);
+}
+
+static void
+_scroll_cb(Evas_Object *obj, void *data EINA_UNUSED)
+{
+ ELM_PANEL_DATA_GET(obj, sd);
+ Elm_Panel_Scroll_Info event;
+ Evas_Coord x, y, w, h;
+
+ if (elm_widget_disabled_get(obj)) return;
+ // in the case of
+ // freeze_set(FALSE) -> mouse_up -> freeze_set(TRUE) -> scroll
+ if (sd->freeze)
+ {
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_NO_BLOCK));
+ sd->freeze = EINA_FALSE;
+ elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
+ }
+
+ eo_do(obj, elm_interface_scrollable_content_pos_get(&x, &y));
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ event.rel_x = 1;
+ event.rel_y = 1 - ((double) y / (double) ((sd->content_size_ratio) * h));
+ break;
+ case ELM_PANEL_ORIENT_BOTTOM:
+ event.rel_x = 1;
+ event.rel_y = (double) y / (double) ((sd->content_size_ratio) * h);
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ event.rel_x = 1 - ((double) x / (double) ((sd->content_size_ratio) * w));
+ event.rel_y = 1;
+ break;
+ case ELM_PANEL_ORIENT_RIGHT:
+ event.rel_x = (double) x / (double) ((sd->content_size_ratio) * w);
+ event.rel_y = 1;
+ break;
+ }
+ evas_object_smart_callback_call(obj, SIG_SCROLL, (void *) &event);
+}
+
+EOLIAN static Eina_Bool
+_elm_panel_elm_widget_disable(Eo *obj, Elm_Panel_Data *sd)
+{
+ Eina_Bool int_ret = EINA_FALSE;
+ eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_disable());
+ if (!int_ret) return EINA_FALSE;
+
+ if (sd->scrollable)
+ {
+ if (elm_widget_disabled_get(obj))
+ {
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN,
+ _on_mouse_down);
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE,
+ _on_mouse_move);
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP,
+ _on_mouse_up);
+ evas_object_event_callback_del(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
+ _event_mouse_up);
+ }
+ else
+ {
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+ _on_mouse_down, sd);
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
+ _on_mouse_move, sd);
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
+ _on_mouse_up, sd);
+ evas_object_event_callback_add(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
+ _event_mouse_up, obj);
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+EOLIAN static void
+_elm_panel_scrollable_content_size_set(Eo *obj EINA_UNUSED, Elm_Panel_Data *sd, double ratio)
+{
+ sd->content_size_ratio = ratio;
+}
+
+EOLIAN static void
+_elm_panel_scrollable_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool scrollable)
+{
+ scrollable = !!scrollable;
+ if (sd->scrollable == scrollable) return;
+ sd->scrollable = scrollable;
+
+ if (scrollable)
+ {
+ elm_layout_content_unset(obj, "elm.swallow.content");
+
+ elm_widget_resize_object_set(obj, NULL, EINA_TRUE);
+ elm_widget_sub_object_add(obj, sd->panel_edje);
+
+ if (!sd->scr_edje)
+ {
+ const char *handler_size;
+
+ sd->scr_edje = edje_object_add(evas_object_evas_get(obj));
+ elm_widget_theme_object_set(obj, sd->scr_edje, "scroller", "panel",
+ elm_widget_style_get(obj));
+ evas_object_size_hint_weight_set
+ (sd->scr_edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set
+ (sd->scr_edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+ handler_size = edje_object_data_get(sd->scr_edje, "handler_size");
+ if (handler_size)
+ sd->handler_size = (int) (elm_object_scale_get(obj)) * (atoi(handler_size));
+ }
+
+ elm_widget_resize_object_set(obj, sd->scr_edje, EINA_TRUE);
+
+ if (!sd->hit_rect)
+ {
+ sd->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
+ evas_object_smart_member_add(sd->hit_rect, obj);
+ elm_widget_sub_object_add(obj, sd->hit_rect);
+ evas_object_color_set(sd->hit_rect, 0, 0, 0, 0);
+ evas_object_show(sd->hit_rect);
+ evas_object_repeat_events_set(sd->hit_rect, EINA_TRUE);
+
+ eo_do(obj,
+ elm_interface_scrollable_objects_set(sd->scr_edje, sd->hit_rect),
+ elm_interface_scrollable_animate_stop_cb_set(_anim_stop_cb),
+ elm_interface_scrollable_scroll_cb_set(_scroll_cb));
+ }
+
+ if (!sd->scr_ly)
+ {
+ sd->scr_ly = elm_layout_add(obj);
+ evas_object_smart_member_add(sd->scr_ly, obj);
+ elm_widget_sub_object_add(obj, sd->scr_ly);
+ _scrollable_layout_theme_set(obj, sd);
+
+ sd->scr_panel = evas_object_rectangle_add(evas_object_evas_get(obj));
+ evas_object_color_set(sd->scr_panel, 0, 0, 0, 0);
+ elm_widget_sub_object_add(obj, sd->scr_panel);
+ elm_layout_content_set(sd->scr_ly, "panel_area", sd->scr_panel);
+
+ sd->scr_event = evas_object_rectangle_add(evas_object_evas_get(obj));
+ evas_object_color_set(sd->scr_event, 0, 0, 0, 0);
+ elm_widget_sub_object_add(obj, sd->scr_event);
+ elm_layout_content_set(sd->scr_ly, "event_area", sd->scr_event);
+ }
+
+ eo_do(obj,
+ elm_interface_scrollable_content_set(sd->scr_ly));
+ sd->freeze = EINA_TRUE;
+ elm_layout_content_set(sd->scr_ly, "elm.swallow.content", sd->bx);
+
+ switch (sd->orient)
+ {
+ case ELM_PANEL_ORIENT_TOP:
+ case ELM_PANEL_ORIENT_BOTTOM:
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL));
+ break;
+ case ELM_PANEL_ORIENT_LEFT:
+ case ELM_PANEL_ORIENT_RIGHT:
+ eo_do(obj, elm_interface_scrollable_movement_block_set
+ (ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL));
+ break;
+ }
+
+ eo_do(obj, elm_interface_scrollable_single_direction_set
+ (ELM_SCROLLER_SINGLE_DIRECTION_NONE));
+
+ if (!elm_widget_disabled_get(obj))
+ {
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+ _on_mouse_down, sd);
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
+ _on_mouse_move, sd);
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
+ _on_mouse_up, sd);
+ evas_object_event_callback_add(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
+ _event_mouse_up, obj);
+ }
+
+ }
+ else
+ {
+ eo_do(obj, elm_interface_scrollable_content_set(NULL));
+
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down);
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE, _on_mouse_move);
+ evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _on_mouse_up);
+ evas_object_event_callback_del(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
+ _event_mouse_up);
+
+ elm_widget_resize_object_set(obj, NULL, EINA_TRUE);
+ elm_widget_sub_object_add(obj, sd->scr_edje);
+
+ elm_widget_resize_object_set(obj, sd->panel_edje, EINA_TRUE);
+
+ elm_layout_content_unset(sd->scr_ly, "elm.swallow.content");
+ elm_layout_content_set(obj, "elm.swallow.content", sd->bx);
+ }
+}
+
static void
_elm_panel_class_constructor(Eo_Class *klass)
{
diff --git a/src/lib/elm_panel.eo b/src/lib/elm_panel.eo
index 8a5e33a50..b4643298a 100644
--- a/src/lib/elm_panel.eo
+++ b/src/lib/elm_panel.eo
@@ -1,4 +1,4 @@
-class Elm_Panel (Elm_Layout)
+class Elm_Panel (Elm_Layout, Elm_Interface_Scrollable)
{
eo_prefix: elm_obj_panel;
properties {
@@ -45,6 +45,28 @@ class Elm_Panel (Elm_Layout)
Eina_Bool hidden; /*@ If true, the panel will run the animation to disappear. */
}
}
+ scrollable {
+ set {
+ /*@
+ @brief Set the scrollability of the panel.
+
+ @ingroup Panel */
+ }
+ values {
+ Eina_Bool scrollable;
+ }
+ }
+ scrollable_content_size {
+ set {
+ /*@
+ @brief Set the size of the scrollable panel.
+
+ @ingroup Panel */
+ }
+ values {
+ double ratio;
+ }
+ }
}
methods {
toggle {
@@ -59,12 +81,17 @@ class Elm_Panel (Elm_Layout)
class.constructor;
Eo_Base.constructor;
Evas_Object_Smart.add;
+ Evas_Object_Smart.member_add;
Evas_Object_Smart.del;
+ Evas_Object_Smart.resize;
+ Evas_Object_Smart.move;
Elm_Widget.theme_apply;
Elm_Widget.focus_next_manager_is;
Elm_Widget.focus_next;
+ Elm_Widget.disable;
Elm_Widget.access;
Elm_Widget.event;
+ Elm_Widget.on_focus_region;
Elm_Container.content_get;
Elm_Container.content_unset;
Elm_Container.content_set;
diff --git a/src/lib/elm_panel.h b/src/lib/elm_panel.h
index 6bf385390..0e957ee5c 100644
--- a/src/lib/elm_panel.h
+++ b/src/lib/elm_panel.h
@@ -23,6 +23,9 @@
*
* This widget emits the following signals, besides the ones sent from
* @ref Layout:
+ * @li @c "scroll" : When the content has been scrolled (moved). (since 1.10)
+ * This signal is emitted only when the panel is scrollable.
+ * Elm_Panel_Scroll_Info will be passed by @c event_info argument.
* @li @c "focused" : When the panel has received focus. (since 1.8)
* @li @c "unfocused" : When the panel has lost focus. (since 1.8)
*
diff --git a/src/lib/elm_panel_common.h b/src/lib/elm_panel_common.h
index 8c84d1ab1..9993b2208 100644
--- a/src/lib/elm_panel_common.h
+++ b/src/lib/elm_panel_common.h
@@ -6,3 +6,9 @@ typedef enum
ELM_PANEL_ORIENT_RIGHT, /**< Panel (dis)appears from the right */
} Elm_Panel_Orient;
+typedef struct _Elm_Panel_Scroll_Info
+{
+ double rel_x; /**<content scrolled position (0.0 ~ 1.0) in the panel>*/
+ double rel_y; /**<content scrolled position (0.0 ~ 1.0) in the panel>*/
+
+} Elm_Panel_Scroll_Info;
diff --git a/src/lib/elm_widget_panel.h b/src/lib/elm_widget_panel.h
index 6982774d0..38740081b 100644
--- a/src/lib/elm_widget_panel.h
+++ b/src/lib/elm_widget_panel.h
@@ -1,6 +1,7 @@
#ifndef ELM_WIDGET_PANEL_H
#define ELM_WIDGET_PANEL_H
+#include "elm_interface_scrollable.h"
#include "elm_widget_layout.h"
/**
@@ -22,11 +23,22 @@ struct _Elm_Panel_Data
{
Evas_Object *bx, *content;
Evas_Object *event;
+ Evas_Object *scr_ly;
+ Evas_Object *hit_rect, *panel_edje, *scr_edje;
+ Evas_Object *scr_panel, *scr_event;
+
Elm_Panel_Orient orient;
+ double content_size_ratio;
+ Evas_Coord down_x, down_y;
+ Evas_Coord handler_size;
+ Ecore_Timer *timer;
+
Eina_Bool hidden : 1;
Eina_Bool delete_me : 1;
+ Eina_Bool scrollable : 1;
+ Eina_Bool freeze: 1;
};
/**