summaryrefslogtreecommitdiff
path: root/src/lib/elementary
diff options
context:
space:
mode:
authorWonki Kim <wonki_.kim@samsung.com>2017-12-18 21:08:25 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-12-19 10:26:25 +0900
commit47bf356435d7b4562e64f45ef59dbf190dff16c7 (patch)
tree32dec1cca747dc2e062ff8a7bd9586500a8289dc /src/lib/elementary
parent29ce7550eb3fa2f1c5f4c82d30e5e625b2c60058 (diff)
scroller: Introducing Efl.Ui.Scroller
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 + many others! Reviewers: akanad, woohyun, cedric, jpeg Subscribers: jenkins, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D5222 Note by @jpeg: Unfortunately this patch comes in a massive single blob, after too many rebase operations. It has now come to a point where I think the API is nice and it works as I'd expect. Now I only wonder how applicable this will be for Efl.Ui.List. As we can see Photocam (legacy and unified API) could be transformed to use this new API.
Diffstat (limited to '')
-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.c701
-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.c197
-rw-r--r--src/lib/elementary/efl_ui_pan.eo55
-rw-r--r--src/lib/elementary/efl_ui_scroll_manager.c2495
-rw-r--r--src/lib/elementary/efl_ui_scroll_manager.eo44
-rw-r--r--src/lib/elementary/efl_ui_scroller.c638
-rw-r--r--src/lib/elementary/efl_ui_scroller.eo23
-rw-r--r--src/lib/elementary/efl_ui_widget_pan.h14
-rw-r--r--src/lib/elementary/efl_ui_widget_scroll_manager.h135
-rw-r--r--src/lib/elementary/efl_ui_widget_scroller.h17
15 files changed, 4124 insertions, 244 deletions
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 1fc4f5419a..3ff72cbbee 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -324,6 +324,9 @@ EAPI extern Elm_Version *elm_version;
324# include <efl_ui_list_relayout.eo.h> 324# include <efl_ui_list_relayout.eo.h>
325# include <efl_ui_list.eo.h> 325# include <efl_ui_list.eo.h>
326# include <efl_ui_list_pan.eo.h> 326# include <efl_ui_list_pan.eo.h>
327# include <efl_ui_scroll_manager.eo.h>
328# include <efl_ui_scroller.eo.h>
329# include <efl_ui_pan.eo.h>
327#endif 330#endif
328 331
329/* include deprecated calls last of all */ 332/* include deprecated calls last of all */
diff --git a/src/lib/elementary/efl_ui.eot b/src/lib/elementary/efl_ui.eot
index f3efc840aa..e89104009a 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 09321aab70..5592fcfa6b 100644
--- a/src/lib/elementary/efl_ui_image_zoomable.c
+++ b/src/lib/elementary/efl_ui_image_zoomable.c
@@ -4,12 +4,14 @@
4 4
5#define EFL_ACCESS_PROTECTED 5#define EFL_ACCESS_PROTECTED
6#define EFL_ACCESS_WIDGET_ACTION_PROTECTED 6#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7#define EFL_UI_SCROLL_MANAGER_PROTECTED
8#define EFL_UI_SCROLLBAR_PROTECTED
9#define EFL_UI_SCROLLBAR_BETA
7 10
8#include <Elementary.h> 11#include <Elementary.h>
9 12
10#include "elm_priv.h" 13#include "elm_priv.h"
11#include "efl_ui_image_zoomable_private.h" 14#include "efl_ui_image_zoomable_private.h"
12#include "elm_interface_scrollable.h"
13 15
14#define MY_PAN_CLASS EFL_UI_IMAGE_ZOOMABLE_PAN_CLASS 16#define MY_PAN_CLASS EFL_UI_IMAGE_ZOOMABLE_PAN_CLASS
15 17
@@ -143,7 +145,7 @@ _calc_job_cb(void *data)
143 sd->minw = minw; 145 sd->minw = minw;
144 sd->minh = minh; 146 sd->minh = minh;
145 147
146 efl_event_callback_legacy_call(sd->pan_obj, ELM_PAN_EVENT_CHANGED, NULL); 148 efl_event_callback_call(sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
147 _sizing_eval(obj); 149 _sizing_eval(obj);
148 } 150 }
149 sd->calc_job = NULL; 151 sd->calc_job = NULL;
@@ -200,11 +202,11 @@ _image_place(Evas_Object *obj,
200 evas_object_move(sd->img, ox + 0 - px + ax, oy + 0 - py + ay); 202 evas_object_move(sd->img, ox + 0 - px + ax, oy + 0 - py + ay);
201 evas_object_resize(sd->img, gw, gh); 203 evas_object_resize(sd->img, gw, gh);
202 204
203 if (sd->show.show) 205 if (sd->show_item)
204 { 206 {
205 sd->show.show = EINA_FALSE; 207 sd->show_item = EINA_FALSE;
206 elm_interface_scrollable_content_region_show 208 efl_ui_scrollable_scroll
207 (obj, sd->show.x, sd->show.y, sd->show.w, sd->show.h); 209 (sd->smanager, sd->show, EINA_FALSE);
208 } 210 }
209} 211}
210 212
@@ -381,23 +383,24 @@ _efl_ui_image_zoomable_pan_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Imag
381} 383}
382 384
383EOLIAN static void 385EOLIAN 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) 386_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Eina_Position2D pos)
385{ 387{
386 if ((x == psd->wsd->pan_x) && (y == psd->wsd->pan_y)) return; 388 if ((pos.x == psd->wsd->pan_x) && (pos.y == psd->wsd->pan_y)) return;
387 psd->wsd->pan_x = x; 389 psd->wsd->pan_x = pos.x;
388 psd->wsd->pan_y = y; 390 psd->wsd->pan_y = pos.y;
389 evas_object_smart_changed(obj); 391 evas_object_smart_changed(obj);
392
393 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
390} 394}
391 395
392EOLIAN static void 396EOLIAN 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) 397_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
394{ 398{
395 if (x) *x = psd->wsd->pan_x; 399 return EINA_POSITION2D(psd->wsd->pan_x, psd->wsd->pan_y);
396 if (y) *y = psd->wsd->pan_y;
397} 400}
398 401
399EOLIAN static void 402EOLIAN 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) 403_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
401{ 404{
402 Evas_Coord ow, oh; 405 Evas_Coord ow, oh;
403 406
@@ -406,28 +409,27 @@ _efl_ui_image_zoomable_pan_elm_pan_pos_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pa
406 if (ow < 0) ow = 0; 409 if (ow < 0) ow = 0;
407 oh = psd->wsd->minh - oh; 410 oh = psd->wsd->minh - oh;
408 if (oh < 0) oh = 0; 411 if (oh < 0) oh = 0;
409 if (x) *x = ow; 412
410 if (y) *y = oh; 413 return EINA_POSITION2D(ow, oh);
411} 414}
412 415
413EOLIAN static void 416EOLIAN 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) 417_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *_pd EINA_UNUSED)
415{ 418{
416 if (x) *x = 0; 419 return EINA_POSITION2D(0, 0);
417 if (y) *y = 0;
418} 420}
419 421
420EOLIAN static void 422EOLIAN 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) 423_efl_ui_image_zoomable_pan_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
422{ 424{
423 if (w) *w = psd->wsd->minw; 425 return EINA_SIZE2D(psd->wsd->minw, psd->wsd->minh);
424 if (h) *h = psd->wsd->minh;
425} 426}
426 427
427EOLIAN static void 428EOLIAN static void
428_efl_ui_image_zoomable_pan_efl_object_destructor(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd) 429_efl_ui_image_zoomable_pan_efl_object_destructor(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
429{ 430{
430 efl_data_unref(psd->wobj, psd->wsd); 431 efl_data_unref(psd->wobj, psd->wsd);
432
431 efl_destructor(efl_super(obj, MY_PAN_CLASS)); 433 efl_destructor(efl_super(obj, MY_PAN_CLASS));
432} 434}
433 435
@@ -725,28 +727,28 @@ static Eina_Bool
725_zoom_do(Evas_Object *obj, 727_zoom_do(Evas_Object *obj,
726 double t) 728 double t)
727{ 729{
728 Evas_Coord xx, yy, ow = 0, oh = 0; 730 Evas_Coord xx, yy;
731 Eina_Rect view = {};
729 732
730 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 733 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
731 734
732 sd->size.w = (sd->size.ow * (1.0 - t)) + (sd->size.nw * t); 735 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); 736 sd->size.h = (sd->size.oh * (1.0 - t)) + (sd->size.nh * t);
734 elm_interface_scrollable_content_viewport_geometry_get 737 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
735 (obj, NULL, NULL, &ow, &oh); 738 xx = (sd->size.spos.x * sd->size.w) - (view.w / 2);
736 xx = (sd->size.spos.x * sd->size.w) - (ow / 2); 739 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; 740 if (xx < 0) xx = 0;
739 else if (xx > (sd->size.w - ow)) 741 else if (xx > (sd->size.w - view.w))
740 xx = sd->size.w - ow; 742 xx = sd->size.w - view.w;
741 if (yy < 0) yy = 0; 743 if (yy < 0) yy = 0;
742 else if (yy > (sd->size.h - oh)) 744 else if (yy > (sd->size.h - view.h))
743 yy = sd->size.h - oh; 745 yy = sd->size.h - view.h;
744 746
745 sd->show.show = EINA_TRUE; 747 sd->show_item = EINA_TRUE;
746 sd->show.x = xx; 748 sd->show.x = xx;
747 sd->show.y = yy; 749 sd->show.y = yy;
748 sd->show.w = ow; 750 sd->show.w = view.w;
749 sd->show.h = oh; 751 sd->show.h = view.h;
750 752
751 if (sd->orientation_changed) 753 if (sd->orientation_changed)
752 { 754 {
@@ -886,7 +888,7 @@ _efl_ui_image_zoomable_elm_widget_on_focus_update(Eo *obj, Efl_Ui_Image_Zoomable
886} 888}
887 889
888EOLIAN static Efl_Ui_Theme_Apply 890EOLIAN static Efl_Ui_Theme_Apply
889_efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED) 891_efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
890{ 892{
891 Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED; 893 Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED;
892 Eina_Bool fdo = EINA_FALSE; 894 Eina_Bool fdo = EINA_FALSE;
@@ -897,47 +899,18 @@ _efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Dat
897 int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS)); 899 int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
898 if (!int_ret) return EFL_UI_THEME_APPLY_FAILED; 900 if (!int_ret) return EFL_UI_THEME_APPLY_FAILED;
899 901
902 efl_ui_mirrored_set(sd->smanager, efl_ui_mirrored_get(obj));
903
900 _sizing_eval(obj); 904 _sizing_eval(obj);
901 905
902 return int_ret; 906 return int_ret;
903} 907}
904 908
905static void 909static void
906_scroll_animate_start_cb(Evas_Object *obj, 910_scroll_cb(void * data,
907 void *data EINA_UNUSED) 911 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{ 912{
913 Evas_Object *obj = data;
941 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 914 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
942 915
943 if (!sd->scr_timer) 916 if (!sd->scr_timer)
@@ -948,63 +921,56 @@ _scroll_cb(Evas_Object *obj,
948 921
949 ecore_timer_del(sd->scr_timer); 922 ecore_timer_del(sd->scr_timer);
950 sd->scr_timer = ecore_timer_add(0.5, _scroll_timeout_cb, obj); 923 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} 924}
955 925
956static Eina_Bool 926static Eina_Bool
957_key_action_move(Evas_Object *obj, const char *params) 927_key_action_move(Evas_Object *obj, const char *params)
958{ 928{
929 Eina_Rect view = {};
930 Eina_Position2D pos = {};
959 const char *dir = params; 931 const char *dir = params;
932 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
960 933
961 Evas_Coord x = 0;
962 Evas_Coord y = 0;
963 Evas_Coord v_h = 0;
964 Evas_Coord step_x = 0; 934 Evas_Coord step_x = 0;
965 Evas_Coord step_y = 0; 935 Evas_Coord step_y = 0;
966 Evas_Coord page_x = 0;
967 Evas_Coord page_y = 0; 936 Evas_Coord page_y = 0;
968 937
969 elm_interface_scrollable_content_pos_get(obj, &x, &y); 938 pos = efl_ui_scrollable_content_pos_get(sd->smanager);
970 elm_interface_scrollable_step_size_get(obj, &step_x, &step_y); 939 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 940
975 if (!strcmp(dir, "left")) 941 if (!strcmp(dir, "left"))
976 { 942 {
977 x -= step_x; 943 pos.x -= step_x;
978 } 944 }
979 else if (!strcmp(dir, "right")) 945 else if (!strcmp(dir, "right"))
980 { 946 {
981 x += step_x; 947 pos.x += step_x;
982 } 948 }
983 else if (!strcmp(dir, "up")) 949 else if (!strcmp(dir, "up"))
984 { 950 {
985 y -= step_y; 951 pos.y -= step_y;
986 } 952 }
987 else if (!strcmp(dir, "down")) 953 else if (!strcmp(dir, "down"))
988 { 954 {
989 y += step_y; 955 pos.y += step_y;
990 } 956 }
991 else if (!strcmp(dir, "prior")) 957 else if (!strcmp(dir, "prior"))
992 { 958 {
993 if (page_y < 0) 959 if (page_y < 0)
994 y -= -(page_y * v_h) / 100; 960 pos.y -= -(page_y * view.h) / 100;
995 else 961 else
996 y -= page_y; 962 pos.y -= page_y;
997 } 963 }
998 else if (!strcmp(dir, "next")) 964 else if (!strcmp(dir, "next"))
999 { 965 {
1000 if (page_y < 0) 966 if (page_y < 0)
1001 y += -(page_y * v_h) / 100; 967 pos.y += -(page_y * view.h) / 100;
1002 else 968 else
1003 y += page_y; 969 pos.y += page_y;
1004 } 970 }
1005 else return EINA_FALSE; 971 else return EINA_FALSE;
1006 972
1007 elm_interface_scrollable_content_pos_set(obj, x, y, EINA_TRUE); 973 efl_ui_scrollable_content_pos_set(sd->smanager, pos);
1008 return EINA_TRUE; 974 return EINA_TRUE;
1009} 975}
1010 976
@@ -1076,7 +1042,7 @@ _bounce_eval(void *data, const Efl_Event *event EINA_UNUSED)
1076 sd->g_layer_zoom.imy = 0; 1042 sd->g_layer_zoom.imy = 0;
1077 sd->zoom_g_layer = EINA_FALSE; 1043 sd->zoom_g_layer = EINA_FALSE;
1078 1044
1079 elm_interface_scrollable_freeze_set(obj, EINA_FALSE); 1045 efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_FALSE);
1080 1046
1081 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj); 1047 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
1082} 1048}
@@ -1112,18 +1078,16 @@ _g_layer_zoom_do(Evas_Object *obj,
1112 Elm_Gesture_Zoom_Info *g_layer) 1078 Elm_Gesture_Zoom_Info *g_layer)
1113{ 1079{
1114 int regx, regy, regw, regh, ix, iy, iw, ih; 1080 int regx, regy, regw, regh, ix, iy, iw, ih;
1115 Evas_Coord rx, ry, rw = 0, rh = 0;
1116 int xx, yy; 1081 int xx, yy;
1082 Eina_Rect view = {};
1117 1083
1118 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1084 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1119 sd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL; 1085 sd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
1120 sd->zoom = sd->g_layer_start / g_layer->zoom; 1086 sd->zoom = sd->g_layer_start / g_layer->zoom;
1121 sd->size.ow = sd->size.w; 1087 sd->size.ow = sd->size.w;
1122 sd->size.oh = sd->size.h; 1088 sd->size.oh = sd->size.h;
1123 elm_interface_scrollable_content_pos_get(obj, &rx, &ry); 1089 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1124 elm_interface_scrollable_content_viewport_geometry_get 1090 if ((view.w <= 0) || (view.h <= 0)) return;
1125 (obj, NULL, NULL, &rw, &rh);
1126 if ((rw <= 0) || (rh <= 0)) return;
1127 1091
1128 sd->size.nw = (double)sd->size.imw / sd->zoom; 1092 sd->size.nw = (double)sd->size.imw / sd->zoom;
1129 sd->size.nh = (double)sd->size.imh / sd->zoom; 1093 sd->size.nh = (double)sd->size.imh / sd->zoom;
@@ -1139,30 +1103,30 @@ _g_layer_zoom_do(Evas_Object *obj,
1139 sd->g_layer_zoom.imx = 0; 1103 sd->g_layer_zoom.imx = 0;
1140 sd->g_layer_zoom.imy = 0; 1104 sd->g_layer_zoom.imy = 0;
1141 1105
1142 if ((xx < 0) || (rw > sd->size.nw)) 1106 if ((xx < 0) || (view.w > sd->size.nw))
1143 { 1107 {
1144 sd->g_layer_zoom.imx = xx; 1108 sd->g_layer_zoom.imx = xx;
1145 xx = 0; 1109 xx = 0;
1146 } 1110 }
1147 else if ((xx + rw) > sd->size.nw) 1111 else if ((xx + view.w) > sd->size.nw)
1148 { 1112 {
1149 sd->g_layer_zoom.imx = xx + rw - sd->size.nw; 1113 sd->g_layer_zoom.imx = xx + view.w - sd->size.nw;
1150 xx = sd->size.nw - rw; 1114 xx = sd->size.nw - view.w;
1151 } 1115 }
1152 1116
1153 if ((yy < 0) || (rh > sd->size.nh)) 1117 if ((yy < 0) || (view.h > sd->size.nh))
1154 { 1118 {
1155 sd->g_layer_zoom.imy = yy; 1119 sd->g_layer_zoom.imy = yy;
1156 yy = 0; 1120 yy = 0;
1157 } 1121 }
1158 else if ((yy + rh) > sd->size.nh) 1122 else if ((yy + view.h) > sd->size.nh)
1159 { 1123 {
1160 sd->g_layer_zoom.imy = yy + rh - sd->size.nh; 1124 sd->g_layer_zoom.imy = yy + view.h - sd->size.nh;
1161 yy = sd->size.nh - rh; 1125 yy = sd->size.nh - view.h;
1162 } 1126 }
1163 1127
1164 sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw); 1128 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); 1129 sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
1166 1130
1167 _zoom_do(obj, 1.0); 1131 _zoom_do(obj, 1.0);
1168} 1132}
@@ -1175,22 +1139,21 @@ _g_layer_zoom_start_cb(void *data,
1175 Elm_Gesture_Zoom_Info *p = event_info; 1139 Elm_Gesture_Zoom_Info *p = event_info;
1176 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1140 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1177 double marginx = 0, marginy = 0; 1141 double marginx = 0, marginy = 0;
1178 Evas_Coord rw = 0, rh = 0;
1179 int x, y, w, h; 1142 int x, y, w, h;
1143 Eina_Rect view = {};
1180 1144
1181 _efl_ui_image_zoomable_bounce_reset(obj, sd); 1145 _efl_ui_image_zoomable_bounce_reset(obj, sd);
1182 sd->zoom_g_layer = EINA_TRUE; 1146 sd->zoom_g_layer = EINA_TRUE;
1183 1147
1184 elm_interface_scrollable_freeze_set(obj, EINA_TRUE); 1148 efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_TRUE);
1185 1149
1186 elm_photocam_image_region_get(obj, &x, &y, &w, &h); 1150 elm_photocam_image_region_get(obj, &x, &y, &w, &h);
1187 elm_interface_scrollable_content_viewport_geometry_get 1151 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1188 (obj, NULL, NULL, &rw, &rh);
1189 1152
1190 if (rw > sd->size.nw) 1153 if (view.w > sd->size.nw)
1191 marginx = (rw - sd->size.nw) / 2; 1154 marginx = (view.w - sd->size.nw) / 2;
1192 if (rh > sd->size.nh) 1155 if (view.h > sd->size.nh)
1193 marginy = (rh - sd->size.nh) / 2; 1156 marginy = (view.h - sd->size.nh) / 2;
1194 1157
1195 sd->g_layer_start = sd->zoom; 1158 sd->g_layer_start = sd->zoom;
1196 1159
@@ -1220,10 +1183,8 @@ _g_layer_zoom_end_cb(void *data,
1220{ 1183{
1221 Evas_Object *obj = data; 1184 Evas_Object *obj = data;
1222 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd); 1185 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1223 Evas_Coord rw, rh;
1224 1186
1225 elm_interface_scrollable_content_viewport_geometry_get 1187 Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1226 (obj, NULL, NULL, &rw, &rh);
1227 sd->g_layer_start = 1.0; 1188 sd->g_layer_start = 1.0;
1228 1189
1229 if (sd->g_layer_zoom.imx || sd->g_layer_zoom.imy) 1190 if (sd->g_layer_zoom.imx || sd->g_layer_zoom.imy)
@@ -1236,13 +1197,13 @@ _g_layer_zoom_end_cb(void *data,
1236 sd->g_layer_zoom.bounce.x_end = 0; 1197 sd->g_layer_zoom.bounce.x_end = 0;
1237 sd->g_layer_zoom.bounce.y_end = 0; 1198 sd->g_layer_zoom.bounce.y_end = 0;
1238 1199
1239 if (rw > sd->size.nw && 1200 if (view.w > sd->size.nw &&
1240 rh > sd->size.nh) 1201 view.h > sd->size.nh)
1241 { 1202 {
1242 Evas_Coord pw, ph; 1203 Evas_Coord pw, ph;
1243 double z; 1204 double z;
1244 1205
1245 if ((sd->size.imw < rw) && (sd->size.imh < rh)) 1206 if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
1246 { 1207 {
1247 sd->zoom = 1; 1208 sd->zoom = 1;
1248 sd->size.nw = sd->size.imw; 1209 sd->size.nw = sd->size.imw;
@@ -1250,15 +1211,15 @@ _g_layer_zoom_end_cb(void *data,
1250 } 1211 }
1251 else 1212 else
1252 { 1213 {
1253 ph = (sd->size.imh * rw) / sd->size.imw; 1214 ph = (sd->size.imh * view.w) / sd->size.imw;
1254 if (ph > rh) 1215 if (ph > view.h)
1255 { 1216 {
1256 pw = (sd->size.imw * rh) / sd->size.imh; 1217 pw = (sd->size.imw * view.h) / sd->size.imh;
1257 ph = rh; 1218 ph = view.h;
1258 } 1219 }
1259 else 1220 else
1260 { 1221 {
1261 pw = rw; 1222 pw = view.w;
1262 } 1223 }
1263 if (sd->size.imw > sd->size.imh) 1224 if (sd->size.imw > sd->size.imh)
1264 z = (double)sd->size.imw / pw; 1225 z = (double)sd->size.imw / pw;
@@ -1269,8 +1230,8 @@ _g_layer_zoom_end_cb(void *data,
1269 sd->size.nw = pw; 1230 sd->size.nw = pw;
1270 sd->size.nh = ph; 1231 sd->size.nh = ph;
1271 } 1232 }
1272 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2; 1233 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; 1234 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
1274 } 1235 }
1275 else 1236 else
1276 { 1237 {
@@ -1282,18 +1243,18 @@ _g_layer_zoom_end_cb(void *data,
1282 if (xx < 0) xx = 0; 1243 if (xx < 0) xx = 0;
1283 if (yy < 0) yy = 0; 1244 if (yy < 0) yy = 0;
1284 1245
1285 if (rw > sd->size.nw) 1246 if (view.w > sd->size.nw)
1286 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2; 1247 sd->g_layer_zoom.bounce.x_end = (sd->size.nw - view.w) / 2;
1287 if ((xx + rw) > sd->size.nw) 1248 if ((xx + view.w) > sd->size.nw)
1288 xx = sd->size.nw - rw; 1249 xx = sd->size.nw - view.w;
1289 1250
1290 if (rh > sd->size.nh) 1251 if (view.h > sd->size.nh)
1291 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - rh) / 2; 1252 sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
1292 if ((yy + rh) > sd->size.nh) 1253 if ((yy + view.h) > sd->size.nh)
1293 yy = sd->size.nh - rh; 1254 yy = sd->size.nh - view.h;
1294 1255
1295 sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw); 1256 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); 1257 sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
1297 } 1258 }
1298 1259
1299 sd->g_layer_zoom.bounce.t_start = t; 1260 sd->g_layer_zoom.bounce.t_start = t;
@@ -1304,7 +1265,7 @@ _g_layer_zoom_end_cb(void *data,
1304 } 1265 }
1305 else 1266 else
1306 { 1267 {
1307 elm_interface_scrollable_freeze_set(obj, EINA_FALSE); 1268 efl_ui_scrollable_scroll_freeze_set(obj, EINA_FALSE);
1308 sd->zoom_g_layer = EINA_FALSE; 1269 sd->zoom_g_layer = EINA_FALSE;
1309 } 1270 }
1310 1271
@@ -1399,6 +1360,297 @@ _efl_ui_image_zoomable_efl_flipable_flip_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Z
1399 return sd->flip; 1360 return sd->flip;
1400} 1361}
1401 1362
1363static void
1364_efl_ui_image_zoomable_bar_read_and_update(Eo *obj)
1365{
1366 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1367 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1368 double vx, vy;
1369
1370 edje_object_part_drag_value_get
1371 (wd->resize_obj, "elm.dragable.vbar", NULL, &vy);
1372 edje_object_part_drag_value_get
1373 (wd->resize_obj, "elm.dragable.hbar", &vx, NULL);
1374 efl_ui_scrollbar_bar_position_set(sd->smanager, vx, vy);
1375}
1376
1377static void
1378_efl_ui_image_zoomable_reload_cb(void *data,
1379 Evas_Object *obj EINA_UNUSED,
1380 const char *emission EINA_UNUSED,
1381 const char *source EINA_UNUSED)
1382{
1383 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1384
1385 efl_ui_scrollbar_bar_visibility_update(sd->smanager);
1386}
1387
1388static void
1389_efl_ui_image_zoomable_vbar_drag_cb(void *data,
1390 Evas_Object *obj EINA_UNUSED,
1391 const char *emission EINA_UNUSED,
1392 const char *source EINA_UNUSED)
1393{
1394 _efl_ui_image_zoomable_bar_read_and_update(data);
1395
1396 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1397 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
1398}
1399
1400static void
1401_efl_ui_image_zoomable_vbar_press_cb(void *data,
1402 Evas_Object *obj EINA_UNUSED,
1403 const char *emission EINA_UNUSED,
1404 const char *source EINA_UNUSED)
1405{
1406 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1407 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
1408}
1409
1410static void
1411_efl_ui_image_zoomable_vbar_unpress_cb(void *data,
1412 Evas_Object *obj EINA_UNUSED,
1413 const char *emission EINA_UNUSED,
1414 const char *source EINA_UNUSED)
1415{
1416 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
1417 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
1418}
1419
1420static void
1421_efl_ui_image_zoomable_edje_drag_start_cb(void *data,
1422 Evas_Object *obj EINA_UNUSED,
1423 const char *emission EINA_UNUSED,
1424 const char *source EINA_UNUSED)
1425{
1426 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1427
1428 _efl_ui_image_zoomable_bar_read_and_update(data);
1429
1430 sd->freeze_want = efl_ui_scrollable_scroll_freeze_get(sd->smanager);
1431 efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_TRUE);
1432 efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
1433}
1434
1435static void
1436_efl_ui_image_zoomable_edje_drag_stop_cb(void *data,
1437 Evas_Object *obj EINA_UNUSED,
1438 const char *emission EINA_UNUSED,
1439 const char *source EINA_UNUSED)
1440{
1441 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
1442
1443 _efl_ui_image_zoomable_bar_read_and_update(data);
1444
1445 efl_ui_scrollable_scroll_freeze_set(sd->smanager, sd->freeze_want);
1446 efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
1447}
1448
1449static void
1450_efl_ui_image_zoomable_edje_drag_cb(void *data,
1451 Evas_Object *obj EINA_UNUSED,
1452 const char *emission EINA_UNUSED,
1453 const char *source EINA_UNUSED)
1454{
1455 _efl_ui_image_zoomable_bar_read_and_update(data);
1456}
1457
1458static void
1459_efl_ui_image_zoomable_hbar_drag_cb(void *data,
1460 Evas_Object *obj EINA_UNUSED,
1461 const char *emission EINA_UNUSED,
1462 const char *source EINA_UNUSED)
1463{
1464 _efl_ui_image_zoomable_bar_read_and_update(data);
1465
1466 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1467 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
1468}
1469
1470static void
1471_efl_ui_image_zoomable_hbar_press_cb(void *data,
1472 Evas_Object *obj EINA_UNUSED,
1473 const char *emission EINA_UNUSED,
1474 const char *source EINA_UNUSED)
1475{
1476 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1477 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
1478}
1479
1480static void
1481_efl_ui_image_zoomable_hbar_unpress_cb(void *data,
1482 Evas_Object *obj EINA_UNUSED,
1483 const char *emission EINA_UNUSED,
1484 const char *source EINA_UNUSED)
1485{
1486 Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
1487 efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
1488}
1489
1490static void
1491_efl_ui_image_zoomable_bar_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
1492{
1493 Eo *obj = data;
1494 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1495 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1496
1497 double width = 0.0, height = 0.0;
1498
1499 efl_ui_scrollbar_bar_size_get(sd->smanager, &width, &height);
1500 edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.hbar", width, 1.0);
1501 edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.vbar", 1.0, height);
1502}
1503
1504static void
1505_efl_ui_image_zoomable_bar_pos_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
1506{
1507 Eo *obj = data;
1508 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
1509 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1510
1511 double posx = 0.0, posy = 0.0;
1512
1513 efl_ui_scrollbar_bar_position_get(sd->smanager, &posx, &posy);
1514 edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.hbar", posx, 0.0);
1515 edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.vbar", 0.0, posy);
1516}
1517
1518static void
1519_efl_ui_image_zoomable_bar_show_cb(void *data, const Efl_Event *event)
1520{
1521 Eo *obj = data;
1522 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1523 Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
1524
1525 if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
1526 edje_object_signal_emit(wd->resize_obj, "elm,action,show,hbar", "elm");
1527 else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
1528 edje_object_signal_emit(wd->resize_obj, "elm,action,show,vbar", "elm");
1529}
1530
1531static void
1532_efl_ui_image_zoomable_bar_hide_cb(void *data, const Efl_Event *event)
1533{
1534 Eo *obj = data;
1535 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1536 Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
1537
1538 if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
1539 edje_object_signal_emit(wd->resize_obj, "elm,action,hide,hbar", "elm");
1540 else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
1541 edje_object_signal_emit(wd->resize_obj, "elm,action,hide,vbar", "elm");
1542}
1543
1544static void
1545_efl_ui_image_zoomable_edje_object_attach(Eo *obj)
1546{
1547 efl_layout_signal_callback_add
1548 (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
1549 efl_layout_signal_callback_add
1550 (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
1551 obj);
1552 efl_layout_signal_callback_add
1553 (obj, "drag,set", "elm.dragable.vbar",
1554 _efl_ui_image_zoomable_edje_drag_cb, obj);
1555 efl_layout_signal_callback_add
1556 (obj, "drag,start", "elm.dragable.vbar",
1557 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1558 efl_layout_signal_callback_add
1559 (obj, "drag,stop", "elm.dragable.vbar",
1560 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1561 efl_layout_signal_callback_add
1562 (obj, "drag,step", "elm.dragable.vbar",
1563 _efl_ui_image_zoomable_edje_drag_cb, obj);
1564 efl_layout_signal_callback_add
1565 (obj, "drag,page", "elm.dragable.vbar",
1566 _efl_ui_image_zoomable_edje_drag_cb, obj);
1567 efl_layout_signal_callback_add
1568 (obj, "elm,vbar,press", "elm",
1569 _efl_ui_image_zoomable_vbar_press_cb, obj);
1570 efl_layout_signal_callback_add
1571 (obj, "elm,vbar,unpress", "elm",
1572 _efl_ui_image_zoomable_vbar_unpress_cb, obj);
1573 efl_layout_signal_callback_add
1574 (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
1575 obj);
1576 efl_layout_signal_callback_add
1577 (obj, "drag,set", "elm.dragable.hbar",
1578 _efl_ui_image_zoomable_edje_drag_cb, obj);
1579 efl_layout_signal_callback_add
1580 (obj, "drag,start", "elm.dragable.hbar",
1581 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1582 efl_layout_signal_callback_add
1583 (obj, "drag,stop", "elm.dragable.hbar",
1584 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1585 efl_layout_signal_callback_add
1586 (obj, "drag,step", "elm.dragable.hbar",
1587 _efl_ui_image_zoomable_edje_drag_cb, obj);
1588 efl_layout_signal_callback_add
1589 (obj, "drag,page", "elm.dragable.hbar",
1590 _efl_ui_image_zoomable_edje_drag_cb, obj);
1591 efl_layout_signal_callback_add
1592 (obj, "elm,hbar,press", "elm",
1593 _efl_ui_image_zoomable_hbar_press_cb, obj);
1594 efl_layout_signal_callback_add
1595 (obj, "elm,hbar,unpress", "elm",
1596 _efl_ui_image_zoomable_hbar_unpress_cb, obj);
1597}
1598
1599static void
1600_efl_ui_image_zoomable_edje_object_detach(Evas_Object *obj)
1601{
1602 efl_layout_signal_callback_del
1603 (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
1604 efl_layout_signal_callback_del
1605 (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
1606 obj);
1607 efl_layout_signal_callback_del
1608 (obj, "drag,set", "elm.dragable.vbar",
1609 _efl_ui_image_zoomable_edje_drag_cb, obj);
1610 efl_layout_signal_callback_del
1611 (obj, "drag,start", "elm.dragable.vbar",
1612 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1613 efl_layout_signal_callback_del
1614 (obj, "drag,stop", "elm.dragable.vbar",
1615 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1616 efl_layout_signal_callback_del
1617 (obj, "drag,step", "elm.dragable.vbar",
1618 _efl_ui_image_zoomable_edje_drag_cb, obj);
1619 efl_layout_signal_callback_del
1620 (obj, "drag,page", "elm.dragable.vbar",
1621 _efl_ui_image_zoomable_edje_drag_cb, obj);
1622 efl_layout_signal_callback_del
1623 (obj, "elm,vbar,press", "elm",
1624 _efl_ui_image_zoomable_vbar_press_cb, obj);
1625 efl_layout_signal_callback_del
1626 (obj, "elm,vbar,unpress", "elm",
1627 _efl_ui_image_zoomable_vbar_unpress_cb, obj);
1628 efl_layout_signal_callback_del
1629 (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
1630 obj);
1631 efl_layout_signal_callback_del
1632 (obj, "drag,set", "elm.dragable.hbar",
1633 _efl_ui_image_zoomable_edje_drag_cb, obj);
1634 efl_layout_signal_callback_del
1635 (obj, "drag,start", "elm.dragable.hbar",
1636 _efl_ui_image_zoomable_edje_drag_start_cb, obj);
1637 efl_layout_signal_callback_del
1638 (obj, "drag,stop", "elm.dragable.hbar",
1639 _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
1640 efl_layout_signal_callback_del
1641 (obj, "drag,step", "elm.dragable.hbar",
1642 _efl_ui_image_zoomable_edje_drag_cb, obj);
1643 efl_layout_signal_callback_del
1644 (obj, "drag,page", "elm.dragable.hbar",
1645 _efl_ui_image_zoomable_edje_drag_cb, obj);
1646 efl_layout_signal_callback_del
1647 (obj, "elm,hbar,press", "elm",
1648 _efl_ui_image_zoomable_hbar_press_cb, obj);
1649 efl_layout_signal_callback_del
1650 (obj, "elm,hbar,unpress", "elm",
1651 _efl_ui_image_zoomable_hbar_unpress_cb, obj);
1652}
1653
1402EOLIAN static void 1654EOLIAN static void
1403_efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *priv) 1655_efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *priv)
1404{ 1656{
@@ -1417,34 +1669,24 @@ _efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable
1417 elm_widget_theme_object_set 1669 elm_widget_theme_object_set
1418 (obj, edje, "photocam", "base", elm_widget_style_get(obj)); 1670 (obj, edje, "photocam", "base", elm_widget_style_get(obj));
1419 1671
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); 1672 elm_widget_can_focus_set(obj, EINA_TRUE);
1430 1673
1431 elm_interface_scrollable_objects_set(obj, edje, priv->hit_rect); 1674 priv->smanager = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj);
1432 1675
1433 elm_interface_scrollable_animate_start_cb_set(obj, _scroll_animate_start_cb); 1676 efl_ui_mirrored_set(priv->smanager, efl_ui_mirrored_get(obj));
1434 elm_interface_scrollable_animate_stop_cb_set(obj, _scroll_animate_stop_cb); 1677 efl_ui_scrollable_bounce_enabled_set(priv->smanager, bounce, bounce);
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 1678
1439 elm_interface_scrollable_bounce_allow_set(obj, bounce, bounce); 1679 priv->pan_obj = efl_add(MY_PAN_CLASS, obj);
1680
1681 efl_ui_scroll_manager_pan_set(priv->smanager, priv->pan_obj);
1682 edje_object_part_swallow(edje, "elm.swallow.content", priv->pan_obj);
1440 1683
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); 1684 pan_data = efl_data_scope_get(priv->pan_obj, MY_PAN_CLASS);
1443 efl_data_ref(obj, MY_CLASS); 1685 efl_data_ref(obj, MY_CLASS);
1444 pan_data->wobj = obj; 1686 pan_data->wobj = obj;
1445 pan_data->wsd = priv; 1687 pan_data->wsd = priv;
1446 1688
1447 elm_interface_scrollable_extern_pan_set(obj, priv->pan_obj); 1689 efl_event_callback_add(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
1448 1690
1449 priv->g_layer_start = 1.0; 1691 priv->g_layer_start = 1.0;
1450 priv->zoom = 1; 1692 priv->zoom = 1;
@@ -1471,8 +1713,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); 1713 edje_object_size_min_calc(edje, &minw, &minh);
1472 evas_object_size_hint_min_set(obj, minw, minh); 1714 evas_object_size_hint_min_set(obj, minw, minh);
1473 1715
1474 _sizing_eval(obj); 1716 _efl_ui_image_zoomable_edje_object_attach(obj);
1475 1717
1718 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED,
1719 _efl_ui_image_zoomable_bar_size_changed_cb, obj);
1720 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED,
1721 _efl_ui_image_zoomable_bar_pos_changed_cb, obj);
1722 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW,
1723 _efl_ui_image_zoomable_bar_show_cb, obj);
1724 efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE,
1725 _efl_ui_image_zoomable_bar_hide_cb, obj);
1726 _sizing_eval(obj);
1476} 1727}
1477 1728
1478EOLIAN static void 1729EOLIAN static void
@@ -1500,38 +1751,38 @@ _efl_ui_image_zoomable_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Image_Zoomable
1500 ecore_timer_del(sd->long_timer); 1751 ecore_timer_del(sd->long_timer);
1501 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _zoom_anim_cb, obj); 1752 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); 1753 efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
1754 efl_event_callback_del(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
1503 1755
1756 _efl_ui_image_zoomable_edje_object_detach(obj);
1757 efl_del(sd->pan_obj);
1758 sd->pan_obj = NULL;
1759 efl_del(sd->smanager);
1760 sd->smanager = NULL;
1504 efl_canvas_group_del(efl_super(obj, MY_CLASS)); 1761 efl_canvas_group_del(efl_super(obj, MY_CLASS));
1505} 1762}
1506 1763
1507EOLIAN static void 1764EOLIAN static void
1508_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Position2D pos) 1765_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sdi EINA_UNUSED, Eina_Position2D pos)
1509{ 1766{
1510 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y)) 1767 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
1511 return; 1768 return;
1512 1769
1513 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos); 1770 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
1514 efl_gfx_position_set(sd->hit_rect, pos);
1515} 1771}
1516 1772
1517EOLIAN static void 1773EOLIAN static void
1518_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Size2D sz) 1774_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Eina_Size2D sz)
1519{ 1775{
1520 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h)) 1776 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
1521 return; 1777 return;
1522 1778
1523 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz); 1779 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
1524 efl_gfx_size_set(sd->hit_rect, sz);
1525} 1780}
1526 1781
1527EOLIAN static void 1782EOLIAN static void
1528_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Evas_Object *member) 1783_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Evas_Object *member)
1529{ 1784{
1530
1531 efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member); 1785 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} 1786}
1536 1787
1537EOLIAN static Eo * 1788EOLIAN static Eo *
@@ -1569,6 +1820,28 @@ _efl_ui_image_zoomable_efl_layout_group_group_size_max_get(Eo *obj EINA_UNUSED,
1569 return EINA_SIZE2D(0, 0); 1820 return EINA_SIZE2D(0, 0);
1570} 1821}
1571 1822
1823EOLIAN static Eina_Bool
1824_efl_ui_image_zoomable_efl_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)
1825{
1826 Eina_Bool ok;
1827 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
1828
1829 ok = efl_layout_signal_callback_add(wd->resize_obj, emission, source, func_cb, data);
1830
1831 return ok;
1832}
1833
1834EOLIAN static Eina_Bool
1835_efl_ui_image_zoomable_efl_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)
1836{
1837 Eina_Bool ok;
1838 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
1839
1840 ok = efl_layout_signal_callback_del(wd->resize_obj, emission, source, func_cb, data);
1841
1842 return ok;
1843}
1844
1572static Eina_Bool 1845static Eina_Bool
1573_img_proxy_set(Evas_Object *obj, Efl_Ui_Image_Zoomable_Data *sd, 1846_img_proxy_set(Evas_Object *obj, Efl_Ui_Image_Zoomable_Data *sd,
1574 const char *file, const Eina_File *f, const char *group, 1847 const char *file, const Eina_File *f, const char *group,
@@ -1960,9 +2233,11 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1960 double z; 2233 double z;
1961 Eina_List *l; 2234 Eina_List *l;
1962 Efl_Ui_Image_Zoomable_Grid *g, *g_zoom = NULL; 2235 Efl_Ui_Image_Zoomable_Grid *g, *g_zoom = NULL;
1963 Evas_Coord pw, ph, rx, ry, rw, rh; 2236 Evas_Coord pw, ph;
1964 int zoom_changed = 0, started = 0; 2237 int zoom_changed = 0, started = 0;
1965 Eina_Bool an = EINA_FALSE; 2238 Eina_Bool an = EINA_FALSE;
2239 Eina_Rect view = {};
2240 Eina_Position2D pos = {};
1966 2241
1967 if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0); 2242 if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0);
1968 if (EINA_DBL_EQ(zoom, sd->zoom)) return; 2243 if (EINA_DBL_EQ(zoom, sd->zoom)) return;
@@ -1970,10 +2245,9 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1970 sd->zoom = zoom; 2245 sd->zoom = zoom;
1971 sd->size.ow = sd->size.w; 2246 sd->size.ow = sd->size.w;
1972 sd->size.oh = sd->size.h; 2247 sd->size.oh = sd->size.h;
1973 elm_interface_scrollable_content_pos_get(obj, &rx, &ry); 2248 pos = efl_ui_scrollable_content_pos_get(sd->smanager);
1974 elm_interface_scrollable_content_viewport_geometry_get 2249 view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
1975 (obj, NULL, NULL, &rw, &rh); 2250 if ((view.w <= 0) || (view.h <= 0)) return;
1976 if ((rw <= 0) || (rh <= 0)) return;
1977 2251
1978 if (sd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL) 2252 if (sd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
1979 { 2253 {
@@ -1989,15 +2263,15 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
1989 } 2263 }
1990 else 2264 else
1991 { 2265 {
1992 ph = (sd->size.imh * rw) / sd->size.imw; 2266 ph = (sd->size.imh * view.w) / sd->size.imw;
1993 if (ph > rh) 2267 if (ph > view.h)
1994 { 2268 {
1995 pw = (sd->size.imw * rh) / sd->size.imh; 2269 pw = (sd->size.imw * view.h) / sd->size.imh;
1996 ph = rh; 2270 ph = view.h;
1997 } 2271 }
1998 else 2272 else
1999 { 2273 {
2000 pw = rw; 2274 pw = view.w;
2001 } 2275 }
2002 if (sd->size.imw > sd->size.imh) 2276 if (sd->size.imw > sd->size.imh)
2003 z = (double)sd->size.imw / pw; 2277 z = (double)sd->size.imw / pw;
@@ -2019,15 +2293,15 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2019 } 2293 }
2020 else 2294 else
2021 { 2295 {
2022 ph = (sd->size.imh * rw) / sd->size.imw; 2296 ph = (sd->size.imh * view.w) / sd->size.imw;
2023 if (ph < rh) 2297 if (ph < view.h)
2024 { 2298 {
2025 pw = (sd->size.imw * rh) / sd->size.imh; 2299 pw = (sd->size.imw * view.h) / sd->size.imh;
2026 ph = rh; 2300 ph = view.h;
2027 } 2301 }
2028 else 2302 else
2029 { 2303 {
2030 pw = rw; 2304 pw = view.w;
2031 } 2305 }
2032 if (sd->size.imw > sd->size.imh) 2306 if (sd->size.imw > sd->size.imh)
2033 z = (double)sd->size.imw / pw; 2307 z = (double)sd->size.imw / pw;
@@ -2047,7 +2321,7 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2047 sd->size.nw = 0; 2321 sd->size.nw = 0;
2048 sd->size.nh = 0; 2322 sd->size.nh = 0;
2049 } 2323 }
2050 else if ((sd->size.imw < rw) && (sd->size.imh < rh)) 2324 else if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
2051 { 2325 {
2052 if (!EINA_DBL_EQ(sd->zoom, 1)) zoom_changed = 1; 2326 if (!EINA_DBL_EQ(sd->zoom, 1)) zoom_changed = 1;
2053 sd->zoom = 1; 2327 sd->zoom = 1;
@@ -2056,14 +2330,14 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
2056 } 2330 }
2057 else 2331 else
2058 { 2332 {
2059 ph = (sd->size.imh * rw) / sd->size.imw; 2333 ph = (sd->size.imh * view.w) / sd->size.imw;
2060 if (ph > rh) 2334 if (ph > view.h)
2061 { 2335 {
2062 pw = (sd->size.imw * rh) / sd->size.imh; 2336 pw = (sd->size.imw * view.h) / sd->size.imh;
2063 ph = rh; 2337 ph = view.h;
2064 } 2338 }
2065 else 2339 else
2066 pw = rw; 2340 pw = view.w;
2067 if (sd->size.imw > sd->size.imh) 2341 if (sd->size.imw > sd->size.imh)
2068 z = (double)sd->size.imw / pw; 2342 z = (double)sd->size.imw / pw;
2069 else 2343 else
@@ -2125,16 +2399,16 @@ done:
2125 sd->t_end = sd->t_start + _elm_config->zoom_friction; 2399 sd->t_end = sd->t_start + _elm_config->zoom_friction;
2126 if ((sd->size.w > 0) && (sd->size.h > 0)) 2400 if ((sd->size.w > 0) && (sd->size.h > 0))
2127 { 2401 {
2128 sd->size.spos.x = (double)(rx + (rw / 2)) / (double)sd->size.w; 2402 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; 2403 sd->size.spos.y = (double)(pos.y + (view.h / 2)) / (double)sd->size.h;
2130 } 2404 }
2131 else 2405 else
2132 { 2406 {
2133 sd->size.spos.x = 0.5; 2407 sd->size.spos.x = 0.5;
2134 sd->size.spos.y = 0.5; 2408 sd->size.spos.y = 0.5;
2135 } 2409 }
2136 if (rw > sd->size.w) sd->size.spos.x = 0.5; 2410 if (view.w > sd->size.w) sd->size.spos.x = 0.5;
2137 if (rh > sd->size.h) sd->size.spos.y = 0.5; 2411 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; 2412 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; 2413 if (sd->size.spos.y > 1.0) sd->size.spos.y = 1.0;
2140 2414
@@ -2212,20 +2486,18 @@ _efl_ui_image_zoomable_efl_gfx_view_view_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Im
2212} 2486}
2213 2487
2214EOLIAN static Eina_Rect 2488EOLIAN static Eina_Rect
2215_efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd) 2489_efl_ui_image_zoomable_image_region_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Data *sd)
2216{ 2490{
2217 Evas_Coord sx, sy, sw, sh;
2218 Eina_Rect region = {}; 2491 Eina_Rect region = {};
2219 2492
2220 elm_interface_scrollable_content_pos_get((Eo *)obj, &sx, &sy); 2493 Eina_Position2D pos = efl_ui_scrollable_content_pos_get(sd->smanager);
2221 elm_interface_scrollable_content_viewport_geometry_get 2494 Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
2222 ((Eo *)obj, NULL, NULL, &sw, &sh);
2223 2495
2224 if (sd->size.w > 0) 2496 if (sd->size.w > 0)
2225 { 2497 {
2226 region.x = (sd->size.imw * sx) / sd->size.w; 2498 region.x = (sd->size.imw * pos.x) / sd->size.w;
2227 if (region.x > sd->size.imw) region.x = sd->size.imw; 2499 if (region.x > sd->size.imw) region.x = sd->size.imw;
2228 region.w = (sd->size.imw * sw) / sd->size.w; 2500 region.w = (sd->size.imw * view.w) / sd->size.w;
2229 if (region.w > sd->size.imw) region.w = sd->size.imw; 2501 if (region.w > sd->size.imw) region.w = sd->size.imw;
2230 else if (region.w < 0) 2502 else if (region.w < 0)
2231 region.w = 0; 2503 region.w = 0;
@@ -2233,9 +2505,9 @@ _efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
2233 2505
2234 if (sd->size.h > 0) 2506 if (sd->size.h > 0)
2235 { 2507 {
2236 region.y = (sd->size.imh * sy) / sd->size.h; 2508 region.y = (sd->size.imh * pos.y) / sd->size.h;
2237 if (region.y > sd->size.imh) region.y = sd->size.imh; 2509 if (region.y > sd->size.imh) region.y = sd->size.imh;
2238 region.h = (sd->size.imh * sh) / sd->size.h; 2510 region.h = (sd->size.imh * view.h) / sd->size.h;
2239 if (region.h > sd->size.imh) region.h = sd->size.imh; 2511 if (region.h > sd->size.imh) region.h = sd->size.imh;
2240 else if (region.h < 0) 2512 else if (region.h < 0)
2241 region.h = 0; 2513 region.h = 0;
@@ -2262,19 +2534,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); 2534 _efl_ui_image_zoomable_bounce_reset(obj, sd);
2263 _efl_ui_image_zoomable_zoom_reset(obj, sd); 2535 _efl_ui_image_zoomable_zoom_reset(obj, sd);
2264 2536
2265 elm_interface_scrollable_content_region_show(obj, rx, ry, rw, rh); 2537 efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(rx, ry, rw, rh), EINA_FALSE);
2266} 2538}
2267 2539
2268EOLIAN static void 2540EOLIAN 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) 2541_efl_ui_image_zoomable_efl_ui_scrollable_interactive_scroll(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Rect rc, Eina_Bool animation)
2270{ 2542{
2271 int rx, ry, rw, rh; 2543 int rx, ry, rw, rh;
2272 2544
2273 if ((sd->size.imw < 1) || (sd->size.imh < 1)) return; 2545 if ((sd->size.imw < 1) || (sd->size.imh < 1)) return;
2274 rx = (x * sd->size.w) / sd->size.imw; 2546 rx = (rc.x * sd->size.w) / sd->size.imw;
2275 ry = (y * sd->size.h) / sd->size.imh; 2547 ry = (rc.y * sd->size.h) / sd->size.imh;
2276 rw = (w * sd->size.w) / sd->size.imw; 2548 rw = (rc.w * sd->size.w) / sd->size.imw;
2277 rh = (h * sd->size.h) / sd->size.imh; 2549 rh = (rc.h * sd->size.h) / sd->size.imh;
2278 if (rw < 1) rw = 1; 2550 if (rw < 1) rw = 1;
2279 if (rh < 1) rh = 1; 2551 if (rh < 1) rh = 1;
2280 if ((rx + rw) > sd->size.w) rx = sd->size.w - rw; 2552 if ((rx + rw) > sd->size.w) rx = sd->size.w - rw;
@@ -2283,7 +2555,7 @@ _efl_ui_image_zoomable_elm_interface_scrollable_region_bring_in(Eo *obj, Efl_Ui_
2283 _efl_ui_image_zoomable_bounce_reset(obj, sd); 2555 _efl_ui_image_zoomable_bounce_reset(obj, sd);
2284 _efl_ui_image_zoomable_zoom_reset(obj, sd); 2556 _efl_ui_image_zoomable_zoom_reset(obj, sd);
2285 2557
2286 elm_interface_scrollable_region_bring_in(efl_super(obj, MY_CLASS), rx, ry, rw, rh); 2558 efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(rx, ry, rw, rh), animation);
2287} 2559}
2288 2560
2289EOLIAN static void 2561EOLIAN static void
@@ -2915,7 +3187,8 @@ elm_photocam_image_region_bring_in(Evas_Object *obj,
2915 int h EINA_UNUSED) 3187 int h EINA_UNUSED)
2916{ 3188{
2917 ELM_PHOTOCAM_CHECK(obj); 3189 ELM_PHOTOCAM_CHECK(obj);
2918 elm_interface_scrollable_region_bring_in(obj, x, y, w, h); 3190 EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
3191 efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(x, y, w, h), EINA_TRUE);
2919} 3192}
2920 3193
2921EAPI void 3194EAPI void
@@ -2925,7 +3198,7 @@ elm_photocam_bounce_set(Evas_Object *obj,
2925{ 3198{
2926 ELM_PHOTOCAM_CHECK(obj); 3199 ELM_PHOTOCAM_CHECK(obj);
2927 3200
2928 elm_interface_scrollable_bounce_allow_set(obj, h_bounce, v_bounce); 3201 efl_ui_scrollable_bounce_enabled_set(obj, h_bounce, v_bounce);
2929} 3202}
2930 3203
2931EAPI void 3204EAPI void
@@ -2935,7 +3208,7 @@ elm_photocam_bounce_get(const Evas_Object *obj,
2935{ 3208{
2936 ELM_PHOTOCAM_CHECK(obj); 3209 ELM_PHOTOCAM_CHECK(obj);
2937 3210
2938 elm_interface_scrollable_bounce_allow_get((Eo *)obj, h_bounce, v_bounce); 3211 efl_ui_scrollable_bounce_enabled_get((Eo *)obj, h_bounce, v_bounce);
2939} 3212}
2940 3213
2941EAPI void 3214EAPI void
diff --git a/src/lib/elementary/efl_ui_image_zoomable.eo b/src/lib/elementary/efl_ui_image_zoomable.eo
index 62dc1b15e7..6aa65eaf64 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 Efl.Access.Widget.Action.elm_actions { get; } 65 Efl.Access.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.Layout.Group.group_size_min { get; } 69 Efl.Layout.Group.group_size_min { get; }
70 Efl.Layout.Group.group_size_max { get; } 70 Efl.Layout.Group.group_size_max { get; }
71 Efl.Layout.Signal.signal_callback_add;
72 Efl.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..35f62a5622 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.pan_position { get; set; }
13 Elm.Pan.pos_min { get; } 13 Efl.Ui.Pan.pan_position_min { get; }
14 Elm.Pan.pos_max { get; } 14 Efl.Ui.Pan.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..f6c065a41a
--- /dev/null
+++ b/src/lib/elementary/efl_ui_pan.c
@@ -0,0 +1,197 @@
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
24EOLIAN static void
25_efl_ui_pan_efl_gfx_position_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
26{
27 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
28 return;
29
30 efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
31
32 psd->x = pos.x;
33 psd->y = pos.y;
34
35 evas_object_smart_changed(obj);
36}
37
38EOLIAN static void
39_efl_ui_pan_efl_gfx_size_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Size2D sz)
40{
41 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
42 return;
43
44 efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
45
46 psd->w = sz.w;
47 psd->h = sz.h;
48
49 evas_object_smart_changed(obj);
50 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, NULL);
51}
52
53EOLIAN static void
54_efl_ui_pan_efl_gfx_visible_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Bool vis)
55{
56 if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
57 return;
58
59 efl_gfx_visible_set(efl_super(obj, MY_CLASS), vis);
60 if (psd->content) efl_gfx_visible_set(psd->content, vis);
61}
62
63EOLIAN static void
64_efl_ui_pan_pan_position_set(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
65{
66 if ((pos.x == psd->px) && (pos.y == psd->py)) return;
67 psd->px = pos.x;
68 psd->py = pos.y;
69
70 evas_object_smart_changed(obj);
71 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
72}
73
74EOLIAN static Eina_Position2D
75_efl_ui_pan_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
76{
77 return EINA_POSITION2D(psd->px, psd->py);
78}
79
80EOLIAN static Eina_Position2D
81_efl_ui_pan_pan_position_max_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
82{
83 Eina_Position2D pos = { 0, 0};
84 if (psd->w < psd->content_w) pos.x = psd->content_w - psd->w;
85 if (psd->h < psd->content_h) pos.y = psd->content_h - psd->h;
86
87 return pos;
88}
89
90EOLIAN static Eina_Position2D
91_efl_ui_pan_pan_position_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
92{
93 return EINA_POSITION2D(0 ,0);
94}
95
96EOLIAN static Eina_Size2D
97_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
98{
99 return EINA_SIZE2D(psd->content_w, psd->content_h);
100}
101
102EOLIAN static Eo *
103_efl_ui_pan_efl_object_constructor(Eo *obj, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
104{
105 efl_canvas_group_clipped_set(obj, EINA_TRUE);
106 obj = efl_constructor(efl_super(obj, MY_CLASS));
107
108 return obj;
109}
110
111EOLIAN static void
112_efl_ui_pan_efl_object_destructor(Eo *obj, Efl_Ui_Pan_Data *sd EINA_UNUSED)
113{
114 efl_content_set(obj, NULL);
115 efl_destructor(efl_super(obj, MY_CLASS));
116}
117
118static void
119_efl_ui_pan_content_del_cb(void *data,
120 Evas *e EINA_UNUSED,
121 Evas_Object *obj EINA_UNUSED,
122 void *event_info EINA_UNUSED)
123{
124 Evas_Object *pobj = data;
125 EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
126
127 psd->content = NULL;
128 psd->content_w = psd->content_h = psd->px = psd->py = 0;
129 efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
130}
131
132static void
133_efl_ui_pan_content_resize_cb(void *data,
134 Evas *e EINA_UNUSED,
135 Evas_Object *obj EINA_UNUSED,
136 void *event_info EINA_UNUSED)
137{
138 Evas_Object *pobj = data;
139 EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
140
141 Eina_Size2D sz = efl_gfx_size_get(psd->content);
142 if ((sz.w != psd->content_w) || (sz.h != psd->content_h))
143 {
144 psd->content_w = sz.w;
145 psd->content_h = sz.h;
146 evas_object_smart_changed(pobj);
147 }
148 efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
149}
150
151EOLIAN static Eina_Bool
152_efl_ui_pan_efl_content_content_set(Evas_Object *obj, Efl_Ui_Pan_Data *psd, Evas_Object *content)
153{
154 Eina_Size2D sz;
155
156 if (content == psd->content) return EINA_TRUE;
157 if (psd->content)
158 {
159 efl_canvas_group_member_del(obj, psd->content);
160 evas_object_event_callback_del_full
161 (psd->content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
162 evas_object_event_callback_del_full
163 (psd->content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb,
164 obj);
165 psd->content = NULL;
166 psd->content_w = psd->content_h = psd->px = psd->py = 0;
167 }
168 if (!content) goto end;
169
170 psd->content = content;
171 efl_canvas_group_member_add(obj, content);
172 sz = efl_gfx_size_get(psd->content);
173 psd->content_w = sz.w;
174 psd->content_h = sz.h;
175 evas_object_event_callback_add
176 (content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
177 evas_object_event_callback_add
178 (content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb, obj);
179
180 if (evas_object_visible_get(obj))
181 evas_object_show(psd->content);
182 else
183 evas_object_hide(psd->content);
184
185 evas_object_smart_changed(obj);
186
187end:
188 efl_event_callback_call(obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
189 return EINA_TRUE;
190}
191
192EOLIAN static void
193_efl_ui_pan_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
194{
195 efl_gfx_position_set(psd->content, EINA_POSITION2D(psd->x - psd->px, psd->y - psd->py));
196}
197#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..5648a85160
--- /dev/null
+++ b/src/lib/elementary/efl_ui_pan.eo
@@ -0,0 +1,55 @@
1class Efl.Ui.Pan (Efl.Canvas.Group,
2 Efl.Content)
3{
4 [[Elementary pan class]]
5 methods {
6 @property pan_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 pan_position_min {
25 [[The minimal position to scroll]]
26 get {
27 }
28 values {
29 pos: Eina.Position2D;
30 }
31 }
32 @property pan_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.Object.destructor;
44 Efl.Gfx.visible { set; }
45 Efl.Gfx.position { set; }
46 Efl.Gfx.size { set; }
47 Efl.Content.content { set; }
48 Efl.Canvas.Group.group_calculate;
49 }
50 events {
51 content,changed; [[Called when pan content changed]]
52 viewport,changed; [[Called when pan viewport changed]]
53 position,changed; [[Called when pan position changed]]
54 }
55}
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..a25e3db763
--- /dev/null
+++ b/src/lib/elementary/efl_ui_scroll_manager.c
@@ -0,0 +1,2495 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#define EFL_UI_SCROLL_MANAGER_PROTECTED
6#define EFL_UI_SCROLLBAR_PROTECTED
7#define EFL_UI_SCROLLBAR_BETA
8
9#include <Elementary.h>
10#include "elm_priv.h"
11#include "efl_ui_widget_scroll_manager.h"
12
13#define MY_CLASS EFL_UI_SCROLL_MANAGER_CLASS
14#define MY_CLASS_NAME "Efl.Ui.Scroll.Manager"
15
16#define ELM_ANIMATOR_CONNECT(Obj, Bool, Callback, Data) \
17 efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
18 efl_event_callback_add(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
19 Bool = 1;
20
21#define ELM_ANIMATOR_DISCONNECT(Obj, Bool, Callback, Data) \
22 efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
23 Bool = 0;
24
25
26static double
27_scroll_manager_linear_interp(void *data EINA_UNUSED, double progress)
28{
29 return progress;
30}
31static double
32_scroll_manager_accel_interp(void *data EINA_UNUSED, double progress)
33{
34 return progress * progress;
35}
36static double
37_scroll_manager_decel_interp(void *data EINA_UNUSED, double progress)
38{
39 return (1.0 - (1.0 - progress) * (1.0 - progress));
40}
41
42static Interpolator
43_scroll_manager_interp_get(InterpType interp)
44{
45 if (interp == ACCEL)
46 return _scroll_manager_accel_interp;
47 else if (interp == DECEL)
48 return _scroll_manager_decel_interp;
49 return _scroll_manager_linear_interp;
50}
51
52// Prototypes --- //
53
54// ANIMATORS - tick function
55static void _efl_ui_scroll_manager_hold_animator(void *data, const Efl_Event *event);
56static void _efl_ui_scroll_manager_on_hold_animator(void *data, const Efl_Event *event);
57static void _efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event);
58static void _efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event);
59static void _efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event);
60static void _efl_ui_scroll_manager_bounce_x_animator(void *data, const Efl_Event *event);
61
62// ANIMATORS - manipulate function
63static void _scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
64static Eina_Bool _scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
65
66static void _scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
67static Eina_Bool _scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
68
69/// Constant scrolling
70static 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);
71static Eina_Bool _scroll_manager_scrollto_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
72static void _scroll_manager_scrollto_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cx, Evas_Coord x, double t, InterpType interp);
73static Eina_Bool _scroll_manager_scrollto_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
74static void _scroll_manager_scrollto_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cy, Evas_Coord y, double t, InterpType interp);
75static Eina_Bool _scroll_manager_scrollto_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
76
77/// Flicking
78static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
79
80// Bounce
81static void _scroll_manager_bounce_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx);
82static Eina_Bool _scroll_manager_bounce_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
83static void _scroll_manager_bounce_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vy);
84static Eina_Bool _scroll_manager_bounce_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
85
86// Util
87static void _scroll_manager_scrollto(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
88static void _scroll_manager_animators_drop(Evas_Object *obj);
89
90// ETC
91static void _efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x,Evas_Coord y);
92// --- Prototypes //
93
94static inline double
95_round(double value, int pos)
96{
97 double temp;
98
99 temp = value * pow( 10, pos );
100 temp = floor( temp + 0.5 );
101 temp *= pow( 10, -pos );
102
103 return temp;
104}
105
106#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(o, ptr) \
107 Efl_Ui_Scroll_Manager_Data *ptr = \
108 (!efl_isa(o, MY_CLASS) ? NULL : \
109 efl_data_scope_safe_get(o, MY_CLASS)); \
110 if (!ptr) \
111 { \
112 CRI("No interface data for object %p (%s)", \
113 o, evas_object_type_get(o)); \
114 return; \
115 }
116
117#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
118 Efl_Ui_Scroll_Manager_Data *ptr = \
119 (!efl_isa(o, MY_CLASS) ? NULL : \
120 efl_data_scope_safe_get(o, MY_CLASS)); \
121 if (!ptr) \
122 { \
123 CRI("No interface data for object %p (%s)", \
124 o, evas_object_type_get(o)); \
125 return val; \
126 }
127
128static void _efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj);
129
130#define LEFT 0
131#define RIGHT 1
132#define UP 2
133#define DOWN 3
134#define EVTIME 1
135//#define SCROLLDBG 1
136/* smoothness debug calls - for debugging how much smooth your app is */
137
138static inline Eina_Bool
139_scroll_manager_thumb_scrollable_get(Efl_Ui_Scroll_Manager_Data *sd)
140{
141 if (!sd) return EINA_FALSE;
142 if ((sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) &&
143 (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL))
144 return EINA_FALSE;
145
146 if (!_elm_config->thumbscroll_enable) return EINA_FALSE;
147
148 return EINA_TRUE;
149}
150
151static inline Eina_Bool
152_scroll_manager_animating_get(Efl_Ui_Scroll_Manager_Data *sd)
153{
154 if (!sd) return EINA_FALSE;
155 return ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
156 (sd->scrollto.x.animator) || (sd->scrollto.y.animator));
157}
158
159static void
160_efl_ui_scroll_manager_scroll_start(Efl_Ui_Scroll_Manager_Data *sd)
161{
162 sd->scrolling = EINA_TRUE;
163 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_START, NULL);
164}
165
166static void
167_efl_ui_scroll_manager_scroll_stop(Efl_Ui_Scroll_Manager_Data *sd)
168{
169 sd->scrolling = EINA_FALSE;
170 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_STOP, NULL);
171}
172
173static void
174_efl_ui_scroll_manager_drag_start(Efl_Ui_Scroll_Manager_Data *sd)
175{
176 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
177 if (!sd->scrolling)
178 _efl_ui_scroll_manager_scroll_start(sd);
179}
180
181static void
182_efl_ui_scroll_manager_drag_stop(Efl_Ui_Scroll_Manager_Data *sd)
183{
184 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
185}
186
187static void
188_efl_ui_scroll_manager_anim_start(Efl_Ui_Scroll_Manager_Data *sd)
189{
190 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_START, NULL);
191 if (!sd->scrolling)
192 _efl_ui_scroll_manager_scroll_start(sd);
193}
194
195static void
196_efl_ui_scroll_manager_anim_stop(Efl_Ui_Scroll_Manager_Data *sd)
197{
198 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_STOP, NULL);
199 if (sd->scrolling)
200 _efl_ui_scroll_manager_scroll_stop(sd);
201}
202
203static void
204_efl_ui_scroll_manager_scroll(Efl_Ui_Scroll_Manager_Data *sd)
205{
206 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL, NULL);
207}
208
209static void
210_efl_ui_scroll_manager_scroll_up(Efl_Ui_Scroll_Manager_Data *sd)
211{
212 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_UP, NULL);
213}
214
215static void
216_efl_ui_scroll_manager_scroll_down(Efl_Ui_Scroll_Manager_Data *sd)
217{
218 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DOWN, NULL);
219}
220
221static void
222_efl_ui_scroll_manager_scroll_left(Efl_Ui_Scroll_Manager_Data *sd)
223{
224 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_LEFT, NULL);
225}
226
227static void
228_efl_ui_scroll_manager_scroll_right(Efl_Ui_Scroll_Manager_Data *sd)
229{
230 efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_RIGHT, NULL);
231}
232
233static void
234_efl_ui_scroll_manager_edge_up(Efl_Ui_Scroll_Manager_Data *sd)
235{
236 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_UP, NULL);
237}
238
239static void
240_efl_ui_scroll_manager_edge_down(Efl_Ui_Scroll_Manager_Data *sd)
241{
242 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_DOWN, NULL);
243}
244
245static void
246_efl_ui_scroll_manager_edge_left(Efl_Ui_Scroll_Manager_Data *sd)
247{
248 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_LEFT, NULL);
249}
250
251static void
252_efl_ui_scroll_manager_edge_right(Efl_Ui_Scroll_Manager_Data *sd)
253{
254 efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_RIGHT, NULL);
255}
256
257EOLIAN static Eina_Size2D
258_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
259{
260 return efl_ui_pan_content_size_get(sd->pan_obj);
261}
262
263EOLIAN static Eina_Rect
264_efl_ui_scroll_manager_efl_ui_scrollable_interactive_viewport_geometry_get(Eo *obj EINA_UNUSED,
265 Efl_Ui_Scroll_Manager_Data *sd)
266{
267 if (!sd->pan_obj) return EINA_RECT(0, 0, 0, 0);
268
269 return efl_gfx_geometry_get(sd->pan_obj);
270}
271
272EOLIAN static void
273_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)
274{
275 sd->match_content_w = !!w;
276 sd->match_content_h = !!h;
277}
278
279static Evas_Coord
280_efl_ui_scroll_manager_x_mirrored_get(const Evas_Object *obj,
281 Evas_Coord x)
282{
283 Evas_Coord ret;
284 Eina_Position2D min = {0, 0}, max = {0, 0};
285
286 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, x);
287
288 if (!sd->pan_obj) return 0;
289
290 min = efl_ui_pan_position_min_get(sd->pan_obj);
291 max = efl_ui_pan_position_max_get(sd->pan_obj);
292 ret = max.x - (x - min.x);
293
294 return (ret >= min.x) ? ret : min.x;
295}
296
297/* Update the wanted coordinates according to the x, y passed
298 * widget directionality, content size and etc. */
299static void
300_efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd,
301 Evas_Coord x,
302 Evas_Coord y)
303{
304 Eina_Position2D min = {0, 0}, max = {0, 0};
305
306 if (!sd->pan_obj) return;
307
308 min = efl_ui_pan_position_min_get(sd->pan_obj);
309 max = efl_ui_pan_position_max_get(sd->pan_obj);
310
311 /* Update wx/y/w/h - and if the requested positions aren't legal
312 * adjust a bit. */
313 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
314 sd->ww = r.w;
315 sd->wh = r.h;
316
317 if (x < min.x && !sd->is_mirrored)
318 {
319 if (!sd->loop_h) sd->wx = min.x;
320 else sd->wx = max.x;
321 }
322 else if (sd->is_mirrored)
323 sd->wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, x);
324 else if (!sd->loop_h && (x > max.x)) sd->wx = max.x;
325 else if (sd->loop_h && x >= (sd->ww + max.x)) sd->wx = min.x;
326 else sd->wx = x;
327
328 if (y < min.y)
329 {
330 if (!sd->loop_v) sd->wy = min.y;
331 else sd->wy = max.y;
332 }
333 else if (!sd->loop_v && (y > max.y)) sd->wy = max.y;
334 else if (sd->loop_v && y >= (sd->wh + max.y)) sd->wy = min.y;
335 else sd->wy = y;
336}
337
338static void
339_scroll_manager_animator_velocity_get(Efl_Ui_Scroll_Manager_Data *sd, double *velx, double *vely)
340{
341 Evas_Coord dx = 0, dy = 0;
342 double vx = 0.0, vy = 0.0;
343 double t = ecore_loop_time_get();
344 Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
345
346 if (t < sd->scrollto.x.start_t + sd->scrollto.x.dur)
347 {
348 dx = sd->scrollto.x.end - cur.x;
349 vx = (double)(dx /((sd->scrollto.x.start_t + sd->scrollto.x.dur) - t));
350
351 if (sd->scrollto.x.interp)
352 vx = sd->scrollto.x.interp(NULL, t/(sd->scrollto.x.start_t + sd->scrollto.x.dur)) * vx;
353 }
354 if (t < sd->scrollto.y.start_t + sd->scrollto.y.dur)
355 {
356 dy = sd->scrollto.y.end - cur.y;
357 vy = (double)(dy /((sd->scrollto.y.start_t + sd->scrollto.y.dur) - t));
358
359 if (sd->scrollto.y.interp)
360 vy = sd->scrollto.y.interp(NULL, t/(sd->scrollto.y.start_t + sd->scrollto.y.dur)) * vy;
361 }
362
363 if (velx) *velx = vx;
364 if (vely) *vely = vy;
365}
366
367static void
368_efl_ui_scroll_manager_bounce_eval(Efl_Ui_Scroll_Manager_Data *sd)
369{
370 double vx = 0.0, vy = 0.0;
371 if (!sd->pan_obj) return;
372
373 if (sd->freeze) return;
374 if ((!sd->bouncemex) && (!sd->bouncemey)) return;
375 if (sd->down.now) return; // down bounce while still held down
376
377 _scroll_manager_on_hold_animator_del(sd);
378 _scroll_manager_hold_animator_del(sd);
379
380 _scroll_manager_animator_velocity_get(sd, &vx, &vy);
381 if (!sd->bounce.x.animator)
382 {
383 if (sd->bouncemex)
384 {
385 _scroll_manager_scrollto_x_animator_del(sd);
386 _scroll_manager_bounce_x_animator_add(sd,vx);
387 }
388 }
389 if (!sd->bounce.y.animator)
390 {
391 if (sd->bouncemey)
392 {
393 _scroll_manager_scrollto_y_animator_del(sd);
394 _scroll_manager_bounce_y_animator_add(sd,vy);
395 }
396 }
397}
398
399EOLIAN static Eina_Position2D
400_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
401{
402 if (!sd->pan_obj) return EINA_POSITION2D(0, 0);
403
404 return efl_ui_pan_position_get(sd->pan_obj);
405}
406
407EOLIAN static void
408_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Position2D pos)
409{
410 Evas_Coord x = pos.x, y = pos.y;
411 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
412 Eina_Size2D content = {0, 0};
413
414 if (!sd->pan_obj) return;
415
416 // FIXME: allow for bounce outsde of range
417 max = efl_ui_pan_position_max_get(sd->pan_obj);
418 min = efl_ui_pan_position_min_get(sd->pan_obj);
419 content = efl_ui_pan_content_size_get(sd->pan_obj);
420 cur = efl_ui_pan_position_get(sd->pan_obj);
421
422 if (sd->loop_h && content.w > 0)
423 {
424 if (x < 0) x = content.w + (x % content.w);
425 else if (x >= content.w) x = (x % content.w);
426 }
427 if (sd->loop_v && content.h > 0)
428 {
429 if (y < 0) y = content.h + (y % content.h);
430 else if (y >= content.h) y = (y % content.h);
431 }
432
433 if (!_elm_config->thumbscroll_bounce_enable)
434 {
435
436 if (x < min.x) x = min.x;
437 if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
438 if (y < min.y) y = min.y;
439 if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
440 }
441
442 if (!sd->bounce_horiz)
443 {
444 if (x < min.x) x = min.x;
445 if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
446 }
447 if (!sd->bounce_vert)
448 {
449 if (y < min.y) y = min.y;
450 if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
451 }
452
453 efl_ui_pan_position_set(sd->pan_obj, EINA_POSITION2D(x, y));
454
455 if (!sd->loop_h && !sd->bounce.x.animator)
456 {
457 if ((x < min.x) ||(x > max.x + min.x))
458 {
459 sd->bouncemex = EINA_TRUE;
460 _efl_ui_scroll_manager_bounce_eval(sd);
461 }
462 else
463 sd->bouncemex = EINA_FALSE;
464 }
465 if (!sd->loop_v && !sd->bounce.y.animator)
466 {
467 if ((y < min.y) ||(y > max.y + min.y))
468 {
469 sd->bouncemey = EINA_TRUE;
470 _efl_ui_scroll_manager_bounce_eval(sd);
471 }
472 else
473 sd->bouncemey = EINA_FALSE;
474 }
475
476 {
477 if ((x != cur.x) || (y != cur.y))
478 {
479 _efl_ui_scroll_manager_scroll(sd);
480 if (x < cur.x)
481 {
482 _efl_ui_scroll_manager_scroll_left(sd);
483 }
484 if (x > cur.x)
485 {
486 _efl_ui_scroll_manager_scroll_right(sd);
487 }
488 if (y < cur.y)
489 {
490 _efl_ui_scroll_manager_scroll_up(sd);
491 }
492 if (y > cur.y)
493 {
494 _efl_ui_scroll_manager_scroll_down(sd);
495 }
496 }
497 if (x != cur.x)
498 {
499 if (x == min.x)
500 {
501 _efl_ui_scroll_manager_edge_left(sd);
502 }
503 if (x == (max.x + min.x))
504 {
505 _efl_ui_scroll_manager_edge_right(sd);
506 }
507 }
508 if (y != cur.y)
509 {
510 if (y == min.y)
511 {
512 _efl_ui_scroll_manager_edge_up(sd);
513 }
514 if (y == max.y + min.y)
515 {
516 _efl_ui_scroll_manager_edge_down(sd);
517 }
518 }
519 }
520}
521
522EOLIAN static void
523_efl_ui_scroll_manager_efl_ui_base_mirrored_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool mirrored)
524{
525 Evas_Coord wx;
526
527 mirrored = !!mirrored;
528
529 if (sd->is_mirrored == mirrored)
530 return;
531
532 sd->is_mirrored = mirrored;
533
534 if (sd->is_mirrored)
535 wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, sd->wx);
536 else
537 wx = sd->wx;
538
539 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(wx, sd->wy));
540}
541
542static void
543_scroll_manager_animators_drop(Evas_Object *obj)
544{
545 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
546 if ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
547 (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
548 {
549 if (_scroll_manager_scrollto_x_animator_del(sd))
550 {
551 }
552 if (_scroll_manager_scrollto_y_animator_del(sd))
553 {
554 }
555 if (_scroll_manager_bounce_x_animator_del(sd))
556 {
557 sd->bouncemex = EINA_FALSE;
558 if (sd->content_info.resized)
559 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
560 }
561 if (_scroll_manager_bounce_y_animator_del(sd))
562 {
563 sd->bouncemey = EINA_FALSE;
564 if (sd->content_info.resized)
565 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
566 }
567 _efl_ui_scroll_manager_anim_stop(sd);
568 }
569 if (_scroll_manager_hold_animator_del(sd))
570 {
571 _efl_ui_scroll_manager_drag_stop(sd);
572 if (sd->content_info.resized)
573 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
574 }
575}
576
577EOLIAN static void
578_efl_ui_scroll_manager_efl_ui_scrollbar_bar_mode_set(Eo *obj EINA_UNUSED,
579 Efl_Ui_Scroll_Manager_Data *sd,
580 Efl_Ui_Scrollbar_Mode hmode,
581 Efl_Ui_Scrollbar_Mode vmode)
582{
583 sd->hbar_mode = hmode;
584 sd->vbar_mode = vmode;
585
586 if (sd->hbar_timer &&
587 hmode == EFL_UI_SCROLLBAR_MODE_ON)
588 ELM_SAFE_FREE(sd->hbar_timer, ecore_timer_del);
589 if (sd->vbar_timer &&
590 vmode == EFL_UI_SCROLLBAR_MODE_ON)
591 ELM_SAFE_FREE(sd->vbar_timer, ecore_timer_del);
592
593 efl_ui_scrollbar_bar_visibility_update(sd->obj);
594}
595
596EOLIAN static void
597_efl_ui_scroll_manager_efl_ui_scrollbar_bar_mode_get(Eo *obj EINA_UNUSED,
598 Efl_Ui_Scroll_Manager_Data *sd,
599 Efl_Ui_Scrollbar_Mode *hmode,
600 Efl_Ui_Scrollbar_Mode *vmode)
601{
602 *hmode = sd->hbar_mode;
603 *vmode = sd->vbar_mode;
604}
605
606/* returns TRUE when we need to move the scroller, FALSE otherwise.
607 * Updates w and h either way, so save them if you need them. */
608static Eina_Bool
609_efl_ui_scroll_manager_content_region_show_internal(Evas_Object *obj,
610 Evas_Coord *_x,
611 Evas_Coord *_y,
612 Evas_Coord w,
613 Evas_Coord h)
614{
615 Evas_Coord nx, ny, x = *_x, y = *_y;
616 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
617 Eina_Size2D pan = {0, 0};
618
619 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
620
621 if (!sd->pan_obj) return EINA_FALSE;
622
623 min = efl_ui_pan_position_min_get(sd->pan_obj);
624 max = efl_ui_pan_position_max_get(sd->pan_obj);
625 cur = efl_ui_pan_position_get(sd->pan_obj);
626 pan = efl_gfx_size_get(sd->pan_obj);
627
628 nx = x;
629 if ((x > cur.x) && (w < pan.w))
630 {
631 if ((cur.x + pan.w) < (x + w)) nx = x - pan.w + w;
632 else nx = cur.x;
633 }
634 ny = y;
635 if ((y > cur.y) && (h < pan.h))
636 {
637 if ((cur.y + pan.h) < (y + h)) ny = y - pan.h + h;
638 else ny = cur.y;
639 }
640
641 x = nx;
642 y = ny;
643
644 if (!sd->loop_h)
645 {
646 if (x > max.x) x = max.x;
647 if (x < min.x) x = min.x;
648 }
649 if (!sd->loop_v)
650 {
651 if (y > max.y) y = max.y;
652 if (y < min.y) y = min.y;
653 }
654
655 if ((x == cur.x) && (y == cur.y)) return EINA_FALSE;
656 *_x = x;
657 *_y = y;
658 return EINA_TRUE;
659}
660
661static void
662_efl_ui_scroll_manager_content_region_set(Eo *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
663{
664 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
665
666 _scroll_manager_animators_drop(obj);
667 if (_efl_ui_scroll_manager_content_region_show_internal(obj, &x, &y, w, h))
668 {
669 efl_ui_scrollable_content_pos_set(obj, EINA_POSITION2D(x, y));
670 sd->down.sx = x;
671 sd->down.sy = y;
672 sd->down.x = sd->down.history[0].x;
673 sd->down.y = sd->down.history[0].y;
674 }
675}
676
677static void
678_efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj)
679{
680 Evas_Coord ww, wh, wx;
681 Eina_Position2D max = {0, 0};
682
683 EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
684
685 wx = sd->wx;
686
687 if (_scroll_manager_animating_get(sd) || sd->down.now ||
688 sd->down.hold_animator || sd->down.onhold_animator) return;
689
690 sd->content_info.resized = EINA_FALSE;
691
692 /* Flip to RTL cords only if init in RTL mode */
693 if (sd->is_mirrored)
694 wx = _efl_ui_scroll_manager_x_mirrored_get(obj, sd->wx);
695
696 if (sd->ww == -1)
697 {
698 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
699 ww = r.w;
700 wh = r.h;
701 }
702 else
703 {
704 ww = sd->ww;
705 wh = sd->wh;
706 }
707
708 max = efl_ui_pan_position_max_get(sd->pan_obj);
709
710 wx += (max.x - sd->prev_cw) * sd->gravity_x;
711 sd->wy += (max.y - sd->prev_ch) * sd->gravity_y;
712
713 sd->prev_cw = max.x;
714 sd->prev_ch = max.y;
715
716 _efl_ui_scroll_manager_content_region_set(obj, wx, sd->wy, ww, wh);
717}
718
719static Eina_Value
720_scroll_wheel_post_event_job(void *data, const Eina_Value v,
721 const Eina_Future *ev EINA_UNUSED)
722{
723 Efl_Ui_Scroll_Manager_Data *sd = data;
724
725 // Animations are disabled if we are here
726 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(sd->wx, sd->wy));
727
728 return v;
729}
730
731static inline void
732_scroll_wheel_post_event_go(Efl_Ui_Scroll_Manager_Data *sd, int x, int y)
733{
734 Eina_Position2D cur;
735 if (sd->hold || sd->freeze) return;
736 _efl_ui_scroll_manager_wanted_coordinates_update(sd, x, y);
737 if (_elm_config->scroll_animation_disable)
738 {
739 Eina_Future *f;
740
741 f = eina_future_then(efl_loop_job(efl_loop_get(sd->obj)),
742 _scroll_wheel_post_event_job, sd);
743 efl_future_Eina_FutureXXX_then(sd->obj, f);
744 }
745 else
746 {
747 cur = efl_ui_pan_position_get(sd->pan_obj);
748 _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, x, y, 0.5, 0.5, LINEAR);
749 }
750}
751
752static Eina_Bool
753_scroll_wheel_post_event_cb(void *data, Evas *e EINA_UNUSED)
754{
755 Efl_Ui_Scroll_Manager_Data *sd = data;
756 Evas_Event_Mouse_Wheel *ev = sd->event_info;
757
758 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
759 Eina_Size2D content = {0, 0};
760 Evas_Coord x = 0, y = 0, vw = 0, vh = 0;
761 Eina_Bool hold = EINA_FALSE;
762 Evas_Coord pwx, pwy;
763 double t;
764 int direction;
765
766 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_TRUE);
767
768 sd->event_info = NULL;
769 direction = ev->direction;
770
771 pwx = sd->wx;
772 pwy = sd->wy;
773
774 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
775 if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
776 direction = !direction;
777
778 cur = efl_ui_pan_position_get(sd->pan_obj);
779 x = cur.x;
780 y = cur.y;
781 if (sd->scrollto.x.animator) x = sd->scrollto.x.end;
782 if (sd->scrollto.y.animator) y = sd->scrollto.y.end;
783 max = efl_ui_pan_position_max_get(sd->pan_obj);
784 min = efl_ui_pan_position_min_get(sd->pan_obj);
785 if (x < min.x) x = min.x;
786 if (x > max.x) x = max.x;
787 if (y < min.y) y = min.y;
788 if (y > max.y) y = max.y;
789
790 t = ecore_loop_time_get();
791
792 _scroll_manager_animators_drop(sd->obj);
793
794 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
795 vw = r.w;
796 vh = r.h;
797
798 if (sd->pan_obj)
799 content = efl_ui_pan_content_size_get(sd->pan_obj);
800
801 int d = ev->z;
802 double delta_t = (double)(ev->timestamp - sd->last_wheel) / 1000.0;
803 double mul;
804
805 if (delta_t > 0.2) sd->last_wheel_mul = 0.0;
806 if (delta_t > 0.2) delta_t = 0.2;
807 mul = 1.0 + (_elm_config->scroll_accel_factor * ((0.2 - delta_t) / 0.2));
808 mul = mul * (1.0 + (0.15 * sd->last_wheel_mul));
809 d *= mul;
810 sd->last_wheel = ev->timestamp;
811 sd->last_wheel_mul = mul;
812
813 if (!direction)
814 {
815 if ((content.h > vh) || (content.w <= vw))
816 y += d * sd->step.y;
817 else
818 {
819 x += d * sd->step.x;
820 direction = 1;
821 }
822 }
823 else
824 {
825 if ((content.w > vw) || (content.h <= vh))
826 x += d * sd->step.x;
827 else
828 {
829 y += d * sd->step.y;
830 direction = 0;
831 }
832 }
833 _scroll_wheel_post_event_go(sd, x, y);
834
835 if (direction)
836 {
837 if ((sd->bounce_horiz) ||
838 (pwx != sd->wx) ||
839 (((t - sd->down.last_time_x_wheel) < 0.5) &&
840 (sd->down.last_hold_x_wheel)))
841 {
842 sd->down.last_hold_x_wheel = EINA_TRUE;
843 hold = EINA_TRUE;
844 }
845 else sd->down.last_hold_x_wheel = EINA_FALSE;
846 sd->down.last_time_x_wheel = t;
847 }
848 else
849 {
850 if ((sd->bounce_vert) ||
851 (pwy != sd->wy) ||
852 (((t - sd->down.last_time_y_wheel) < 0.5) &&
853 (sd->down.last_hold_y_wheel)))
854 {
855 sd->down.last_hold_y_wheel = EINA_TRUE;
856 hold = EINA_TRUE;
857 }
858 else sd->down.last_hold_y_wheel = EINA_FALSE;
859 sd->down.last_time_y_wheel = t;
860 }
861 return !hold;
862}
863
864static void
865_efl_ui_scroll_manager_wheel_event_cb(void *data,
866 Evas *e,
867 Evas_Object *obj EINA_UNUSED,
868 void *event_info)
869{
870 Efl_Ui_Scroll_Manager_Data *sd;
871 Evas_Event_Mouse_Wheel *ev;
872 int direction;
873
874 sd = data;
875 ev = event_info;
876 sd->event_info = event_info;
877 direction = ev->direction;
878
879 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
880 if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
881 (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
882 (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
883 (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
884 (evas_key_modifier_is_set(ev->modifiers, "Super")))
885 return;
886 if (direction)
887 {
888 if (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL) return;
889 }
890 else
891 {
892 if (sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) return;
893 }
894
895 evas_post_event_callback_push(e, _scroll_wheel_post_event_cb, sd);
896}
897
898static void
899_efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event EINA_UNUSED)
900{
901 Efl_Ui_Scroll_Manager_Data *sd = data;
902 Eina_Position2D min = {0, 0}, max = {0, 0};
903 Evas_Coord nx = 0;
904 double t = 0.0, dt = 0.0, progx = 0.0, rx = 0.0;
905 Interpolator interp = NULL;
906 Eina_Bool no_bounce_x_end = EINA_FALSE;
907
908 t = ecore_loop_time_get();
909 dt = t - sd->scrollto.x.start_t;
910
911 if ( dt > sd->scrollto.x.dur) progx = 1.0;
912 else progx = dt / sd->scrollto.x.dur;
913
914 if (sd->scrollto.x.interp) interp = sd->scrollto.x.interp;
915 else interp = _scroll_manager_interp_get(LINEAR);
916
917 rx = interp(NULL, progx);
918 nx = sd->scrollto.x.start + (sd->scrollto.x.end - sd->scrollto.x.start) * rx;
919
920 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
921 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
922 _efl_ui_scroll_manager_wanted_coordinates_update(sd, nx, cur.y);
923
924 min = efl_ui_pan_position_min_get(sd->pan_obj);
925 max = efl_ui_pan_position_max_get(sd->pan_obj);
926
927 if (!_elm_config->thumbscroll_bounce_enable || !sd->bounce_horiz)
928 {
929 if (nx < min.x) no_bounce_x_end = EINA_TRUE;
930 if (!sd->loop_h && (nx - min.x) > max.x) no_bounce_x_end = EINA_TRUE;
931 }
932 if (dt >= sd->scrollto.x.dur || no_bounce_x_end)
933 {
934 if ((!sd->scrollto.y.animator) &&
935 (!sd->bounce.y.animator))
936 _efl_ui_scroll_manager_anim_stop(sd);
937 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
938 }
939}
940
941static void
942_efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
943{
944 Efl_Ui_Scroll_Manager_Data *sd = data;
945 Eina_Position2D min = {0, 0}, max = {0, 0};
946 Evas_Coord ny = 0;
947 double t = 0.0, dt = 0.0, progy = 0.0, ry = 0.0;
948 Interpolator interp = NULL;
949 Eina_Bool no_bounce_y_end = EINA_FALSE;
950
951 t = ecore_loop_time_get();
952 dt = t - sd->scrollto.y.start_t;
953
954 if ( dt > sd->scrollto.y.dur) progy = 1.0;
955 else progy = dt / sd->scrollto.y.dur;
956
957 if (sd->scrollto.y.interp) interp = sd->scrollto.y.interp;
958 else interp = _scroll_manager_interp_get(LINEAR);
959
960 ry = interp(NULL, progy);
961 ny = sd->scrollto.y.start + (sd->scrollto.y.end - sd->scrollto.y.start) * ry;
962
963 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
964 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
965 _efl_ui_scroll_manager_wanted_coordinates_update(sd, cur.x, ny);
966
967 min = efl_ui_pan_position_min_get(sd->pan_obj);
968 max = efl_ui_pan_position_max_get(sd->pan_obj);
969
970 if (!_elm_config->thumbscroll_bounce_enable || !sd->bounce_vert)
971 {
972 if (ny < min.y) no_bounce_y_end = EINA_TRUE;
973 if (!sd->loop_v && (ny - min.y) > max.y) no_bounce_y_end = EINA_TRUE;
974 }
975 if (dt >= sd->scrollto.y.dur || no_bounce_y_end)
976 {
977 if ((!sd->scrollto.x.animator) &&
978 (!sd->bounce.x.animator))
979 _efl_ui_scroll_manager_anim_stop(sd);
980 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
981 }
982}
983
984static void
985_efl_ui_scroll_manager_mouse_up_event_smooth(Efl_Ui_Scroll_Manager_Data *sd, double t, Evas_Coord *ox, Evas_Coord *oy, double *ot)
986{
987 static const unsigned int HISTORY_MAX = 60;
988 unsigned int i = 0;
989 double dt = 0, at = 0;
990 Evas_Coord ax = 0, ay = 0;
991
992 for (i = 0; i < HISTORY_MAX; i++)
993 {
994 dt = t - sd->down.history[i].timestamp;
995 if (dt > 0.2) break;
996#ifdef SCROLLDBG
997 DBG("H: %i %i @ %1.3f\n",
998 sd->down.history[i].x,
999 sd->down.history[i].y, dt);
1000#endif
1001 ax = sd->down.history[i].x;
1002 ay = sd->down.history[i].y;
1003 at = sd->down.history[i].timestamp;
1004 }
1005 if (ox) *ox = ax;
1006 if (oy) *oy = ay;
1007 if (ot) *ot = t - at;
1008
1009 return;
1010 if (ox) *ox = (Evas_Coord)(ax / (i + 1));
1011 if (oy) *oy = (Evas_Coord)(ay / (i + 1));
1012 if (ot) *ot = (double)(at / (i + 1));
1013}
1014
1015static void
1016_efl_ui_scroll_manager_mouse_up_event_momentum_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Up *ev)
1017{
1018 double t, at;
1019 Evas_Coord dx, dy, ax, ay, vel;
1020 char sdx, sdy;
1021
1022#ifdef EVTIME
1023 t = ev->timestamp / 1000.0;
1024#else
1025 t = ecore_loop_time_get();
1026#endif
1027
1028 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1029 ax = ev->canvas.x;
1030 ay = ev->canvas.y;
1031 at = 0.0;
1032#ifdef SCROLLDBG
1033 DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1034#endif
1035 _efl_ui_scroll_manager_mouse_up_event_smooth(sd, t, &ax, &ay, &at);
1036 dx = ev->canvas.x - ax;
1037 dy = ev->canvas.y - ay;
1038
1039 sdx = (dx > 0) - (dx < 0);
1040 sdy = (dy > 0) - (dy < 0);
1041
1042 dx = abs(dx);
1043 dy = abs(dy);
1044 if (at > 0)
1045 {
1046 vel = (Evas_Coord)(sqrt((dx * dx) + (dy * dy)) / at);
1047 if ((_elm_config->thumbscroll_friction > 0.0) &&
1048 (vel > _elm_config->thumbscroll_momentum_threshold))
1049 {
1050 _scroll_manager_momentum_animator_add(sd, -sdx*dx/at, -sdy*dy/at);
1051 }
1052 else if (!sd->bouncemex && !sd->bouncemey)
1053 {
1054 _efl_ui_scroll_manager_scroll_stop(sd);
1055 }
1056 }
1057}
1058
1059static void
1060_efl_ui_scroll_manager_mouse_up_event_cb(void *data,
1061 Evas *e,
1062 Evas_Object *obj EINA_UNUSED,
1063 void *event_info)
1064{
1065 Efl_Ui_Scroll_Manager_Data *sd = data;
1066 Evas_Event_Mouse_Up *ev;
1067
1068 if (!sd->pan_obj) return;
1069 if (!_scroll_manager_thumb_scrollable_get(sd)) return;
1070
1071 ev = event_info;
1072
1073 if (ev->button == 1)
1074 {
1075 _scroll_manager_on_hold_animator_del(sd);
1076
1077 if (sd->down.dragged)
1078 {
1079 _efl_ui_scroll_manager_drag_stop(sd);
1080 if ((!sd->hold) && (!sd->freeze))
1081 {
1082 _efl_ui_scroll_manager_mouse_up_event_momentum_eval(sd, ev);
1083 }
1084 evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1085 }
1086
1087 _scroll_manager_hold_animator_del(sd);
1088
1089 if (sd->down.scroll)
1090 {
1091 ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1092 sd->down.scroll = EINA_FALSE;
1093 }
1094 if (sd->down.hold)
1095 {
1096 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1097 sd->down.hold = EINA_FALSE;
1098 }
1099
1100 sd->down.dragged_began = EINA_FALSE;
1101 sd->down.dir_x = EINA_FALSE;
1102 sd->down.dir_y = EINA_FALSE;
1103 sd->down.dragged = EINA_FALSE;
1104 sd->down.now = EINA_FALSE;
1105
1106 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
1107 efl_ui_scrollable_content_pos_set(sd->obj, cur);
1108 _efl_ui_scroll_manager_wanted_coordinates_update(sd, cur.x, cur.y);
1109
1110 if (sd->content_info.resized)
1111 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
1112 }
1113}
1114
1115static void
1116_efl_ui_scroll_manager_mouse_down_event_cb(void *data,
1117 Evas *e EINA_UNUSED,
1118 Evas_Object *obj EINA_UNUSED,
1119 void *event_info)
1120{
1121 Efl_Ui_Scroll_Manager_Data *sd;
1122 Evas_Event_Mouse_Down *ev;
1123 Eina_Position2D cur = {0, 0};
1124
1125 sd = data;
1126 ev = event_info;
1127
1128 if (!_scroll_manager_thumb_scrollable_get(sd)) return;
1129
1130 sd->down.hold = EINA_FALSE;
1131 if (_scroll_manager_animating_get(sd))
1132 {
1133 ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
1134 EVAS_EVENT_FLAG_ON_HOLD;
1135 sd->down.scroll = EINA_TRUE;
1136 sd->down.hold = EINA_TRUE;
1137
1138 _scroll_manager_animators_drop(sd->obj);
1139 }
1140
1141 if (ev->button == 1)
1142 {
1143 sd->down.hist.est_timestamp_diff =
1144 ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
1145 sd->down.hist.tadd = 0.0;
1146 sd->down.hist.dxsum = 0.0;
1147 sd->down.hist.dysum = 0.0;
1148 sd->down.now = EINA_TRUE;
1149 sd->down.dragged = EINA_FALSE;
1150 sd->down.dir_x = EINA_FALSE;
1151 sd->down.dir_y = EINA_FALSE;
1152 sd->down.x = ev->canvas.x;
1153 sd->down.y = ev->canvas.y;
1154 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1155 sd->down.sx = cur.x;
1156 sd->down.sy = cur.y;
1157 memset(&(sd->down.history[0]), 0,
1158 sizeof(sd->down.history[0]) * 60);
1159#ifdef EVTIME
1160 sd->down.history[0].timestamp = ev->timestamp / 1000.0;
1161 sd->down.history[0].localtimestamp = ecore_loop_time_get();
1162#else
1163 sd->down.history[0].timestamp = ecore_loop_time_get();
1164#endif
1165 sd->down.dragged_began_timestamp = sd->down.history[0].timestamp;
1166 sd->down.history[0].x = ev->canvas.x;
1167 sd->down.history[0].y = ev->canvas.y;
1168 }
1169 sd->down.dragged_began = EINA_FALSE;
1170 if (sd->hold || sd->freeze)
1171 sd->down.want_reset = EINA_TRUE;
1172 else
1173 sd->down.want_reset = EINA_FALSE;
1174}
1175
1176static Eina_Bool
1177_efl_ui_scroll_manager_can_scroll(Efl_Ui_Scroll_Manager_Data *sd,
1178 int dir)
1179{
1180 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
1181
1182 if (!sd->pan_obj) return EINA_FALSE;
1183
1184 max = efl_ui_pan_position_max_get(sd->pan_obj);
1185 min = efl_ui_pan_position_min_get(sd->pan_obj);
1186 cur = efl_ui_pan_position_get(sd->pan_obj);
1187 switch (dir)
1188 {
1189 case LEFT:
1190 if (cur.x > min.x) return EINA_TRUE;
1191 break;
1192
1193 case RIGHT:
1194 if ((cur.x - min.x) < max.x) return EINA_TRUE;
1195 break;
1196
1197 case UP:
1198 if (cur.y > min.y) return EINA_TRUE;
1199 break;
1200
1201 case DOWN:
1202 if ((cur.y - min.y) < max.y) return EINA_TRUE;
1203 break;
1204
1205 default:
1206 break;
1207 }
1208 return EINA_FALSE;
1209}
1210
1211static void
1212_efl_ui_scroll_manager_bounce_weight_apply(Efl_Ui_Scroll_Manager_Data *sd,
1213 Evas_Coord *x,
1214 Evas_Coord *y)
1215{
1216 Eina_Position2D min = {0, 0}, max = {0, 0};
1217 min = efl_ui_pan_position_min_get(sd->pan_obj);
1218 max = efl_ui_pan_position_max_get(sd->pan_obj);
1219
1220 if (!sd->loop_h && *x < min.x)
1221 *x += (min.x - *x) * _elm_config->thumbscroll_border_friction;
1222 else if (!sd->loop_h && max.x <= 0)
1223 *x += (sd->down.sx - *x) * _elm_config->thumbscroll_border_friction;
1224 else if (!sd->loop_h && (max.x + min.x) < *x)
1225 *x += (max.x + min.x - *x) *
1226 _elm_config->thumbscroll_border_friction;
1227
1228 if (!sd->loop_v && *y < min.y)
1229 *y += (min.y - *y) * _elm_config->thumbscroll_border_friction;
1230 else if (!sd->loop_v && max.y <= 0)
1231 *y += (sd->down.sy - *y) * _elm_config->thumbscroll_border_friction;
1232 else if (!sd->loop_v && (max.y + min.y) < *y)
1233 *y += (max.y + min.y - *y) *
1234 _elm_config->thumbscroll_border_friction;
1235}
1236
1237static inline double
1238_scroll_manager_animation_duration_get(Evas_Coord dx, Evas_Coord dy)
1239{
1240 double dist = 0.0, vel = 0.0, dur = 0.0;
1241 dist = sqrt(dx * dx + dy *dy);
1242 vel = _elm_config->thumbscroll_friction_standard / _elm_config->thumbscroll_friction;
1243 dur = dist / vel;
1244 dur = (dur > _elm_config->thumbscroll_friction) ? _elm_config->thumbscroll_friction : dur;
1245 return dur;
1246}
1247
1248static Eina_Bool
1249_scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1250{
1251 if (sd->down.onhold_animator)
1252 {
1253 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
1254 if (sd->content_info.resized)
1255 _efl_ui_scroll_manager_wanted_region_set(sd->obj);
1256 return EINA_TRUE;
1257 }
1258 return EINA_FALSE;
1259}
1260
1261static void
1262_scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
1263{
1264 sd->down.onhold_vx = vx;
1265 sd->down.onhold_vy = vy;
1266 if (!sd->down.onhold_animator)
1267 {
1268 sd->down.onhold_vxe = 0.0;
1269 sd->down.onhold_vye = 0.0;
1270 sd->down.onhold_tlast = 0.0;
1271
1272 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
1273 }
1274}
1275
1276static void
1277_scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y)
1278{
1279 sd->down.hold_x = x;
1280 sd->down.hold_y = y;
1281 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
1282}
1283
1284static Eina_Bool
1285_scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1286{
1287 if (sd->down.hold_animator || sd->down.hold_enterer)
1288 {
1289 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
1290 ELM_SAFE_FREE(sd->down.hold_enterer, ecore_idle_enterer_del);
1291 return EINA_TRUE;
1292 }
1293 return EINA_FALSE;
1294}
1295
1296static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
1297{
1298 static const double friction = 5000;
1299 static const double inverse_mass = 1;
1300 static const double accel = friction * inverse_mass;
1301 double dur = 0.0, vel = 0.0;
1302 char sdx = 0, sdy = 0;
1303 Evas_Coord dstx = 0, dsty = 0;
1304
1305/*
1306 if (_scroll_manager_scrollto_animator_del(sd))
1307 {
1308 restore current veolocity
1309 add to vx/vy
1310 }
1311*/
1312 Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
1313
1314 sdx = (vx > 0) - (vx < 0);
1315 sdy = (vy > 0) - (vy < 0);
1316
1317 dstx = cur.x + sdx * (vx * vx) / (2 * accel);
1318 dsty = cur.y + sdy * (vy * vy) / (2 * accel);
1319
1320 vel = sqrt(vx*vx + vy*vy);
1321 dur = vel / accel;
1322
1323 _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, dstx, dsty, dur, dur, DECEL);
1324}
1325
1326static void
1327_efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
1328{
1329 Efl_Ui_Scroll_Manager_Data *sd = data;
1330 Evas_Coord ny = 0;
1331 Eina_Position2D cur = {0, 0};
1332 double t = 0.0, dt = 0.0, r = 0.0;
1333
1334 t = ecore_loop_time_get();
1335 if (sd->bounce.y.start_t + sd->bounce.y.t01 >= t)
1336 {
1337 dt = sd->bounce.y.start_t + sd->bounce.y.t01 - t;
1338 r = 1.0 - (dt / sd->bounce.y.t01);
1339 r = _scroll_manager_decel_interp(NULL, r);
1340 ny = sd->bounce.y.p0 + (sd->bounce.y.p1 - sd->bounce.y.p0) * r;
1341
1342 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1343 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
1344 }
1345 else if (sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 >= t)
1346 {
1347 dt = sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 - t;
1348 r = 1.0 - (dt / sd->bounce.y.t12);
1349 r = _scroll_manager_decel_interp(NULL, r);
1350 ny = sd->bounce.y.p1 + (sd->bounce.y.p2 - sd->bounce.y.p1) * r;
1351
1352 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1353 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
1354 }
1355 else
1356 {
1357 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1358 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, sd->bounce.y.p2));
1359 if ((!sd->scrollto.x.animator) &&
1360 (!sd->bounce.x.animator))
1361 _efl_ui_scroll_manager_anim_stop(sd);
1362 _scroll_manager_bounce_y_animator_del(sd);
1363 }
1364}
1365
1366static void
1367_efl_ui_scroll_manager_bounce_x_animator(void *data, const Efl_Event *event EINA_UNUSED)
1368{
1369 Efl_Ui_Scroll_Manager_Data *sd = data;
1370 Evas_Coord nx;
1371 Eina_Position2D cur = {0, 0};
1372 double t = 0.0, dt = 0.0, r = 0.0;
1373
1374 t = ecore_loop_time_get();
1375
1376 if (sd->bounce.x.start_t + sd->bounce.x.t01 >= t)
1377 {
1378 dt = sd->bounce.x.start_t + sd->bounce.x.t01 - t;
1379 r = 1.0 - (dt / sd->bounce.x.t01);
1380 r = _scroll_manager_decel_interp(NULL, r);
1381 nx = sd->bounce.x.p0 + (sd->bounce.x.p1 - sd->bounce.x.p0) * r;
1382
1383 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1384 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
1385 }
1386 else if (sd->bounce.x.start_t + sd->bounce.x.t01 + sd->bounce.x.t12 >= t)
1387 {
1388 dt = sd->bounce.x.start_t + sd->bounce.x.t01 + sd->bounce.x.t12 - t;
1389 r = 1.0 - (dt / sd->bounce.x.t12);
1390 r = _scroll_manager_decel_interp(NULL, r);
1391 nx = sd->bounce.x.p1 + (sd->bounce.x.p2 - sd->bounce.x.p1) * r;
1392
1393 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1394 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
1395 }
1396 else
1397 {
1398 cur = efl_ui_scrollable_content_pos_get(sd->obj);
1399 efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(sd->bounce.x.p2, cur.y));
1400 if ((!sd->scrollto.y.animator) &&
1401 (!sd->bounce.y.animator))
1402 _efl_ui_scroll_manager_anim_stop(sd);
1403 _scroll_manager_bounce_x_animator_del(sd);
1404 }
1405}
1406
1407static void _scroll_manager_bounce_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx)
1408{
1409 static const double spring_k = 1000;
1410 static const double mass = 1;
1411 char sign = (vx > 0) - (vx < 0);
1412 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
1413
1414 _scroll_manager_bounce_x_animator_del(sd);
1415
1416 cur = efl_ui_pan_position_get(sd->pan_obj);
1417 min = efl_ui_pan_position_min_get(sd->pan_obj);
1418 max = efl_ui_pan_position_max_get(sd->pan_obj);
1419
1420 double max_x = sqrt((mass * vx * vx) / spring_k);
1421 sd->bounce.x.start_t = ecore_loop_time_get();
1422 sd->bounce.x.vel = vx;
1423 sd->bounce.x.p0 = cur.x;
1424 if (fabs(vx) > 0.0)
1425 sd->bounce.x.t01 = 0.2;
1426 else
1427 sd->bounce.x.t01 = 0.0;
1428 sd->bounce.x.p1 = cur.x + sign * max_x;;
1429 sd->bounce.x.t12 = 0.2;
1430 if ( cur.x < min.x )
1431 {
1432 sd->bounce.x.p2 = min.x;
1433 }
1434 else if ( cur.x > max.x)
1435 {
1436 sd->bounce.x.p2 = max.x;
1437 }
1438
1439 if ((!sd->bounce.y.animator) &&
1440 (!sd->scrollto.y.animator))
1441 _efl_ui_scroll_manager_anim_start(sd);
1442 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->bounce.x.animator, _efl_ui_scroll_manager_bounce_x_animator, sd);
1443}
1444
1445static Eina_Bool _scroll_manager_bounce_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1446{
1447 if (sd->bounce.x.animator)
1448 {
1449 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.x.animator, _efl_ui_scroll_manager_bounce_x_animator, sd);
1450 return EINA_TRUE;
1451 }
1452 return EINA_FALSE;
1453}
1454
1455static void _scroll_manager_bounce_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vy)
1456{
1457 static const double spring_k = 1000;
1458 static const double mass = 1;
1459 char sign = (vy > 0) - (vy < 0);
1460 Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
1461
1462 _scroll_manager_bounce_y_animator_del(sd);
1463
1464 cur = efl_ui_pan_position_get(sd->pan_obj);
1465 min = efl_ui_pan_position_min_get(sd->pan_obj);
1466 max = efl_ui_pan_position_max_get(sd->pan_obj);
1467
1468 double max_y = sqrt((mass * vy * vy) / spring_k);
1469 sd->bounce.y.start_t = ecore_loop_time_get();
1470 sd->bounce.y.vel = vy;
1471 sd->bounce.y.p0 = cur.y;
1472 if (fabs(vy) > 0.0)
1473 sd->bounce.y.t01 = 0.2;
1474 else
1475 sd->bounce.y.t01 = 0.0;
1476
1477 sd->bounce.y.p1 = cur.y + sign * max_y;
1478 sd->bounce.y.t12 = 0.2;
1479 if ( cur.y < min.y )
1480 {
1481 sd->bounce.y.p2 = min.y;
1482 }
1483 else if ( cur.y > max.y)
1484 {
1485 sd->bounce.y.p2 = max.y;
1486 }
1487
1488 if ((!sd->bounce.x.animator) &&
1489 (!sd->scrollto.x.animator))
1490 _efl_ui_scroll_manager_anim_start(sd);
1491 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->bounce.y.animator, _efl_ui_scroll_manager_bounce_y_animator, sd);
1492}
1493
1494static Eina_Bool _scroll_manager_bounce_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1495{
1496 if (sd->bounce.y.animator)
1497 {
1498 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.y.animator, _efl_ui_scroll_manager_bounce_y_animator, sd);
1499 return EINA_TRUE;
1500 }
1501 return EINA_FALSE;
1502}
1503
1504static void
1505_scroll_manager_scrollto_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord sx, Evas_Coord ex, double t, InterpType interp)
1506{
1507 sd->scrollto.x.start_t = ecore_loop_time_get();
1508 sd->scrollto.x.dur = t;
1509
1510 sd->scrollto.x.start = sx;
1511 sd->scrollto.x.end = ex;
1512
1513 sd->scrollto.x.interp = _scroll_manager_interp_get(interp);
1514 if (!sd->scrollto.x.animator)
1515 {
1516 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
1517 if (!sd->scrollto.y.animator) _efl_ui_scroll_manager_anim_start(sd);
1518 }
1519}
1520
1521static Eina_Bool
1522_scroll_manager_scrollto_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1523{
1524 if (sd->scrollto.x.animator)
1525 {
1526 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
1527 return EINA_TRUE;
1528 }
1529 return EINA_FALSE;
1530}
1531
1532static void
1533_scroll_manager_scrollto_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord sy, Evas_Coord ey, double t, InterpType interp)
1534{
1535 sd->scrollto.y.start_t = ecore_loop_time_get();
1536 sd->scrollto.y.dur = t;
1537
1538 sd->scrollto.y.start = sy;
1539 sd->scrollto.y.end = ey;
1540
1541 sd->scrollto.y.interp = _scroll_manager_interp_get(interp);
1542 if (!sd->scrollto.y.animator)
1543 {
1544 ELM_ANIMATOR_CONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
1545 if (!sd->scrollto.x.animator) _efl_ui_scroll_manager_anim_start(sd);
1546 }
1547}
1548
1549static Eina_Bool
1550_scroll_manager_scrollto_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1551{
1552 if (sd->scrollto.y.animator)
1553 {
1554 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
1555 return EINA_TRUE;
1556 }
1557 return EINA_FALSE;
1558}
1559
1560static void
1561_scroll_manager_scrollto_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord sx, Evas_Coord sy, Evas_Coord x, Evas_Coord y, double tx, double ty, InterpType interp)
1562{
1563 _scroll_manager_scrollto_animator_del(sd);
1564
1565 if (!sd->pan_obj) return;
1566 if (sd->freeze) return;
1567 _scroll_manager_scrollto_x_animator_add(sd, sx, x, tx, interp);
1568 _scroll_manager_scrollto_y_animator_add(sd, sy, y, ty, interp);
1569}
1570
1571static Eina_Bool
1572_scroll_manager_scrollto_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
1573{
1574 if ((sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1575 {
1576 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
1577 ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
1578 return EINA_TRUE;
1579 }
1580 return EINA_FALSE;
1581}
1582
1583static void
1584_scroll_manager_scrollto(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y)
1585{
1586 double dur = 0.0;
1587 Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
1588 dur = _scroll_manager_animation_duration_get(x - cur.x, y - cur.y);
1589 _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, x, y, dur, dur, LINEAR);
1590}
1591
1592static void
1593_efl_ui_scroll_manager_post_event_move_on_hold_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev)
1594{
1595 Evas_Coord x = 0, y = 0;
1596 double vx = 0.0, vy = 0.0;
1597 char sx = 0, sy = 0;
1598
1599 Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
1600
1601 x = (r.x - ev->cur.canvas.x) > 0 ? (r.x - ev->cur.canvas.x) : 0;
1602 y = (r.y - ev->cur.canvas.y) > 0 ? (r.y - ev->cur.canvas.y) : 0;
1603 x = (ev->cur.canvas.x - (r.x + r.w)) > 0 ? (ev->cur.canvas.x - (r.x + r.w)) : x;
1604 y = (ev->cur.canvas.y - (r.y + r.h)) > 0 ? (ev->cur.canvas.y - (r.y + r.h)) : y;
1605 sx = r.x - ev->cur.canvas.x > 0 ? -1 : 1;
1606 sy = r.y - ev->cur.canvas.y > 0 ? -1 : 1;
1607
1608 if (x > _elm_config->thumbscroll_hold_threshold)
1609 {
1610 vx = 1.0;
1611 if (_elm_config->thumbscroll_hold_threshold > 0.0)
1612 vx = (double)(x - _elm_config->thumbscroll_hold_threshold) /
1613 _elm_config->thumbscroll_hold_threshold;
1614 }
1615
1616 if (y > _elm_config->thumbscroll_hold_threshold)
1617 {
1618 vy = 1.0;
1619 if (_elm_config->thumbscroll_hold_threshold > 0.0)
1620 vy = (double)(y - _elm_config->thumbscroll_hold_threshold) /
1621 _elm_config->thumbscroll_hold_threshold;
1622 }
1623
1624 if ((vx != 0.0) || (vy != 0.0)) _scroll_manager_on_hold_animator_add(sd, vx*sx, vy*sy);
1625 else _scroll_manager_on_hold_animator_del(sd);
1626}
1627
1628
1629static Eina_Bool
1630_efl_ui_scroll_manager_post_event_move_direction_restrict_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev EINA_UNUSED,
1631 Evas_Coord dx, Evas_Coord dy)
1632{
1633 if (sd->down.dragged) return EINA_FALSE;
1634
1635 sd->down.hdir = -1;
1636 sd->down.vdir = -1;
1637
1638 if (dx > 0) sd->down.hdir = LEFT;
1639 else if (dx < 0)
1640 sd->down.hdir = RIGHT;
1641 if (dy > 0) sd->down.vdir = UP;
1642 else if (dy < 0)
1643 sd->down.vdir = DOWN;
1644
1645 if (!(sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL))
1646 sd->down.dir_x = EINA_TRUE;
1647
1648 if (!(sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL))
1649 sd->down.dir_y = EINA_TRUE;
1650
1651 return EINA_TRUE;
1652}
1653
1654static Eina_Bool
1655_efl_ui_scroll_manager_post_event_move_hold_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev,
1656 Evas_Coord dx, Evas_Coord dy)
1657{
1658 if (!sd->down.dragged)
1659 {
1660 if(((dx * dx) + (dy * dy)) >
1661 (_elm_config->thumbscroll_threshold * _elm_config->thumbscroll_threshold))
1662 {
1663 if (_elm_config->scroll_smooth_start_enable)
1664 {
1665 sd->down.x = ev->cur.canvas.x;
1666 sd->down.y = ev->cur.canvas.y;
1667#ifdef EVTIME
1668 sd->down.dragged_began_timestamp = ev->timestamp / 1000.0;
1669#else
1670 sd->down.dragged_began_timestamp = ecore_loop_time_get();
1671#endif
1672 }
1673 // TODO 다른조건들도 can_scroll 안쪽으로 넣는다?
1674 if ((((_efl_ui_scroll_manager_can_scroll(sd, sd->down.hdir) || sd->bounce_horiz) && sd->down.dir_x) ||
1675 ((_efl_ui_scroll_manager_can_scroll(sd, sd->down.vdir) || sd->bounce_vert) && sd->down.dir_y)))
1676 {
1677 _efl_ui_scroll_manager_drag_start(sd);
1678 sd->down.dragged = EINA_TRUE;
1679 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1680 }
1681 else if (!sd->down.dragged)
1682 return EINA_FALSE;
1683 }
1684 return EINA_TRUE;
1685 }
1686
1687 if (sd->down.want_reset)
1688 {
1689 sd->down.x = ev->cur.canvas.x;
1690 sd->down.y = ev->cur.canvas.y;
1691 sd->down.want_reset = EINA_FALSE;
1692 }
1693
1694 if (sd->down.dir_x) dx = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
1695 else dx = sd->down.sx;
1696 if (sd->down.dir_y) dy = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
1697 else dy = sd->down.sy;
1698
1699 _efl_ui_scroll_manager_bounce_weight_apply(sd, &dx, &dy);
1700 _scroll_manager_hold_animator_add(sd, dx, dy);
1701
1702 return EINA_TRUE;
1703}
1704
1705
1706static Eina_Bool
1707_efl_ui_scroll_manager_post_event_move(void *data,
1708 Evas *e EINA_UNUSED)
1709{
1710 Efl_Ui_Scroll_Manager_Data *sd = data;
1711 Evas_Event_Mouse_Move *ev = sd->event_info;
1712 sd->event_info = NULL;
1713 Evas_Coord dx, dy;
1714
1715 dx = ev->cur.canvas.x - sd->down.x;
1716 dy = ev->cur.canvas.y - sd->down.y;
1717
1718 _efl_ui_scroll_manager_post_event_move_direction_restrict_eval(sd, ev, dx, dy);
1719
1720 if (!sd->freeze)
1721 {
1722 if (!sd->hold)
1723 {
1724 if (!_efl_ui_scroll_manager_post_event_move_hold_eval(sd, ev, dx, dy))
1725 return EINA_TRUE;
1726 }
1727 else
1728 {
1729 _efl_ui_scroll_manager_post_event_move_on_hold_eval(sd, ev);
1730 }
1731 }
1732
1733 return EINA_FALSE;
1734}
1735
1736static void
1737_efl_ui_scroll_manager_down_coord_eval(Efl_Ui_Scroll_Manager_Data *sd,
1738 Evas_Coord *x,
1739 Evas_Coord *y)
1740{
1741 if (!sd->pan_obj) return;
1742
1743 if (sd->down.dir_x) *x = sd->down.sx - (*x - sd->down.x);
1744 else *x = sd->down.sx;
1745 if (sd->down.dir_y) *y = sd->down.sy - (*y - sd->down.y);
1746 else *y = sd->down.sy;
1747
1748 _efl_ui_scroll_manager_bounce_weight_apply(sd, x, y);
1749}
1750
1751static Eina_Bool
1752_efl_ui_scroll_manager_hold_enterer(void *data)
1753{
1754 Efl_Ui_Scroll_Manager_Data *sd = data;
1755 Evas_Coord fx = 0, fy = 0;
1756
1757 sd->down.hold_enterer = NULL;
1758 fx = sd->down.hold_x;
1759 fy = sd->down.hold_y;
1760
1761 if ((_elm_config->scroll_smooth_amount > 0.0) &&
1762 (_elm_config->scroll_smooth_time_window > 0.0))
1763 {
1764 int i, count = 0;
1765 Evas_Coord basex = 0, basey = 0, x, y;
1766 double dt, tdiff, tnow, twin, ttot;
1767 double xx, yy, tot;
1768 struct
1769 {
1770 Evas_Coord x, y;
1771 double t;
1772 } pos[100];
1773
1774 tdiff = sd->down.hist.est_timestamp_diff;
1775 tnow = ecore_loop_time_get();
1776 twin = _elm_config->scroll_smooth_time_window;
1777 for (i = 0; i < 60; i++)
1778 {
1779 if ((sd->down.history[i].timestamp - tdiff) > tnow)
1780 continue;
1781 if ((sd->down.history[i].timestamp >
1782 sd->down.dragged_began_timestamp) || (count == 0))
1783 {
1784 x = sd->down.history[i].x;
1785 y = sd->down.history[i].y;
1786 _efl_ui_scroll_manager_down_coord_eval(sd, &x, &y);
1787 if (count == 0)
1788 {
1789 basex = x;
1790 basey = y;
1791 }
1792 dt = (tnow + tdiff) - sd->down.history[i].timestamp;
1793 if ((dt > twin) && (count > 0)) break;
1794 if ((dt > 0.0) && (count == 0))
1795 {
1796 pos[count].x = x - basex;
1797 pos[count].y = y - basey;
1798 pos[count].t = 0.0;
1799 count++;
1800 }
1801 pos[count].x = x - basex;
1802 pos[count].y = y - basey;
1803 pos[count].t = dt;
1804 count++;
1805 }
1806 }
1807 if (count > 0)
1808 {
1809 xx = 0.0;
1810 yy = 0.0;
1811 tot = 0.0;
1812 ttot = pos[count - 1].t;
1813 for (i = 0; i < count; i++)
1814 {
1815 double wt;
1816
1817 if (ttot > 0.0)
1818 {
1819 if (i < (count - 1))
1820 wt = (ttot - pos[i].t) * (pos[i + 1].t - pos[i].t);
1821 else
1822 wt = 0.0;
1823 }
1824 else wt = 1.0;
1825
1826 xx += ((double)(pos[i].x)) * wt;
1827 yy += ((double)(pos[i].y)) * wt;
1828 tot += wt;
1829 }