diff --git a/data/elementary/themes/Makefile.am b/data/elementary/themes/Makefile.am index 2e176633f7..7116e63b0c 100644 --- a/data/elementary/themes/Makefile.am +++ b/data/elementary/themes/Makefile.am @@ -1026,6 +1026,7 @@ elementary/themes/edc/efl/grid.edc \ elementary/themes/edc/efl/navigation_bar.edc \ elementary/themes/edc/efl/navigation_layout.edc \ elementary/themes/edc/efl/tags.edc \ +elementary/themes/edc/efl/panel.edc \ elementary/themes/edc/efl/nstate.edc \ elementary/themes/edc/efl/panes.edc \ elementary/themes/edc/efl/photocam.edc \ diff --git a/data/elementary/themes/default.edc b/data/elementary/themes/default.edc index d0e7126fd4..95f879a8a8 100644 --- a/data/elementary/themes/default.edc +++ b/data/elementary/themes/default.edc @@ -186,6 +186,7 @@ collections { #include "edc/efl/video.edc" #include "edc/efl/focus.edc" #include "edc/efl/tags.edc" +#include "edc/efl/panel.edc" #include "edc/efl/tooltip.edc" #include "edc/efl/photocam.edc" #include "edc/efl/progress.edc" diff --git a/data/elementary/themes/edc/efl/panel.edc b/data/elementary/themes/edc/efl/panel.edc new file mode 100644 index 0000000000..aee2e31f6f --- /dev/null +++ b/data/elementary/themes/edc/efl/panel.edc @@ -0,0 +1,831 @@ +group { name: "efl/panel"; + data { + item: "handler_size" "30"; + } + parts { + part { name: "efl.content"; + type: SWALLOW; + description { state: "default" 0.0; + } + } + } +} +group { name: "efl/panel/scrollable/left"; + parts { + part { name: "efl.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: "efl.event_area"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 1.0 0.0; + to: "efl.panel_area"; + } + rel2 { + relative: 1.0 1.0; + to: "efl.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: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 0 0 0 0; + } + } + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 64 64 64 255; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "efl.content"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + } + programs { + program { name: "active"; + signal: "efl,state,content,visible"; + source: "efl"; + action: STATE_SET "visible" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + program { name: "inactive"; + signal: "efl,state,content,hidden"; + source: "efl"; + action: STATE_SET "default" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + } +} + +group { name: "efl/panel/scrollable/right"; + parts { + part { name: "efl.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: "efl.panel_area"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 1.0 0.0; + to: "efl.event_area"; + } + rel2 { + relative: 1.0 1.0; + to: "efl.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: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 0 0 0 0; + } + } + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 64 64 64 255; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "efl.content"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + } + programs { + program { name: "active"; + signal: "efl,state,content,visible"; + source: "efl"; + action: STATE_SET "visible" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + program { name: "inactive"; + signal: "efl,state,content,hidden"; + source: "efl"; + action: STATE_SET "default" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + } +} + +group { name: "efl/panel/scrollable/top"; + parts { + part { name: "efl.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: "efl.event_area"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 0.0 1.0; + to: "efl.panel_area"; + } + rel2 { + relative: 1.0 1.0; + to: "efl.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: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 0 0 0 0; + } + } + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 64 64 64 255; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "efl.content"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + } + programs { + program { name: "active"; + signal: "efl,state,content,visible"; + source: "efl"; + action: STATE_SET "visible" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + program { name: "inactive"; + signal: "efl,state,content,hidden"; + source: "efl"; + action: STATE_SET "default" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + } +} + +group { name: "efl/panel/scrollable/bottom"; + parts { + part { name: "efl.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: "efl.panel_area"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 0.0 1.0; + to: "efl.event_area"; + } + rel2 { + relative: 1.0 1.0; + to: "efl.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: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 0 0 0 0; + } + } + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + color: 64 64 64 255; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "efl.content"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.to: "efl.panel_area"; + rel2.to: "efl.panel_area"; + visible: 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + } + programs { + program { name: "active"; + signal: "efl,state,content,visible"; + source: "efl"; + action: STATE_SET "visible" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + program { name: "inactive"; + signal: "efl,state,content,hidden"; + source: "efl"; + action: STATE_SET "default" 0.0; + target: "efl.panel_area"; + target: "efl.event_area"; + target: "bg"; + target: "efl.content"; + } + } +} + +group { name: "efl/panel/left"; + images.image: "bevel_out.png" COMP; + images.image: "shine.png" COMP; + images.image: "shadow_square_tiny.png" COMP; + images.image: "holes_tiny_glow_vert.png" COMP; + images.image: "holes_tiny_glow_horiz.png" COMP; + images.image: "win_glow.png" COMP; + images.image: "icon_arrow_right.png" COMP; + images.image: "icon_arrow_left.png" COMP; + images.image: "icon_arrow_up.png" COMP; + images.image: "icon_arrow_down.png" COMP; + data.item: "focus_highlight" "on"; + script { + public is_rtl = 0; + } + parts { + part { name: "shadow"; mouse_events: 0; + description { state: "default" 0.0; + rel1.offset: -3 -2; + rel1.to: "base"; + rel2.offset: 2 4; + rel2.to: "base"; + image.normal: "shadow_square_tiny.png"; + image.border: 6 6 6 6; + fill.smooth: 0; + } + } + part { name: "glow"; mouse_events: 0; + description { state: "default" 0.0; + image.normal: "win_glow.png"; + image.border: 9 9 9 9; + image.middle: 0; + rel1.offset: -5 -5; + rel1.to: "base"; + rel2.offset: 4 4; + rel2.to: "base"; + fill.smooth: 0; + color: 255 255 255 0; + visible: 0; + } + description { state: "focused" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + visible: 1; + } + } + part { name: "all"; type: SPACER; + description { state: "default" 0.0; + } + } + part { name: "base"; type: RECT; + description { state: "default" 0.0; + rel1.to_x: "all"; + rel2.to_x: "efl.swallow.event"; + rel2.relative: 0.0 1.0; + rel2.offset: -4 -1; + color: 64 64 64 255; + } + } + part { name: "efl.content"; type: SWALLOW; + description { state: "default" 0.0; + rel1.offset: 4 4; + rel1.to: "base"; + rel2.offset: -5 -5; + rel2.to: "base"; + } + } + part { name: "bevel"; mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "bevel_out.png"; + image.border: 1 1 1 1; + image.middle: 0; + fill.smooth: 0; + } + } + part { name: "shine"; mouse_events: 0; + description { state: "default" 0.0; + image.normal: "shine.png"; + rel1.offset: 0 -2; + rel1.to: "base"; + rel2.relative: 1.0 0.0; + rel2.offset: -1 2; + rel2.to: "base"; + FIXED_SIZE(69, 5) + } + } + part { name: "efl.swallow.event"; type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 1; + min: 20 20; + max: 20 20; + align: 1.0 0.5; + rel1.relative: 1.0 0.0; + rel2.relative: 1.0 1.0; + color: 0 0 0 0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + align: 0.0 0.5; + rel1.relative: 0.0 0.0; + rel2.relative: 0.0 1.0; + } + } + part { name: "btn"; type: RECT; + description { state: "default" 0.0; + rel1.to: "efl.swallow.event"; + rel2.to: "efl.swallow.event"; + color: 0 0 0 0; + } + description { state: "hidden" 0.0; + rel1.to: "efl.swallow.event"; + rel2.to: "efl.swallow.event"; + } + } + part { name: "dots"; mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "icn"; + rel2.to: "icn"; + align: 0.0 0.5; + image.normal: "holes_tiny_glow_vert.png"; + FIXED_SIZE(11, 17) + } + } + part { name: "icn"; mouse_events: 0; + scale: 1; + description { state: "default" 0.0; + fixed: 1 1; + min: 20 20; + max: 20 20; + rel1.to: "btn"; + rel2.to: "btn"; + image.normal: "icon_arrow_left.png"; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + image.normal: "icon_arrow_right.png"; + } + } + } + programs { + program { + signal: "mouse,clicked,1"; source: "btn"; + action: SIGNAL_EMIT "efl,action,panel,toggle" "efl"; + } + program { + signal: "efl,action,show"; source: "efl"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.3; + target: "efl.swallow.event"; + target: "base"; + } + program { + signal: "efl,action,show"; source: "efl"; + script { + if (get_int(is_rtl) == 0) + set_state(PART:"icn", "default", 0.0); + else + set_state(PART:"icn", "hidden", 0.0); + } + } + program { + signal: "edje,state,rtl"; + source: "edje"; + script { + new st[31]; + new Float:vl; + get_state(PART:"efl.swallow.event", st, 30, vl); + if (!strcmp(st, "default")) + set_state(PART:"icn", "hidden", 0.0); + else + set_state(PART:"icn", "default", 0.0); + set_int(is_rtl, 1); + } + } + program { + signal: "edje,state,ltr"; + source: "edje"; + script { + new st[31]; + new Float:vl; + get_state(PART:"efl.swallow.event", st, 30, vl); + if (!strcmp(st, "default")) + set_state(PART:"icn", "default", 0.0); + else + set_state(PART:"icn", "hidden", 0.0); + set_int(is_rtl, 0); + } + } + program { + signal: "efl,action,hide"; source: "efl"; + action: STATE_SET "hidden" 0.0; + transition: ACCELERATE 0.3; + target: "efl.swallow.event"; + } + program { + signal: "efl,action,hide"; source: "efl"; + script { + if (get_int(is_rtl) == 0) + set_state(PART:"icn", "hidden", 0.0); + else + set_state(PART:"icn", "default", 0.0); + } + } + program { name: "hide1"; + signal: "efl,action,hide"; source: "efl"; + script { + new x, y, w, h; + if (get_int(is_rtl) == 0) + { + custom_state(PART:"base", "default", 0.0); + set_state_val(PART:"base", STATE_REL1, -1.0, 0.0); + get_geometry(PART:"efl.swallow.event", x, y, w, h); + set_state_val(PART:"base", STATE_REL1_OFFSET, w, 0); + } + else + { + custom_state(PART:"base", "default", 0.0); + set_state_val(PART:"base", STATE_REL1, -1.0, 0.0); + set_state_val(PART:"base", STATE_REL2, -2.0, 1.0); + get_geometry(PART:"efl.swallow.event", x, y, w, h); + set_state_val(PART:"base", STATE_REL2_OFFSET, -w, 0); + } + } + after: "hide2"; + } + program { name: "hide2"; + action: STATE_SET "custom" 0.0; + transition: ACCELERATE 0.3; + target: "base"; + } + program { + signal: "efl,action,focus_highlight,show"; source: "efl"; + action: STATE_SET "focused" 0.0; + transition: ACCELERATE 0.2; + target: "glow"; + } + program { + signal: "efl,action,focus_highlight,hide"; source: "efl"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.5; + target: "glow"; + } + } +} + +group { name: "efl/panel/right"; + inherit: "efl/panel/left"; + parts { + part { name: "base"; + description { state: "default" 0.0; + rel1.relative: 1.0 0.0; + rel1.to_x: "efl.swallow.event"; + rel1.offset: 3 0; + rel2.relative: 1.0 1.0; + rel2.to_x: "all"; + rel2.offset: -1 -1; + } + } + part { name: "efl.swallow.event"; + description { state: "default" 0.0; + align: 0.0 0.5; + rel1.relative: 0.0 0.0; + rel2.relative: 0.0 1.0; + } + description { state: "hidden" 0.0; + align: 1.0 0.5; + rel1.relative: 1.0 0.0; + rel2.relative: 1.0 1.0; + } + } + part { name: "dots"; + description { state: "default" 0.0; + align: 1.0 0.5; + } + } + part { name: "icn"; + description { state: "default" 0.0; + image.normal: "icon_arrow_right.png"; + } + description { state: "hidden" 0.0; + image.normal: "icon_arrow_left.png"; + } + } + } + programs { + program { name: "hide1"; + script { + new x, y, w, h; + + custom_state(PART:"base", "default", 0.0); + set_state_val(PART:"base", STATE_REL1, 1.0, 0.0); + set_state_val(PART:"base", STATE_REL2, 2.0, 1.0); + get_geometry(PART:"efl.swallow.event", x, y, w, h); + set_state_val(PART:"base", STATE_REL2_OFFSET, -w, 0); + } + } + } +} + +group { name: "efl/panel/top"; + inherit: "efl/panel/left"; + parts { + part { name: "base"; + description { state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel1.to_x: "all"; + rel1.to_y: "all"; + rel1.offset: 0 0; + rel2.relative: 1.0 0.0; + rel2.to_x: "all"; + rel2.to_y: "efl.swallow.event"; + rel2.offset: -1 -4; + } + } + part { name: "efl.swallow.event"; + description { state: "default" 0.0; + align: 0.5 1.0; + rel1.relative: 0.0 1.0; + rel2.relative: 1.0 1.0; + } + description { state: "hidden" 0.0; + align: 0.5 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 0.0; + } + } + part { name: "dots"; + description { state: "default" 0.0; + align: 0.5 0.0; + image.normal: "holes_tiny_glow_horiz.png"; + FIXED_SIZE(17, 11) + } + } + part { name: "icn"; + description { state: "default" 0.0; + image.normal: "icon_arrow_up.png"; + } + description { state: "hidden" 0.0; + image.normal: "icon_arrow_down.png"; + } + } + } + programs { + program { name: "hide1"; + script { + new x, y, w, h; + + custom_state(PART:"base", "default", 0.0); + set_state_val(PART:"base", STATE_REL1, 0.0, -1.0); + set_state_val(PART:"base", STATE_REL2, 1.0, 0.0); + get_geometry(PART:"efl.swallow.event", x, y, w, h); + set_state_val(PART:"base", STATE_REL1_OFFSET, 0, h); + } + } + program { + signal: "efl,action,show"; source: "efl"; + action: STATE_SET "default" 0.0; + target: "icn"; + } + program { + signal: "edje,state,rtl"; + source: "edje"; + script { + new st[31]; + new Float:vl; + get_state(PART:"efl.swallow.event", st, 30, vl); + if (!strcmp(st, "default")) + set_state(PART:"icn", "default", 0.0); + else + set_state(PART:"icn", "hidden", 0.0); + } + } + program { + signal: "edje,state,ltr"; + source: "edje"; + script { + new st[31]; + new Float:vl; + get_state(PART:"efl.swallow.event", st, 30, vl); + if (!strcmp(st, "default")) + set_state(PART:"icn", "default", 0.0); + else + set_state(PART:"icn", "hidden", 0.0); + } + } + program { + signal: "efl,action,hide"; source: "efl"; + action: STATE_SET "hidden" 0.0; + target: "icn"; + } + } +} + +group { name: "efl/panel/bottom"; + inherit: "efl/panel/top"; + parts { + part { name: "base"; + description { state: "default" 0.0; + rel1.relative: 0.0 1.0; + rel1.to_x: "all"; + rel1.to_y: "efl.swallow.event"; + rel1.offset: 0 3; + rel2.relative: 1.0 1.0; + rel2.to_x: "all"; + rel2.to_y: "all"; + rel2.offset: -1 -1; + } + } + part { name: "efl.swallow.event"; + description { state: "default" 0.0; + align: 0.5 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 0.0; + } + description { state: "hidden" 0.0; + align: 0.5 1.0; + rel1.relative: 0.0 1.0; + rel2.relative: 1.0 1.0; + } + } + part { name: "dots"; + description { state: "default" 0.0; + align: 0.5 0.0; + image.normal: "holes_tiny_glow_horiz.png"; + FIXED_SIZE(17, 11) + } + } + part { name: "icn"; + description { state: "default" 0.0; + image.normal: "icon_arrow_down.png"; + } + description { state: "hidden" 0.0; + image.normal: "icon_arrow_up.png"; + } + } + } + programs { + program { name: "hide1"; + script { + new x, y, w, h; + custom_state(PART:"base", "default", 0.0); + set_state_val(PART:"base", STATE_REL1, 0.0, 1.0); + set_state_val(PART:"base", STATE_REL2, 1.0, 2.0); + get_geometry(PART:"efl.swallow.event", x, y, w, h); + set_state_val(PART:"base", STATE_REL2_OFFSET, 0, -h); + } + } + } +} diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index 0c75466680..af5d06abfe 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -29,6 +29,7 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_datepicker.eo \ lib/elementary/efl_ui_timepicker.eo \ lib/elementary/efl_ui_tags.eo \ + lib/elementary/efl_ui_panel.eo \ lib/elementary/efl_ui_video.eo \ lib/elementary/efl_ui_win.eo \ lib/elementary/efl_ui_win_inlined.eo \ @@ -414,6 +415,7 @@ includesunstable_HEADERS = \ lib/elementary/efl_ui_datepicker_private.h \ lib/elementary/efl_ui_timepicker_private.h \ lib/elementary/efl_ui_tags_private.h \ + lib/elementary/efl_ui_panel_private.h \ lib/elementary/elm_widget_table.h \ lib/elementary/elm_widget_thumb.h \ lib/elementary/elm_widget_toolbar.h \ @@ -787,6 +789,7 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/efl_ui_datepicker.c \ lib/elementary/efl_ui_timepicker.c \ lib/elementary/efl_ui_tags.c \ + lib/elementary/efl_ui_panel.c \ lib/elementary/elm_slideshow.c \ lib/elementary/elm_spinner.c \ lib/elementary/elm_store.c \ @@ -1064,6 +1067,7 @@ bin/elementary/test_ui_spin_button.c \ bin/elementary/test_ui_datepicker.c \ bin/elementary/test_ui_timepicker.c \ bin/elementary/test_ui_tags.c \ +bin/elementary/test_ui_panel.c \ bin/elementary/test_slideshow.c \ bin/elementary/test_spinner.c \ bin/elementary/test_store.c \ diff --git a/src/bin/elementary/Makefile.am b/src/bin/elementary/Makefile.am index 8828276e26..290ea0e110 100644 --- a/src/bin/elementary/Makefile.am +++ b/src/bin/elementary/Makefile.am @@ -136,6 +136,7 @@ test_ui_buttonspin.c \ test_ui_datepicker.c \ test_ui_timepicker.c \ test_ui_tags.c \ +test_ui_panel.c \ test_store.c \ test_sys_notify.c \ test_systray.c \ diff --git a/src/bin/elementary/meson.build b/src/bin/elementary/meson.build index ddc778ba2c..f8ca71e9c8 100644 --- a/src/bin/elementary/meson.build +++ b/src/bin/elementary/meson.build @@ -98,6 +98,7 @@ elementary_test_src = [ 'test_panel.c', 'test_panes.c', 'test_ui_panes.c', + 'test_ui_panel.c', 'test_part_bg.c', 'test_part_shadow.c', 'test_photo.c', diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index 9298e9b2e2..de66b96582 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -189,6 +189,8 @@ void test_ui_spin_button(void *data, Evas_Object *obj, void *event_info); void test_ui_datepicker(void *data, Evas_Object *obj, void *event_info); void test_ui_timepicker(void *data, Evas_Object *obj, void *event_info); void test_ui_tags(void *data, Evas_Object *obj, void *event_info); +void test_ui_panel(void *data, Evas_Object *obj, void *event_info); +void test_ui_panel2(void *data, Evas_Object *obj, void *event_info); void test_index(void *data, Evas_Object *obj, void *event_info); void test_index2(void *data, Evas_Object *obj, void *event_info); void test_index3(void *data, Evas_Object *obj, void *event_info); @@ -1165,6 +1167,8 @@ add_tests: ADD_TEST(NULL, "Dividers", "Panel Scrollable", test_panel2); ADD_TEST(NULL, "Dividers", "Panes", test_panes); ADD_TEST_EO(NULL, "Dividers", "Efl.Ui.Panes", test_panes_minsize); + ADD_TEST_EO(NULL, "Dividers", "Efl.Ui.Panel", test_ui_panel); + ADD_TEST_EO(NULL, "Dividers", "Efl.Ui.Panel Scrollable", test_ui_panel2); //------------------------------// ADD_TEST(NULL, "Standardization", "Conformant", test_conformant); diff --git a/src/bin/elementary/test_ui_panel.c b/src/bin/elementary/test_ui_panel.c new file mode 100644 index 0000000000..eed8d14759 --- /dev/null +++ b/src/bin/elementary/test_ui_panel.c @@ -0,0 +1,159 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include + +void +test_ui_panel(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + char buf[PATH_MAX] = {0}; + Eo *win, *table, *panel; + + win = efl_add_ref(EFL_UI_WIN_CLASS, NULL, + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Panel"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + table = efl_add(EFL_UI_TABLE_CLASS, win, + efl_content_set(win, efl_added)); + + snprintf(buf, sizeof(buf), "%s/images/plant_01.jpg", elm_app_data_dir_get()); + efl_add(EFL_UI_IMAGE_CLASS, table, + efl_file_set(efl_added, buf, NULL), + efl_gfx_size_hint_weight_set(efl_added, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND), + efl_gfx_size_hint_align_set(efl_added, EVAS_HINT_FILL, EVAS_HINT_FILL), + efl_pack_table(table, efl_added, 0, 0, 4, 5)); + + // Top Panel + panel = efl_add(EFL_UI_PANEL_CLASS, table, + efl_ui_panel_orient_set(efl_added, EFL_UI_PANEL_ORIENT_TOP), + efl_pack_table(table, efl_added, 0, 0, 4, 1)); + + efl_add(EFL_UI_BUTTON_CLASS, panel, + efl_text_set(efl_added, "Top Panel"), + efl_content_set(panel, efl_added)); + + // Left Panel + panel = efl_add(EFL_UI_PANEL_CLASS, table, + efl_ui_panel_orient_set(efl_added, EFL_UI_PANEL_ORIENT_LEFT), + efl_pack_table(table, efl_added, 0, 2, 2, 1)); + + efl_add(EFL_UI_BUTTON_CLASS, panel, + efl_text_set(efl_added, "Left Panel"), + efl_content_set(panel, efl_added)); + + // Right Panel + panel = efl_add(EFL_UI_PANEL_CLASS, table, + efl_ui_panel_orient_set(efl_added, EFL_UI_PANEL_ORIENT_RIGHT), + efl_pack_table(table, efl_added, 2, 2, 2, 1)); + + efl_add(EFL_UI_BUTTON_CLASS, panel, + efl_text_set(efl_added, "Right Panel"), + efl_content_set(panel, efl_added)); + + // Bottom Panel + panel = efl_add(EFL_UI_PANEL_CLASS, table, + efl_ui_panel_orient_set(efl_added, EFL_UI_PANEL_ORIENT_BOTTOM), + efl_pack_table(table, efl_added, 0, 4, 4, 1)); + + efl_add(EFL_UI_BUTTON_CLASS, panel, + efl_text_set(efl_added, "Bottom Panel"), + efl_content_set(panel, efl_added)); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(280, 320)); +} + +static void +_check_changed(void *data EINA_UNUSED, const Efl_Event *ev) +{ + elm_config_scroll_thumbscroll_enabled_set(efl_ui_nstate_value_get(ev->object)); +} + +static void +_panel_toggled(void *data, const Efl_Event *ev) +{ + Evas_Object *list; + int i; + + if (!efl_ui_nstate_value_get(data)) return; + + list = efl_content_get(ev->object); + evas_object_del(list); + + list = elm_list_add(ev->object); + 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); + efl_content_set(ev->object, list); + + printf("Panel toggled:%s\n", efl_ui_panel_hidden_get(ev->object) ? "hidden" : "visible"); +} + +static void +_btn_clicked(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Eo *panel = data; + efl_ui_panel_toggle(panel); +} +void +test_ui_panel2(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + int i; + Eo *win, *box, *check, *btn, *table, *list, *panel; + + win = efl_add_ref(EFL_UI_WIN_CLASS, NULL, + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Panel"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + box = efl_add(EFL_UI_BOX_CLASS, win, + efl_content_set(win, efl_added)); + + efl_add(EFL_UI_CHECK_CLASS, box, + efl_ui_check_selected_set(efl_added, elm_config_scroll_thumbscroll_enabled_get()), + efl_text_set(efl_added, "Enable thumb scroll (temporarily"), + efl_event_callback_add(efl_added, EFL_UI_NSTATE_EVENT_CHANGED, _check_changed, NULL), + efl_gfx_size_hint_weight_set(efl_added, EVAS_HINT_EXPAND, 0), + efl_pack(box, efl_added)); + + check = efl_add(EFL_UI_CHECK_CLASS, box, + efl_text_set(efl_added, "Reset content on toggle"), + efl_gfx_size_hint_weight_set(efl_added, EVAS_HINT_EXPAND, 0), + efl_pack(box, efl_added)); + + btn = efl_add(EFL_UI_BUTTON_CLASS, box, + efl_text_set(efl_added, "toggle"), + efl_gfx_size_hint_weight_set(efl_added, EVAS_HINT_EXPAND, 0), + efl_pack(box, efl_added)); + + table = efl_add(EFL_UI_TABLE_CLASS, box, + efl_pack(box, efl_added)); + + 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); + efl_pack_table(table, list, 0, 0, 1, 1); + + panel = efl_add(EFL_UI_PANEL_CLASS, table, + efl_ui_panel_orient_set(efl_added, EFL_UI_PANEL_ORIENT_LEFT), + efl_ui_panel_scrollable_set(efl_added, EINA_TRUE), + efl_ui_panel_hidden_set(efl_added, EINA_TRUE), + efl_ui_panel_scrollable_content_size_set(efl_added, 0.75), + efl_pack_table(table, efl_added, 0, 0, 1, 1)); + + 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, "left panel item", NULL, NULL, NULL, NULL); + efl_content_set(panel, list); + + efl_event_callback_add(panel, EFL_UI_PANEL_EVENT_TOGGLED, _panel_toggled, check); + efl_event_callback_add(btn, EFL_UI_EVENT_CLICKED, _btn_clicked, panel); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(320, 400)); +} diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 9bd33c4feb..99798e77cd 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -323,6 +323,7 @@ typedef Eo Efl_Ui_Focus_Manager; # include # include # include +# include # include # include # include diff --git a/src/lib/elementary/efl_ui_panel.c b/src/lib/elementary/efl_ui_panel.c new file mode 100644 index 0000000000..06d33235a5 --- /dev/null +++ b/src/lib/elementary/efl_ui_panel.c @@ -0,0 +1,1386 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#define EFL_ACCESS_OBJECT_PROTECTED +#define EFL_ACCESS_WIDGET_ACTION_PROTECTED +#define EFL_UI_FOCUS_LAYER_PROTECTED +#define EFL_PART_PROTECTED + +#include + +#include "elm_priv.h" +#include "efl_ui_panel_private.h" + +#include "els_box.h" + +#include "elm_part_helper.h" + +#define MY_CLASS EFL_UI_PANEL_CLASS + +#define MY_CLASS_NAME "Efl.Ui.Panel" + +static const char ACCESS_OUTLINE_PART[] = "access.outline"; +static const char SIG_TOGGLED[] = "toggled"; +static const char SIG_SCROLL[] = "scroll"; + +static const Evas_Smart_Cb_Description _smart_callbacks[] = { + {SIG_TOGGLED, ""}, + {SIG_SCROLL, ""}, + {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */ + {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */ + {NULL, NULL} +}; +static void _panel_toggle(void *, Evas_Object *, const char *,const char *); +static Eina_Bool _key_action_toggle(Evas_Object *obj, const char *params); +static void _drawer_open(Evas_Object *, Evas_Coord , Evas_Coord , Eina_Bool ); +static void _drawer_close(Evas_Object *, Evas_Coord , Evas_Coord , Eina_Bool); + +static const Elm_Action key_actions[] = { + {"toggle", _key_action_toggle}, + {NULL, NULL} +}; + +static void +_mirrored_set(Evas_Object *obj, + Eina_Bool rtl) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + + if ((sd->content) && (efl_isa(sd->content, EFL_UI_WIDGET_CLASS))) + efl_ui_mirrored_set(sd->content, rtl); + efl_ui_panel_orient_set(obj, efl_ui_panel_orient_get(obj)); +} + +EOLIAN static void +_efl_ui_panel_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Panel_Data *sd) +{ + Evas_Coord mw = 0, mh = 0; + + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + if (sd->delete_me) return; + + if (sd->scrollable) + { + if (sd->hidden) _drawer_close(obj, wd->w, wd->h, EINA_FALSE); + else _drawer_open(obj, wd->w, wd->h, EINA_FALSE); + } + + evas_object_smart_calculate(sd->bx); + edje_object_size_min_calc(wd->resize_obj, &mw, &mh); + evas_object_size_hint_min_set(obj, mw, mh); + evas_object_size_hint_max_set(obj, -1, -1); +} + +static char * +_access_state_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + EFL_UI_PANEL_DATA_GET(data, sd); + + if (!sd->hidden) return strdup(E_("state: opened")); + else return strdup(E_("state: closed")); + + return NULL; +} + +static Evas_Object * +_access_object_get(const Evas_Object *obj, const char *part) +{ + Evas_Object *po, *ao, *o; + EFL_UI_PANEL_DATA_GET(obj, sd); + + o = elm_layout_edje_get(sd->scr_ly); + edje_object_freeze(o); + po = (Evas_Object *)edje_object_part_object_get(o, part); + edje_object_thaw(o); + 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) +{ + efl_ui_panel_hidden_set(data, EINA_TRUE); +} + +static void +_access_obj_process(Evas_Object *obj, Eina_Bool is_access) +{ + Evas_Object *ao; + EFL_UI_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 panel is open")); + _elm_access_text_set(_elm_access_info_get(ao), + ELM_ACCESS_CONTEXT_INFO, E_("Double tap to close panel 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) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + elm_widget_theme_element_set(obj, "top"); + break; + case EFL_UI_PANEL_ORIENT_BOTTOM: + elm_widget_theme_element_set(obj, "bottom"); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + elm_widget_theme_element_set(obj, "left"); + break; + case EFL_UI_PANEL_ORIENT_RIGHT: + elm_widget_theme_element_set(obj, "right"); + break; + } + + efl_ui_widget_theme_apply(obj); + + /* access */ + if (_elm_config->access_mode == ELM_ACCESS_MODE_ON) + { + Evas_Object *ao; + ao = _elm_access_edje_object_part_object_register + (obj, wd->resize_obj, "btn_icon"); + _elm_access_text_set(_elm_access_info_get(ao), + ELM_ACCESS_TYPE, E_("panel button")); + _elm_access_callback_set + (_elm_access_info_get(ao), ELM_ACCESS_STATE, _access_state_cb, obj); + } +} + +static void +_scrollable_layout_theme_set(Eo *obj, Efl_Ui_Panel_Data *sd) +{ + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + elm_widget_theme_element_set(sd->scr_ly, "scrollable/top"); + break; + case EFL_UI_PANEL_ORIENT_BOTTOM: + elm_widget_theme_element_set(sd->scr_ly, "scrollable/bottom"); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + elm_widget_theme_element_set(sd->scr_ly, "scrollable/left"); + break; + case EFL_UI_PANEL_ORIENT_RIGHT: + elm_widget_theme_element_set(sd->scr_ly, "scrollable/right"); + break; + } + + efl_ui_widget_theme_apply(sd->scr_ly); + + /* access */ + if (_elm_config->access_mode == ELM_ACCESS_MODE_ON) + _access_obj_process(obj, EINA_TRUE); +} + +EOLIAN static Efl_Ui_Theme_Apply_Result +_efl_ui_panel_efl_ui_widget_theme_apply(Eo *obj, Efl_Ui_Panel_Data *sd) +{ + const char *str; + Evas_Coord minw = 0, minh = 0; + + Efl_Ui_Theme_Apply_Result int_ret = EFL_UI_THEME_APPLY_RESULT_FAIL; + + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_RESULT_FAIL); + + int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS)); + if (!int_ret) return EFL_UI_THEME_APPLY_RESULT_FAIL; + + _mirrored_set(obj, efl_ui_mirrored_get(obj)); + + if (sd->scrollable) + { + const char *handler_size; + elm_widget_theme_object_set(obj, sd->scr_edje, "panel", NULL, + elm_widget_style_get(obj)); + 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 + { + 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); + + 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, "efl.swallow.event")) + efl_content_set(efl_part(efl_super(obj, MY_CLASS), "efl.swallow.event"), sd->event); + } + + if (efl_finalized_get(obj)) + elm_layout_sizing_eval(obj); + + return int_ret; +} + +static void +_box_layout_cb(Evas_Object *o, + Evas_Object_Box_Data *_pd, + void *data EINA_UNUSED) +{ + _els_box_layout(o, _pd, EINA_TRUE, EINA_FALSE, EINA_FALSE); +} + +static void +_handler_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + + if (sd->handler_size == 0) return; + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + elm_interface_scrollable_region_bring_in + (obj, 0, (h * sd->content_size_ratio) - sd->handler_size, w, h); + break; + case EFL_UI_PANEL_ORIENT_BOTTOM: + elm_interface_scrollable_region_bring_in + (obj, 0, sd->handler_size, w, h); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + elm_interface_scrollable_region_bring_in + (obj, (w * sd->content_size_ratio) - sd->handler_size, 0, w, h); + break; + case EFL_UI_PANEL_ORIENT_RIGHT: + elm_interface_scrollable_region_bring_in + (obj, sd->handler_size, 0, w, h); + break; + } +} + +static void +_drawer_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + int x = 0, y = 0; + + if (sd->freeze) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + break; + case EFL_UI_PANEL_ORIENT_LEFT: + if (efl_ui_mirrored_get(obj)) + x = w * sd->content_size_ratio; + break; + + case EFL_UI_PANEL_ORIENT_BOTTOM: + y = h * sd->content_size_ratio; + break; + + case EFL_UI_PANEL_ORIENT_RIGHT: + if (!efl_ui_mirrored_get(obj)) + x = w * sd->content_size_ratio; + break; + } + + if (anim) + elm_interface_scrollable_region_bring_in + (obj, x, y, w, h); + else + elm_interface_scrollable_content_region_show + (obj, x, y, w, h); +} + +static void +_drawer_close(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + int x = 0, y = 0, cx, cy; + Eina_Bool horizontal = EINA_FALSE; + + elm_widget_tree_unfocusable_set(obj, EINA_TRUE); + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + y = h * sd->content_size_ratio; + break; + + case EFL_UI_PANEL_ORIENT_LEFT: + if (!efl_ui_mirrored_get(obj)) + x = w * sd->content_size_ratio; + horizontal = EINA_TRUE; + break; + + case EFL_UI_PANEL_ORIENT_BOTTOM: + break; + + case EFL_UI_PANEL_ORIENT_RIGHT: + if (efl_ui_mirrored_get(obj)) + x = w * sd->content_size_ratio; + horizontal = EINA_TRUE; + break; + } + + elm_interface_scrollable_content_pos_get(obj, &cx, &cy); + + if ((x == cx) && (y == cy)) + { + if (!sd->freeze) + { + if (horizontal) + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_HORIZONTAL); + else + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_VERTICAL); + sd->freeze = EINA_TRUE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,hidden", "efl"); + } + + return; + } + + if (anim) + { + if (sd->freeze) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + elm_interface_scrollable_region_bring_in(obj, x, y, w, h); + } + else + { + elm_interface_scrollable_content_region_show(obj, x, y, w, h); + if (!sd->freeze) + { + if (horizontal) + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_HORIZONTAL); + else + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_VERTICAL); + sd->freeze = EINA_TRUE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,hidden", "efl"); + } + } +} + +static void +_panel_toggle(void *data EINA_UNUSED, + Evas_Object *obj, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + int w, h; + + if (sd->scrollable) + { + 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 + { + if (sd->hidden) + { + elm_layout_signal_emit(obj, "efl,action,show", "efl"); + sd->hidden = EINA_FALSE; + evas_object_repeat_events_set(obj, EINA_FALSE); + } + else + { + elm_layout_signal_emit(obj, "efl,action,hide", "efl"); + sd->hidden = EINA_TRUE; + evas_object_repeat_events_set(obj, EINA_TRUE); + } + + //if the panel is hidden, make this thing unfocusable + elm_widget_tree_unfocusable_set(obj, sd->hidden); + edje_object_message_signal_process(wd->resize_obj); + } + + efl_ui_focus_layer_enable_set(obj, !sd->hidden); + efl_event_callback_call(obj, EFL_UI_PANEL_EVENT_TOGGLED, NULL); +} + +static Eina_Bool +_state_sync(Evas_Object *obj) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + Evas_Coord pos, panel_size, w, h, threshold; + Eina_Bool horizontal = EINA_FALSE, reverse = EINA_FALSE; + + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + + if (!evas_object_visible_get(sd->bx)) return EINA_TRUE; + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_BOTTOM: + reverse = EINA_TRUE; + case EFL_UI_PANEL_ORIENT_TOP: + break; + + case EFL_UI_PANEL_ORIENT_RIGHT: + reverse = EINA_TRUE; + EINA_FALLTHROUGH; + case EFL_UI_PANEL_ORIENT_LEFT: + horizontal = EINA_TRUE; + break; + } + + if (horizontal) + { + if (w <= 0) return EINA_TRUE; + + panel_size = w * sd->content_size_ratio; + elm_interface_scrollable_content_pos_get(obj, &pos, NULL); + reverse ^= efl_ui_mirrored_get(obj); + } + else + { + if (h <= 0) return EINA_TRUE; + + panel_size = h * sd->content_size_ratio; + elm_interface_scrollable_content_pos_get(obj, NULL, &pos); + } + threshold = (sd->hidden) ? panel_size - (panel_size / 4) : (panel_size / 4); + + if (reverse) + { + if (pos > panel_size - threshold) sd->hidden = EINA_FALSE; + else sd->hidden = EINA_TRUE; + } + else + { + if (pos < threshold) sd->hidden = EINA_FALSE; + else sd->hidden = EINA_TRUE; + } + + return EINA_FALSE; +} + +static Eina_Bool +_timer_cb(void *data) +{ + EFL_UI_PANEL_DATA_GET(data, sd); + Evas_Object *obj = data; + Evas_Coord w, h; + + sd->timer = NULL; + + if (sd->freeze) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + 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) +{ + EFL_UI_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->canvas.x - x; + up_y = ev->canvas.y - y; + + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + + if ((!sd->hidden) && (up_x == sd->down_x) && (up_y == sd->down_y)) + efl_ui_panel_hidden_set(data, EINA_TRUE); +} + +static void +_on_mouse_down(void *data, + Evas *e EINA_UNUSED, + Evas_Object *obj, + void *event_info) +{ + Efl_Ui_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); + Eina_Bool is_mirrored = efl_ui_mirrored_get(obj); + + sd->down_x = ev->canvas.x - x; + sd->down_y = ev->canvas.y - y; + + // if freeze state & mouse down on the edge + // then set timer for un-freeze + switch (sd->orient) + { + case EFL_UI_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 EFL_UI_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 EFL_UI_PANEL_ORIENT_LEFT: + if ((!is_mirrored && (sd->freeze) && (sd->down_x >= 0) && (sd->down_x < finger_size)) || + ((is_mirrored && (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; + case EFL_UI_PANEL_ORIENT_RIGHT: + if ((is_mirrored && (sd->freeze) && (sd->down_x >= 0) && (sd->down_x < finger_size)) || + (!is_mirrored && (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) +{ + Efl_Ui_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(); + Eina_Bool is_mirrored = efl_ui_mirrored_get(obj); + + 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 EFL_UI_PANEL_ORIENT_TOP: + if (sd->timer && ((cur_y - sd->down_y) > finger_size)) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + break; + case EFL_UI_PANEL_ORIENT_BOTTOM: + if (sd->timer && ((sd->down_y - cur_y) > finger_size)) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + break; + case EFL_UI_PANEL_ORIENT_LEFT: + if ((!is_mirrored && (sd->timer) && ((cur_x - sd->down_x) > finger_size)) || + ((is_mirrored) && (sd->timer) && ((sd->down_x - cur_x) > finger_size))) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + break; + case EFL_UI_PANEL_ORIENT_RIGHT: + if ((is_mirrored && (sd->timer) && ((cur_x - sd->down_x) > finger_size)) || + (!is_mirrored && (sd->timer) && ((sd->down_x - cur_x) > finger_size))) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + 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) +{ + Efl_Ui_Panel_Data *sd = data; + Evas_Event_Mouse_Up *ev = event_info; + Evas_Coord w, h; + Eina_Bool hidden; + + hidden = sd->hidden; + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + + ELM_SAFE_FREE(sd->timer, ecore_timer_del); + + if (_state_sync(obj)) return; + + if (sd->hidden) _drawer_close(obj, w, h, EINA_TRUE); + else _drawer_open(obj, w, h, EINA_TRUE); + + if (sd->hidden != hidden) + efl_event_callback_legacy_call(obj, EFL_UI_PANEL_EVENT_TOGGLED, NULL); + + if (!sd->freeze && sd->hidden) + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; +} + +static Eina_Bool +_key_action_toggle(Evas_Object *obj, const char *params EINA_UNUSED) +{ + _panel_toggle(NULL, obj, NULL, NULL); + return EINA_TRUE; +} + +// _panel_elm_widget_widget_event +ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(panel, Efl_Ui_Panel_Data) + +EOLIAN static Eina_Bool +_efl_ui_panel_efl_ui_widget_widget_event(Eo *obj, Efl_Ui_Panel_Data *pd, const Efl_Event *eo_event, Evas_Object *src) +{ + if (src != obj) return EINA_FALSE; + return _panel_efl_ui_widget_widget_event(obj, pd, eo_event, src); +} + +static Eina_Bool +_efl_ui_panel_efl_content_content_set(Eo *obj, Efl_Ui_Panel_Data *sd, Efl_Gfx_Entity *content) +{ + if (sd->content == content) return EINA_TRUE; + if (sd->content) + evas_object_box_remove_all(sd->bx, EINA_TRUE); + sd->content = content; + if (content) + { + evas_object_box_append(sd->bx, sd->content); + evas_object_show(sd->content); + if (sd->scrollable) + elm_widget_sub_object_add(sd->scr_ly, sd->content); + else + elm_widget_sub_object_add(obj, sd->content); + } + + if (efl_finalized_get(obj)) + elm_layout_sizing_eval(obj); + + return EINA_TRUE; +} + +static Efl_Gfx_Entity* +_efl_ui_panel_efl_content_content_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + return sd->content; +} + +static Efl_Gfx_Entity* +_efl_ui_panel_efl_content_content_unset(Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + Efl_Gfx_Entity *ret = NULL; + + if (!sd->content) return NULL; + ret = sd->content; + + evas_object_box_remove_all(sd->bx, EINA_FALSE); + if (sd->scrollable) + _elm_widget_sub_object_redirect_to_top(sd->scr_ly, sd->content); + sd->content = NULL; + + return ret; +} + +EOLIAN static void +_efl_ui_panel_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Position2D pos) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y)) + return; + + efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos); + efl_gfx_entity_position_set(sd->hit_rect, pos); +} + +static void +_scrollable_layout_resize(Eo *obj, Efl_Ui_Panel_Data *sd, Evas_Coord w, Evas_Coord h) +{ + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + case EFL_UI_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 EFL_UI_PANEL_ORIENT_LEFT: + case EFL_UI_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 (efl_finalized_get(obj)) + elm_layout_sizing_eval(obj); +} + +EOLIAN static void +_efl_ui_panel_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Size2D sz) +{ + if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h)) + return; + + efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz); + + if (!sd->scrollable) return; + + efl_gfx_entity_size_set(sd->hit_rect, sz); + _scrollable_layout_resize(obj, sd, sz.w, sz.h); +} + +EOLIAN static void +_efl_ui_panel_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Panel_Data *sd, Evas_Object *member) +{ + efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member); + + if (sd->hit_rect) evas_object_raise(sd->hit_rect); +} + +EOLIAN static void +_efl_ui_panel_efl_ui_widget_on_access_update(Eo *obj, Efl_Ui_Panel_Data *_pd, Eina_Bool is_access) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + Efl_Ui_Panel_Data *sd = _pd; + + if (sd->scrollable) + { + _access_obj_process(obj, is_access); + return; + } + + if (is_access) + _elm_access_edje_object_part_object_register + (obj, wd->resize_obj, "btn_icon"); + else + _elm_access_edje_object_part_object_unregister + (obj, wd->resize_obj, "btn_icon"); +} + +EOLIAN static Eo * +_efl_ui_panel_efl_object_constructor(Eo *obj, Efl_Ui_Panel_Data *_pd) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); + + obj = efl_constructor(efl_super(obj, MY_CLASS)); + elm_widget_sub_object_parent_add(obj); + elm_widget_can_focus_set(obj, EINA_TRUE); + + _pd->panel_edje = wd->resize_obj; + + efl_ui_widget_theme_apply(obj); + + _pd->bx = evas_object_box_add(evas_object_evas_get(obj)); + evas_object_box_layout_set(_pd->bx, _box_layout_cb, _pd, NULL); + evas_object_show(_pd->bx); + + elm_layout_signal_callback_add + (obj, "efl,action,panel,toggle", "*", _panel_toggle, obj); + + _mirrored_set(obj, efl_ui_mirrored_get(obj)); + + _pd->event = evas_object_rectangle_add(evas_object_evas_get(obj)); + evas_object_color_set(_pd->event, 0, 0, 0, 0); + evas_object_pass_events_set(_pd->event, EINA_TRUE); + elm_widget_sub_object_add(obj, _pd->event); + + /* just to bootstrap and have theme hook to work */ + if (!elm_layout_theme_set(obj, "panel", "top", elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + else + { + elm_layout_content_set(obj, "efl.content", _pd->bx); + + if (edje_object_part_exists + (wd->resize_obj, "efl.swallow.event")) + { + Evas_Coord minw = 0, minh = 0; + + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + evas_object_size_hint_min_set(_pd->event, minw, minh); + efl_content_set(efl_part(efl_super(obj, MY_CLASS), "efl.swallow.event"), _pd->event); + } + } + + evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks); + efl_access_object_role_set(obj, EFL_ACCESS_ROLE_PANEL); + + efl_ui_focus_layer_behaviour_set(obj, EINA_FALSE, EINA_FALSE); + + return obj; +} + +EOLIAN static void +_efl_ui_panel_efl_object_destructor(Eo *obj, Efl_Ui_Panel_Data *sd) +{ + Evas_Object *child; + Eina_List *l; + + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + sd->delete_me = EINA_TRUE; + + ELM_SAFE_FREE(sd->timer, ecore_timer_del); + + /* let's make our panel object the *last* to be processed, since it + * may (smart) parent other sub objects here */ + EINA_LIST_FOREACH(wd->subobjs, l, child) + { + if (child == sd->bx) + { + wd->subobjs = + eina_list_demote_list(wd->subobjs, l); + break; + } + } + + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_panel_orient_set(Eo *obj, Efl_Ui_Panel_Data *sd, Efl_Ui_Panel_Orient orient) +{ + if (sd->orient == orient) return; + sd->orient = orient; + + if (sd->scrollable) + { + _scrollable_layout_theme_set(obj, sd); + + if (!sd->freeze) + { + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + case EFL_UI_PANEL_ORIENT_BOTTOM: + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_VERTICAL); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + case EFL_UI_PANEL_ORIENT_RIGHT: + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_HORIZONTAL); + break; + } + + sd->freeze = EINA_TRUE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,hidden", "efl"); + } + + efl_ui_panel_scrollable_content_size_set(obj, sd->content_size_ratio); + } + else + _orient_set_do(obj); + + if (efl_finalized_get(obj)) + elm_layout_sizing_eval(obj); +} + +EOLIAN static Efl_Ui_Panel_Orient +_efl_ui_panel_orient_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + return sd->orient; +} + +EOLIAN static void +_efl_ui_panel_hidden_set(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Bool hidden) +{ + 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); +} + +EOLIAN static Eina_Bool +_efl_ui_panel_hidden_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + return sd->hidden; +} + +EOLIAN static void +_efl_ui_panel_toggle(Eo *obj, Efl_Ui_Panel_Data *_pd EINA_UNUSED) +{ + _panel_toggle(NULL, obj, NULL, NULL); +} + +EOLIAN static Eina_Rect +_efl_ui_panel_efl_ui_widget_interest_region_get(const Eo *obj, Efl_Ui_Panel_Data *sd) +{ + Eina_Rect r = {}; + + elm_interface_scrollable_content_pos_get(obj, &r.x, &r.y); + evas_object_geometry_get(obj, NULL, NULL, &r.w, &r.h); + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + case EFL_UI_PANEL_ORIENT_BOTTOM: + r.h *= sd->content_size_ratio; + break; + case EFL_UI_PANEL_ORIENT_LEFT: + case EFL_UI_PANEL_ORIENT_RIGHT: + r.w *= sd->content_size_ratio; + break; + } + if (r.w < 1) r.w = 1; + if (r.h < 1) r.h = 1; + + return r; +} + +static void +_anim_stop_cb(Evas_Object *obj, void *data EINA_UNUSED) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + Evas_Object *ao; + Evas_Coord pos, w, h, panel_size = 0; + Eina_Bool open = EINA_FALSE, horizontal = EINA_FALSE, reverse = EINA_FALSE; + + if (elm_widget_disabled_get(obj)) return; + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_BOTTOM: + reverse = EINA_TRUE; + case EFL_UI_PANEL_ORIENT_TOP: + break; + + case EFL_UI_PANEL_ORIENT_RIGHT: + reverse = EINA_TRUE; + EINA_FALLTHROUGH; + case EFL_UI_PANEL_ORIENT_LEFT: + horizontal = EINA_TRUE; + break; + } + + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + if (horizontal) + { + if (w <= 0) return; + + panel_size = w * sd->content_size_ratio; + elm_interface_scrollable_content_pos_get(obj, &pos, NULL); + reverse ^= efl_ui_mirrored_get(obj); + } + else + { + if (h <= 0) return; + + panel_size = h * sd->content_size_ratio; + elm_interface_scrollable_content_pos_get(obj, NULL, &pos); + } + + if (pos == 0) open = !reverse; + else if (pos == panel_size) open = reverse; + else return; + + if (open) + { + elm_interface_scrollable_single_direction_set + (obj, 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 (horizontal) + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_HORIZONTAL); + else + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_VERTICAL); + sd->freeze = EINA_TRUE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,hidden", "efl"); + + elm_interface_scrollable_single_direction_set + (obj, 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); + } + } +} + +static void +_scroll_cb(Evas_Object *obj, void *data EINA_UNUSED) +{ + EFL_UI_PANEL_DATA_GET(obj, sd); + Efl_Ui_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) + { + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_NONE); + sd->freeze = EINA_FALSE; + elm_layout_signal_emit(sd->scr_ly, "efl,state,content,visible", "efl"); + } + + elm_interface_scrollable_content_pos_get(obj, &x, &y); + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + event.rel_x = 1; + event.rel_y = 1 - ((double) y / (double) ((sd->content_size_ratio) * h)); + break; + case EFL_UI_PANEL_ORIENT_BOTTOM: + event.rel_x = 1; + event.rel_y = (double) y / (double) ((sd->content_size_ratio) * h); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + if (!efl_ui_mirrored_get(obj)) + { + event.rel_x = 1 - ((double) x / (double) ((sd->content_size_ratio) * w)); + event.rel_y = 1; + } + else + { + event.rel_x = (double) x / (double) ((sd->content_size_ratio) * w); + event.rel_y = 1; + } + break; + case EFL_UI_PANEL_ORIENT_RIGHT: + if (efl_ui_mirrored_get(obj)) + { + event.rel_x = 1 - ((double) x / (double) ((sd->content_size_ratio) * w)); + event.rel_y = 1; + } + else + { + event.rel_x = (double) x / (double) ((sd->content_size_ratio) * w); + event.rel_y = 1; + } + break; + } + efl_event_callback_legacy_call + (obj, EFL_UI_EVENT_SCROLL, (void *) &event); +} + +EOLIAN static Eina_Bool +_efl_ui_panel_efl_ui_widget_on_disabled_update(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Bool disabled) +{ + if (!efl_ui_widget_on_disabled_update(efl_super(obj, MY_CLASS), disabled)) + return EINA_FALSE; + + if (sd->scrollable) + { + if (disabled && sd->callback_added) + { + 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); + + sd->callback_added = EINA_FALSE; + } + else if (!disabled && !sd->callback_added) + { + 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); + + sd->callback_added = EINA_TRUE; + } + } + + return EINA_TRUE; +} + +EOLIAN static double +_efl_ui_panel_scrollable_content_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + return sd->content_size_ratio; +} + +EOLIAN static void +_efl_ui_panel_scrollable_content_size_set(Eo *obj, Efl_Ui_Panel_Data *sd, double ratio) +{ + if (ratio < 0) ratio = 0; + else if (ratio > 1.0) ratio = 1.0; + + sd->content_size_ratio = ratio; + + if (sd->scrollable) + { + Evas_Coord w, h; + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + + _scrollable_layout_resize(obj, sd, w, h); + } +} + +EOLIAN static Eina_Bool +_efl_ui_panel_scrollable_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *sd) +{ + return sd->scrollable; +} + +EOLIAN static void +_efl_ui_panel_scrollable_set(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Bool scrollable) +{ + scrollable = !!scrollable; + if (sd->scrollable == scrollable) return; + sd->scrollable = scrollable; + + if (scrollable) + { + elm_layout_content_unset(obj, "efl.content"); + + elm_widget_resize_object_set(obj, NULL); + 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, "panel", NULL, + 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); + + 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); + + elm_interface_scrollable_objects_set(obj, sd->scr_edje, sd->hit_rect); + elm_interface_scrollable_animate_stop_cb_set(obj, _anim_stop_cb); + elm_interface_scrollable_scroll_cb_set(obj, _scroll_cb); + } + + if (!sd->scr_ly) + { + sd->scr_ly = efl_add(EFL_UI_LAYOUT_CLASS, obj, + elm_layout_theme_set(efl_added, + "panel", + "scrollable/left", + elm_widget_style_get(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); + if (!elm_layout_content_set(sd->scr_ly, "efl.panel_area", 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); + if (!elm_layout_content_set(sd->scr_ly, "efl.event_area", sd->scr_event)) + elm_layout_content_set(sd->scr_ly, "event_area", sd->scr_event); + } + + elm_interface_scrollable_content_set(obj, sd->scr_ly); + sd->freeze = EINA_TRUE; + efl_content_set(efl_part(sd->scr_ly, "efl.content"), sd->bx); + if (sd->content) elm_widget_sub_object_add(sd->scr_ly, sd->content); + + switch (sd->orient) + { + case EFL_UI_PANEL_ORIENT_TOP: + case EFL_UI_PANEL_ORIENT_BOTTOM: + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_VERTICAL); + break; + case EFL_UI_PANEL_ORIENT_LEFT: + case EFL_UI_PANEL_ORIENT_RIGHT: + elm_interface_scrollable_movement_block_set + (obj, EFL_UI_SCROLL_BLOCK_HORIZONTAL); + break; + } + + elm_interface_scrollable_single_direction_set + (obj, ELM_SCROLLER_SINGLE_DIRECTION_NONE); + + if (!elm_widget_disabled_get(obj) && !sd->callback_added) + { + 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); + + sd->callback_added = EINA_TRUE; + } + + } + else + { + elm_interface_scrollable_content_set(obj, NULL); + + if (sd->callback_added) + { + 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); + + sd->callback_added = EINA_FALSE; + } + + elm_widget_resize_object_set(obj, NULL); + elm_widget_sub_object_add(obj, sd->scr_edje); + + elm_widget_resize_object_set(obj, sd->panel_edje); + + elm_layout_content_unset(sd->scr_ly, "efl.content"); + elm_layout_content_set(obj, "efl.content", sd->bx); + if (sd->content) elm_widget_sub_object_add(obj, sd->content); + } +} + +EOLIAN static void +_efl_ui_panel_efl_ui_base_mirrored_set(Eo *obj, Efl_Ui_Panel_Data *sd, Eina_Bool mirrored) +{ + if (sd->scrollable) + efl_ui_mirrored_set(efl_cast(obj, ELM_INTERFACE_SCROLLABLE_MIXIN), mirrored); + else + efl_ui_mirrored_set(efl_cast(obj, EFL_UI_WIDGET_CLASS), mirrored); +} + +EOLIAN const Efl_Access_Action_Data * +_efl_ui_panel_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Efl_Ui_Panel_Data *pd EINA_UNUSED) +{ + static Efl_Access_Action_Data atspi_actions[] = { + { "toggle", "toggle", NULL, _key_action_toggle}, + { NULL, NULL, NULL, NULL } + }; + return &atspi_actions[0]; +} + +/* Internal EO APIs and hidden overrides */ + +#define EFL_UI_PANEL_EXTRA_OPS \ + ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_panel) + +#include "efl_ui_panel.eo.c" diff --git a/src/lib/elementary/efl_ui_panel.eo b/src/lib/elementary/efl_ui_panel.eo new file mode 100644 index 0000000000..8fb5c1d359 --- /dev/null +++ b/src/lib/elementary/efl_ui_panel.eo @@ -0,0 +1,95 @@ +enum Efl.Ui.Panel_Orient +{ + [[Panel orientation mode]] + + top, [[Panel (dis)appears from the top]] + bottom, [[Panel (dis)appears from the bottom]] + left, [[Panel (dis)appears from the left]] + right [[Panel (dis)appears from the right]] +} + +struct Efl.Ui.Panel_Scroll_Info +{ + [[Panel scroll information]] + rel_x: double; [[content scrolled position (0.0 ~ 1.0) in the panel]] + rel_y: double; [[content scrolled position (0.0 ~ 1.0) in the panel]] +} + +class Efl.Ui.Panel (Efl.Ui.Layout, Efl.Ui.Focus.Layer, Elm.Interface_Scrollable, Efl.Content, + Efl.Access.Widget.Action) +{ + [[Elementary panel class]] + methods { + @property orient { + set { + [[Sets the orientation of the panel + + Sets from where the panel will (dis)appear. + ]] + } + get { + [[Gets the orientation of the panel.]] + } + values { + orient: Efl.Ui.Panel_Orient; [[The panel orientation.]] + } + } + @property hidden { + set { + [[Sets the state of the panel.]] + } + get { + [[Gets the state of the panel.]] + } + values { + hidden: bool; [[If $true, the panel will run the animation to disappear.]] + } + } + @property scrollable { + set { + [[Sets the scrollability of the panel.]] + } + get { + [[Gets the state of the scrollability. + ]] + } + values { + scrollable: bool; [[The scrollable state.]] + } + } + @property scrollable_content_size { + set { + [[Sets the size of the scrollable panel.]] + } + get { + [[Gets the size of the scrollable panel. + ]] + } + values { + ratio: double; [[Size ratio]] + } + } + toggle { + [[Toggle the hidden state of the panel from code]] + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + Efl.Gfx.Entity.position { set; } + Efl.Gfx.Entity.size { set; } + Efl.Canvas.Group.group_member_add; + Efl.Ui.Widget.theme_apply; + Efl.Ui.Widget.on_disabled_update; + Efl.Ui.Widget.on_access_update; + Efl.Ui.Widget.widget_event; + Efl.Ui.Widget.interest_region { get; } + Efl.Access.Widget.Action.elm_actions { get; } + Efl.Ui.Base.mirrored { set; } + Efl.Content.content { get; set; } + Efl.Content.content_unset; + } + events { + toggled: void; [[Called when the hidden state was toggled]] + } +} diff --git a/src/lib/elementary/efl_ui_panel_private.h b/src/lib/elementary/efl_ui_panel_private.h new file mode 100644 index 0000000000..18a32735b3 --- /dev/null +++ b/src/lib/elementary/efl_ui_panel_private.h @@ -0,0 +1,81 @@ +#ifndef EFL_UI_PANEL_H +#define EFL_UI_PANEL_H + +#include "elm_interface_scrollable.h" +#include "elm_widget_layout.h" +#include "efl_ui_panel.eo.h" + +/* DO NOT USE THIS HEADER UNLESS YOU ARE PREPARED FOR BREAKING OF YOUR + * CODE. THIS IS ELEMENTARY'S INTERNAL WIDGET API (for now) AND IS NOT + * FINAL. CALL elm_widget_api_check(EFL_UI_INTERNAL_API_VERSION) TO CHECK + * IT AT RUNTIME. + */ + +/** + * @addtogroup Widget + * @{ + * + * @section elm-panel-class The Elementary Panel Class + * + * Elementary, besides having the @ref Panel widget, exposes its + * foundation -- the Elementary Panel Class -- in order to create other + * widgets which are a panel with some more logic on top. + */ + +/** + * Base layout smart data extended with panel instance data. + */ +typedef struct _Efl_Ui_Panel_Data Efl_Ui_Panel_Data; +struct _Efl_Ui_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; + + + Efl_Ui_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; + Eina_Bool callback_added: 1; +}; + +/** + * @} + */ + +#define EFL_UI_PANEL_DATA_GET(o, sd) \ + Efl_Ui_Panel_Data * sd = efl_data_scope_get(o, EFL_UI_PANEL_CLASS) + +#define EFL_UI_PANEL_DATA_GET_OR_RETURN(o, ptr) \ + EFL_UI_PANEL_DATA_GET(o, ptr); \ + if (EINA_UNLIKELY(!ptr)) \ + { \ + ERR("No widget data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return; \ + } + +#define EFL_UI_PANEL_DATA_GET_OR_RETURN_VAL(o, ptr, val) \ + EFL_UI_PANEL_DATA_GET(o, ptr); \ + if (EINA_UNLIKELY(!ptr)) \ + { \ + ERR("No widget data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return val; \ + } + +#define EFL_UI_PANEL_CHECK(obj) \ + if (EINA_UNLIKELY(!efl_isa((obj), EFL_UI_PANEL_CLASS))) \ + return + +#endif diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 335b8f581b..6b34dce2cb 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -154,6 +154,7 @@ pub_eo_files = [ 'efl_ui_slider_interval.eo', 'efl_ui_spin.eo', 'efl_ui_spin_button.eo', + 'efl_ui_panel.eo', 'efl_ui_datepicker.eo', 'efl_ui_timepicker.eo', 'efl_ui_tags.eo', @@ -437,6 +438,7 @@ elementary_headers_unstable = [ 'elm_widget_spinner.h', 'efl_ui_spin_private.h', 'efl_ui_spin_button_private.h', + 'efl_ui_panel_private.h', 'efl_ui_datepicker_private.h', 'efl_ui_timepicker_private.h', 'efl_ui_tags_private.h', @@ -806,6 +808,7 @@ elementary_src = [ 'efl_ui_slider_interval.c', 'efl_ui_spin.c', 'efl_ui_spin_button.c', + 'efl_ui_panel.c', 'efl_ui_datepicker.c', 'efl_ui_timepicker.c', 'efl_ui_tags.c',