summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWonki Kim <wonki_.kim@samsung.com>2017-11-15 17:27:20 +0900
committerSangHyeon Jade Lee <dltkdgus1764@gmail.com>2017-11-15 17:28:29 +0900
commit480970d62feb0fec4292dc2410aef762c2d1814d (patch)
tree7b7f219197570edf2588d673c1b189764426990d
parente649d932beddc9913525249d53c11b1fddf0641b (diff)
scroll_manager: new scoller scratch
Summary: scrollable widgets had a interface_scrollable as a mixin so that the widgets had a 'is-a' relation with interface_scrollabe. however, new scroller concept don't have 'is-a' relationship, but 'has-a' relationship. scrollable widgets should have a scroll manager inside them, then scroll manager handles event from user and api implementations. and also we cut the features such as paging because there will be aka 'elm_pager'. we are expecting that the new concept make us to maintain the scroller easier. please excuse for many unorganized code and logics. : ( [contained commit] scrollable: add efl_ui_scroller example scrollable: refactoring for behavior in case of multiple scroller scrollable: remove repetitive scrollbar code. scrollable: combine calculating bounce distance code. scroll_manager: mouse up function refactoring scroll_manager: mouse move function refactoring scroll_manager: warp animator wip scroll_manager: fix denominator value when calculating flicking behavior. Fix to disconnect bounce animator once animation is done gather duplicated animator drop logics gather duplicated conditions Rearrange prototypes and append comment Add manipulate functions for animators scroll_manager: change member_add function. scroll_manger: apply mirroring logic scroll_manager: apply scrollbar apply API to scroller widget scroll_manager: apply scroll event callback Change logics for all about scroll animating efl_ui_pan: add efl_ui_pan scrollable: change content_min_limit to match_content scroll theme: apply overlapped scrollbar Reviewers: akanad, woohyun, cedric, jpeg Subscribers: jenkins, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D5222
-rw-r--r--data/elementary/themes/edc/elm/scroller.edc26
-rw-r--r--src/Makefile_Efl.am2
-rw-r--r--src/Makefile_Elementary.am10
-rw-r--r--src/bin/elementary/test.c4
-rw-r--r--src/bin/elementary/test_scroller.c45
-rw-r--r--src/examples/elementary/efl_ui_scroller_example.c31
-rw-r--r--src/lib/efl/Efl.h2
-rw-r--r--src/lib/efl/interfaces/efl_interfaces_main.c2
-rw-r--r--src/lib/efl/interfaces/efl_ui_scrollable.eo26
-rw-r--r--src/lib/efl/interfaces/efl_ui_scrollable_interactive.eo169
-rw-r--r--src/lib/efl/interfaces/efl_ui_scrollbar.eo60
-rw-r--r--src/lib/elementary/Elementary.h3
-rw-r--r--src/lib/elementary/efl_ui.eot14
-rw-r--r--src/lib/elementary/efl_ui_image_zoomable.c694
-rw-r--r--src/lib/elementary/efl_ui_image_zoomable.eo8
-rw-r--r--src/lib/elementary/efl_ui_image_zoomable_pan.eo10
-rw-r--r--src/lib/elementary/efl_ui_image_zoomable_private.h14
-rw-r--r--src/lib/elementary/efl_ui_pan.c208
-rw-r--r--src/lib/elementary/efl_ui_pan.eo53
-rw-r--r--src/lib/elementary/efl_ui_scroll_manager.c2491
-rw-r--r--src/lib/elementary/efl_ui_scroll_manager.eo51
-rw-r--r--src/lib/elementary/efl_ui_scroller.c535
-rw-r--r--src/lib/elementary/efl_ui_scroller.eo22
-rw-r--r--src/lib/elementary/efl_ui_widget_pan.h14
-rw-r--r--src/lib/elementary/efl_ui_widget_scroll_manager.h134
-rw-r--r--src/lib/elementary/efl_ui_widget_scroller.h15
26 files changed, 4401 insertions, 242 deletions
diff --git a/data/elementary/themes/edc/elm/scroller.edc b/data/elementary/themes/edc/elm/scroller.edc
index 091cfb1b23..e3f4f6fec6 100644
--- a/data/elementary/themes/edc/elm/scroller.edc
+++ b/data/elementary/themes/edc/elm/scroller.edc
@@ -1289,6 +1289,32 @@ group { name: "elm/scroller/base/noclip";
1289 } 1289 }
1290} 1290}
1291 1291
1292group { name: "elm/scroller/base/hidden_bar";
1293 inherit: "elm/scroller/base/default";
1294 parts {
1295 part { name: "elm.swallow.background"; type: SWALLOW;
1296 clip_to: "clipper";
1297 description { state: "default" 0.0;
1298 rel1.offset: 1 1;
1299 rel2.relative: 1.0 1.0;
1300 rel2.offset: -2 -2;
1301 rel2.to_x: "sb_vbar";
1302 rel2.to_y: "sb_hbar";
1303 }
1304 }
1305 part { name: "elm.swallow.content"; type: SWALLOW;
1306 clip_to: "clipper";
1307 description { state: "default" 0.0;
1308 rel1.offset: 1 1;
1309 rel2.relative: 1.0 1.0;
1310 rel2.offset: -2 -2;
1311 rel2.to_x: "sb_vbar";
1312 rel2.to_y: "sb_hbar";
1313 }
1314 }
1315 }
1316}
1317
1292group { name: "elm/scroller/contents/default"; 1318group { name: "elm/scroller/contents/default";
1293 parts { 1319 parts {
1294 part { name: "elm.swallow.content"; 1320 part { name: "elm.swallow.content";
diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am
index f9cdc7fe3c..c246126718 100644
--- a/src/Makefile_Efl.am
+++ b/src/Makefile_Efl.am
@@ -8,6 +8,8 @@ efl_eolian_legacy_files = \
8 lib/efl/interfaces/efl_ui_draggable.eo \ 8 lib/efl/interfaces/efl_ui_draggable.eo \
9 lib/efl/interfaces/efl_ui_clickable.eo \ 9 lib/efl/interfaces/efl_ui_clickable.eo \
10 lib/efl/interfaces/efl_ui_scrollable.eo \ 10 lib/efl/interfaces/efl_ui_scrollable.eo \
11 lib/efl/interfaces/efl_ui_scrollable_interactive.eo \
12 lib/efl/interfaces/efl_ui_scrollbar.eo \
11 lib/efl/interfaces/efl_ui_selectable.eo \ 13 lib/efl/interfaces/efl_ui_selectable.eo \
12 lib/efl/interfaces/efl_ui_zoom.eo \ 14 lib/efl/interfaces/efl_ui_zoom.eo \
13 $(NULL) 15 $(NULL)
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index 9aa406fe19..d3cfd53152 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -61,6 +61,9 @@ elm_public_eolian_files = \
61 lib/elementary/efl_ui_textpath_part.eo \ 61 lib/elementary/efl_ui_textpath_part.eo \
62 lib/elementary/efl_ui_widget_part.eo \ 62 lib/elementary/efl_ui_widget_part.eo \
63 lib/elementary/efl_ui_win_part.eo \ 63 lib/elementary/efl_ui_win_part.eo \
64 lib/elementary/efl_ui_scroller.eo \
65 lib/elementary/efl_ui_scroll_manager.eo \
66 lib/elementary/efl_ui_pan.eo \
64 lib/elementary/efl_access.eo \ 67 lib/elementary/efl_access.eo \
65 lib/elementary/efl_access_action.eo \ 68 lib/elementary/efl_access_action.eo \
66 lib/elementary/efl_access_component.eo \ 69 lib/elementary/efl_access_component.eo \
@@ -366,6 +369,10 @@ includesunstable_HEADERS = \
366 lib/elementary/elm_code_syntax.h \ 369 lib/elementary/elm_code_syntax.h \
367 lib/elementary/efl_ui_multibuttonentry.h \ 370 lib/elementary/efl_ui_multibuttonentry.h \
368 lib/elementary/Efl_Ui.h 371 lib/elementary/Efl_Ui.h
372 lib/elementary/efl_ui_widget_scroller.h \
373 lib/elementary/efl_ui_widget_scroll_manager.h \
374 lib/elementary/efl_ui_widget_pan.h \
375 lib/elementary/elm_code_syntax.h
369includesunstabledir = $(includedir)/elementary-@VMAJ@ 376includesunstabledir = $(includedir)/elementary-@VMAJ@
370 377
371nodist_includesunstable_HEADERS = \ 378nodist_includesunstable_HEADERS = \
@@ -747,6 +754,9 @@ lib_elementary_libelementary_la_SOURCES = \
747 lib/elementary/efl_ui_list_precise_layouter.c \ 754 lib/elementary/efl_ui_list_precise_layouter.c \
748 lib/elementary/efl_ui_list_segarray.c \ 755 lib/elementary/efl_ui_list_segarray.c \
749 lib/elementary/efl_ui_layout_factory.c \ 756 lib/elementary/efl_ui_layout_factory.c \
757 lib/elementary/efl_ui_scroller.c \
758 lib/elementary/efl_ui_scroll_manager.c \
759 lib/elementary/efl_ui_pan.c \
750 $(NULL) 760 $(NULL)
751 761
752 762
diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index 57b1916d53..081edbf074 100644
--- a/src/bin/elementary/test.c
+++ b/src/bin/elementary/test.c
@@ -175,6 +175,8 @@ void test_scroller2(void *data, Evas_Object *obj, void *event_info);
175void test_scroller3(void *data, Evas_Object *obj, void *event_info); 175void test_scroller3(void *data, Evas_Object *obj, void *event_info);
176void test_scroller4(void *data, Evas_Object *obj, void *event_info); 176void test_scroller4(void *data, Evas_Object *obj, void *event_info);
177void test_scroller5(void *data, Evas_Object *obj, void *event_info); 177void test_scroller5(void *data, Evas_Object *obj, void *event_info);
178void test_efl_ui_scroller(void *data, Evas_Object *obj, void *event_info);
179void test_efl_ui_scroller2(void *data, Evas_Object *obj, void *event_info);
178void test_spinner(void *data, Evas_Object *obj, void *event_info); 180void test_spinner(void *data, Evas_Object *obj, void *event_info);
179void test_index(void *data, Evas_Object *obj, void *event_info); 181void test_index(void *data, Evas_Object *obj, void *event_info);
180void test_index2(void *data, Evas_Object *obj, void *event_info); 182void test_index2(void *data, Evas_Object *obj, void *event_info);
@@ -971,6 +973,8 @@ add_tests:
971 ADD_TEST(NULL, "Scroller", "Scroller 3", test_scroller3); 973 ADD_TEST(NULL, "Scroller", "Scroller 3", test_scroller3);
972 ADD_TEST(NULL, "Scroller", "Page Scroller", test_scroller4); 974 ADD_TEST(NULL, "Scroller", "Page Scroller", test_scroller4);
973 ADD_TEST(NULL, "Scroller", "Scroller on Popup", test_scroller5); 975 ADD_TEST(NULL, "Scroller", "Scroller on Popup", test_scroller5);
976 ADD_TEST(NULL, "Scroller", "Efl Ui Scroller", test_efl_ui_scroller);
977 ADD_TEST(NULL, "Scroller", "Efl Ui Scroller 2", test_efl_ui_scroller2);
974 978
975 //------------------------------// 979 //------------------------------//
976 // FIXME: add frame test 980 // FIXME: add frame test
diff --git a/src/bin/elementary/test_scroller.c b/src/bin/elementary/test_scroller.c
index ead5bbca34..639f201a89 100644
--- a/src/bin/elementary/test_scroller.c
+++ b/src/bin/elementary/test_scroller.c
@@ -1017,3 +1017,48 @@ test_scroller5(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event
1017 evas_object_resize(win, 400, 550); 1017 evas_object_resize(win, 400, 550);
1018 evas_object_show(win); 1018 evas_object_show(win);
1019} 1019}
1020
1021void
1022test_efl_ui_scroller(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1023{
1024 Eo *win, *scroller, *content;
1025 char buf[64];
1026
1027 win = efl_add(EFL_UI_WIN_CLASS, NULL, "TEST", ELM_WIN_BASIC,
1028 efl_text_set(efl_added, "Efl Ui Scroller"),
1029 efl_ui_win_autodel_set(efl_added, EINA_TRUE));
1030 efl_gfx_size_set(win, EINA_SIZE2D(300, 400));
1031
1032 scroller = efl_add(EFL_UI_SCROLLER_CLASS, win);
1033 efl_content_set(win, scroller);
1034
1035 content = efl_add(EFL_UI_IMAGE_CLASS, scroller);
1036 snprintf(buf, sizeof(buf), "%s/images/plant_01.jpg", elm_app_data_dir_get());
1037 efl_file_set(content, buf, NULL);
1038 efl_gfx_size_set(content, EINA_SIZE2D(1000, 1000));
1039 efl_content_set(scroller, content);
1040}
1041
1042void
1043test_efl_ui_scroller2(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1044{
1045 Eo *win, *scroller, *content;
1046 char buf[64];
1047
1048 win = efl_add(EFL_UI_WIN_CLASS, NULL, "TEST", ELM_WIN_BASIC,
1049 efl_text_set(efl_added, "Efl Ui Scroller 2"),
1050 efl_ui_win_autodel_set(efl_added, EINA_TRUE));
1051 efl_gfx_size_set(win, EINA_SIZE2D(300, 400));
1052
1053 scroller = efl_add(EFL_UI_SCROLLER_CLASS, win,
1054 elm_object_style_set(efl_added, "hidden_bar"));
1055 efl_ui_scrollbar_mode_set(scroller, EFL_UI_SCROLLBAR_MODE_HIDDEN, EFL_UI_SCROLLBAR_MODE_HIDDEN);
1056 efl_content_set(win, scroller);
1057
1058 content = efl_add(EFL_UI_IMAGE_CLASS, scroller);
1059 snprintf(buf, sizeof(buf), "%s/images/plant_01.jpg", elm_app_data_dir_get());
1060 efl_file_set(content, buf, NULL);
1061 efl_gfx_size_set(content, EINA_SIZE2D(5000, 5000));
1062 efl_content_set(scroller, content);
1063}
1064
diff --git a/src/examples/elementary/efl_ui_scroller_example.c b/src/examples/elementary/efl_ui_scroller_example.c
new file mode 100644
index 0000000000..b09756c272
--- /dev/null
+++ b/src/examples/elementary/efl_ui_scroller_example.c
@@ -0,0 +1,31 @@
1//Compile with:
2//gcc -g efl_ui_scroller_example.c -o efl_ui_scroller_example `pkg-config --cflags --libs elementary`
3
4#define EFL_BETA_API_SUPPORT
5#define EFL_EO_API_SUPPORT
6
7#include <Elementary.h>
8
9EAPI_MAIN void
10efl_main(void *data EINA_UNUSED, const Efl_Event *ev)
11{
12 Eo *win, *scroller, *content;
13 char buf[64];
14
15 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
16 elm_app_info_set(efl_main, "elementary", "images/plant_01.jpg");
17
18 win = efl_add(EFL_UI_WIN_CLASS, NULL, "TEST", ELM_WIN_BASIC,
19 efl_ui_win_autodel_set(efl_added, EINA_TRUE));
20 efl_gfx_size_set(win, EINA_SIZE2D(300, 400));
21
22 scroller = efl_add(EFL_UI_SCROLLER_CLASS, win);
23 efl_content_set(win, scroller);
24
25 content = efl_add(EFL_UI_IMAGE_CLASS, scroller);
26 snprintf(buf, sizeof(buf), "%s/images/plant_01.jpg", elm_app_data_dir_get());
27 efl_file_set(content, buf, NULL);
28 efl_gfx_size_set(content, EINA_SIZE2D(5000, 5000));
29 efl_content_set(scroller, content);
30}
31EFL_MAIN()
diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h
index 32b43717b5..e207feb7cf 100644
--- a/src/lib/efl/Efl.h
+++ b/src/lib/efl/Efl.h
@@ -98,6 +98,8 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
98#include "interfaces/efl_ui_draggable.eo.h" 98#include "interfaces/efl_ui_draggable.eo.h"
99#include "interfaces/efl_ui_clickable.eo.h" 99#include "interfaces/efl_ui_clickable.eo.h"
100#include "interfaces/efl_ui_scrollable.eo.h" 100#include "interfaces/efl_ui_scrollable.eo.h"
101#include "interfaces/efl_ui_scrollbar.eo.h"
102#include "interfaces/efl_ui_scrollable_interactive.eo.h"
101#include "interfaces/efl_ui_selectable.eo.h" 103#include "interfaces/efl_ui_selectable.eo.h"
102#include "interfaces/efl_ui_zoom.eo.h" 104#include "interfaces/efl_ui_zoom.eo.h"
103 105
diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c
index 30769e6433..5c2bdad139 100644
--- a/src/lib/efl/interfaces/efl_interfaces_main.c
+++ b/src/lib/efl/interfaces/efl_interfaces_main.c
@@ -70,6 +70,8 @@
70#include "interfaces/efl_ui_draggable.eo.c" 70#include "interfaces/efl_ui_draggable.eo.c"
71#include "interfaces/efl_ui_clickable.eo.c" 71#include "interfaces/efl_ui_clickable.eo.c"
72#include "interfaces/efl_ui_scrollable.eo.c" 72#include "interfaces/efl_ui_scrollable.eo.c"
73#include "interfaces/efl_ui_scrollable_interactive.eo.c"
74#include "interfaces/efl_ui_scrollbar.eo.c"
73#include "interfaces/efl_ui_selectable.eo.c" 75#include "interfaces/efl_ui_selectable.eo.c"
74#include "interfaces/efl_ui_zoom.eo.c" 76#include "interfaces/efl_ui_zoom.eo.c"
75 77
diff --git a/src/lib/efl/interfaces/efl_ui_scrollable.eo b/src/lib/efl/interfaces/efl_ui_scrollable.eo
index 366e2c02f9..203120613d 100644
--- a/src/lib/efl/interfaces/efl_ui_scrollable.eo
+++ b/src/lib/efl/interfaces/efl_ui_scrollable.eo
@@ -1,9 +1,33 @@
1enum Efl.Ui.Scroll_Block
2{
3 [[Direction in which a scroller should be blocked.
4
5 Note: These options may be effective only in case of thumbscroll (i.e.
6 when scrolling by dragging).
7
8 @since 1.21
9 ]]
10 none = 0, [[Don't block any movement.]]
11 vertical = 1, [[Block vertical movement.]]
12 horizontal = 2 [[Block horizontal movement.]]
13}
14
1interface Efl.Ui.Scrollable () 15interface Efl.Ui.Scrollable ()
2{ 16{
3 [[Efl UI scrollable interface]] 17 [[Efl UI scrollable interface]]
4 event_prefix: efl_ui; 18 event_prefix: efl_ui;
5 events { 19 events {
6 scroll; [[Called when scroll operation started]] 20 scroll,start; [[Called when scroll operation started]]
21 scroll; [[Called when scroll operation]]
22 scroll,stop; [[Called when scroll operation stopped]]
23 scroll,up; [[Called when scrolling to upwards]]
24 scroll,down; [[Called when scrolling to downwards]]
25 scroll,left; [[Called when scrolling to left]]
26 scroll,right; [[Called when scrolling to right]]
27 edge,up; [[Called when hitting the top edge]]
28 edge,down; [[Called when hitting the bottom edge]]
29 edge,left; [[Called when hitting the left edge]]
30 edge,right; [[Called when hitting the right edge]]
7 scroll,anim,start; [[Called when scroll animation started]] 31 scroll,anim,start; [[Called when scroll animation started]]
8 scroll,anim,stop; [[Called when scroll animation stopped]] 32 scroll,anim,stop; [[Called when scroll animation stopped]]
9 scroll,drag,start; [[Called when scroll drag started]] 33 scroll,drag,start; [[Called when scroll drag started]]
diff --git a/src/lib/efl/interfaces/efl_ui_scrollable_interactive.eo b/src/lib/efl/interfaces/efl_ui_scrollable_interactive.eo
new file mode 100644
index 0000000000..045c297bbe
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_scrollable_interactive.eo
@@ -0,0 +1,169 @@
1import eina_types;
2
3interface Efl.Ui.Scrollable.Interactive (Efl.Ui.Scrollable)
4{
5 eo_prefix: efl_ui_scrollable;
6 methods {
7 @property content_pos {
8 [[The content position]]
9 set {
10 }
11 get {
12 }
13 values {
14 pos: Eina.Position2D; [[The position is virtual value, (0, 0) starting at the top-left.]]
15 }
16 }
17 @property content_size {
18 [[The content size]]
19 get {
20 }
21 values {
22 size: Eina.Size2D; [[The content size in pixels.]]
23 }
24 }
25 @property viewport_geometry {
26 [[The viewport geometry]]
27 get {
28 }
29 values {
30 rect: Eina.Rect; [[It is absolute geometry.]]
31 }
32 }
33 @property bounce_enabled {
34 [[Bouncing behavior
35
36 When scrolling, the scroller may "bounce" when reaching an edge of the
37 content object. This is a visual way to indicate the end has been reached.
38 This is enabled by default for both axis. This API will set if it is enabled
39 for the given axis with the boolean parameters for each axis.]]
40 set {
41 }
42 get {
43 }
44 values {
45 horiz: bool; [[Horizontal bounce policy.]]
46 vert: bool; [[Vertical bounce policy.]]
47 }
48 }
49 @property freeze {
50 [[Freeze property
51 This function will freeze scrolling movement (by input of a user).
52 Unlike efl_ui_scrollable_movement_block_set, this function freezes bidirectional.
53 If you want to freeze only one direction,
54 See @.movement_block.set.
55 ]]
56 get {
57 }
58 set {
59 }
60 values {
61 freeze: bool; [[$true if freeze, $false otherwise]]
62 }
63 }
64 @property hold {
65 [[Hold property
66 When hold turns on, it only scrolls by holding action.
67 Holding action is same as blocking text.
68 ]]
69 get {
70 }
71 set {
72 }
73 values {
74 hold: bool; [[$true if hold, $false otherwise]]
75 }
76 }
77 @property loop {
78 [[Controls an infinite loop for a scroller.]]
79 set {
80 }
81 get {
82 }
83 values {
84 loop_h: bool; [[The scrolling horizontal loop]]
85 loop_v: bool; [[The Scrolling vertical loop]]
86 }
87 }
88 @property movement_block {
89 [[Blocking of scrolling (per axis)
90
91 This function will block scrolling movement (by input of a user) in
92 a given direction. One can disable movements in the X axis, the Y
93 axis or both. The default value is $none, where movements are
94 allowed in both directions.
95 ]]
96 set {
97 }
98 get {
99 }
100 values {
101 block: Efl.Ui.Scroll_Block(Efl.Ui.Scroll_Block.none); [[Which axis (or axes) to block]]
102 }
103 }
104 @property gravity {
105 [[Control scrolling gravity on the scrollable
106
107 The gravity defines how the scroller will adjust its view
108 when the size of the scroller contents increases.
109
110 The scroller will adjust the view to glue itself as follows.
111
112 x=0.0, for staying where it is relative to the left edge of the content
113 x=1.0, for staying where it is relative to the rigth edge of the content
114 y=0.0, for staying where it is relative to the top edge of the content
115 y=1.0, for staying where it is relative to the bottom edge of the content
116
117 Default values for x and y are 0.0]]
118 set {
119 }
120 get {
121 }
122 values {
123 x: double; [[Horizontal scrolling gravity]]
124 y: double; [[Vertical scrolling gravity]]
125 }
126 }
127 @property match_content {
128 [[Prevent the scrollable from being smaller than the minimum size of the content.
129
130 By default the scroller will be as small as its design allows,
131 irrespective of its content. This will make the scroller minimum size the
132 right size horizontally and/or vertically to perfectly fit its content in
133 that direction.]]
134 set {
135 }
136 values {
137 w: bool; [[Whether to limit the minimum horizontal size]]
138 h: bool; [[Whether to limit the minimum vertical size]]
139 }
140 }
141 scroll {
142 [[Show a specific virtual region within the scroller content object.
143
144 This will ensure all (or part if it does not fit) of the designated
145 region in the virtual content object (0, 0 starting at the top-left of the
146 virtual content object) is shown within the scroller. Unlike
147 efl_ui_scrollable_show(), this allows the scroller to "smoothly slide"
148 to this location (if configuration in general calls for transitions). It
149 may not jump immediately to the new location and make take a while and
150 show other content along the way.
151
152 See @.show]]
153 params {
154 @in rect: Eina.Rect; [[The position where to scroll. and The size user want to see]]
155 }
156 }
157 show {
158 [[Show a specific virtual region within the scroller content object
159
160 This will ensure all (or part if it does not fit) of the designated
161 region in the virtual content object (0, 0 starting at the top-left of the
162 virtual content object) is shown within the scroller.
163 ]]
164 params {
165 @in rect: Eina.Rect; [[The position where to scroll. and The size user want to see]]
166 }
167 }
168 }
169}
diff --git a/src/lib/efl/interfaces/efl_ui_scrollbar.eo b/src/lib/efl/interfaces/efl_ui_scrollbar.eo
new file mode 100644
index 0000000000..29bba6c658
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_ui_scrollbar.eo
@@ -0,0 +1,60 @@
1enum Efl.Ui.Scrollbar_Mode
2{
3 auto = 0, [[Visible if necessary]]
4 on, [[Always visible]]
5 off, [[Always invisible]]
6 hidden, [[Visible when user input occurs]]
7 last [[]]
8}
9
10enum Efl.Ui.Scrollbar_Direction
11{
12 horizontal = 0,
13 vertical,
14 last
15}
16interface Efl.Ui.Scrollbar ()
17{
18 methods {
19 @property mode {
20 [[Scrollbar visibility policy]]
21 set {
22 }
23 get {
24 }
25 values {
26 hbar: Efl.Ui.Scrollbar_Mode; [[Horizontal scrollbar]]
27 vbar: Efl.Ui.Scrollbar_Mode; [[Vertical scrollbar]]
28 }
29 }
30 @property size {
31 get {
32 }
33 values {
34 width: double;
35 height: double;
36 }
37 }
38 @property position {
39 set {
40 }
41 get {
42 }
43 values {
44 posx: double;
45 posy: double;
46 }
47 }
48 visibility_update {
49 }
50 }
51 events {
52 bar,press; [[Called when bar is pressed]]
53 bar,unpress; [[Called when bar is unpressed]]
54 bar,drag; [[Called when bar is dragged]]
55 bar,size,changed;
56 bar,pos,changed;
57 bar,show;
58 bar,hide;
59 }
60}
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 2b0a4677eb..f5ae473f5d 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -292,6 +292,9 @@ EAPI extern Elm_Version *elm_version;
292# include <efl_ui_list_relayout.eo.h> 292# include <efl_ui_list_relayout.eo.h>
293# include <efl_ui_list.eo.h> 293# include <efl_ui_list.eo.h>
294# include <efl_ui_list_pan.eo.h> 294# include <efl_ui_list_pan.eo.h>
295# include <efl_ui_scroll_manager.eo.h>
296# include <efl_ui_scroller.eo.h>
297# include <efl_ui_pan.eo.h>
295#endif 298#endif
296 299
297/* include deprecated calls last of all */ 300/* include deprecated calls last of all */
diff --git a/src/lib/elementary/efl_ui.eot b/src/lib/elementary/efl_ui.eot
index 4483acc10d..4b69a20039 100644
--- a/src/lib/elementary/efl_ui.eot
+++ b/src/lib/elementary/efl_ui.eot
@@ -76,20 +76,6 @@ enum Efl.Ui.Softcursor_Mode
76 off [[Never use a softcursor.]] 76 off [[Never use a softcursor.]]
77} 77}
78 78
79enum Efl.Ui.Scroll_Block
80{
81 [[Direction in which a scroller should be blocked.
82
83 Note: These options may be effective only in case of thumbscroll (i.e.
84 when scrolling by dragging).
85
86 @since 1.21
87 ]]
88 none = 0, [[Don't block any movement.]]
89 vertical = 1, [[Block vertical movement.]]
90 horizontal = 2 [[Block horizontal movement.]]
91}
92
93/* 'on_access_activate' is beta API in the Widget class */ 79/* 'on_access_activate' is beta API in the Widget class */
94enum Efl.Ui.Activate 80enum Efl.Ui.Activate
95{ 81{
diff --git a/src/lib/elementary/efl_ui_image_zoomable.c b/src/lib/elementary/efl_ui_image_zoomable.c
index dc2a5ba2df..aa3b17d479 100644
--- a/src/lib/elementary/efl_ui_image_zoomable.c
+++ b/src/lib/elementary/efl_ui_image_zoomable.c
@@ -9,7 +9,6 @@
9 9
10#include "elm_priv.h" 10#include "elm_priv.h"
11#include "efl_ui_image_zoomable_private.h" 11#include "efl_ui_image_zoomable_private.h"
12#include "elm_interface_scrollable.h"
13 12
14#define MY_PAN_CLASS EFL_UI_IMAGE_ZOOMABLE_PAN_CLASS 13#define MY_PAN_CLASS EFL_UI_IMAGE_ZOOMABLE_PAN_CLASS
15 14
@@ -143,7 +142,7 @@ _calc_job_cb(void *data)
143 sd->minw = minw; 142 sd->minw = minw;
144 sd->minh = minh; 143 sd->minh = minh;
145 144
146 efl_event_callback_legacy_call(sd->pan_obj, ELM_PAN_EVENT_CHANGED, NULL); 145 efl_event_callback_call(sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
147 _sizing_eval(obj); 146 _sizing_eval(obj);
148 } 147 }
149 sd->calc_job = NULL; 148 sd->calc_job = NULL;
@@ -200,11 +199,11 @@ _image_place(Evas_Object *obj,
200 evas_object_move(sd->img, ox + 0 - px + ax, oy + 0 - py + ay); 199 evas_object_move(sd->img, ox + 0 - px + ax, oy + 0 - py + ay);
201 evas_object_resize(sd->img, gw, gh); 200 evas_object_resize(sd->img, gw, gh);
202 201
203 if (sd->show.show) 202 if (sd->show_item)
204 { 203 {
205 sd->show.show = EINA_FALSE; 204 sd->show_item = EINA_FALSE;
206 elm_interface_scrollable_content_region_show 205 efl_ui_scrollable_show
207 (obj, sd->show.x, sd->show.y, sd->show.w, sd->show.h); 206 (sd->smanager, sd->show);
208 } 207 }
209} 208}
210 209
@@ -381,23 +380,24 @@ _efl_ui_image_zoomable_pan_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Imag
381} 380}
382 381
383EOLIAN static void 382EOLIAN static void
384_efl_ui_image_zoomable_pan_elm_pan_pos_set(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Evas_Coord x, Evas_Coord y) 383_efl_ui_image_zoomable_pan_efl_ui_pan_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Eina_Position2D pos)
385{ 384{
386 if ((x == psd->wsd->pan_x) && (y == psd->wsd->pan_y)) return; 385 if ((pos.x == psd->wsd->pan_x) && (pos.y == psd->wsd->pan_y)) return;
387 psd->wsd->pan_x = x; 386 psd->wsd->pan_x = pos.x;
388 psd->wsd->pan_y = y; 387 psd->wsd->pan_y = pos.y;
389 evas_object_smart_changed(obj); 388 evas_object_smart_changed(obj);
389
390 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
390} 391}
391 392
392EOLIAN static void 393EOLIAN static Eina_Position2D
393_efl_ui_image_zoomable_pan_elm_pan_pos_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd, Evas_Coord *x, Evas_Coord *y) 394_efl_ui_image_zoomable_pan_efl_ui_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
394{ 395{
395 if (x) *x = psd->wsd->pan_x; 396 return EINA_POSITION2D(psd->wsd->pan_x, psd->wsd->pan_y);
396 if (y) *y = psd->wsd->pan_y;
397} 397}
398 398
399EOLIAN static void 399EOLIAN static Eina_Position2D
400_efl_ui_image_zoomable_pan_elm_pan_pos_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Evas_Coord *x, Evas_Coord *y) 400_efl_ui_image_zoomable_pan_efl_ui_pan_position_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
401{ 401{
402 Evas_Coord ow, oh; 402 Evas_Coord ow, oh;
403 403
@@ -406,28 +406,27 @@ _efl_ui_image_zoomable_pan_elm_pan_pos_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pa
406 if (ow < 0) ow = 0; 406 if (ow < 0) ow = 0;
407 oh = psd->wsd->minh - oh; 407 oh = psd->wsd->minh - oh;
408 if (oh < 0) oh = 0; 408 if (oh < 0) oh = 0;
409 if (x) *x = ow; 409
410 if (y) *y = oh; 410 return EINA_POSITION2D(ow, oh);
411} 411}
412 412
413EOLIAN static void 413EOLIAN static Eina_Position2D
414_efl_ui_image_zoomable_pan_elm_pan_pos_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *_pd EINA_UNUSED, Evas_Coord *x, Evas_Coord *y) 414_efl_ui_image_zoomable_pan_efl_ui_pan_position_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *_pd EINA_UNUSED)
415{ 415{
416 if (x) *x = 0; 416 return EINA_POSITION2D(0, 0);
417 if (y) *y = 0;
418} 417}
419 418
420EOLIAN static void 419EOLIAN static Eina_Size2D
421_efl_ui_image_zoomable_pan_elm_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd, Evas_Coord *w, Evas_Coord *h) 420_efl_ui_image_zoomable_pan_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
422{ 421{
423 if (w) *w = psd->wsd->minw; 422 return EINA_SIZE2D(psd->wsd->minw, psd->wsd->minh);
424 if (h) *h = psd->wsd->minh;
425} 423}
426 424
427EOLIAN static void 425EOLIAN static void
428_efl_ui_image_zoomable_pan_efl_object_destructor(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd) 426_efl_ui_image_zoomable_pan_efl_object_destructor(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
429{ 427{
430 efl_data_unref(psd->wobj, psd->wsd); 428 efl_data_unref(psd->wobj, psd->wsd);
429
431 efl_destructor(efl_super(obj, MY_PAN_CLASS)); 430 efl_destructor(efl_super(obj, MY_PAN_CLASS));
432} 431}
433 432
@@ -725,28 +724,28 @@ static Eina_Bool
725_zoom_do(Evas_Object *obj, 724_zoom_do(Evas_Object *obj,
726 double t) 725 double t)
727{ 726{
728 Evas_Coord xx, yy, ow = 0, oh = 0; 727 Evas_Coord xx, yy;
728 Eina_Rect view = {};
729 729
730 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 730 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
731 731
732 sd->size.w = (sd->size.ow * (1.0 - t)) + (sd->size.nw * t); 732 sd->size.w = (sd->size.ow * (1.0 - t)) + (sd->size.nw * t);
733 sd->size.h = (sd->size.oh * (1.0 - t)) + (sd->size.nh * t); 733 sd->size.h = (sd->size.oh * (1.0 - t)) + (sd->size.nh * t);
734 elm_interface_scrollable_content_viewport_geometry_get 734 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
735 (obj, NULL, NULL, &ow, &oh); 735 xx = (sd->size.spos.x * sd->size.w) - (view.w / 2);
736 xx = (sd->size.spos.x * sd->size.w) - (ow / 2); 736 yy = (sd->size.spos.y * sd->size.h) - (view.h / 2);
737 yy = (sd->size.spos.y * sd->size.h) - (oh / 2);
738 if (xx < 0) xx = 0; 737 if (xx < 0) xx = 0;
739 else if (xx > (sd->size.w - ow)) 738 else if (xx > (sd->size.w - view.w))
740 xx = sd->size.w - ow; 739 xx = sd->size.w - view.w;
741 if (yy < 0) yy = 0; 740 if (yy < 0) yy = 0;
742 else if (yy > (sd->size.h - oh)) 741 else if (yy > (sd->size.h - view.h))
743 yy = sd->size.h - oh; 742 yy = sd->size.h - view.h;
744 743
745 sd->show.show = EINA_TRUE; 744 sd->show_item = EINA_TRUE;
746 sd->show.x = xx; 745 sd->show.x = xx;
747 sd->show.y = yy; 746 sd->show.y = yy;
748 sd->show.w = ow; 747 sd->show.w = view.w;
749 sd->show.h = oh; 748 sd->show.h = view.h;
750 749
751 if (sd->orientation_changed) 750 if (sd->orientation_changed)
752 { 751 {
@@ -903,41 +902,10 @@ _efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Dat
903} 902}
904 903
905static void 904static void
906_scroll_animate_start_cb(Evas_Object *obj, 905_scroll_cb(void * data,
907 void *data EINA_UNUSED) 906 const Efl_Event *event EINA_UNUSED)
908{
909 efl_event_callback_legacy_call
910 (obj, EFL_UI_EVENT_SCROLL_ANIM_START, NULL);
911}
912
913static void
914_scroll_animate_stop_cb(Evas_Object *obj,
915 void *data EINA_UNUSED)
916{
917 efl_event_callback_legacy_call
918 (obj, EFL_UI_EVENT_SCROLL_ANIM_STOP, NULL);
919}
920
921static void
922_scroll_drag_start_cb(Evas_Object *obj,
923 void *data EINA_UNUSED)
924{
925 efl_event_callback_legacy_call
926 (obj, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
927}
928
929static void
930_scroll_drag_stop_cb(Evas_Object *obj,
931 void *data EINA_UNUSED)
932{
933 efl_event_callback_legacy_call
934 (obj, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
935}
936
937static void
938_scroll_cb(Evas_Object *obj,
939 void *data EINA_UNUSED)
940{ 907{
908 Evas_Object *obj = data;
941 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 909 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
942 910
943 if (!sd->scr_timer) 911 if (!sd->scr_timer)
@@ -948,63 +916,57 @@ _scroll_cb(Evas_Object *obj,
948 916
949 ecore_timer_del(sd->scr_timer); 917 ecore_timer_del(sd->scr_timer);
950 sd->scr_timer = ecore_timer_add(0.5, _scroll_timeout_cb, obj); 918 sd->scr_timer = ecore_timer_add(0.5, _scroll_timeout_cb, obj);
951
952 efl_event_callback_legacy_call
953 (obj, EFL_UI_EVENT_SCROLL, NULL);
954} 919}
955 920
956static Eina_Bool 921static Eina_Bool
957_key_action_move(Evas_Object *obj, const char *params) 922_key_action_move(Evas_Object *obj, const char *params)
958{ 923{
924 Eina_Rect view = {};
925 Eina_Position2D pos = {};
959 const char *dir = params; 926 const char *dir = params;
927 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
960 928
961 Evas_Coord x = 0;
962 Evas_Coord y = 0;
963 Evas_Coord v_h = 0;
964 Evas_Coord step_x = 0; 929 Evas_Coord step_x = 0;
965 Evas_Coord step_y = 0; 930 Evas_Coord step_y = 0;
966 Evas_Coord page_x = 0; 931 Evas_Coord page_x = 0;
967 Evas_Coord page_y = 0; 932 Evas_Coord page_y = 0;
968 933
969 elm_interface_scrollable_content_pos_get(obj, &x, &y); 934 pos = efl_ui_scrollable_content_pos_get(sd->smanager);
970 elm_interface_scrollable_step_size_get(obj, &step_x, &step_y); 935 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
971 elm_interface_scrollable_page_size_get(obj, &page_x, &page_y);
972 elm_interface_scrollable_content_viewport_geometry_get
973 (obj, NULL, NULL, NULL, &v_h);
974 936
975 if (!strcmp(dir, "left")) 937 if (!strcmp(dir, "left"))
976 { 938 {
977 x -= step_x; 939 pos.x -= step_x;
978 } 940 }
979 else if (!strcmp(dir, "right")) 941 else if (!strcmp(dir, "right"))
980 { 942 {
981 x += step_x; 943 pos.x += step_x;
982 } 944 }
983 else if (!strcmp(dir, "up")) 945 else if (!strcmp(dir, "up"))
984 { 946 {
985 y -= step_y; 947 pos.y -= step_y;
986 } 948 }
987 else if (!strcmp(dir, "down")) 949 else if (!strcmp(dir, "down"))
988 { 950 {
989 y += step_y; 951 pos.y += step_y;
990 } 952 }
991 else if (!strcmp(dir, "prior")) 953 else if (!strcmp(dir, "prior"))
992 { 954 {
993 if (page_y < 0) 955 if (page_y < 0)
994 y -= -(page_y * v_h) / 100; 956 pos.y -= -(page_y * view.h) / 100;
995 else 957 else
996 y -= page_y; 958 pos.y -= page_y;
997 } 959 }
998 else if (!strcmp(dir, "next")) 960 else if (!strcmp(dir, "next"))
999 { 961 {
1000 if (page_y < 0) 962 if (page_y < 0)
1001 y += -(page_y * v_h) / 100; 963 pos.y += -(page_y * view.h) / 100;
1002 else 964 else
1003 y += page_y; 965 pos.y += page_y;
1004 } 966 }
1005 else return EINA_FALSE; 967 else return EINA_FALSE;
1006 968
1007 elm_interface_scrollable_content_pos_set(obj, x, y, EINA_TRUE); 969 efl_ui_scrollable_content_pos_set(sd->smanager, pos);
1008 return EINA_TRUE; 970 return EINA_TRUE;
1009} 971}
1010 972
@@ -1076,7 +1038,7 @@ _bounce_eval(void *data, const Efl_Event *event EINA_UNUSED)
1076 sd->g_layer_zoom.imy = 0; 1038 sd->g_layer_zoom.imy = 0;
1077 sd->zoom_g_layer = EINA_FALSE; 1039 sd->zoom_g_layer = EINA_FALSE;
1078 1040
1079 elm_interface_scrollable_freeze_set(obj, EINA_FALSE); 1041 efl_ui_scrollable_freeze_set(sd->smanager, EINA_FALSE);
1080 1042
1081 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj); 1043 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
1082} 1044}
@@ -1112,18 +1074,16 @@ _g_layer_zoom_do(Evas_Object *obj,
1112 Elm_Gesture_Zoom_Info *g_layer) 1074 Elm_Gesture_Zoom_Info *g_layer)
1113{ 1075{
1114 int regx, regy, regw, regh, ix, iy, iw, ih; 1076 int regx, regy, regw, regh, ix, iy, iw, ih;
1115 Evas_Coord rx, ry, rw = 0, rh = 0;
1116 int xx, yy; 1077 int xx, yy;
1078 Eina_Rect view = {};
1117 1079
1118 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1080 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1119 sd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL; 1081 sd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
1120 sd->zoom = sd->g_layer_start / g_layer->zoom; 1082 sd->zoom = sd->g_layer_start / g_layer->zoom;
1121 sd->size.ow = sd->size.w; 1083 sd->size.ow = sd->size.w;
1122 sd->size.oh = sd->size.h; 1084 sd->size.oh = sd->size.h;
1123 elm_interface_scrollable_content_pos_get(obj, &rx, &ry); 1085 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1124 elm_interface_scrollable_content_viewport_geometry_get 1086 if ((view.w <= 0) || (view.h <= 0)) return;
1125 (obj, NULL, NULL, &rw, &rh);
1126 if ((rw <= 0) || (rh <= 0)) return;
1127 1087
1128 sd->size.nw = (double)sd->size.imw / sd->zoom; 1088 sd->size.nw = (double)sd->size.imw / sd->zoom;
1129 sd->size.nh = (double)sd->size.imh / sd->zoom; 1089 sd->size.nh = (double)sd->size.imh / sd->zoom;
@@ -1139,30 +1099,30 @@ _g_layer_zoom_do(Evas_Object *obj,
1139 sd->g_layer_zoom.imx = 0; 1099 sd->g_layer_zoom.imx = 0;
1140 sd->g_layer_zoom.imy = 0; 1100 sd->g_layer_zoom.imy = 0;
1141 1101
1142 if ((xx < 0) || (rw > sd->size.nw)) 1102 if ((xx < 0) || (view.w > sd->size.nw))
1143 { 1103 {
1144 sd->g_layer_zoom.imx = xx; 1104 sd->g_layer_zoom.imx = xx;
1145 xx = 0; 1105 xx = 0;
1146 } 1106 }
1147 else if ((xx + rw) > sd->size.nw) 1107 else if ((xx + view.w) > sd->size.nw)
1148 { 1108 {
1149 sd->g_layer_zoom.imx = xx + rw - sd->size.nw; 1109 sd->g_layer_zoom.imx = xx + view.w - sd->size.nw;
1150 xx = sd->size.nw - rw; 1110 xx = sd->size.nw - view.w;
1151 } 1111 }
1152 1112
1153 if ((yy < 0) || (rh > sd->size.nh)) 1113 if ((yy < 0) || (view.h > sd->size.nh))
1154 { 1114 {
1155 sd->g_layer_zoom.imy = yy; 1115 sd->g_layer_zoom.imy = yy;
1156 yy = 0; 1116 yy = 0;
1157 } 1117 }
1158 else if ((yy + rh) > sd->size.nh) 1118 else if ((yy + view.h) > sd->size.nh)
1159 { 1119 {
1160 sd->g_layer_zoom.imy = yy + rh - sd->size.nh; 1120 sd->g_layer_zoom.imy = yy + view.h - sd->size.nh;
1161 yy = sd->size.nh - rh; 1121 yy = sd->size.nh - view.h;
1162 } 1122 }
1163 1123
1164 sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw); 1124 sd->size.spos.x = (double)(xx + (view.w / 2)) / (double)(sd->size.nw);
1165 sd->size.spos.y = (double)(yy + (rh / 2)) / (double)(sd->size.nh); 1125 sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
1166 1126
1167 _zoom_do(obj, 1.0); 1127 _zoom_do(obj, 1.0);
1168} 1128}
@@ -1175,22 +1135,21 @@ _g_layer_zoom_start_cb(void *data,
1175 Elm_Gesture_Zoom_Info *p = event_info; 1135 Elm_Gesture_Zoom_Info *p = event_info;
1176 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1136 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1177 double marginx = 0, marginy = 0; 1137 double marginx = 0, marginy = 0;
1178 Evas_Coord rw = 0, rh = 0;
1179 int x, y, w, h; 1138 int x, y, w, h;
1139 Eina_Rect view = {};
1180 1140
1181 _efl_ui_image_zoomable_bounce_reset(obj, sd); 1141 _efl_ui_image_zoomable_bounce_reset(obj, sd);
1182 sd->zoom_g_layer = EINA_TRUE; 1142 sd->zoom_g_layer = EINA_TRUE;
1183 1143
1184 elm_interface_scrollable_freeze_set(obj, EINA_TRUE); 1144 efl_ui_scrollable_freeze_set(sd->smanager, EINA_TRUE);
1185 1145
1186 elm_photocam_image_region_get(obj, &x, &y, &w, &h); 1146 elm_photocam_image_region_get(obj, &x, &y, &w, &h);
1187 elm_interface_scrollable_content_viewport_geometry_get 1147 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1188 (obj, NULL, NULL, &rw, &rh);
1189 1148
1190 if (rw > sd->size.nw) 1149 if (view.w > sd->size.nw)
1191 marginx = (rw - sd->size.nw) / 2; 1150 marginx = (view.w - sd->size.nw) / 2;
1192 if (rh > sd->size.nh) 1151 if (view.h > sd->size.nh)
1193 marginy = (rh - sd->size.nh) / 2; 1152 marginy = (view.h - sd->size.nh) / 2;
1194 1153
1195 sd->g_layer_start = sd->zoom; 1154 sd->g_layer_start = sd->zoom;
1196 1155
@@ -1220,10 +1179,8 @@ _g_layer_zoom_end_cb(void *data,
1220{ 1179{
1221 Evas_Object *obj = data; 1180 Evas_Object *obj = data;
1222 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1181 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1223 Evas_Coord rw, rh;
1224 1182
1225 elm_interface_scrollable_content_viewport_geometry_get 1183 Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1226 (obj, NULL, NULL, &rw, &rh);
1227 sd->g_layer_start = 1.0; 1184 sd->g_layer_start = 1.0;
1228 1185
1229 if (sd->g_layer_zoom.imx || sd->g_layer_zoom.imy) 1186 if (sd->g_layer_zoom.imx || sd->g_layer_zoom.imy)
@@ -1236,13 +1193,13 @@ _g_layer_zoom_end_cb(void *data,
1236 sd->g_layer_zoom.bounce.x_end = 0; 1193 sd->g_layer_zoom.bounce.x_end = 0;
1237 sd->g_layer_zoom.bounce.y_end = 0; 1194 sd->g_layer_zoom.bounce.y_end = 0;
1238 1195
1239 if (rw > sd->size.nw && 1196 if (view.w > sd->size.nw &&
1240 rh > sd->size.nh) 1197 view.h > sd->size.nh)
1241 { 1198 {
1242 Evas_Coord pw, ph; 1199 Evas_Coord pw, ph;
1243 double z; 1200 double z;
1244 1201
1245 if ((sd->size.imw < rw) && (sd->size.imh < rh)) 1202 if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
1246 { 1203 {
1247 sd->zoom = 1; 1204 sd->zoom = 1;
1248 sd->size.nw = sd->size.imw; 1205 sd->size.nw = sd->size.imw;
@@ -1250,15 +1207,15 @@ _g_layer_zoom_end_cb(void *data,
1250 } 1207 }
1251 else 1208 else
1252 { 1209 {
1253 ph = (sd->size.imh * rw) / sd->size.imw; 1210 ph = (sd->size.imh * view.w) / sd->size.imw;
1254 if (ph > rh) 1211 if (ph > view.h)
1255 { 1212 {
1256 pw = (sd->size.imw * rh) / sd->size.imh; 1213 pw = (sd->size.imw * view.h) / sd->size.imh;
1257 ph = rh; 1214 ph = view.h;
1258 } 1215 }
1259 else 1216 else
1260 { 1217 {
1261 pw = rw; 1218 pw = view.w;
1262 } 1219 }
1263 if (sd->size.imw > sd->size.imh) 1220 if (sd->size.imw > sd->size.imh)
1264 z = (double)sd->size.imw / pw; 1221 z = (double)sd->size.imw / pw;
@@ -1269,8 +1226,8 @@ _g_layer_zoom_end_cb(void *data,
1269 sd->size.nw = pw; 1226 sd->size.nw = pw;
1270 sd->size.nh = ph; 1227 sd->size.nh = ph;
1271 } 1228 }
1272 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2; 1229 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - view.w) / 2;
1273 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - rh) / 2; 1230 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
1274 } 1231 }
1275 else 1232 else
1276 { 1233 {
@@ -1282,18 +1239,18 @@ _g_layer_zoom_end_cb(void *data,
1282 if (xx < 0) xx = 0; 1239 if (xx < 0) xx = 0;
1283 if (yy < 0) yy = 0; 1240 if (yy < 0) yy = 0;
1284 1241
1285 if (rw > sd->size.nw) 1242 if (view.w > sd->size.nw)
1286 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2; 1243 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - view.w) / 2;
1287 if ((xx + rw) > sd->size.nw) 1244 if ((xx + view.w) > sd->size.nw)
1288 xx = sd->size.nw - rw; 1245 xx = sd->size.nw - view.w;
1289 1246
1290 if (rh > sd->size.nh) 1247 if (view.h > sd->size.nh)
1291 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - rh) / 2; 1248 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
1292 if ((yy + rh) > sd->size.nh) 1249 if ((yy + view.h) > sd->size.nh)
1293 yy = sd->size.nh - rh; 1250 yy = sd->size.nh - view.h;
1294 1251
1295 sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw); 1252 sd->size.spos.x = (double)(xx + (view.w / 2)) / (double)(sd->size.nw);
1296 sd->size.spos.y = (double)(yy + (rh / 2)) / (double)(sd->size.nh); 1253 sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
1297 } 1254 }
1298 1255
1299 sd->g_layer_zoom.bounce.t_start = t; 1256 sd->g_layer_zoom.bounce.t_start = t;
@@ -1399,6 +1356,297 @@ _efl_ui_image_zoomable_efl_flipable_flip_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Z
1399 return sd->flip; 1356 return sd->flip;
1400} 1357}
1401 1358
1359static void
1360_efl_ui_image_zoomable_bar_read_and_update(Eo *obj)
1361{
1362 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1363 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1364 double vx, vy;
1365
1366 edje_object_part_drag_value_get
1367 (wd->resize_obj, "elm.dragable.vbar", NULL, &vy);
1368 edje_object_part_drag_value_get
1369 (wd->resize_obj, "elm.dragable.hbar", &vx, NULL);
1370 efl_ui_scrollbar_position_set(sd->smanager, vx, vy);
1371}
1372
1373static void
1374_efl_ui_image_zoomable_reload_cb(void *data,
1375 Evas_Object *obj EINA_UNUSED,
1376 const char *emission EINA_UNUSED,
1377 const char *source EINA_UNUSED)
1378{
1379 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1380
1381 efl_ui_scrollbar_visibility_update(sd->smanager);
1382}
1383
1384static void
1385_efl_ui_image_zoomable_vbar_drag_cb(void *data,
1386 Evas_Object *obj EINA_UNUSED,
1387 const char *emission EINA_UNUSED,
1388 const char *source EINA_UNUSED)
1389{
1390 _efl_ui_image_zoomable_bar_read_and_update(data);
1391
1392 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1393 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
1394}
1395
1396static void
1397_efl_ui_image_zoomable_vbar_press_cb(void *data,
1398 Evas_Object *obj EINA_UNUSED,
1399 const char *emission EINA_UNUSED,
1400 const char *source EINA_UNUSED)
1401{
1402 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1403 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
1404}
1405
1406static void
1407_efl_ui_image_zoomable_vbar_unpress_cb(void *data,
1408 Evas_Object *obj EINA_UNUSED,
1409 const char *emission EINA_UNUSED,
1410 const char *source EINA_UNUSED)
1411{
1412 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1413 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
1414}
1415
1416static void
1417_efl_ui_image_zoomable_edje_drag_start_cb(void *data,
1418 Evas_Object *obj EINA_UNUSED,
1419 const char *emission EINA_UNUSED,
1420 const char *source EINA_UNUSED)
1421{
1422 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1423
1424 _efl_ui_image_zoomable_bar_read_and_update(data);
1425
1426 sd->freeze_want = efl_ui_scrollable_freeze_get(sd->smanager);
1427 efl_ui_scrollable_freeze_set(sd->smanager, EINA_TRUE);
1428 efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
1429}
1430
1431static void
1432_efl_ui_image_zoomable_edje_drag_stop_cb(void *data,
1433 Evas_Object *obj EINA_UNUSED,
1434 const char *emission EINA_UNUSED,
1435 const char *source EINA_UNUSED)
1436{
1437 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1438
1439 _efl_ui_image_zoomable_bar_read_and_update(data);
1440
1441 efl_ui_scrollable_freeze_set(sd->smanager, sd->freeze_want);
1442 efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
1443}
1444
1445static void
1446_efl_ui_image_zoomable_edje_drag_cb(void *data,
1447 Evas_Object *obj EINA_UNUSED,
1448 const char *emission EINA_UNUSED,
1449 const char *source EINA_UNUSED)
1450{
1451 _efl_ui_image_zoomable_bar_read_and_update(data);
1452}
1453
1454static void
1455_efl_ui_image_zoomable_hbar_drag_cb(void *data,
1456 Evas_Object *obj EINA_UNUSED,
1457 const char *emission EINA_UNUSED,
1458 const char *source EINA_UNUSED)
1459{
1460 _efl_ui_image_zoomable_bar_read_and_update(data);
1461
1462 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1463 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
1464}
1465
1466static void
1467_efl_ui_image_zoomable_hbar_press_cb(void *data,
1468 Evas_Object *obj EINA_UNUSED,
1469 const char *emission EINA_UNUSED,
1470 const char *source EINA_UNUSED)
1471{
1472 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1473 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
1474}
1475
1476static void
1477_efl_ui_image_zoomable_hbar_unpress_cb(void *data,
1478 Evas_Object *obj EINA_UNUSED,
1479 const char *emission EINA_UNUSED,
1480 const char *source EINA_UNUSED)
1481{
1482 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1483 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
1484}
1485
1486static void
1487_efl_ui_image_zoomable_bar_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
1488{
1489 Eo *obj = data;
1490 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1491 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1492
1493 double width = 0.0, height = 0.0;
1494
1495 efl_ui_scrollbar_size_get(sd->smanager, &width, &height);
1496 edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.hbar", width, 1.0);
1497 edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.vbar", 1.0, height);
1498}
1499
1500static void
1501_efl_ui_image_zoomable_bar_pos_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
1502{
1503 Eo *obj = data;
1504 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1505 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1506
1507 double posx = 0.0, posy = 0.0;
1508
1509 efl_ui_scrollbar_position_get(sd->smanager, &posx, &posy);
1510 edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.hbar", posx, 0.0);
1511 edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.vbar", 0.0, posy);
1512}
1513
1514static void
1515_efl_ui_image_zoomable_bar_show_cb(void *data, const Efl_Event *event)
1516{
1517 Eo *obj = data;
1518 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1519 Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
1520
1521 if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
1522 edje_object_signal_emit(wd->resize_obj, "elm,action,show,hbar", "elm");
1523 else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
1524 edje_object_signal_emit(wd->resize_obj, "elm,action,show,vbar", "elm");
1525}
1526
1527static void
1528_efl_ui_image_zoomable_bar_hide_cb(void *data, const Efl_Event *event)
1529{
1530 Eo *obj = data;
1531 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1532 Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
1533
1534 if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
1535 edje_object_signal_emit(wd->resize_obj, "elm,action,hide,hbar", "elm");
1536 else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
1537 edje_object_signal_emit(wd->resize_obj, "elm,action,hide,vbar", "elm");
1538}
1539
1540static void
1541_efl_ui_image_zoomable_edje_object_attach(Eo *obj)
1542{
1543 efl_canvas_layout_signal_callback_add
1544 (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
1545 efl_canvas_layout_signal_callback_add
1546 (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
1547 obj);
1548 efl_canvas_layout_signal_callback_add
1549 (obj, "drag,set", "elm.dragable.vbar",
1550 _efl_ui_image_zoomable_edje_drag_cb, obj);
1551 efl_canvas_layout_signal_callback_add
1552 (obj, "drag,start", "elm.dragable.vbar",
1553 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1554 efl_canvas_layout_signal_callback_add
1555 (obj, "drag,stop", "elm.dragable.vbar",
1556 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1557 efl_canvas_layout_signal_callback_add
1558 (obj, "drag,step", "elm.dragable.vbar",
1559 _efl_ui_image_zoomable_edje_drag_cb, obj);
1560 efl_canvas_layout_signal_callback_add
1561 (obj, "drag,page", "elm.dragable.vbar",
1562 _efl_ui_image_zoomable_edje_drag_cb, obj);
1563 efl_canvas_layout_signal_callback_add
1564 (obj, "elm,vbar,press", "elm",
1565 _efl_ui_image_zoomable_vbar_press_cb, obj);
1566 efl_canvas_layout_signal_callback_add
1567 (obj, "elm,vbar,unpress", "elm",
1568 _efl_ui_image_zoomable_vbar_unpress_cb, obj);
1569 efl_canvas_layout_signal_callback_add
1570 (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
1571 obj);
1572 efl_canvas_layout_signal_callback_add
1573 (obj, "drag,set", "elm.dragable.hbar",
1574 _efl_ui_image_zoomable_edje_drag_cb, obj);
1575 efl_canvas_layout_signal_callback_add
1576 (obj, "drag,start", "elm.dragable.hbar",
1577 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1578 efl_canvas_layout_signal_callback_add
1579 (obj, "drag,stop", "elm.dragable.hbar",
1580 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1581 efl_canvas_layout_signal_callback_add
1582 (obj, "drag,step", "elm.dragable.hbar",
1583 _efl_ui_image_zoomable_edje_drag_cb, obj);
1584 efl_canvas_layout_signal_callback_add
1585 (obj, "drag,page", "elm.dragable.hbar",
1586 _efl_ui_image_zoomable_edje_drag_cb, obj);
1587 efl_canvas_layout_signal_callback_add
1588 (obj, "elm,hbar,press", "elm",
1589 _efl_ui_image_zoomable_hbar_press_cb, obj);
1590 efl_canvas_layout_signal_callback_add
1591 (obj, "elm,hbar,unpress", "elm",
1592 _efl_ui_image_zoomable_hbar_unpress_cb, obj);
1593}
1594
1595static void
1596_efl_ui_image_zoomable_edje_object_detach(Evas_Object *obj)
1597{
1598 efl_canvas_layout_signal_callback_del
1599 (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
1600 efl_canvas_layout_signal_callback_del
1601 (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
1602 obj);
1603 efl_canvas_layout_signal_callback_del
1604 (obj, "drag,set", "elm.dragable.vbar",
1605 _efl_ui_image_zoomable_edje_drag_cb, obj);
1606 efl_canvas_layout_signal_callback_del
1607 (obj, "drag,start", "elm.dragable.vbar",
1608 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1609 efl_canvas_layout_signal_callback_del
1610 (obj, "drag,stop", "elm.dragable.vbar",
1611 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1612 efl_canvas_layout_signal_callback_del
1613 (obj, "drag,step", "elm.dragable.vbar",
1614 _efl_ui_image_zoomable_edje_drag_cb, obj);
1615 efl_canvas_layout_signal_callback_del
1616 (obj, "drag,page", "elm.dragable.vbar",
1617 _efl_ui_image_zoomable_edje_drag_cb, obj);
1618 efl_canvas_layout_signal_callback_del
1619 (obj, "elm,vbar,press", "elm",
1620 _efl_ui_image_zoomable_vbar_press_cb, obj);
1621 efl_canvas_layout_signal_callback_del
1622 (obj, "elm,vbar,unpress", "elm",
1623 _efl_ui_image_zoomable_vbar_unpress_cb, obj);
1624 efl_canvas_layout_signal_callback_del
1625 (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
1626 obj);
1627 efl_canvas_layout_signal_callback_del
1628 (obj, "drag,set", "elm.dragable.hbar",
1629 _efl_ui_image_zoomable_edje_drag_cb, obj);
1630 efl_canvas_layout_signal_callback_del
1631 (obj, "drag,start", "elm.dragable.hbar",
1632 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1633 efl_canvas_layout_signal_callback_del
1634 (obj, "drag,stop", "elm.dragable.hbar",
1635 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1636 efl_canvas_layout_signal_callback_del
1637 (obj, "drag,step", "elm.dragable.hbar",
1638 _efl_ui_image_zoomable_edje_drag_cb, obj);
1639 efl_canvas_layout_signal_callback_del
1640 (obj, "drag,page", "elm.dragable.hbar",
1641 _efl_ui_image_zoomable_edje_drag_cb, obj);
1642 efl_canvas_layout_signal_callback_del
1643 (obj, "elm,hbar,press", "elm",
1644 _efl_ui_image_zoomable_hbar_press_cb, obj);
1645 efl_canvas_layout_signal_callback_del
1646 (obj, "elm,hbar,unpress", "elm",
1647 _efl_ui_image_zoomable_hbar_unpress_cb, obj);
1648}
1649
1402EOLIAN static void 1650EOLIAN static void
1403_efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *priv) 1651_efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *priv)
1404{ 1652{
@@ -1417,34 +1665,27 @@ _efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable
1417 elm_widget_theme_object_set 1665 elm_widget_theme_object_set
1418 (obj, edje, "photocam", "base", elm_widget_style_get(obj)); 1666 (obj, edje, "photocam", "base", elm_widget_style_get(obj));
1419 1667
1420 priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
1421 evas_object_smart_member_add(priv->hit_rect, obj);
1422 elm_widget_sub_object_add(obj, priv->hit_rect);
1423
1424 /* common scroller hit rectangle setup */
1425 evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
1426 evas_object_show(priv->hit_rect);
1427 evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
1428
1429 elm_widget_can_focus_set(obj, EINA_TRUE); 1668 elm_widget_can_focus_set(obj, EINA_TRUE);
1430 1669
1431 elm_interface_scrollable_objects_set(obj, edje, priv->hit_rect); 1670 priv->smanager = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj);
1671
1672 efl_ui_scroll_manager_mirrored_set(priv->smanager, efl_ui_mirrored_get(obj));
1673 efl_ui_scrollable_bounce_enabled_set(priv->smanager, bounce, bounce);
1432 1674
1433 elm_interface_scrollable_animate_start_cb_set(obj, _scroll_animate_start_cb); 1675 priv->pan_obj = efl_add(MY_PAN_CLASS, obj);
1434 elm_interface_scrollable_animate_stop_cb_set(obj, _scroll_animate_stop_cb);
1435 elm_interface_scrollable_drag_start_cb_set(obj, _scroll_drag_start_cb);
1436 elm_interface_scrollable_drag_stop_cb_set(obj, _scroll_drag_stop_cb);
1437 elm_interface_scrollable_scroll_cb_set(obj, _scroll_cb);
1438 1676
1439 elm_interface_scrollable_bounce_allow_set(obj, bounce, bounce); 1677 efl_ui_scroll_manager_pan_set(priv->smanager, priv->pan_obj);
1678 edje_object_part_swallow(edje, "elm.swallow.content", priv->pan_obj);
1440 1679
1441 priv->pan_obj = efl_add(MY_PAN_CLASS, evas_object_evas_get(obj));
1442 pan_data = efl_data_scope_get(priv->pan_obj, MY_PAN_CLASS); 1680 pan_data = efl_data_scope_get(priv->pan_obj, MY_PAN_CLASS);
1443 efl_data_ref(obj, MY_CLASS); 1681 efl_data_ref(obj, MY_CLASS);
1444 pan_data->wobj = obj; 1682 pan_data->wobj = obj;
1445 pan_data->wsd = priv; 1683 pan_data->wsd = priv;
1446 1684
1447 elm_interface_scrollable_extern_pan_set(obj, priv->pan_obj); 1685 evas_object_raise(edje_object_part_object_get(edje, "elm.dragable.hbar"));
1686 evas_object_raise(edje_object_part_object_get(edje, "elm.dragable.vbar"));
1687
1688 efl_event_callback_add(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
1448 1689
1449 priv->g_layer_start = 1.0; 1690 priv->g_layer_start = 1.0;
1450 priv->zoom = 1; 1691 priv->zoom = 1;
@@ -1471,8 +1712,17 @@ _efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable
1471 edje_object_size_min_calc(edje, &minw, &minh); 1712 edje_object_size_min_calc(edje, &minw, &minh);
1472 evas_object_size_hint_min_set(obj, minw, minh); 1713 evas_object_size_hint_min_set(obj, minw, minh);
1473 1714
1474 _sizing_eval(obj); 1715 _efl_ui_image_zoomable_edje_object_attach(obj);
1475 1716
1717 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED,
1718 _efl_ui_image_zoomable_bar_size_changed_cb, obj);
1719 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED,
1720 _efl_ui_image_zoomable_bar_pos_changed_cb, obj);
1721 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW,
1722 _efl_ui_image_zoomable_bar_show_cb, obj);
1723 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE,
1724 _efl_ui_image_zoomable_bar_hide_cb, obj);
1725 _sizing_eval(obj);
1476} 1726}
1477 1727
1478EOLIAN static void 1728EOLIAN static void
@@ -1500,38 +1750,38 @@ _efl_ui_image_zoomable_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Image_Zoomable
1500 ecore_timer_del(sd->long_timer); 1750 ecore_timer_del(sd->long_timer);
1501 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _zoom_anim_cb, obj); 1751 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _zoom_anim_cb, obj);
1502 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj); 1752 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
1753 efl_event_callback_del(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
1503 1754
1755 _efl_ui_image_zoomable_edje_object_detach(obj);
1756 efl_del(sd->pan_obj);
1757 sd->pan_obj = NULL;
1758 efl_del(sd->smanager);
1759 sd->smanager = NULL;
1504 efl_canvas_group_del(efl_super(obj, MY_CLASS)); 1760 efl_canvas_group_del(efl_super(obj, MY_CLASS));
1505} 1761}
1506 1762
1507EOLIAN static void 1763EOLIAN static void
1508_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Position2D pos) 1764_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sdi EINA_UNUSED, Eina_Position2D pos)
1509{ 1765{
1510 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y)) 1766 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
1511 return; 1767 return;
1512 1768
1513 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos); 1769 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
1514 efl_gfx_position_set(sd->hit_rect, pos);
1515} 1770}
1516 1771
1517EOLIAN static void 1772EOLIAN static void
1518_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Size2D sz) 1773_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Eina_Size2D sz)
1519{ 1774{
1520 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h)) 1775 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
1521 return; 1776 return;
1522 1777
1523 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz); 1778 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
1524 efl_gfx_size_set(sd->hit_rect, sz);
1525} 1779}
1526 1780
1527EOLIAN static void 1781EOLIAN static void
1528_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Evas_Object *member) 1782_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Evas_Object *member)
1529{ 1783{
1530
1531 efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member); 1784 efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member);
1532
1533 if (sd->hit_rect)
1534 evas_object_raise(sd->hit_rect);
1535} 1785}
1536 1786
1537EOLIAN static Eo * 1787EOLIAN static Eo *
@@ -1569,6 +1819,28 @@ _efl_ui_image_zoomable_efl_canvas_layout_group_group_size_max_get(Eo *obj EINA_U
1569 return EINA_SIZE2D(0, 0); 1819 return EINA_SIZE2D(0, 0);
1570} 1820}
1571 1821
1822EOLIAN static Eina_Bool
1823_efl_ui_image_zoomable_efl_canvas_layout_signal_signal_callback_add(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
1824{
1825 Eina_Bool ok;
1826 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
1827
1828 ok = efl_canvas_layout_signal_callback_add(wd->resize_obj, emission, source, func_cb, data);
1829
1830 return ok;
1831}
1832
1833EOLIAN static Eina_Bool
1834_efl_ui_image_zoomable_efl_canvas_layout_signal_signal_callback_del(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
1835{
1836 Eina_Bool ok;
1837 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
1838
1839 ok = efl_canvas_layout_signal_callback_del(wd->resize_obj, emission, source, func_cb, data);
1840
1841 return ok;
1842}
1843
1572static Eina_Bool 1844static Eina_Bool
1573_img_proxy_set(Evas_Object *obj, Efl_Ui_Image_Zoomable_Data *sd, 1845_img_proxy_set(Evas_Object *obj, Efl_Ui_Image_Zoomable_Data *sd,
1574 const char *file, const Eina_File *f, const char *group, 1846 const char *file, const Eina_File *f, const char *group,
@@ -1960,9 +2232,11 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1960 double z; 2232 double z;
1961 Eina_List *l; 2233 Eina_List *l;
1962 Efl_Ui_Image_Zoomable_Grid *g, *g_zoom = NULL; 2234 Efl_Ui_Image_Zoomable_Grid *g, *g_zoom = NULL;
1963 Evas_Coord pw, ph, rx, ry, rw, rh; 2235 Evas_Coord pw, ph;
1964 int zoom_changed = 0, started = 0; 2236 int zoom_changed = 0, started = 0;
1965 Eina_Bool an = EINA_FALSE; 2237 Eina_Bool an = EINA_FALSE;
2238 Eina_Rect view = {};
2239 Eina_Position2D pos = {};
1966 2240
1967 if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0); 2241 if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0);
1968 if (EINA_DBL_EQ(zoom, sd->zoom)) return; 2242 if (EINA_DBL_EQ(zoom, sd->zoom)) return;
@@ -1970,10 +2244,9 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1970 sd->zoom = zoom; 2244 sd->zoom = zoom;
1971 sd->size.ow = sd->size.w; 2245 sd->size.ow = sd->size.w;
1972 sd->size.oh = sd->size.h; 2246 sd->size.oh = sd->size.h;
1973 elm_interface_scrollable_content_pos_get(obj, &rx, &ry); 2247 pos = efl_ui_scrollable_content_pos_get(sd->smanager);
1974 elm_interface_scrollable_content_viewport_geometry_get 2248 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1975 (obj, NULL, NULL, &rw, &rh); 2249 if ((view.w <= 0) || (view.h <= 0)) return;
1976 if ((rw <= 0) || (rh <= 0)) return;
1977 2250
1978 if (sd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL) 2251 if (sd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
1979 { 2252 {
@@ -1989,15 +2262,15 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1989 } 2262 }
1990 else 2263 else
1991 { 2264 {
1992 ph = (sd->size.imh * rw) / sd->size.imw; 2265 ph = (sd->size.imh * view.w) / sd->size.imw;
1993 if (ph > rh) 2266 if (ph > view.h)
1994 { 2267 {
1995 pw = (sd->size.imw * rh) / sd->size.imh; 2268 pw = (sd->size.imw * view.h) / sd->size.imh;
1996 ph = rh; 2269 ph = view.h;
1997 } 2270 }
1998 else 2271 else
1999 { 2272 {
2000 pw = rw; 2273 pw = view.w;
2001 } 2274 }
2002 if (sd->size.imw > sd->size.imh) 2275 if (sd->size.imw > sd->size.imh)
2003 z = (double)sd->size.imw / pw; 2276 z = (double)sd->size.imw / pw;
@@ -2019,15 +2292,15 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2019 } 2292 }
2020 else 2293 else
2021 { 2294 {
2022 ph = (sd->size.imh * rw) / sd->size.imw; 2295 ph = (sd->size.imh * view.w) / sd->size.imw;
2023 if (ph < rh) 2296 if (ph < view.h)
2024 { 2297 {
2025 pw = (sd->size.imw * rh) / sd->size.imh; 2298 pw = (sd->size.imw * view.h) / sd->size.imh;
2026 ph = rh; 2299 ph = view.h;
2027 } 2300 }
2028 else 2301 else
2029 { 2302 {
2030 pw = rw; 2303 pw = view.w;
2031 } 2304 }
2032 if (sd->size.imw > sd->size.imh) 2305 if (sd->size.imw > sd->size.imh)
2033 z = (double)sd->size.imw / pw; 2306 z = (double)sd->size.imw / pw;
@@ -2047,7 +2320,7 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2047 sd->size.nw = 0; 2320 sd->size.nw = 0;
2048 sd->size.nh = 0; 2321 sd->size.nh = 0;
2049 } 2322 }
2050 else if ((sd->size.imw < rw) && (sd->size.imh < rh)) 2323 else if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
2051 { 2324 {
2052 if (!EINA_DBL_EQ(sd->zoom, 1)) zoom_changed = 1; 2325 if (!EINA_DBL_EQ(sd->zoom, 1)) zoom_changed = 1;
2053 sd->zoom = 1; 2326 sd->zoom = 1;
@@ -2056,14 +2329,14 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2056 } 2329 }
2057 else 2330 else
2058 { 2331 {
2059 ph = (sd->size.imh * rw) / sd->size.imw; 2332 ph = (sd->size.imh * view.w) / sd->size.imw;
2060 if (ph > rh) 2333 if (ph > view.h)
2061 { 2334 {
2062 pw = (sd->size.imw * rh) / sd->size.imh; 2335 pw = (sd->size.imw * view.h) / sd->size.imh;
2063 ph = rh; 2336 ph = view.h;
2064 } 2337 }
2065 else 2338 else
2066 pw = rw; 2339 pw = view.w;
2067 if (sd->size.imw > sd->size.imh) 2340 if (sd->size.imw > sd->size.imh)
2068 z = (double)sd->size.imw / pw; 2341 z = (double)sd->size.imw / pw;
2069 else 2342 else
@@ -2125,16 +2398,16 @@ done:
2125 sd->t_end = sd->t_start + _elm_config->zoom_friction; 2398 sd->t_end = sd->t_start + _elm_config->zoom_friction;
2126 if ((sd->size.w > 0) && (sd->size.h > 0)) 2399 if ((sd->size.w > 0) && (sd->size.h > 0))
2127 { 2400 {
2128 sd->size.spos.x = (double)(rx + (rw / 2)) / (double)sd->size.w; 2401 sd->size.spos.x = (double)(pos.x + (view.w / 2)) / (double)sd->size.w;
2129 sd->size.spos.y = (double)(ry + (rh / 2)) / (double)sd->size.h; 2402 sd->size.spos.y = (double)(pos.y + (view.h / 2)) / (double)sd->size.h;
2130 } 2403 }
2131 else 2404 else
2132 { 2405 {
2133 sd->size.spos.x = 0.5; 2406 sd->size.spos.x = 0.5;
2134 sd->size.spos.y = 0.5; 2407 sd->size.spos.y = 0.5;
2135 } 2408 }
2136 if (rw > sd->size.w) sd->size.spos.x = 0.5; 2409 if (view.w > sd->size.w) sd->size.spos.x = 0.5;
2137 if (rh > sd->size.h) sd->size.spos.y = 0.5; 2410 if (view.h > sd->size.h) sd->size.spos.y = 0.5;
2138 if (sd->size.spos.x > 1.0) sd->size.spos.x = 1.0; 2411 if (sd->size.spos.x > 1.0) sd->size.spos.x = 1.0;
2139 if (sd->size.spos.y > 1.0) sd->size.spos.y = 1.0; 2412 if (sd->size.spos.y > 1.0) sd->size.spos.y = 1.0;
2140 2413
@@ -2212,20 +2485,18 @@ _efl_ui_image_zoomable_efl_gfx_view_view_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Im
2212} 2485}
2213 2486
2214EOLIAN static Eina_Rect 2487EOLIAN static Eina_Rect
2215_efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd) 2488_efl_ui_image_zoomable_image_region_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Data *sd)
2216{ 2489{
2217 Evas_Coord sx, sy, sw, sh;
2218 Eina_Rect region = {}; 2490 Eina_Rect region = {};
2219 2491
2220 elm_interface_scrollable_content_pos_get((Eo *)obj, &sx, &sy); 2492 Eina_Position2D pos = efl_ui_scrollable_content_pos_get(sd->smanager);
2221 elm_interface_scrollable_content_viewport_geometry_get 2493 Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
2222 ((Eo *)obj, NULL, NULL, &sw, &sh);
2223 2494
2224 if (sd->size.w > 0) 2495 if (sd->size.w > 0)
2225 { 2496 {
2226 region.x = (sd->size.imw * sx) / sd->size.w; 2497 region.x = (sd->size.imw * pos.x) / sd->size.w;
2227 if (region.x > sd->size.imw) region.x = sd->size.imw; 2498 if (region.x > sd->size.imw) region.x = sd->size.imw;
2228 region.w = (sd->size.imw * sw) / sd->size.w; 2499 region.w = (sd->size.imw * view.w) / sd->size.w;
2229 if (region.w > sd->size.imw) region.w = sd->size.imw; 2500 if (region.w > sd->size.imw) region.w = sd->size.imw;
2230 else if (region.w < 0) 2501 else if (region.w < 0)
2231 region.w = 0; 2502 region.w = 0;
@@ -2233,9 +2504,9 @@ _efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
2233 2504
2234 if (sd->size.h > 0) 2505 if (sd->size.h > 0)
2235 { 2506 {
2236 region.y = (sd->size.imh * sy) / sd->size.h; 2507 region.y = (sd->size.imh * pos.y) / sd->size.h;
2237 if (region.y > sd->size.imh) region.y = sd->size.imh; 2508 if (region.y > sd->size.imh) region.y = sd->size.imh;
2238 region.h = (sd->size.imh * sh) / sd->size.h; 2509 region.h = (sd->size.imh * view.h) / sd->size.h;
2239 if (region.h > sd->size.imh) region.h = sd->size.imh; 2510 if (region.h > sd->size.imh) region.h = sd->size.imh;
2240 else if (region.h < 0) 2511 else if (region.h < 0)
2241 region.h = 0; 2512 region.h = 0;
@@ -2262,19 +2533,19 @@ _efl_ui_image_zoomable_image_region_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd,
2262 _efl_ui_image_zoomable_bounce_reset(obj, sd); 2533 _efl_ui_image_zoomable_bounce_reset(obj, sd);
2263 _efl_ui_image_zoomable_zoom_reset(obj, sd); 2534 _efl_ui_image_zoomable_zoom_reset(obj, sd);
2264 2535
2265 elm_interface_scrollable_content_region_show(obj, rx, ry, rw, rh); 2536 efl_ui_scrollable_show(sd->smanager, EINA_RECT(rx, ry, rw, rh));
2266} 2537}
2267 2538
2268EOLIAN static void 2539EOLIAN static void
2269_efl_ui_image_zoomable_elm_interface_scrollable_region_bring_in(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) 2540_efl_ui_image_zoomable_efl_ui_scrollable_interactive_scroll(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Rect rc)
2270{ 2541{
2271 int rx, ry, rw, rh; 2542 int rx, ry, rw, rh;
2272 2543
2273 if ((sd->size.imw < 1) || (sd->size.imh < 1)) return; 2544 if ((sd->size.imw < 1) || (sd->size.imh < 1)) return;
2274 rx = (x * sd->size.w) / sd->size.imw; 2545 rx = (rc.x * sd->size.w) / sd->size.imw;
2275 ry = (y * sd->size.h) / sd->size.imh; 2546 ry = (rc.y * sd->size.h) / sd->size.imh;
2276 rw = (w * sd->size.w) / sd->size.imw; 2547 rw = (rc.w * sd->size.w) / sd->size.imw;
2277 rh = (h * sd->size.h) / sd->size.imh; 2548 rh = (rc.h * sd->size.h) / sd->size.imh;
2278 if (rw < 1) rw = 1; 2549 if (rw < 1) rw = 1;
2279 if (rh < 1) rh = 1; 2550 if (rh < 1) rh = 1;
2280 if ((rx + rw) > sd->size.w) rx = sd->size.w - rw; 2551 if ((rx + rw) > sd->size.w) rx = sd->size.w - rw;
@@ -2283,7 +2554,7 @@ _efl_ui_image_zoomable_elm_interface_scrollable_region_bring_in(Eo *obj, Efl_Ui_
2283 _efl_ui_image_zoomable_bounce_reset(obj, sd); 2554 _efl_ui_image_zoomable_bounce_reset(obj, sd);
2284 _efl_ui_image_zoomable_zoom_reset(obj, sd); 2555 _efl_ui_image_zoomable_zoom_reset(obj, sd);
2285 2556
2286 elm_interface_scrollable_region_bring_in(efl_super(obj, MY_CLASS), rx, ry, rw, rh); 2557 efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(rx, ry, rw, rh));
2287} 2558}
2288 2559
2289EOLIAN static void 2560EOLIAN static void
@@ -2915,7 +3186,8 @@ elm_photocam_image_region_bring_in(Evas_Object *obj,
2915 int h EINA_UNUSED) 3186 int h EINA_UNUSED)
2916{ 3187{
2917 ELM_PHOTOCAM_CHECK(obj); 3188 ELM_PHOTOCAM_CHECK(obj);
2918 elm_interface_scrollable_region_bring_in(obj, x, y, w, h); 3189 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
3190 efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(x, y, w, h));
2919} 3191}
2920 3192
2921EAPI void 3193EAPI void
@@ -2925,7 +3197,7 @@ elm_photocam_bounce_set(Evas_Object *obj,
2925{ 3197{
2926 ELM_PHOTOCAM_CHECK(obj); 3198 ELM_PHOTOCAM_CHECK(obj);
2927 3199
2928 elm_interface_scrollable_bounce_allow_set(obj, h_bounce, v_bounce); 3200 efl_ui_scrollable_bounce_enabled_set(obj, h_bounce, v_bounce);
2929} 3201}
2930 3202
2931EAPI void 3203EAPI void
@@ -2935,7 +3207,7 @@ elm_photocam_bounce_get(const Evas_Object *obj,
2935{ 3207{
2936 ELM_PHOTOCAM_CHECK(obj); 3208 ELM_PHOTOCAM_CHECK(obj);
2937 3209
2938 elm_interface_scrollable_bounce_allow_get((Eo *)obj, h_bounce, v_bounce); 3210 efl_ui_scrollable_bounce_enabled_get((Eo *)obj, h_bounce, v_bounce);
2939} 3211}
2940 3212
2941EAPI void 3213EAPI void
diff --git a/src/lib/elementary/efl_ui_image_zoomable.eo b/src/lib/elementary/efl_ui_image_zoomable.eo
index c214f9abe8..142faf612d 100644
--- a/src/lib/elementary/efl_ui_image_zoomable.eo
+++ b/src/lib/elementary/efl_ui_image_zoomable.eo
@@ -1,6 +1,6 @@
1class Efl.Ui.Image_Zoomable (Elm.Widget, Efl.Ui.Image, Efl.Ui.Zoom, 1class Efl.Ui.Image_Zoomable (Elm.Widget, Efl.Ui.Image, Efl.Ui.Zoom,
2 Elm.Interface_Scrollable, 2 Efl.Ui.Scrollable.Interactive,
3 Efl.Ui.Scrollable) 3 Efl.Ui.Scrollbar)
4{ 4{
5 [[Elementary Image Zoomable class]] 5 [[Elementary Image Zoomable class]]
6 legacy_prefix: elm_photocam; 6 legacy_prefix: elm_photocam;
@@ -61,13 +61,15 @@ class Efl.Ui.Image_Zoomable (Elm.Widget, Efl.Ui.Image, Efl.Ui.Zoom,
61 Elm.Widget.theme_apply; 61 Elm.Widget.theme_apply;
62 Elm.Widget.on_focus_update; 62 Elm.Widget.on_focus_update;
63 Elm.Widget.widget_event; 63 Elm.Widget.widget_event;
64 Elm.Interface_Scrollable.region_bring_in; 64 Efl.Ui.Scrollable.Interactive.scroll;
65 Elm.Interface.Atspi_Widget_Action.elm_actions { get; } 65 Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
66 Efl.File.file { get; set; } 66 Efl.File.file { get; set; }
67 Efl.Orientation.orientation { get; set; } 67 Efl.Orientation.orientation { get; set; }
68 Efl.Flipable.flip { get; set; } 68 Efl.Flipable.flip { get; set; }
69 Efl.Canvas.Layout_Group.group_size_min { get; } 69 Efl.Canvas.Layout_Group.group_size_min { get; }
70 Efl.Canvas.Layout_Group.group_size_max { get; } 70 Efl.Canvas.Layout_Group.group_size_max { get; }
71 Efl.Canvas.Layout_Signal.signal_callback_add;
72 Efl.Canvas.Layout_Signal.signal_callback_del;
71 //Efl.Canvas.Layout_Group.group_data { get; } 73 //Efl.Canvas.Layout_Group.group_data { get; }
72 } 74 }
73 events { 75 events {
diff --git a/src/lib/elementary/efl_ui_image_zoomable_pan.eo b/src/lib/elementary/efl_ui_image_zoomable_pan.eo
index e448a144bf..5a60bb4ef5 100644
--- a/src/lib/elementary/efl_ui_image_zoomable_pan.eo
+++ b/src/lib/elementary/efl_ui_image_zoomable_pan.eo
@@ -1,4 +1,4 @@
1class Efl.Ui.Image_Zoomable_Pan (Elm.Pan) 1class Efl.Ui.Image_Zoomable_Pan (Efl.Ui.Pan)
2{ 2{
3 [[Elementary photocom pan class]] 3 [[Elementary photocom pan class]]
4 legacy_prefix: elm_photocam_pan; 4 legacy_prefix: elm_photocam_pan;
@@ -8,10 +8,10 @@ class Efl.Ui.Image_Zoomable_Pan (Elm.Pan)
8 Efl.Gfx.position { set; } 8 Efl.Gfx.position { set; }
9 Efl.Gfx.size { set; } 9 Efl.Gfx.size { set; }
10 Efl.Canvas.Group.group_calculate; 10 Efl.Canvas.Group.group_calculate;
11 Elm.Pan.content_size { get; } 11 Efl.Ui.Pan.content_size { get; }
12 Elm.Pan.pos { get; set; } 12 Efl.Ui.Pan.position { get; set; }
13 Elm.Pan.pos_min { get; } 13 Efl.Ui.Pan.position_min { get; }
14 Elm.Pan.pos_max { get; } 14 Efl.Ui.Pan.position_max { get; }
15 } 15 }
16 events { 16 events {
17 load; [[Called when load started]] 17 load; [[Called when load started]]
diff --git a/src/lib/elementary/efl_ui_image_zoomable_private.h b/src/lib/elementary/efl_ui_image_zoomable_private.h
index bfe58ef93d..1f867a9a4c 100644
--- a/src/lib/elementary/efl_ui_image_zoomable_private.h
+++ b/src/lib/elementary/efl_ui_image_zoomable_private.h
@@ -59,10 +59,10 @@ struct _Efl_Ui_Image_Zoomable_Grid
59 59
60struct _Efl_Ui_Image_Zoomable_Data 60struct _Efl_Ui_Image_Zoomable_Data
61{ 61{
62 Evas_Object *hit_rect; 62 Eo *smanager;
63 Eo *pan_obj;
63 Evas_Object *g_layer; 64 Evas_Object *g_layer;
64 65
65 Evas_Object *pan_obj;
66 66
67 Evas_Coord pan_x, pan_y, minw, minh; 67 Evas_Coord pan_x, pan_y, minw, minh;
68 68
@@ -109,11 +109,7 @@ struct _Efl_Ui_Image_Zoomable_Data
109 } spos; 109 } spos;
110 } size; 110 } size;
111 111
112 struct 112 Eina_Rect show;
113 {
114 Eina_Bool show : 1;
115 Evas_Coord x, y, w, h;
116 } show;
117 113
118 int tsize; 114 int tsize;
119 Evas_Object *img; /* low res version of image (scale down == 8) */ 115 Evas_Object *img; /* low res version of image (scale down == 8) */
@@ -147,11 +143,13 @@ struct _Efl_Ui_Image_Zoomable_Data
147 Eina_Bool orientation_changed : 1; 143 Eina_Bool orientation_changed : 1;
148 Eina_Bool play : 1; 144 Eina_Bool play : 1;
149 Eina_Bool anim : 1; 145 Eina_Bool anim : 1;
146 Eina_Bool freeze_want : 1;
147 Eina_Bool show_item: 1;
150}; 148};
151 149
152struct _Efl_Ui_Image_Zoomable_Pan_Data 150struct _Efl_Ui_Image_Zoomable_Pan_Data
153{ 151{
154 Evas_Object *wobj; 152 Eo *wobj;
155 Efl_Ui_Image_Zoomable_Data *wsd; 153 Efl_Ui_Image_Zoomable_Data *wsd;
156}; 154};
157 155
diff --git a/src/lib/elementary/efl_ui_pan.c b/src/lib/elementary/efl_ui_pan.c
new file mode 100644
index 0000000000..24e2e3612b
--- /dev/null
+++ b/src/lib/elementary/efl_ui_pan.c
@@ -0,0 +1,208 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6#include "elm_priv.h"
7#include "efl_ui_widget_pan.h"
8
9#define MY_CLASS EFL_UI_PAN_CLASS
10#define MY_CLASS_NAME "Efl_Ui_Pan"
11
12#define EFL_UI_PAN_DATA_GET(o, sd) \
13 Efl_Ui_Pan_Data *sd = efl_data_scope_safe_get(o, MY_CLASS)
14
15#define EFL_UI_PAN_DATA_GET_OR_RETURN(o, ptr, ...) \
16 EFL_UI_PAN_DATA_GET(o, ptr); \
17 if (EINA_UNLIKELY(!ptr)) \
18 { \
19 CRI("No widget data for object %p (%s)", \
20 o, evas_object_type_get(o)); \
21 return __VA_ARGS__; \
22 }
23
24static void
25_efl_ui_pan_update(Efl_Ui_Pan_Data *psd)
26{
27 efl_gfx_position_set(psd->content, EINA_POSITION2D(psd->x - psd->px, psd->y - psd->py));
28}
29
30EOLIAN static void
31_efl_ui_pan_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Pan_Data *psd EINA_UNUSED)
32{
33 efl_canvas_group_add(efl_super(obj, MY_CLASS));
34}
35
36EOLIAN static void
37_efl_ui_pan_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
38{
39 efl_content_set(obj, NULL);
40 efl_canvas_group_del(efl_super(obj, MY_CLASS));
41}
42
43EOLIAN static void
44_efl_ui_pan_efl_gfx_position_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
45{
46 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
47 return;
48
49 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
50
51 psd->x = pos.x;
52 psd->y = pos.y;
53
54 _efl_ui_pan_update(psd);
55}
56
57EOLIAN static void
58_efl_ui_pan_efl_gfx_size_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Size2D sz)
59{
60 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
61 return;
62
63 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
64
65 psd->w = sz.w;
66 psd->h = sz.h;
67
68 _efl_ui_pan_update(psd);
69 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, NULL);
70}
71
72EOLIAN static void
73_efl_ui_pan_efl_gfx_visible_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Bool vis)
74{
75 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
76 return;
77
78 efl_gfx_visible_set(efl_super(obj, MY_CLASS), vis);
79 if (psd->content) efl_gfx_visible_set(psd->content, vis);
80}
81
82EOLIAN static void
83_efl_ui_pan_position_set(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
84{
85 if ((pos.x == psd->px) && (pos.y == psd->py)) return;
86 psd->px = pos.x;
87 psd->py = pos.y;
88
89 _efl_ui_pan_update(psd);
90 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
91}
92
93EOLIAN static Eina_Position2D
94_efl_ui_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
95{
96 return EINA_POSITION2D(psd->px, psd->py);
97}
98
99EOLIAN static Eina_Position2D
100_efl_ui_pan_position_max_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
101{
102 Eina_Position2D pos = { 0, 0};
103 if (psd->w < psd->content_w) pos.x = psd->content_w - psd->w;
104 if (psd->h < psd->content_h) pos.y = psd->content_h - psd->h;
105
106 return pos;
107}
108
109EOLIAN static Eina_Position2D
110_efl_ui_pan_position_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
111{
112 return EINA_POSITION2D(0 ,0);
113}
114
115EOLIAN static Eina_Size2D
116_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
117{
118 return EINA_SIZE2D(psd->content_w, psd->content_h);
119}
120
121EOLIAN static Eo *
122_efl_ui_pan_efl_object_constructor(Eo *obj, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
123{
124 efl_canvas_group_clipped_set(obj, EINA_TRUE);
125 obj = efl_constructor(efl_super(obj, MY_CLASS));
126
127 return obj;
128}
129
130static void
131_efl_ui_pan_content_del_cb(void *data,
132 Evas *e EINA_UNUSED,
133 Evas_Object *obj EINA_UNUSED,
134 void *event_info EINA_UNUSED)
135{
136 Evas_Object *pobj = data;
137 EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
138
139 psd->content = NULL;
140 psd->content_w = psd->content_h = psd->px = psd->py = 0;
141 efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
142}
143
144static void
145_efl_ui_pan_content_resize_cb(void *data,
146 Evas *e EINA_UNUSED,
147 Evas_Object *obj EINA_UNUSED,
148 void *event_info EINA_UNUSED)
149{
150 Evas_Object *pobj = data;
151 EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
152
153 Eina_Size2D sz = efl_gfx_size_get(psd->content);
154 if ((sz.w != psd->content_w) || (sz.h != psd->content_h))
155 {
156 psd->content_w = sz.w;
157 psd->content_h = sz.h;
158 _efl_ui_pan_update(psd);
159 }
160 efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
161}
162
163EOLIAN static Eina_Bool
164_efl_ui_pan_efl_container_content_set(Evas_Object *obj, Efl_Ui_Pan_Data *psd, Evas_Object *content)
165{
166 Eina_Size2D sz;
167
168 if (content == psd->content) return EINA_TRUE;
169 if (psd->content)
170 {
171 efl_canvas_group_member_del(obj, psd->content);
172 evas_object_event_callback_del_full
173 (psd->content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
174 evas_object_event_callback_del_full
175 (psd->content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb,
176 obj);
177 psd->content = NULL;
178 psd->content_w = psd->content_h = psd->px = psd->py = 0;
179 }
180 if (!content) goto end;
181
182 psd->content = content;
183 efl_canvas_group_member_add(obj, content);
184 sz = efl_gfx_size_get(psd->content);
185 psd->content_w = sz.w;
186 psd->content_h = sz.h;
187 evas_object_event_callback_add
188 (content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
189 evas_object_event_callback_add
190 (content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb, obj);
191
192 if (evas_object_visible_get(obj))
193 evas_object_show(psd->content);
194 else
195 evas_object_hide(psd->content);
196
197 _efl_ui_pan_update(psd);
198
199end:
200 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
201 return EINA_TRUE;
202}
203
204/* Internal EO APIs and hidden overrides */
205#define EFL_UI_PAN_EXTRA_OPS \
206 EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_pan)
207
208#include "efl_ui_pan.eo.c"
diff --git a/src/lib/elementary/efl_ui_pan.eo b/src/lib/elementary/efl_ui_pan.eo
new file mode 100644
index 0000000000..6c6690f013
--- /dev/null
+++ b/src/lib/elementary/efl_ui_pan.eo
@@ -0,0 +1,53 @@
1class Efl.Ui.Pan (Efl.Canvas.Group,
2 Efl.Container)
3{
4 [[Elementary pan class]]
5 methods {
6 @property position {
7 [[Position]]
8 set {
9 }
10 get {
11 }
12 values {
13 position: Eina.Position2D;
14 }
15 }
16 @property content_size {
17 [[Content size]]
18 get {
19 }
20 values {
21 size: Eina.Size2D;
22 }
23 }
24 @property position_min {
25 [[The minimal position to scroll]]
26 get {
27 }
28 values {
29 pos: Eina.Position2D;
30 }
31 }
32 @property position_max {
33 [[The maximal position to scroll]]
34 get {
35 }
36 values {
37 pos: Eina.Position2D;
38 }
39 }
40 }
41 implements {
42 Efl.Object.constructor;
43 Efl.Gfx.visible { set; }
44 Efl.Gfx.position { set; }
45 Efl.Gfx.size { set; }
46 Efl.Container.content { set; }
47 }
48 events {
49 content,changed; [[Called when pan content changed]]
50 viewport,changed; [[Called when pan viewport changed]]
51 position,changed; [[Called when pan position changed]]
52 }
53}
diff --git a/src/lib/elementary/efl_ui_scroll_manager.c b/src/lib/elementary/efl_ui_scroll_manager.c
new file mode 100644
index 0000000000..3e38665d08
--- /dev/null
+++ b/src/lib/elementary/efl_ui_scroll_manager.c
@@ -0,0 +1,2491 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6#include "elm_priv.h"
7#include "efl_ui_widget_scroll_manager.h"
8
9#define MY_CLASS EFL_UI_SCROLL_MANAGER_CLASS
10#define MY_CLASS_NAME "Efl_Ui_Scroll_Manager"
11
12#define ELM_ANIMATOR_CONNECT(Obj, Bool, Callback, Data) \
13 efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
14 efl_event_callback_add(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
15 Bool = 1;
16
17#define ELM_ANIMATOR_DISCONNECT(Obj, Bool, Callback, Data) \
18 efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
19 Bool = 0;
20
21
22static double
23_scroll_manager_linear_interp(void *data EINA_UNUSED, double progress)
24{
25 return progress;
26}
27static double
28_scroll_manager_accel_interp(void *data EINA_UNUSED, double progress)
29{
30 return progress * progress;
31}
32static double
33_scroll_manager_decel_interp(void *data EINA_UNUSED, double progress)
34{
35 return (1.0 - (1.0 - progress) * (1.0 - progress));
36}
37
38static Interpolator
39_scroll_manager_interp_get(InterpType interp)
40{
41 if (interp == ACCEL)
42 return _scroll_manager_accel_interp;
43 else if (interp == DECEL)
44 return _scroll_manager_decel_interp;
45 return _scroll_manager_linear_interp;
46}
47
48// Prototypes --- //
49
50// ANIMATORS - tick function
51static void _efl_ui_scroll_manager_hold_animator(void *data, const Efl_Event *event);
52static void _efl_ui_scroll_manager_on_hold_animator(void *data, const Efl_Event *event);
53static void _efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event);
54static void _efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event);
55static void _efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event);
56static void _efl_ui_scroll_manager_bounce_x_animator(void *data, const Efl_Event *event);
57
58// ANIMATORS - manipulate function
59static void _scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
60static Eina_Bool _scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
61
62static void _scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
63static Eina_Bool _scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
64
65/// Constant scrolling
66static void _scroll_manager_scrollto_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cx, Evas_Coord cy, Evas_Coord x, Evas_Coord y, double tx, double ty, InterpType interp);
67static Eina_Bool _scroll_manager_scrollto_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
68static void _scroll_manager_scrollto_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cx, Evas_Coord x, double t, InterpType interp);
69static Eina_Bool _scroll_manager_scrollto_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
70static void _scroll_manager_scrollto_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cy, Evas_Coord y, double t, InterpType interp);
71static Eina_Bool _scroll_manager_scrollto_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
72
73/// Flicking
74static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
75
76// Bounce
77static void _scroll_manager_bounce_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx);
78static Eina_Bool _scroll_manager_bounce_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
79static void _scroll_manager_bounce_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vy);
80static Eina_Bool _scroll_manager_bounce_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
81
82// Util
83static void _scroll_manager_scrollto(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
84static void _scroll_manager_animators_drop(Evas_Object *obj);
85
86// ETC
87static void _efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x,Evas_Coord y);
88// --- Prototypes //
89
90static inline double
91_round(double value, int pos)
92{
93 double temp;
94
95 temp = value * pow( 10, pos );
96 temp = floor( temp + 0.5 );
97 temp *= pow( 10, -pos );
98
99 return temp;
100}
101
102static inline Eina_Bool
103_inside_range(int value, int min, int max)
104{
105 if (value < min) return EINA_FALSE;
106 if (value > max) return EINA_FALSE;
107 return EINA_TRUE;
108}
109
110#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(o, ptr) \
111 Efl_Ui_Scroll_Manager_Data *ptr = \
112 (!efl_isa(o, MY_CLASS) ? NULL : \
113 efl_data_scope_safe_get(o, MY_CLASS)); \
114 if (!ptr) \
115 { \
116 CRI("No interface data for object %p (%s)", \
117 o, evas_object_type_get(o)); \
118 return; \
119 }
120
121#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
122 Efl_Ui_Scroll_Manager_Data *ptr = \
123 (!efl_isa(o, MY_CLASS) ? NULL : \
124 efl_data_scope_safe_get(o, MY_CLASS)); \
125 if (!ptr) \
126 { \
127 CRI("No interface data for object %p (%s)", \
128 o, evas_object_type_get(o)); \
129 return val; \
130 }
131
132static void _efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj);
133
134#define LEFT 0
135#define RIGHT 1
136#define UP 2
137#define DOWN 3
138#define EVTIME 1
139//#define SCROLLDBG 1
140/* smoothness debug calls - for debugging how much smooth your app is */
141
142static inline Eina_Bool
143_scroll_manager_thumb_scrollable_get(Efl_Ui_Scroll_Manager_Data *sd)
144{
145 if (!sd) return EINA_FALSE;
146 if ((sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) &&
147 (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL))
148 return EINA_FALSE;
149
150 if (!_elm_config->thumbscroll_enable) return EINA_FALSE;
151
152 return EINA_TRUE;
153}
154
155static inline Eina_Bool
156_scroll_manager_animating_get(Efl_Ui_Scroll_Manager_Data *sd)
157{
158 if (!sd) return EINA_FALSE;
159 return ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
160 (sd->scrollto.x.animator) || (sd->scrollto.y.animator));
161}
162
163static void
164_efl_ui_scroll_manager_drag_start(Efl_Ui_Scroll_Manager_Data *sd)
165{
166 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
167}
168
169static void
170_efl_ui_scroll_manager_drag_stop(Efl_Ui_Scroll_Manager_Data *sd)
171{
172 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
173}
174
175static void
176_efl_ui_scroll_manager_anim_start(Efl_Ui_Scroll_Manager_Data *sd)
177{
178 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_START, NULL);
179}
180
181static void
182_efl_ui_scroll_manager_anim_stop(Efl_Ui_Scroll_Manager_Data *sd)
183{
184 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_STOP, NULL);
185}
186
187static void
188_efl_ui_scroll_manager_scroll(Efl_Ui_Scroll_Manager_Data *sd)
189{
190 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL, NULL);
191}
192
193static void
194_efl_ui_scroll_manager_scroll_up(Efl_Ui_Scroll_Manager_Data *sd)
195{
196 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_UP, NULL);
197}
198
199static void
200_efl_ui_scroll_manager_scroll_down(Efl_Ui_Scroll_Manager_Data *sd)
201{
202 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DOWN, NULL);
203}
204
205static void
206_efl_ui_scroll_manager_scroll_left(Efl_Ui_Scroll_Manager_Data *sd)
207{
208 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_LEFT, NULL);
209}
210
211static void
212_efl_ui_scroll_manager_scroll_right(Efl_Ui_Scroll_Manager_Data *sd)
213{
214 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_RIGHT, NULL);
215}
216
217static void
218_efl_ui_scroll_manager_edge_up(Efl_Ui_Scroll_Manager_Data *sd)
219{
220 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_UP, NULL);
221}
222
223static void
224_efl_ui_scroll_manager_edge_down(Efl_Ui_Scroll_Manager_Data *sd)
225{
226 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_DOWN, NULL);
227}
228
229static void
230_efl_ui_scroll_manager_edge_left(Efl_Ui_Scroll_Manager_Data *sd)
231{
232 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_LEFT, NULL);
233}
234
235static void
236_efl_ui_scroll_manager_edge_right(Efl_Ui_Scroll_Manager_Data *sd)
237{
238 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_RIGHT, NULL);
239}
240
241static void
242_efl_ui_scroll_manager_scroll_start(Efl_Ui_Scroll_Manager_Data *sd)
243{
244}
245
246static void
247_efl_ui_scroll_manager_scroll_stop(Efl_Ui_Scroll_Manager_Data *sd)
248{
249}
250
251EOLIAN static Eina_Size2D
252_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
253{
254 return efl_ui_pan_content_size_get(sd->pan_obj);
255}
256
257EOLIAN static Eina_Rect
258_efl_ui_scroll_manager_efl_ui_scrollable_interactive_viewport_geometry_get(Eo *obj EINA_UNUSED,
259 Efl_Ui_Scroll_Manager_Data *sd)
260{
261 if (!sd->pan_obj) return EINA_RECT(0, 0, 0, 0);
262
263 return efl_gfx_geometry_get(sd->pan_obj);
264}
265
266EOLIAN static void
267_efl_ui_scroll_manager_efl_ui_scrollable_interactive_match_content_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool w, Eina_Bool h)
268{
269 sd->match_content_w = !!w;
270 sd->match_content_h = !!h;
271}
272
273static Evas_Coord
274_efl_ui_scroll_manager_x_mirrored_get(const Evas_Object *obj,
275 Evas_Coord x)
276{
277 Evas_Coord ret;
278 Eina_Position2D min = {0, 0}, max = {0, 0};
279
280 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, x);
281
282 if (!sd->pan_obj) return 0;
283
284 min = efl_ui_pan_position_min_get(sd->pan_obj);
285 max = efl_ui_pan_position_max_get(sd->pan_obj);
286 ret = max.x - (x - min.x);
287
288 return (ret >= min.x) ? ret : min.x;
289}
290
291/* Update the wanted coordinates according to the x, y passed
292 * widget directionality, content size and etc. */
293static void
294_efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd,
295 Evas_Coord x,
296 Evas_Coord y)
297{
298 Eina_Position2D min = {0, 0}, max = {0, 0};
299
300 if (!sd->pan_obj) return;
301
302 min = efl_ui_pan_position_min_get(sd->pan_obj);
303 max = efl_ui_pan_position_max_get(sd->pan_obj);
304
305 /* Update wx/y/w/h - and if the requested positions aren't legal
306 * adjust a bit. */
307 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
308 sd->ww = r.w;
309 sd->wh = r.h;
310
311 if (x < min.x && !sd->is_mirrored)
312 {
313 if (!sd->loop_h) sd->wx = min.x;
314 else sd->wx = max.x;
315 }
316 else if (sd->is_mirrored)
317 sd->wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, x);
318 else if (!sd->loop_h && (x > max.x)) sd->wx = max.x;
319 else if (sd->loop_h && x >= (sd->ww + max.x)) sd->wx = min.x;
320 else sd->wx = x;
321
322 if (y < min.y)
323 {
324 if (!sd->loop_v) sd->wy = min.y;
325 else sd->wy = max.y;
326 }
327 else if (!sd->loop_v && (y > max.y)) sd->wy = max.y;
328 else if (sd->loop_v && y >= (sd->wh + max.y)) sd->wy = min.y;
329 else sd->wy = y;
330}
331
332static void
333_scroll_manager_animator_velocity_get(Efl_Ui_Scroll_Manager_Data *sd, double *velx, double *vely)
334{
335 Evas_Coord dx = 0, dy = 0;
336 double vx = 0.0, vy = 0.0;
337 double t = ecore_loop_time_get();
338 Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
339
340 if (t < sd->scrollto.x.start_t + sd->scrollto.x.dur)
341 {
342 dx = sd->scrollto.x.end - cur.x;
343 vx = (double)(dx /((sd->scrollto.x.start_t + sd->scrollto.x.dur) - t));
344
345 if (sd->scrollto.x.interp)
346 vx = sd->scrollto.x.interp(NULL, t/(sd->scrollto.x.start_t + sd->scrollto.x.dur)) * vx;
347 }
348 if (t < sd->scrollto.y.start_t + sd->scrollto.y.dur)
349 {
350 dy = sd->scrollto.y.end - cur.y;
351 vy = (double)(dy /((sd->scrollto.y.start_t + sd->scrollto.y.dur) - t));
352
353 if (sd->scrollto.y.interp)
354 vy = sd->scrollto.y.interp(NULL, t/(sd->scrollto.y.start_t + sd->scrollto.y.dur)) * vy;
355 }
356
357 if (velx) *velx = vx;
358 if (vely) *vely = vy;
359}
360
361static void
362_efl_ui_scroll_manager_bounce_eval(Efl_Ui_Scroll_Manager_Data *sd)
363{
364 double vx = 0.0, vy = 0.0;
365 if (!sd->pan_obj) return;
366
367 if (sd->freeze) return;
368 if ((!sd->bouncemex) && (!sd->bouncemey)) return;
369 if (sd->down.now) return; // down bounce while still held down
370
371 _scroll_manager_on_hold_animator_del(sd);
372 _scroll_manager_hold_animator_del(sd);
373
374 _scroll_manager_animator_velocity_get(sd, &vx, &vy);
375 if (!sd->bounce.x.animator)
376 {
377 if (sd->bouncemex)
378 {
379 _scroll_manager_scrollto_x_animator_del(sd);
380 _scroll_manager_bounce_x_animator_add(sd,vx);
381 }
382 }
383 if (!sd->bounce.y.animator)
384 {
385 if (sd->bouncemey)
386 {
387 _scroll_manager_scrollto_y_animator_del(sd);
388 _scroll_manager_bounce_y_animator_add(sd,vy);
389 }
390 }
391}
392
393EOLIAN static Eina_Position2D
394_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
395{
396 if (!sd->pan_obj) return EINA_POSITION2D(0, 0);
397
398 return efl_ui_pan_position_get(sd->pan_obj);
399}
400
401EOLIAN static void
402_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Position2D pos)
403{
404 Evas_Coord x = pos.x, y = pos.y;
405 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
406 Eina_Size2D content = {0, 0};
407
408 if (!sd->pan_obj) return;
409
410 // FIXME: allow for bounce outsde of range
411 max = efl_ui_pan_position_max_get(sd->pan_obj);
412 min = efl_ui_pan_position_min_get(sd->pan_obj);
413 content = efl_ui_pan_content_size_get(sd->pan_obj);
414 cur = efl_ui_pan_position_get(sd->pan_obj);
415
416 if (sd->loop_h && content.w > 0)
417 {
418 if (x < 0) x = content.w + (x % content.w);
419 else if (x >= content.w) x = (x % content.w);
420 }
421 if (sd->loop_v && content.h > 0)
422 {
423 if (y < 0) y = content.h + (y % content.h);
424 else if (y >= content.h) y = (y % content.h);
425 }
426
427 if (!_elm_config->thumbscroll_bounce_enable)
428 {
429
430 if (x < min.x) x = min.x;
431 if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
432 if (y < min.y) y = min.y;
433 if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
434 }
435
436 if (!sd->bounce_horiz)
437 {
438 if (x < min.x) x = min.x;
439 if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
440 }
441 if (!sd->bounce_vert)
442 {
443 if (y < min.y) y = min.y;
444 if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
445 }
446
447 efl_ui_pan_position_set(sd->pan_obj, EINA_POSITION2D(x, y));
448
449 if (!sd->loop_h && !sd->bounce.x.animator)
450 {
451 if ((x < min.x) ||(x > max.x + min.x))
452 {
453 sd->bouncemex = EINA_TRUE;
454 _efl_ui_scroll_manager_bounce_eval(sd);
455 }
456 else
457 sd->bouncemex = EINA_FALSE;
458 }
459 if (!sd->loop_v && !sd->bounce.y.animator)
460 {
461 if ((y < min.y) ||(y > max.y + min.y))
462 {
463 sd->bouncemey = EINA_TRUE;
464 _efl_ui_scroll_manager_bounce_eval(sd);
465 }
466 else
467 sd->bouncemey = EINA_FALSE;
468 }
469
470 {
471 if ((x != cur.x) || (y != cur.y))
472 {
473 _efl_ui_scroll_manager_scroll(sd);
474 if (x < cur.x)
475 {
476 _efl_ui_scroll_manager_scroll_left(sd);
477 }
478 if (x > cur.x)
479 {
480 _efl_ui_scroll_manager_scroll_right(sd);
481 }
482 if (y < cur.y)
483 {
484 _efl_ui_scroll_manager_scroll_up(sd);
485 }
486 if (y > cur.y)
487 {
488 _efl_ui_scroll_manager_scroll_down(sd);
489 }
490 }
491 if (x != cur.x)
492 {
493 if (x == min.x)
494 {
495 _efl_ui_scroll_manager_edge_left(sd);
496 }
497 if (x == (max.x + min.x))
498 {
499 _efl_ui_scroll_manager_edge_right(sd);
500 }
501 }
502 if (y != cur.y)
503 {
504 if (y == min.y)
505 {
506 _efl_ui_scroll_manager_edge_up(sd);
507 }
508 if (y == max.y + min.y)
509 {
510 _efl_ui_scroll_manager_edge_down(sd);
511 }
512 }
513 }
514}
515
516EOLIAN static void
517_efl_ui_scroll_manager_mirrored_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool mirrored)
518{
519 Evas_Coord wx;
520
521 mirrored = !!mirrored;
522
523 if (sd->is_mirrored == mirrored)
524 return;
525
526 sd->is_mirrored = mirrored;
527
528 if (sd->is_mirrored)
529 wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, sd->wx);
530 else
531 wx = sd->wx;
532
533 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(wx, sd->wy));
534}
535
536static void
537_scroll_manager_animators_drop(Evas_Object *obj)
538{
539 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
540 if ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
541 (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
542 {
543 if (_scroll_manager_scrollto_x_animator_del(sd))
544 {
545 }
546 if (_scroll_manager_scrollto_y_animator_del(sd))
547 {
548 }
549 if (_scroll_manager_bounce_x_animator_del(sd))
550 {
551 sd->bouncemex = EINA_FALSE;
552 if (sd->content_info.resized)
553 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
554 }
555 if (_scroll_manager_bounce_y_animator_del(sd))
556 {
557 sd->bouncemey = EINA_FALSE;
558 if (sd->content_info.resized)
559 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
560 }
561 _efl_ui_scroll_manager_anim_stop(sd);
562 }
563 if (_scroll_manager_hold_animator_del(sd))
564 {
565 _efl_ui_scroll_manager_drag_stop(sd);
566 if (sd->content_info.resized)
567 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
568 }
569}
570
571EOLIAN static void
572_efl_ui_scroll_manager_efl_ui_scrollbar_mode_set(Eo *obj EINA_UNUSED,
573 Efl_Ui_Scroll_Manager_Data *sd,
574 Efl_Ui_Scrollbar_Mode hmode,
575 Efl_Ui_Scrollbar_Mode vmode)
576{
577 sd->hbar_mode = hmode;
578 sd->vbar_mode = vmode;
579
580 if (sd->hbar_timer &&
581 hmode == EFL_UI_SCROLLBAR_MODE_ON)
582 ELM_SAFE_FREE(sd->hbar_timer, ecore_timer_del);
583 if (sd->vbar_timer &&
584 vmode == EFL_UI_SCROLLBAR_MODE_ON)
585 ELM_SAFE_FREE(sd->vbar_timer, ecore_timer_del);
586
587 efl_ui_scrollbar_visibility_update(sd->obj);
588}
589
590EOLIAN static void
591_efl_ui_scroll_manager_efl_ui_scrollbar_mode_get(Eo *obj EINA_UNUSED,
592 Efl_Ui_Scroll_Manager_Data *sd,
593 Efl_Ui_Scrollbar_Mode *hmode,
594 Efl_Ui_Scrollbar_Mode *vmode)
595{
596 *hmode = sd->hbar_mode;
597 *vmode = sd->vbar_mode;
598}
599
600/* returns TRUE when we need to move the scroller, FALSE otherwise.
601 * Updates w and h either way, so save them if you need them. */
602static Eina_Bool
603_efl_ui_scroll_manager_content_region_show_internal(Evas_Object *obj,
604 Evas_Coord *_x,
605 Evas_Coord *_y,
606 Evas_Coord w,
607 Evas_Coord h)
608{
609 Evas_Coord nx, ny, x = *_x, y = *_y;
610 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
611 Eina_Size2D pan = {0, 0};
612
613 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
614
615 if (!sd->pan_obj) return EINA_FALSE;
616
617 min = efl_ui_pan_position_min_get(sd->pan_obj);
618 max = efl_ui_pan_position_max_get(sd->pan_obj);
619 cur = efl_ui_pan_position_get(sd->pan_obj);
620 pan = efl_gfx_size_get(sd->pan_obj);
621
622 nx = x;
623 if ((x > cur.x) && (w < pan.w))
624 {
625 if ((cur.x + pan.w) < (x + w)) nx = x - pan.w + w;
626 else nx = cur.x;
627 }
628 ny = y;
629 if ((y > cur.y) && (h < pan.h))
630 {
631 if ((cur.y + pan.h) < (y + h)) ny = y - pan.h + h;
632 else ny = cur.y;
633 }
634
635 x = nx;
636 y = ny;
637
638 if (!sd->loop_h)
639 {
640 if (x > max.x) x = max.x;
641 if (x < min.x) x = min.x;
642 }
643 if (!sd->loop_v)
644 {
645 if (y > max.y) y = max.y;
646 if (y < min.y) y = min.y;
647 }
648
649 if ((x == cur.x) && (y == cur.y)) return EINA_FALSE;
650 *_x = x;
651 *_y = y;
652 return EINA_TRUE;
653}
654
655static void
656_efl_ui_scroll_manager_content_region_set(Eo *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
657{
658 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
659
660 _scroll_manager_animators_drop(obj);
661 if (_efl_ui_scroll_manager_content_region_show_internal(obj, &x, &y, w, h))
662 {
663 efl_ui_scrollable_content_pos_set(obj, EINA_POSITION2D(x, y));
664 sd->down.sx = x;
665 sd->down.sy = y;
666 sd->down.x = sd->down.history[0].x;
667 sd->down.y = sd->down.history[0].y;
668 }
669}
670
671/* Set should be used for setting the wanted position, for example a
672 * user scroll or moving the cursor in an entry. */
673EOLIAN static void
674_efl_ui_scroll_manager_efl_ui_scrollable_interactive_show(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd, Eina_Rect rect)
675{
676 sd->wx = (sd->is_mirrored ? _efl_ui_scroll_manager_x_mirrored_get(sd->obj, rect.x) : rect.x);
677 sd->wy = rect.y;
678 sd->ww = rect.w;
679 sd->wh = rect.h;
680 _scroll_manager_animators_drop(obj);
681 if (_efl_ui_scroll_manager_content_region_show_internal(obj, &(rect.x), &(rect.y), rect.w, rect.h))
682 {
683 efl_ui_scrollable_content_pos_set(obj, EINA_POSITION2D(rect.x, rect.y));
684 sd->down.sx = rect.x;
685 sd->down.sy = rect.y;
686 sd->down.x = sd->down.history[0].x;
687 sd->down.y = sd->down.history[0].y;
688 }
689}
690
691static void
692_efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj)
693{
694 Evas_Coord ww, wh, wx;
695 Eina_Position2D max = {0, 0};
696
697 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
698
699 wx = sd->wx;
700
701 if (_scroll_manager_animating_get(sd) || sd->down.now ||
702 sd->down.hold_animator || sd->down.onhold_animator) return;
703
704 sd->content_info.resized = EINA_FALSE;
705
706 /* Flip to RTL cords only if init in RTL mode */
707 if (sd->is_mirrored)
708 wx = _efl_ui_scroll_manager_x_mirrored_get(obj, sd->wx);
709
710 if (sd->ww == -1)
711 {
712 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
713 ww = r.w;
714 wh = r.h;
715 }
716 else
717 {
718 ww = sd->ww;
719 wh = sd->wh;
720 }
721
722 max = efl_ui_pan_position_max_get(sd->pan_obj);
723
724 wx += (max.x - sd->prev_cw) * sd->gravity_x;
725 sd->wy += (max.y - sd->prev_ch) * sd->gravity_y;
726
727 sd->prev_cw = max.x;
728 sd->prev_ch = max.y;
729
730 _efl_ui_scroll_manager_content_region_set(obj, wx, sd->wy, ww, wh);
731}
732
733static void
734_scroll_wheel_post_event_job(void *data, const Efl_Event *ev EINA_UNUSED)
735{
736 Efl_Ui_Scroll_Manager_Data *sd = data;
737
738 // Animations are disabled if we are here
739 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(sd->wx, sd->wy));
740}
741
742static inline void
743_scroll_wheel_post_event_go(Efl_Ui_Scroll_Manager_Data *sd, int x, int y)
744{
745 if (sd->hold || sd->freeze) return;
746 _efl_ui_scroll_manager_wanted_coordinates_update(sd, x, y);
747 if (_elm_config->scroll_animation_disable)
748 {
749 efl_future_then(efl_loop_job(efl_loop_get(sd->obj), NULL),
750 _scroll_wheel_post_event_job, NULL, NULL, sd);
751 }
752 else
753 {
754 _scroll_manager_scrollto(sd, x, y);
755 }
756}
757
758static Eina_Bool
759_scroll_wheel_post_event_cb(void *data, Evas *e EINA_UNUSED)
760{
761 Efl_Ui_Scroll_Manager_Data *sd = data;
762 Evas_Event_Mouse_Wheel *ev = sd->event_info;
763
764 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
765 Eina_Size2D content = {0, 0};
766 Evas_Coord x = 0, y = 0, vw = 0, vh = 0;
767 Eina_Bool hold = EINA_FALSE;
768 Evas_Coord pwx, pwy;
769 double t;
770 int direction;
771
772 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_TRUE);
773
774 sd->event_info = NULL;
775 direction = ev->direction;
776
777 pwx = sd->wx;
778 pwy = sd->wy;
779
780 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
781 if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
782 direction = !direction;
783
784 cur = efl_ui_pan_position_get(sd->pan_obj);
785 x = cur.x;
786 y = cur.y;
787 if (sd->scrollto.x.animator) x = sd->scrollto.x.end;
788 if (sd->scrollto.y.animator) y = sd->scrollto.y.end;
789 max = efl_ui_pan_position_max_get(sd->pan_obj);
790 min = efl_ui_pan_position_min_get(sd->pan_obj);
791 if (x < min.x) x = min.x;
792 if (x > max.x) x = max.x;
793 if (y < min.y) y = min.y;
794 if (y > max.y) y = max.y;
795
796 t = ecore_loop_time_get();
797
798 _scroll_manager_animators_drop(sd->obj);
799
800 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
801 vw = r.w;
802 vh = r.h;
803
804 if (sd->pan_obj)
805 content = efl_ui_pan_content_size_get(sd->pan_obj);
806 {
807 int d = ev->z;
808 double delta_t = (double)(ev->timestamp - sd->last_wheel) / 1000.0;
809 double mul;
810
811 if (delta_t > 0.2) sd->last_wheel_mul = 0.0;
812 if (delta_t > 0.2) delta_t = 0.2;
813 mul = 1.0 + (_elm_config->scroll_accel_factor * ((0.2 - delta_t) / 0.2));
814 mul = mul * (1.0 + (0.15 * sd->last_wheel_mul));
815 d *= mul;
816 sd->last_wheel = ev->timestamp;
817 sd->last_wheel_mul = mul;
818
819 if (!direction)
820 {
821 if ((content.h > vh) || (content.w <= vw))
822 y += d * sd->step.y;
823 else
824 {
825 x += d * sd->step.x;
826 direction = 1;
827 }
828 }
829 else
830 {
831 if ((content.w > vw) || (content.h <= vh))
832 x += d * sd->step.x;
833 else
834 {
835 y += d * sd->step.y;
836 direction = 0;
837 }
838 }
839 _scroll_wheel_post_event_go(sd, x, y);
840 }
841
842 if (direction)
843 {
844 if ((pwx != sd->wx) ||
845 (((t - sd->down.last_time_x_wheel) < 0.5) &&
846 (sd->down.last_hold_x_wheel)))
847 {
848 sd->down.last_hold_x_wheel = EINA_TRUE;
849 hold = EINA_TRUE;
850 }
851 else sd->down.last_hold_x_wheel = EINA_FALSE;
852 sd->down.last_time_x_wheel = t;
853 }
854 else
855 {
856 if ((pwy != sd->wy) ||
857 (((t - sd->down.last_time_y_wheel) < 0.5) &&
858 (sd->down.last_hold_y_wheel)))
859 {
860 sd->down.last_hold_y_wheel = EINA_TRUE;
861 hold = EINA_TRUE;
862 }
863 else sd->down.last_hold_y_wheel = EINA_FALSE;
864 sd->down.last_time_y_wheel = t;
865 }
866
867 return !hold;
868}
869
870static void
871_efl_ui_scroll_manager_wheel_event_cb(void *data,
872 Evas *e,
873 Evas_Object *obj EINA_UNUSED,
874 void *event_info)
875{
876 Efl_Ui_Scroll_Manager_Data *sd;
877 Evas_Event_Mouse_Wheel *ev;
878 int direction;
879
880 sd = data;
881 ev = event_info;
882 sd->event_info = event_info;
883 direction = ev->direction;
884
885 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
886 if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
887 (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
888 (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
889 (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
890 (evas_key_modifier_is_set(ev->modifiers, "Super")))
891 return;
892 if (direction)
893 {
894 if (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL) return;
895 }
896 else
897 {
898 if (sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) return;
899 }
900
901 evas_post_event_callback_push(e, _scroll_wheel_post_event_cb, sd);
902}
903
904static Eina_Bool
905_efl_ui_scroll_manager_post_event_up(void *data,
906 Evas *e EINA_UNUSED)
907{
908 Efl_Ui_Scroll_Manager_Data *sd = data;
909
910 if (sd->obj)
911 {
912 if (sd->down.dragged)
913 {
914 }
915 }
916 return EINA_FALSE;
917}
918
919static void
920_efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event EINA_UNUSED)
921{
922 Efl_Ui_Scroll_Manager_Data *sd = data;
923 Evas_Coord nx = 0, cy = 0;
924 double t = 0.0, dt = 0.0, progx = 0.0, rx = 0.0;
925 Interpolator interp = NULL;
926
927 t = ecore_loop_time_get();
928 dt = t - sd->scrollto.x.start_t;
929
930 if ( dt > sd->scrollto.x.dur) progx = 1.0;
931 else progx = dt / sd->scrollto.x.dur;
932
933 if (sd->scrollto.x.interp) interp = sd->scrollto.x.interp;
934 else interp = _scroll_manager_interp_get(LINEAR);
935
936 rx = interp(NULL, progx);
937 nx = sd->scrollto.x.start + (sd->scrollto.x.end - sd->scrollto.x.start) * rx;
938
939 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
940 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
941 _efl_ui_scroll_manager_wanted_coordinates_update(sd, nx, cy);
942
943 if (dt >= sd->scrollto.x.dur)
944 {
945 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
946 }
947}
948
949static void
950_efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
951{
952 Efl_Ui_Scroll_Manager_Data *sd = data;
953 Evas_Coord ny = 0, cx = 0;
954 double t = 0.0, dt = 0.0, progy = 0.0, ry = 0.0;
955 Interpolator interp = NULL;
956
957 t = ecore_loop_time_get();
958 dt = t - sd->scrollto.y.start_t;
959
960 if ( dt > sd->scrollto.y.dur) progy = 1.0;
961 else progy = dt / sd->scrollto.y.dur;
962
963 if (sd->scrollto.y.interp) interp = sd->scrollto.y.interp;
964 else interp = _scroll_manager_interp_get(LINEAR);
965
966 ry = interp(NULL, progy);
967 ny = sd->scrollto.y.start + (sd->scrollto.y.end - sd->scrollto.y.start) * ry;
968
969 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
970 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
971 _efl_ui_scroll_manager_wanted_coordinates_update(sd, cx, ny);
972
973 if (dt >= sd->scrollto.y.dur)
974 {
975 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
976 }
977}
978
979static void
980_efl_ui_scroll_manager_mouse_up_event_smooth(Efl_Ui_Scroll_Manager_Data *sd, double t, Evas_Coord *ox, Evas_Coord *oy, double *ot)
981{
982 static const unsigned int HISTORY_MAX = 60;
983 unsigned int i = 0;
984 double dt = 0, at = 0;
985 Evas_Coord ax = 0, ay = 0;
986
987 for (i = 0; i < HISTORY_MAX; i++)
988 {
989 dt = t - sd->down.history[i].timestamp;
990 if (dt > 0.2) break;
991#ifdef SCROLLDBG
992 DBG("H: %i %i @ %1.3f\n",
993 sd->down.history[i].x,
994 sd->down.history[i].y, dt);
995#endif
996 ax = sd->down.history[i].x;
997 ay = sd->down.history[i].y;
998 at = sd->down.history[i].timestamp;
999 }
1000 if (ox) *ox = ax;
1001 if (oy) *oy = ay;
1002 if (ot) *ot = t - at;
1003
1004 return;
1005 if (ox) *ox = (Evas_Coord)(ax / (i + 1));
1006 if (oy) *oy = (Evas_Coord)(ay / (i + 1));
1007 if (ot) *ot = (double)(at / (i + 1));
1008}
1009
1010static void
1011_efl_ui_scroll_manager_mouse_up_event_momentum_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Up *ev)
1012{
1013 double t, at;
1014 Evas_Coord dx, dy, ax, ay, vel;
1015 char sdx, sdy;
1016
1017#ifdef EVTIME
1018 t = ev->timestamp / 1000.0;
1019#else
1020 t = ecore_loop_time_get();
1021#endif
1022
1023 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1024 ax = ev->canvas.x;
1025 ay = ev->canvas.y;
1026 at = 0.0;
1027#ifdef SCROLLDBG
1028 DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1029#endif
1030 _efl_ui_scroll_manager_mouse_up_event_smooth(sd, t, &ax, &ay, &at);
1031 dx = ev->canvas.x - ax;
1032 dy = ev->canvas.y - ay;
1033
1034 sdx = (dx > 0) - (dx < 0);
1035 sdy = (dy > 0) - (dy < 0);
1036
1037 dx = abs(dx);
1038 dy = abs(dy);
1039 if (at > 0)
1040 {
1041 vel = (Evas_Coord)(sqrt((dx * dx) + (dy * dy)) / at);
1042 if ((_elm_config->thumbscroll_friction > 0.0) &&
1043 (vel > _elm_config->thumbscroll_momentum_threshold))
1044 {
1045 _scroll_manager_momentum_animator_add(sd, -sdx*dx/at, -sdy*dy/at);
1046 }
1047 }
1048}
1049
1050static void
1051_efl_ui_scroll_manager_mouse_up_event_cb(void *data,
1052 Evas *e,
1053 Evas_Object *obj EINA_UNUSED,
1054 void *event_info)
1055{
1056 Efl_Ui_Scroll_Manager_Data *sd = data;
1057 Evas_Event_Mouse_Up *ev;
1058
1059 if (!sd->pan_obj) return;
1060 if (!_scroll_manager_thumb_scrollable_get(sd)) return;
1061
1062 ev = event_info;
1063 evas_post_event_callback_push(e, _efl_ui_scroll_manager_post_event_up, sd);
1064
1065 if (ev->button == 1)
1066 {
1067 _scroll_manager_on_hold_animator_del(sd);
1068
1069 if (sd->down.dragged)
1070 {
1071 _efl_ui_scroll_manager_drag_stop(sd);
1072 if ((!sd->hold) && (!sd->freeze))
1073 {
1074 _efl_ui_scroll_manager_mouse_up_event_momentum_eval(sd, ev);
1075 }
1076 evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1077 }
1078
1079 _scroll_manager_hold_animator_del(sd);
1080
1081 if (sd->down.scroll)
1082 {
1083 ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1084 sd->down.scroll = EINA_FALSE;
1085 }
1086 if (sd->down.hold)
1087 {
1088 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1089 sd->down.hold = EINA_FALSE;
1090 }
1091
1092 sd->down.dragged_began = EINA_FALSE;
1093 sd->down.dir_x = EINA_FALSE;
1094 sd->down.dir_y = EINA_FALSE;
1095 sd->down.dragged = EINA_FALSE;
1096 sd->down.now = EINA_FALSE;
1097
1098 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
1099 efl_ui_scrollable_content_pos_set(sd->obj, cur);
1100 _efl_ui_scroll_manager_wanted_coordinates_update(sd, cur.x, cur.y);
1101
1102 if (sd->content_info.resized)
1103 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
1104 }
1105}
1106
1107static void
1108_efl_ui_scroll_manager_mouse_down_event_cb(void *data,
1109 Evas *e EINA_UNUSED,
1110 Evas_Object *obj EINA_UNUSED,
1111 void *event_info)
1112{
1113 Efl_Ui_Scroll_Manager_Data *sd;
1114 Evas_Event_Mouse_Down *ev;
1115 Eina_Position2D cur = {0, 0};
1116
1117 sd = data;
1118 ev = event_info;
1119
1120 if (!_scroll_manager_thumb_scrollable_get(sd)) return;
1121
1122 sd->down.hold = EINA_FALSE;
1123 if (_scroll_manager_animating_get(sd))
1124 {
1125 ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
1126 EVAS_EVENT_FLAG_ON_HOLD;
1127 sd->down.scroll = EINA_TRUE;
1128 sd->down.hold = EINA_TRUE;
1129
1130 _scroll_manager_animators_drop(sd->obj);
1131 }
1132
1133 if (ev->button == 1)
1134 {
1135 sd->down.hist.est_timestamp_diff =
1136 ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
1137 sd->down.hist.tadd = 0.0;
1138 sd->down.hist.dxsum = 0.0;
1139 sd->down.hist.dysum = 0.0;
1140 sd->down.now = EINA_TRUE;
1141 sd->down.dragged = EINA_FALSE;
1142 sd->down.dir_x = EINA_FALSE;
1143 sd->down.dir_y = EINA_FALSE;
1144 sd->down.x = ev->canvas.x;
1145 sd->down.y = ev->canvas.y;
1146 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1147 sd->down.sx = cur.x;
1148 sd->down.sy = cur.y;
1149 memset(&(sd->down.history[0]), 0,
1150 sizeof(sd->down.history[0]) * 60);
1151#ifdef EVTIME
1152 sd->down.history[0].timestamp = ev->timestamp / 1000.0;
1153 sd->down.history[0].localtimestamp = ecore_loop_time_get();
1154#else
1155 sd->down.history[0].timestamp = ecore_loop_time_get();
1156#endif
1157 sd->down.dragged_began_timestamp = sd->down.history[0].timestamp;
1158 sd->down.history[0].x = ev->canvas.x;
1159 sd->down.history[0].y = ev->canvas.y;
1160 }
1161 sd->down.dragged_began = EINA_FALSE;
1162 if (sd->hold || sd->freeze)
1163 sd->down.want_reset = EINA_TRUE;
1164 else
1165 sd->down.want_reset = EINA_FALSE;
1166}
1167
1168static Eina_Bool
1169_efl_ui_scroll_manager_can_scroll(Efl_Ui_Scroll_Manager_Data *sd,
1170 int dir)
1171{
1172 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
1173
1174 if (!sd->pan_obj) return EINA_FALSE;
1175
1176 max = efl_ui_pan_position_max_get(sd->pan_obj);
1177 min = efl_ui_pan_position_min_get(sd->pan_obj);
1178 cur = efl_ui_pan_position_get(sd->pan_obj);
1179 switch (dir)
1180 {
1181 case LEFT:
1182 if (cur.x > min.x) return EINA_TRUE;
1183 break;
1184
1185 case RIGHT:
1186 if ((cur.x - min.x) < max.x) return EINA_TRUE;
1187 break;
1188
1189 case UP:
1190 if (cur.y > min.y) return EINA_TRUE;
1191 break;
1192
1193 case DOWN:
1194 if ((cur.y - min.y) < max.y) return EINA_TRUE;
1195 break;
1196
1197 default:
1198 break;
1199 }
1200 return EINA_FALSE;
1201}
1202
1203static void
1204_efl_ui_scroll_manager_bounce_weight_apply(Efl_Ui_Scroll_Manager_Data *sd,
1205 Evas_Coord *x,
1206 Evas_Coord *y)
1207{
1208 Eina_Position2D min = {0, 0}, max = {0, 0};
1209 min = efl_ui_pan_position_min_get(sd->pan_obj);
1210 max = efl_ui_pan_position_max_get(sd->pan_obj);
1211
1212 if (!sd->loop_h && *x < min.x)
1213 *x += (min.x - *x) * _elm_config->thumbscroll_border_friction;
1214 else if (!sd->loop_h && max.x <= 0)
1215 *x += (sd->down.sx - *x) * _elm_config->thumbscroll_border_friction;
1216 else if (!sd->loop_h && (max.x + min.x) < *x)
1217 *x += (max.x + min.x - *x) *
1218 _elm_config->thumbscroll_border_friction;
1219
1220 if (!sd->loop_v && *y < min.y)
1221 *y += (min.y - *y) * _elm_config->thumbscroll_border_friction;
1222 else if (!sd->loop_v && max.y <= 0)
1223 *y += (sd->down.sy - *y) * _elm_config->thumbscroll_border_friction;
1224 else if (!sd->loop_v && (max.y + min.y) < *y)
1225 *y += (max.y + min.y - *y) *
1226 _elm_config->thumbscroll_border_friction;
1227}
1228
1229static inline double
1230_scroll_manager_animation_duration_get(Evas_Coord dx, Evas_Coord dy)
1231{
1232 double dist = 0.0, vel = 0.0, dur = 0.0;
1233 dist = sqrt(dx * dx + dy *dy);
1234 vel = _elm_config->thumbscroll_friction_standard / _elm_config->thumbscroll_friction;
1235 dur = dist / vel;
1236 dur = (dur > _elm_config->thumbscroll_friction) ? _elm_config->thumbscroll_friction : dur;
1237 return dur;
1238}
1239
1240static Eina_Bool
1241_scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1242{
1243 if (sd->down.onhold_animator)
1244 {
1245 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
1246 if (sd->content_info.resized)
1247 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
1248 return EINA_TRUE;
1249 }
1250 return EINA_FALSE;
1251}
1252
1253static void
1254_scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
1255{
1256 sd->down.onhold_vx = vx;
1257 sd->down.onhold_vy = vy;
1258 if (!sd->down.onhold_animator)
1259 {
1260 sd->down.onhold_vxe = 0.0;
1261 sd->down.onhold_vye = 0.0;
1262 sd->down.onhold_tlast = 0.0;
1263
1264 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
1265 }
1266}
1267
1268static void
1269_scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y)
1270{
1271 sd->down.hold_x = x;
1272 sd->down.hold_y = y;
1273 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
1274}
1275
1276static Eina_Bool
1277_scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1278{
1279 if (sd->down.hold_animator || sd->down.hold_enterer)
1280 {
1281 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
1282 ELM_SAFE_FREE(sd->down.hold_enterer, ecore_idle_enterer_del);
1283 return EINA_TRUE;
1284 }
1285 return EINA_FALSE;
1286}
1287
1288static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
1289{
1290 static const double friction = 5000;
1291 static const double inverse_mass = 1;
1292 static const double accel = friction * inverse_mass;
1293 double dur = 0.0, vel = 0.0;
1294 char sdx = 0, sdy = 0;
1295 Evas_Coord dstx = 0, dsty = 0;
1296
1297/*
1298 if (_scroll_manager_scrollto_animator_del(sd))
1299 {
1300 restore current veolocity
1301 add to vx/vy
1302 }
1303*/
1304 Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
1305
1306 sdx = (vx > 0) - (vx < 0);
1307 sdy = (vy > 0) - (vy < 0);
1308
1309 dstx = cur.x + sdx * (vx * vx) / (2 * accel);
1310 dsty = cur.y + sdy * (vy * vy) / (2 * accel);
1311
1312 vel = sqrt(vx*vx + vy*vy);
1313 dur = vel / accel;
1314
1315 _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, dstx, dsty, dur, dur, DECEL);
1316}
1317
1318static void
1319_efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
1320{
1321 Efl_Ui_Scroll_Manager_Data *sd = data;
1322 Evas_Coord ny = 0;
1323 Eina_Position2D cur = {0, 0};
1324 double t = 0.0, dt = 0.0, r = 0.0;
1325
1326 t = ecore_loop_time_get();
1327 if (sd->bounce.y.start_t + sd->bounce.y.t01 >= t)
1328 {
1329 dt = sd->bounce.y.start_t + sd->bounce.y.t01 - t;
1330 r = 1.0 - (dt / sd->bounce.y.t01);
1331 r = _scroll_manager_decel_interp(NULL, r);
1332 ny = sd->bounce.y.p0 + (sd->bounce.y.p1 - sd->bounce.y.p0) * r;
1333
1334 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1335 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
1336 }
1337 else if (sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 >= t)
1338 {
1339 dt = sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 - t;
1340 r = 1.0 - (dt / sd->bounce.y.t12);
1341 r = _scroll_manager_decel_interp(NULL, r);
1342 ny = sd->bounce.y.p1 + (sd->bounce.y.p2 - sd->bounce.y.p1) * r;
1343
1344 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1345 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
1346 }