summaryrefslogtreecommitdiff
path: root/src/lib/elementary
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/elementary')
-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;
# include <efl_ui_list_relayout.eo.h>
# include <efl_ui_list.eo.h>
# include <efl_ui_list_pan.eo.h>
+# include <efl_ui_scroll_manager.eo.h>
+# include <efl_ui_scroller.eo.h>
+# include <efl_ui_pan.eo.h>
#endif
/* 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
off [[Never use a softcursor.]]
}
-enum Efl.Ui.Scroll_Block
-{
- [[Direction in which a scroller should be blocked.
-
- Note: These options may be effective only in case of thumbscroll (i.e.
- when scrolling by dragging).
-
- @since 1.21
- ]]
- none = 0, [[Don't block any movement.]]
- vertical = 1, [[Block vertical movement.]]
- horizontal = 2 [[Block horizontal movement.]]
-}
-
/* 'on_access_activate' is beta API in the Widget class */
enum Efl.Ui.Activate
{
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 @@
#define EFL_ACCESS_PROTECTED
#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
+#define EFL_UI_SCROLL_MANAGER_PROTECTED
+#define EFL_UI_SCROLLBAR_PROTECTED
+#define EFL_UI_SCROLLBAR_BETA
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_image_zoomable_private.h"
-#include "elm_interface_scrollable.h"
#define MY_PAN_CLASS EFL_UI_IMAGE_ZOOMABLE_PAN_CLASS
@@ -143,7 +145,7 @@ _calc_job_cb(void *data)
sd->minw = minw;
sd->minh = minh;
- efl_event_callback_legacy_call(sd->pan_obj, ELM_PAN_EVENT_CHANGED, NULL);
+ efl_event_callback_call(sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
_sizing_eval(obj);
}
sd->calc_job = NULL;
@@ -200,11 +202,11 @@ _image_place(Evas_Object *obj,
evas_object_move(sd->img, ox + 0 - px + ax, oy + 0 - py + ay);
evas_object_resize(sd->img, gw, gh);
- if (sd->show.show)
+ if (sd->show_item)
{
- sd->show.show = EINA_FALSE;
- elm_interface_scrollable_content_region_show
- (obj, sd->show.x, sd->show.y, sd->show.w, sd->show.h);
+ sd->show_item = EINA_FALSE;
+ efl_ui_scrollable_scroll
+ (sd->smanager, sd->show, EINA_FALSE);
}
}
@@ -381,23 +383,24 @@ _efl_ui_image_zoomable_pan_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Imag
}
EOLIAN static void
-_efl_ui_image_zoomable_pan_elm_pan_pos_set(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Evas_Coord x, Evas_Coord y)
+_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd, Eina_Position2D pos)
{
- if ((x == psd->wsd->pan_x) && (y == psd->wsd->pan_y)) return;
- psd->wsd->pan_x = x;
- psd->wsd->pan_y = y;
+ if ((pos.x == psd->wsd->pan_x) && (pos.y == psd->wsd->pan_y)) return;
+ psd->wsd->pan_x = pos.x;
+ psd->wsd->pan_y = pos.y;
evas_object_smart_changed(obj);
+
+ efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
}
-EOLIAN static void
-_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)
+EOLIAN static Eina_Position2D
+_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
{
- if (x) *x = psd->wsd->pan_x;
- if (y) *y = psd->wsd->pan_y;
+ return EINA_POSITION2D(psd->wsd->pan_x, psd->wsd->pan_y);
}
-EOLIAN static void
-_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)
+EOLIAN static Eina_Position2D
+_efl_ui_image_zoomable_pan_efl_ui_pan_pan_position_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
{
Evas_Coord ow, oh;
@@ -406,28 +409,27 @@ _efl_ui_image_zoomable_pan_elm_pan_pos_max_get(Eo *obj, Efl_Ui_Image_Zoomable_Pa
if (ow < 0) ow = 0;
oh = psd->wsd->minh - oh;
if (oh < 0) oh = 0;
- if (x) *x = ow;
- if (y) *y = oh;
+
+ return EINA_POSITION2D(ow, oh);
}
-EOLIAN static void
-_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)
+EOLIAN static Eina_Position2D
+_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)
{
- if (x) *x = 0;
- if (y) *y = 0;
+ return EINA_POSITION2D(0, 0);
}
-EOLIAN static void
-_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)
+EOLIAN static Eina_Size2D
+_efl_ui_image_zoomable_pan_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Pan_Data *psd)
{
- if (w) *w = psd->wsd->minw;
- if (h) *h = psd->wsd->minh;
+ return EINA_SIZE2D(psd->wsd->minw, psd->wsd->minh);
}
EOLIAN static void
_efl_ui_image_zoomable_pan_efl_object_destructor(Eo *obj, Efl_Ui_Image_Zoomable_Pan_Data *psd)
{
efl_data_unref(psd->wobj, psd->wsd);
+
efl_destructor(efl_super(obj, MY_PAN_CLASS));
}
@@ -725,28 +727,28 @@ static Eina_Bool
_zoom_do(Evas_Object *obj,
double t)
{
- Evas_Coord xx, yy, ow = 0, oh = 0;
+ Evas_Coord xx, yy;
+ Eina_Rect view = {};
EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
sd->size.w = (sd->size.ow * (1.0 - t)) + (sd->size.nw * t);
sd->size.h = (sd->size.oh * (1.0 - t)) + (sd->size.nh * t);
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, &ow, &oh);
- xx = (sd->size.spos.x * sd->size.w) - (ow / 2);
- yy = (sd->size.spos.y * sd->size.h) - (oh / 2);
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
+ xx = (sd->size.spos.x * sd->size.w) - (view.w / 2);
+ yy = (sd->size.spos.y * sd->size.h) - (view.h / 2);
if (xx < 0) xx = 0;
- else if (xx > (sd->size.w - ow))
- xx = sd->size.w - ow;
+ else if (xx > (sd->size.w - view.w))
+ xx = sd->size.w - view.w;
if (yy < 0) yy = 0;
- else if (yy > (sd->size.h - oh))
- yy = sd->size.h - oh;
+ else if (yy > (sd->size.h - view.h))
+ yy = sd->size.h - view.h;
- sd->show.show = EINA_TRUE;
+ sd->show_item = EINA_TRUE;
sd->show.x = xx;
sd->show.y = yy;
- sd->show.w = ow;
- sd->show.h = oh;
+ sd->show.w = view.w;
+ sd->show.h = view.h;
if (sd->orientation_changed)
{
@@ -886,7 +888,7 @@ _efl_ui_image_zoomable_elm_widget_on_focus_update(Eo *obj, Efl_Ui_Image_Zoomable
}
EOLIAN static Efl_Ui_Theme_Apply
-_efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED)
+_efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
{
Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED;
Eina_Bool fdo = EINA_FALSE;
@@ -897,47 +899,18 @@ _efl_ui_image_zoomable_elm_widget_theme_apply(Eo *obj, Efl_Ui_Image_Zoomable_Dat
int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
if (!int_ret) return EFL_UI_THEME_APPLY_FAILED;
+ efl_ui_mirrored_set(sd->smanager, efl_ui_mirrored_get(obj));
+
_sizing_eval(obj);
return int_ret;
}
static void
-_scroll_animate_start_cb(Evas_Object *obj,
- void *data EINA_UNUSED)
-{
- efl_event_callback_legacy_call
- (obj, EFL_UI_EVENT_SCROLL_ANIM_START, NULL);
-}
-
-static void
-_scroll_animate_stop_cb(Evas_Object *obj,
- void *data EINA_UNUSED)
-{
- efl_event_callback_legacy_call
- (obj, EFL_UI_EVENT_SCROLL_ANIM_STOP, NULL);
-}
-
-static void
-_scroll_drag_start_cb(Evas_Object *obj,
- void *data EINA_UNUSED)
-{
- efl_event_callback_legacy_call
- (obj, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
-}
-
-static void
-_scroll_drag_stop_cb(Evas_Object *obj,
- void *data EINA_UNUSED)
-{
- efl_event_callback_legacy_call
- (obj, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
-}
-
-static void
-_scroll_cb(Evas_Object *obj,
- void *data EINA_UNUSED)
+_scroll_cb(void * data,
+ const Efl_Event *event EINA_UNUSED)
{
+ Evas_Object *obj = data;
EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
if (!sd->scr_timer)
@@ -948,63 +921,56 @@ _scroll_cb(Evas_Object *obj,
ecore_timer_del(sd->scr_timer);
sd->scr_timer = ecore_timer_add(0.5, _scroll_timeout_cb, obj);
-
- efl_event_callback_legacy_call
- (obj, EFL_UI_EVENT_SCROLL, NULL);
}
static Eina_Bool
_key_action_move(Evas_Object *obj, const char *params)
{
+ Eina_Rect view = {};
+ Eina_Position2D pos = {};
const char *dir = params;
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
- Evas_Coord x = 0;
- Evas_Coord y = 0;
- Evas_Coord v_h = 0;
Evas_Coord step_x = 0;
Evas_Coord step_y = 0;
- Evas_Coord page_x = 0;
Evas_Coord page_y = 0;
- elm_interface_scrollable_content_pos_get(obj, &x, &y);
- elm_interface_scrollable_step_size_get(obj, &step_x, &step_y);
- elm_interface_scrollable_page_size_get(obj, &page_x, &page_y);
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, NULL, &v_h);
+ pos = efl_ui_scrollable_content_pos_get(sd->smanager);
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
if (!strcmp(dir, "left"))
{
- x -= step_x;
+ pos.x -= step_x;
}
else if (!strcmp(dir, "right"))
{
- x += step_x;
+ pos.x += step_x;
}
else if (!strcmp(dir, "up"))
{
- y -= step_y;
+ pos.y -= step_y;
}
else if (!strcmp(dir, "down"))
{
- y += step_y;
+ pos.y += step_y;
}
else if (!strcmp(dir, "prior"))
{
if (page_y < 0)
- y -= -(page_y * v_h) / 100;
+ pos.y -= -(page_y * view.h) / 100;
else
- y -= page_y;
+ pos.y -= page_y;
}
else if (!strcmp(dir, "next"))
{
if (page_y < 0)
- y += -(page_y * v_h) / 100;
+ pos.y += -(page_y * view.h) / 100;
else
- y += page_y;
+ pos.y += page_y;
}
else return EINA_FALSE;
- elm_interface_scrollable_content_pos_set(obj, x, y, EINA_TRUE);
+ efl_ui_scrollable_content_pos_set(sd->smanager, pos);
return EINA_TRUE;
}
@@ -1076,7 +1042,7 @@ _bounce_eval(void *data, const Efl_Event *event EINA_UNUSED)
sd->g_layer_zoom.imy = 0;
sd->zoom_g_layer = EINA_FALSE;
- elm_interface_scrollable_freeze_set(obj, EINA_FALSE);
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_FALSE);
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
}
@@ -1112,18 +1078,16 @@ _g_layer_zoom_do(Evas_Object *obj,
Elm_Gesture_Zoom_Info *g_layer)
{
int regx, regy, regw, regh, ix, iy, iw, ih;
- Evas_Coord rx, ry, rw = 0, rh = 0;
int xx, yy;
+ Eina_Rect view = {};
EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
sd->mode = ELM_PHOTOCAM_ZOOM_MODE_MANUAL;
sd->zoom = sd->g_layer_start / g_layer->zoom;
sd->size.ow = sd->size.w;
sd->size.oh = sd->size.h;
- elm_interface_scrollable_content_pos_get(obj, &rx, &ry);
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, &rw, &rh);
- if ((rw <= 0) || (rh <= 0)) return;
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
+ if ((view.w <= 0) || (view.h <= 0)) return;
sd->size.nw = (double)sd->size.imw / sd->zoom;
sd->size.nh = (double)sd->size.imh / sd->zoom;
@@ -1139,30 +1103,30 @@ _g_layer_zoom_do(Evas_Object *obj,
sd->g_layer_zoom.imx = 0;
sd->g_layer_zoom.imy = 0;
- if ((xx < 0) || (rw > sd->size.nw))
+ if ((xx < 0) || (view.w > sd->size.nw))
{
sd->g_layer_zoom.imx = xx;
xx = 0;
}
- else if ((xx + rw) > sd->size.nw)
+ else if ((xx + view.w) > sd->size.nw)
{
- sd->g_layer_zoom.imx = xx + rw - sd->size.nw;
- xx = sd->size.nw - rw;
+ sd->g_layer_zoom.imx = xx + view.w - sd->size.nw;
+ xx = sd->size.nw - view.w;
}
- if ((yy < 0) || (rh > sd->size.nh))
+ if ((yy < 0) || (view.h > sd->size.nh))
{
sd->g_layer_zoom.imy = yy;
yy = 0;
}
- else if ((yy + rh) > sd->size.nh)
+ else if ((yy + view.h) > sd->size.nh)
{
- sd->g_layer_zoom.imy = yy + rh - sd->size.nh;
- yy = sd->size.nh - rh;
+ sd->g_layer_zoom.imy = yy + view.h - sd->size.nh;
+ yy = sd->size.nh - view.h;
}
- sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw);
- sd->size.spos.y = (double)(yy + (rh / 2)) / (double)(sd->size.nh);
+ sd->size.spos.x = (double)(xx + (view.w / 2)) / (double)(sd->size.nw);
+ sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
_zoom_do(obj, 1.0);
}
@@ -1175,22 +1139,21 @@ _g_layer_zoom_start_cb(void *data,
Elm_Gesture_Zoom_Info *p = event_info;
EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
double marginx = 0, marginy = 0;
- Evas_Coord rw = 0, rh = 0;
int x, y, w, h;
+ Eina_Rect view = {};
_efl_ui_image_zoomable_bounce_reset(obj, sd);
sd->zoom_g_layer = EINA_TRUE;
- elm_interface_scrollable_freeze_set(obj, EINA_TRUE);
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_TRUE);
elm_photocam_image_region_get(obj, &x, &y, &w, &h);
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, &rw, &rh);
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
- if (rw > sd->size.nw)
- marginx = (rw - sd->size.nw) / 2;
- if (rh > sd->size.nh)
- marginy = (rh - sd->size.nh) / 2;
+ if (view.w > sd->size.nw)
+ marginx = (view.w - sd->size.nw) / 2;
+ if (view.h > sd->size.nh)
+ marginy = (view.h - sd->size.nh) / 2;
sd->g_layer_start = sd->zoom;
@@ -1220,10 +1183,8 @@ _g_layer_zoom_end_cb(void *data,
{
Evas_Object *obj = data;
EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
- Evas_Coord rw, rh;
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, &rw, &rh);
+ Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
sd->g_layer_start = 1.0;
if (sd->g_layer_zoom.imx || sd->g_layer_zoom.imy)
@@ -1236,13 +1197,13 @@ _g_layer_zoom_end_cb(void *data,
sd->g_layer_zoom.bounce.x_end = 0;
sd->g_layer_zoom.bounce.y_end = 0;
- if (rw > sd->size.nw &&
- rh > sd->size.nh)
+ if (view.w > sd->size.nw &&
+ view.h > sd->size.nh)
{
Evas_Coord pw, ph;
double z;
- if ((sd->size.imw < rw) && (sd->size.imh < rh))
+ if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
{
sd->zoom = 1;
sd->size.nw = sd->size.imw;
@@ -1250,15 +1211,15 @@ _g_layer_zoom_end_cb(void *data,
}
else
{
- ph = (sd->size.imh * rw) / sd->size.imw;
- if (ph > rh)
+ ph = (sd->size.imh * view.w) / sd->size.imw;
+ if (ph > view.h)
{
- pw = (sd->size.imw * rh) / sd->size.imh;
- ph = rh;
+ pw = (sd->size.imw * view.h) / sd->size.imh;
+ ph = view.h;
}
else
{
- pw = rw;
+ pw = view.w;
}
if (sd->size.imw > sd->size.imh)
z = (double)sd->size.imw / pw;
@@ -1269,8 +1230,8 @@ _g_layer_zoom_end_cb(void *data,
sd->size.nw = pw;
sd->size.nh = ph;
}
- sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2;
- sd->g_layer_zoom.bounce.y_end = (sd->size.nh - rh) / 2;
+ sd->g_layer_zoom.bounce.x_end = (sd->size.nw - view.w) / 2;
+ sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
}
else
{
@@ -1282,18 +1243,18 @@ _g_layer_zoom_end_cb(void *data,
if (xx < 0) xx = 0;
if (yy < 0) yy = 0;
- if (rw > sd->size.nw)
- sd->g_layer_zoom.bounce.x_end = (sd->size.nw - rw) / 2;
- if ((xx + rw) > sd->size.nw)
- xx = sd->size.nw - rw;
+ if (view.w > sd->size.nw)
+ sd->g_layer_zoom.bounce.x_end = (sd->size.nw - view.w) / 2;
+ if ((xx + view.w) > sd->size.nw)
+ xx = sd->size.nw - view.w;
- if (rh > sd->size.nh)
- sd->g_layer_zoom.bounce.y_end = (sd->size.nh - rh) / 2;
- if ((yy + rh) > sd->size.nh)
- yy = sd->size.nh - rh;
+ if (view.h > sd->size.nh)
+ sd->g_layer_zoom.bounce.y_end = (sd->size.nh - view.h) / 2;
+ if ((yy + view.h) > sd->size.nh)
+ yy = sd->size.nh - view.h;
- sd->size.spos.x = (double)(xx + (rw / 2)) / (double)(sd->size.nw);
- sd->size.spos.y = (double)(yy + (rh / 2)) / (double)(sd->size.nh);
+ sd->size.spos.x = (double)(xx + (view.w / 2)) / (double)(sd->size.nw);
+ sd->size.spos.y = (double)(yy + (view.h / 2)) / (double)(sd->size.nh);
}
sd->g_layer_zoom.bounce.t_start = t;
@@ -1304,7 +1265,7 @@ _g_layer_zoom_end_cb(void *data,
}
else
{
- elm_interface_scrollable_freeze_set(obj, EINA_FALSE);
+ efl_ui_scrollable_scroll_freeze_set(obj, EINA_FALSE);
sd->zoom_g_layer = EINA_FALSE;
}
@@ -1399,6 +1360,297 @@ _efl_ui_image_zoomable_efl_flipable_flip_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Z
return sd->flip;
}
+static void
+_efl_ui_image_zoomable_bar_read_and_update(Eo *obj)
+{
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ double vx, vy;
+
+ edje_object_part_drag_value_get
+ (wd->resize_obj, "elm.dragable.vbar", NULL, &vy);
+ edje_object_part_drag_value_get
+ (wd->resize_obj, "elm.dragable.hbar", &vx, NULL);
+ efl_ui_scrollbar_bar_position_set(sd->smanager, vx, vy);
+}
+
+static void
+_efl_ui_image_zoomable_reload_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
+
+ efl_ui_scrollbar_bar_visibility_update(sd->smanager);
+}
+
+static void
+_efl_ui_image_zoomable_vbar_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_image_zoomable_bar_read_and_update(data);
+
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
+}
+
+static void
+_efl_ui_image_zoomable_vbar_press_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
+}
+
+static void
+_efl_ui_image_zoomable_vbar_unpress_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
+}
+
+static void
+_efl_ui_image_zoomable_edje_drag_start_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
+
+ _efl_ui_image_zoomable_bar_read_and_update(data);
+
+ sd->freeze_want = efl_ui_scrollable_scroll_freeze_get(sd->smanager);
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_TRUE);
+ efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
+}
+
+static void
+_efl_ui_image_zoomable_edje_drag_stop_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(data, sd);
+
+ _efl_ui_image_zoomable_bar_read_and_update(data);
+
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, sd->freeze_want);
+ efl_event_callback_call(data, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
+}
+
+static void
+_efl_ui_image_zoomable_edje_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_image_zoomable_bar_read_and_update(data);
+}
+
+static void
+_efl_ui_image_zoomable_hbar_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_image_zoomable_bar_read_and_update(data);
+
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
+}
+
+static void
+_efl_ui_image_zoomable_hbar_press_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
+}
+
+static void
+_efl_ui_image_zoomable_hbar_unpress_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
+}
+
+static void
+_efl_ui_image_zoomable_bar_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Eo *obj = data;
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ double width = 0.0, height = 0.0;
+
+ efl_ui_scrollbar_bar_size_get(sd->smanager, &width, &height);
+ edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.hbar", width, 1.0);
+ edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.vbar", 1.0, height);
+}
+
+static void
+_efl_ui_image_zoomable_bar_pos_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Eo *obj = data;
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ double posx = 0.0, posy = 0.0;
+
+ efl_ui_scrollbar_bar_position_get(sd->smanager, &posx, &posy);
+ edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.hbar", posx, 0.0);
+ edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.vbar", 0.0, posy);
+}
+
+static void
+_efl_ui_image_zoomable_bar_show_cb(void *data, const Efl_Event *event)
+{
+ Eo *obj = data;
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
+
+ if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,show,hbar", "elm");
+ else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,show,vbar", "elm");
+}
+
+static void
+_efl_ui_image_zoomable_bar_hide_cb(void *data, const Efl_Event *event)
+{
+ Eo *obj = data;
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
+
+ if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,hide,hbar", "elm");
+ else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,hide,vbar", "elm");
+}
+
+static void
+_efl_ui_image_zoomable_edje_object_attach(Eo *obj)
+{
+ efl_layout_signal_callback_add
+ (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,set", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,start", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,stop", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,step", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,page", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,vbar,press", "elm",
+ _efl_ui_image_zoomable_vbar_press_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,vbar,unpress", "elm",
+ _efl_ui_image_zoomable_vbar_unpress_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,set", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,start", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,stop", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,step", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,page", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,hbar,press", "elm",
+ _efl_ui_image_zoomable_hbar_press_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,hbar,unpress", "elm",
+ _efl_ui_image_zoomable_hbar_unpress_cb, obj);
+}
+
+static void
+_efl_ui_image_zoomable_edje_object_detach(Evas_Object *obj)
+{
+ efl_layout_signal_callback_del
+ (obj, "reload", "elm", _efl_ui_image_zoomable_reload_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag", "elm.dragable.vbar", _efl_ui_image_zoomable_vbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,set", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,start", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,stop", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,step", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,page", "elm.dragable.vbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,vbar,press", "elm",
+ _efl_ui_image_zoomable_vbar_press_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,vbar,unpress", "elm",
+ _efl_ui_image_zoomable_vbar_unpress_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag", "elm.dragable.hbar", _efl_ui_image_zoomable_hbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,set", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,start", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,stop", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,step", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,page", "elm.dragable.hbar",
+ _efl_ui_image_zoomable_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,hbar,press", "elm",
+ _efl_ui_image_zoomable_hbar_press_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,hbar,unpress", "elm",
+ _efl_ui_image_zoomable_hbar_unpress_cb, obj);
+}
+
EOLIAN static void
_efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *priv)
{
@@ -1417,34 +1669,24 @@ _efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable
elm_widget_theme_object_set
(obj, edje, "photocam", "base", elm_widget_style_get(obj));
- priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
- evas_object_smart_member_add(priv->hit_rect, obj);
- elm_widget_sub_object_add(obj, priv->hit_rect);
-
- /* common scroller hit rectangle setup */
- evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
- evas_object_show(priv->hit_rect);
- evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
-
elm_widget_can_focus_set(obj, EINA_TRUE);
- elm_interface_scrollable_objects_set(obj, edje, priv->hit_rect);
+ priv->smanager = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj);
- elm_interface_scrollable_animate_start_cb_set(obj, _scroll_animate_start_cb);
- elm_interface_scrollable_animate_stop_cb_set(obj, _scroll_animate_stop_cb);
- elm_interface_scrollable_drag_start_cb_set(obj, _scroll_drag_start_cb);
- elm_interface_scrollable_drag_stop_cb_set(obj, _scroll_drag_stop_cb);
- elm_interface_scrollable_scroll_cb_set(obj, _scroll_cb);
+ efl_ui_mirrored_set(priv->smanager, efl_ui_mirrored_get(obj));
+ efl_ui_scrollable_bounce_enabled_set(priv->smanager, bounce, bounce);
- elm_interface_scrollable_bounce_allow_set(obj, bounce, bounce);
+ priv->pan_obj = efl_add(MY_PAN_CLASS, obj);
+
+ efl_ui_scroll_manager_pan_set(priv->smanager, priv->pan_obj);
+ edje_object_part_swallow(edje, "elm.swallow.content", priv->pan_obj);
- priv->pan_obj = efl_add(MY_PAN_CLASS, evas_object_evas_get(obj));
pan_data = efl_data_scope_get(priv->pan_obj, MY_PAN_CLASS);
efl_data_ref(obj, MY_CLASS);
pan_data->wobj = obj;
pan_data->wsd = priv;
- elm_interface_scrollable_extern_pan_set(obj, priv->pan_obj);
+ efl_event_callback_add(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
priv->g_layer_start = 1.0;
priv->zoom = 1;
@@ -1471,8 +1713,17 @@ _efl_ui_image_zoomable_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Image_Zoomable
edje_object_size_min_calc(edje, &minw, &minh);
evas_object_size_hint_min_set(obj, minw, minh);
- _sizing_eval(obj);
+ _efl_ui_image_zoomable_edje_object_attach(obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED,
+ _efl_ui_image_zoomable_bar_size_changed_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED,
+ _efl_ui_image_zoomable_bar_pos_changed_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW,
+ _efl_ui_image_zoomable_bar_show_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE,
+ _efl_ui_image_zoomable_bar_hide_cb, obj);
+ _sizing_eval(obj);
}
EOLIAN static void
@@ -1500,38 +1751,38 @@ _efl_ui_image_zoomable_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Image_Zoomable
ecore_timer_del(sd->long_timer);
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _zoom_anim_cb, obj);
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _bounce_eval, obj);
+ efl_event_callback_del(obj, EFL_UI_EVENT_SCROLL, _scroll_cb, obj);
+ _efl_ui_image_zoomable_edje_object_detach(obj);
+ efl_del(sd->pan_obj);
+ sd->pan_obj = NULL;
+ efl_del(sd->smanager);
+ sd->smanager = NULL;
efl_canvas_group_del(efl_super(obj, MY_CLASS));
}
EOLIAN static void
-_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Position2D pos)
+_efl_ui_image_zoomable_efl_gfx_position_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sdi EINA_UNUSED, Eina_Position2D pos)
{
if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
return;
efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
- efl_gfx_position_set(sd->hit_rect, pos);
}
EOLIAN static void
-_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Size2D sz)
+_efl_ui_image_zoomable_efl_gfx_size_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Eina_Size2D sz)
{
if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
return;
efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
- efl_gfx_size_set(sd->hit_rect, sz);
}
EOLIAN static void
-_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Evas_Object *member)
+_efl_ui_image_zoomable_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd EINA_UNUSED, Evas_Object *member)
{
-
efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member);
-
- if (sd->hit_rect)
- evas_object_raise(sd->hit_rect);
}
EOLIAN static Eo *
@@ -1569,6 +1820,28 @@ _efl_ui_image_zoomable_efl_layout_group_group_size_max_get(Eo *obj EINA_UNUSED,
return EINA_SIZE2D(0, 0);
}
+EOLIAN static Eina_Bool
+_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)
+{
+ Eina_Bool ok;
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+
+ ok = efl_layout_signal_callback_add(wd->resize_obj, emission, source, func_cb, data);
+
+ return ok;
+}
+
+EOLIAN static Eina_Bool
+_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)
+{
+ Eina_Bool ok;
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
+
+ ok = efl_layout_signal_callback_del(wd->resize_obj, emission, source, func_cb, data);
+
+ return ok;
+}
+
static Eina_Bool
_img_proxy_set(Evas_Object *obj, Efl_Ui_Image_Zoomable_Data *sd,
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
double z;
Eina_List *l;
Efl_Ui_Image_Zoomable_Grid *g, *g_zoom = NULL;
- Evas_Coord pw, ph, rx, ry, rw, rh;
+ Evas_Coord pw, ph;
int zoom_changed = 0, started = 0;
Eina_Bool an = EINA_FALSE;
+ Eina_Rect view = {};
+ Eina_Position2D pos = {};
if (zoom <= (1.0 / 256.0)) zoom = (1.0 / 256.0);
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
sd->zoom = zoom;
sd->size.ow = sd->size.w;
sd->size.oh = sd->size.h;
- elm_interface_scrollable_content_pos_get(obj, &rx, &ry);
- elm_interface_scrollable_content_viewport_geometry_get
- (obj, NULL, NULL, &rw, &rh);
- if ((rw <= 0) || (rh <= 0)) return;
+ pos = efl_ui_scrollable_content_pos_get(sd->smanager);
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
+ if ((view.w <= 0) || (view.h <= 0)) return;
if (sd->mode == ELM_PHOTOCAM_ZOOM_MODE_MANUAL)
{
@@ -1989,15 +2263,15 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
}
else
{
- ph = (sd->size.imh * rw) / sd->size.imw;
- if (ph > rh)
+ ph = (sd->size.imh * view.w) / sd->size.imw;
+ if (ph > view.h)
{
- pw = (sd->size.imw * rh) / sd->size.imh;
- ph = rh;
+ pw = (sd->size.imw * view.h) / sd->size.imh;
+ ph = view.h;
}
else
{
- pw = rw;
+ pw = view.w;
}
if (sd->size.imw > sd->size.imh)
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
}
else
{
- ph = (sd->size.imh * rw) / sd->size.imw;
- if (ph < rh)
+ ph = (sd->size.imh * view.w) / sd->size.imw;
+ if (ph < view.h)
{
- pw = (sd->size.imw * rh) / sd->size.imh;
- ph = rh;
+ pw = (sd->size.imw * view.h) / sd->size.imh;
+ ph = view.h;
}
else
{
- pw = rw;
+ pw = view.w;
}
if (sd->size.imw > sd->size.imh)
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
sd->size.nw = 0;
sd->size.nh = 0;
}
- else if ((sd->size.imw < rw) && (sd->size.imh < rh))
+ else if ((sd->size.imw < view.w) && (sd->size.imh < view.h))
{
if (!EINA_DBL_EQ(sd->zoom, 1)) zoom_changed = 1;
sd->zoom = 1;
@@ -2056,14 +2330,14 @@ _efl_ui_image_zoomable_efl_ui_zoom_zoom_set(Eo *obj, Efl_Ui_Image_Zoomable_Data
}
else
{
- ph = (sd->size.imh * rw) / sd->size.imw;
- if (ph > rh)
+ ph = (sd->size.imh * view.w) / sd->size.imw;
+ if (ph > view.h)
{
- pw = (sd->size.imw * rh) / sd->size.imh;
- ph = rh;
+ pw = (sd->size.imw * view.h) / sd->size.imh;
+ ph = view.h;
}
else
- pw = rw;
+ pw = view.w;
if (sd->size.imw > sd->size.imh)
z = (double)sd->size.imw / pw;
else
@@ -2125,16 +2399,16 @@ done:
sd->t_end = sd->t_start + _elm_config->zoom_friction;
if ((sd->size.w > 0) && (sd->size.h > 0))
{
- sd->size.spos.x = (double)(rx + (rw / 2)) / (double)sd->size.w;
- sd->size.spos.y = (double)(ry + (rh / 2)) / (double)sd->size.h;
+ sd->size.spos.x = (double)(pos.x + (view.w / 2)) / (double)sd->size.w;
+ sd->size.spos.y = (double)(pos.y + (view.h / 2)) / (double)sd->size.h;
}
else
{
sd->size.spos.x = 0.5;
sd->size.spos.y = 0.5;
}
- if (rw > sd->size.w) sd->size.spos.x = 0.5;
- if (rh > sd->size.h) sd->size.spos.y = 0.5;
+ if (view.w > sd->size.w) sd->size.spos.x = 0.5;
+ if (view.h > sd->size.h) sd->size.spos.y = 0.5;
if (sd->size.spos.x > 1.0) sd->size.spos.x = 1.0;
if (sd->size.spos.y > 1.0) sd->size.spos.y = 1.0;
@@ -2212,20 +2486,18 @@ _efl_ui_image_zoomable_efl_gfx_view_view_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Im
}
EOLIAN static Eina_Rect
-_efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
+_efl_ui_image_zoomable_image_region_get(Eo *obj EINA_UNUSED, Efl_Ui_Image_Zoomable_Data *sd)
{
- Evas_Coord sx, sy, sw, sh;
Eina_Rect region = {};
- elm_interface_scrollable_content_pos_get((Eo *)obj, &sx, &sy);
- elm_interface_scrollable_content_viewport_geometry_get
- ((Eo *)obj, NULL, NULL, &sw, &sh);
+ Eina_Position2D pos = efl_ui_scrollable_content_pos_get(sd->smanager);
+ Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
if (sd->size.w > 0)
{
- region.x = (sd->size.imw * sx) / sd->size.w;
+ region.x = (sd->size.imw * pos.x) / sd->size.w;
if (region.x > sd->size.imw) region.x = sd->size.imw;
- region.w = (sd->size.imw * sw) / sd->size.w;
+ region.w = (sd->size.imw * view.w) / sd->size.w;
if (region.w > sd->size.imw) region.w = sd->size.imw;
else if (region.w < 0)
region.w = 0;
@@ -2233,9 +2505,9 @@ _efl_ui_image_zoomable_image_region_get(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd)
if (sd->size.h > 0)
{
- region.y = (sd->size.imh * sy) / sd->size.h;
+ region.y = (sd->size.imh * pos.y) / sd->size.h;
if (region.y > sd->size.imh) region.y = sd->size.imh;
- region.h = (sd->size.imh * sh) / sd->size.h;
+ region.h = (sd->size.imh * view.h) / sd->size.h;
if (region.h > sd->size.imh) region.h = sd->size.imh;
else if (region.h < 0)
region.h = 0;
@@ -2262,19 +2534,19 @@ _efl_ui_image_zoomable_image_region_set(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd,
_efl_ui_image_zoomable_bounce_reset(obj, sd);
_efl_ui_image_zoomable_zoom_reset(obj, sd);
- elm_interface_scrollable_content_region_show(obj, rx, ry, rw, rh);
+ efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(rx, ry, rw, rh), EINA_FALSE);
}
EOLIAN static void
-_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)
+_efl_ui_image_zoomable_efl_ui_scrollable_interactive_scroll(Eo *obj, Efl_Ui_Image_Zoomable_Data *sd, Eina_Rect rc, Eina_Bool animation)
{
int rx, ry, rw, rh;
if ((sd->size.imw < 1) || (sd->size.imh < 1)) return;
- rx = (x * sd->size.w) / sd->size.imw;
- ry = (y * sd->size.h) / sd->size.imh;
- rw = (w * sd->size.w) / sd->size.imw;
- rh = (h * sd->size.h) / sd->size.imh;
+ rx = (rc.x * sd->size.w) / sd->size.imw;
+ ry = (rc.y * sd->size.h) / sd->size.imh;
+ rw = (rc.w * sd->size.w) / sd->size.imw;
+ rh = (rc.h * sd->size.h) / sd->size.imh;
if (rw < 1) rw = 1;
if (rh < 1) rh = 1;
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_
_efl_ui_image_zoomable_bounce_reset(obj, sd);
_efl_ui_image_zoomable_zoom_reset(obj, sd);
- elm_interface_scrollable_region_bring_in(efl_super(obj, MY_CLASS), rx, ry, rw, rh);
+ efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(rx, ry, rw, rh), animation);
}
EOLIAN static void
@@ -2915,7 +3187,8 @@ elm_photocam_image_region_bring_in(Evas_Object *obj,
int h EINA_UNUSED)
{
ELM_PHOTOCAM_CHECK(obj);
- elm_interface_scrollable_region_bring_in(obj, x, y, w, h);
+ EFL_UI_IMAGE_ZOOMABLE_DATA_GET(obj, sd);
+ efl_ui_scrollable_scroll(sd->smanager, EINA_RECT(x, y, w, h), EINA_TRUE);
}
EAPI void
@@ -2925,7 +3198,7 @@ elm_photocam_bounce_set(Evas_Object *obj,
{
ELM_PHOTOCAM_CHECK(obj);
- elm_interface_scrollable_bounce_allow_set(obj, h_bounce, v_bounce);
+ efl_ui_scrollable_bounce_enabled_set(obj, h_bounce, v_bounce);
}
EAPI void
@@ -2935,7 +3208,7 @@ elm_photocam_bounce_get(const Evas_Object *obj,
{
ELM_PHOTOCAM_CHECK(obj);
- elm_interface_scrollable_bounce_allow_get((Eo *)obj, h_bounce, v_bounce);
+ efl_ui_scrollable_bounce_enabled_get((Eo *)obj, h_bounce, v_bounce);
}
EAPI 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 @@
class Efl.Ui.Image_Zoomable (Elm.Widget, Efl.Ui.Image, Efl.Ui.Zoom,
- Elm.Interface_Scrollable,
- Efl.Ui.Scrollable)
+ Efl.Ui.Scrollable.Interactive,
+ Efl.Ui.Scrollbar)
{
[[Elementary Image Zoomable class]]
legacy_prefix: elm_photocam;
@@ -61,13 +61,15 @@ class Efl.Ui.Image_Zoomable (Elm.Widget, Efl.Ui.Image, Efl.Ui.Zoom,
Elm.Widget.theme_apply;
Elm.Widget.on_focus_update;
Elm.Widget.widget_event;
- Elm.Interface_Scrollable.region_bring_in;
+ Efl.Ui.Scrollable.Interactive.scroll;
Efl.Access.Widget.Action.elm_actions { get; }
Efl.File.file { get; set; }
Efl.Orientation.orientation { get; set; }
Efl.Flipable.flip { get; set; }
Efl.Layout.Group.group_size_min { get; }
Efl.Layout.Group.group_size_max { get; }
+ Efl.Layout.Signal.signal_callback_add;
+ Efl.Layout.Signal.signal_callback_del;
//Efl.Canvas.Layout_Group.group_data { get; }
}
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 @@
-class Efl.Ui.Image_Zoomable_Pan (Elm.Pan)
+class Efl.Ui.Image_Zoomable_Pan (Efl.Ui.Pan)
{
[[Elementary photocom pan class]]
legacy_prefix: elm_photocam_pan;
@@ -8,10 +8,10 @@ class Efl.Ui.Image_Zoomable_Pan (Elm.Pan)
Efl.Gfx.position { set; }
Efl.Gfx.size { set; }
Efl.Canvas.Group.group_calculate;
- Elm.Pan.content_size { get; }
- Elm.Pan.pos { get; set; }
- Elm.Pan.pos_min { get; }
- Elm.Pan.pos_max { get; }
+ Efl.Ui.Pan.content_size { get; }
+ Efl.Ui.Pan.pan_position { get; set; }
+ Efl.Ui.Pan.pan_position_min { get; }
+ Efl.Ui.Pan.pan_position_max { get; }
}
events {
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
struct _Efl_Ui_Image_Zoomable_Data
{
- Evas_Object *hit_rect;
+ Eo *smanager;
+ Eo *pan_obj;
Evas_Object *g_layer;
- Evas_Object *pan_obj;
Evas_Coord pan_x, pan_y, minw, minh;
@@ -109,11 +109,7 @@ struct _Efl_Ui_Image_Zoomable_Data
} spos;
} size;
- struct
- {
- Eina_Bool show : 1;
- Evas_Coord x, y, w, h;
- } show;
+ Eina_Rect show;
int tsize;
Evas_Object *img; /* low res version of image (scale down == 8) */
@@ -147,11 +143,13 @@ struct _Efl_Ui_Image_Zoomable_Data
Eina_Bool orientation_changed : 1;
Eina_Bool play : 1;
Eina_Bool anim : 1;
+ Eina_Bool freeze_want : 1;
+ Eina_Bool show_item: 1;
};
struct _Efl_Ui_Image_Zoomable_Pan_Data
{
- Evas_Object *wobj;
+ Eo *wobj;
Efl_Ui_Image_Zoomable_Data *wsd;
};
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 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "efl_ui_widget_pan.h"
+
+#define MY_CLASS EFL_UI_PAN_CLASS
+#define MY_CLASS_NAME "Efl_Ui_Pan"
+
+#define EFL_UI_PAN_DATA_GET(o, sd) \
+ Efl_Ui_Pan_Data *sd = efl_data_scope_safe_get(o, MY_CLASS)
+
+#define EFL_UI_PAN_DATA_GET_OR_RETURN(o, ptr, ...) \
+ EFL_UI_PAN_DATA_GET(o, ptr); \
+ if (EINA_UNLIKELY(!ptr)) \
+ { \
+ CRI("No widget data for object %p (%s)", \
+ o, evas_object_type_get(o)); \
+ return __VA_ARGS__; \
+ }
+
+EOLIAN static void
+_efl_ui_pan_efl_gfx_position_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
+{
+ if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
+ return;
+
+ efl_gfx_position_set(efl_super(obj, MY_CLASS), pos);
+
+ psd->x = pos.x;
+ psd->y = pos.y;
+
+ evas_object_smart_changed(obj);
+}
+
+EOLIAN static void
+_efl_ui_pan_efl_gfx_size_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Size2D sz)
+{
+ if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
+ return;
+
+ efl_gfx_size_set(efl_super(obj, MY_CLASS), sz);
+
+ psd->w = sz.w;
+ psd->h = sz.h;
+
+ evas_object_smart_changed(obj);
+ efl_event_callback_call(obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, NULL);
+}
+
+EOLIAN static void
+_efl_ui_pan_efl_gfx_visible_set(Eo *obj, Efl_Ui_Pan_Data *psd, Eina_Bool vis)
+{
+ if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
+ return;
+
+ efl_gfx_visible_set(efl_super(obj, MY_CLASS), vis);
+ if (psd->content) efl_gfx_visible_set(psd->content, vis);
+}
+
+EOLIAN static void
+_efl_ui_pan_pan_position_set(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd, Eina_Position2D pos)
+{
+ if ((pos.x == psd->px) && (pos.y == psd->py)) return;
+ psd->px = pos.x;
+ psd->py = pos.y;
+
+ evas_object_smart_changed(obj);
+ efl_event_callback_call(obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, NULL);
+}
+
+EOLIAN static Eina_Position2D
+_efl_ui_pan_pan_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
+{
+ return EINA_POSITION2D(psd->px, psd->py);
+}
+
+EOLIAN static Eina_Position2D
+_efl_ui_pan_pan_position_max_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
+{
+ Eina_Position2D pos = { 0, 0};
+ if (psd->w < psd->content_w) pos.x = psd->content_w - psd->w;
+ if (psd->h < psd->content_h) pos.y = psd->content_h - psd->h;
+
+ return pos;
+}
+
+EOLIAN static Eina_Position2D
+_efl_ui_pan_pan_position_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
+{
+ return EINA_POSITION2D(0 ,0);
+}
+
+EOLIAN static Eina_Size2D
+_efl_ui_pan_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
+{
+ return EINA_SIZE2D(psd->content_w, psd->content_h);
+}
+
+EOLIAN static Eo *
+_efl_ui_pan_efl_object_constructor(Eo *obj, Efl_Ui_Pan_Data *_pd EINA_UNUSED)
+{
+ efl_canvas_group_clipped_set(obj, EINA_TRUE);
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+
+ return obj;
+}
+
+EOLIAN static void
+_efl_ui_pan_efl_object_destructor(Eo *obj, Efl_Ui_Pan_Data *sd EINA_UNUSED)
+{
+ efl_content_set(obj, NULL);
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+static void
+_efl_ui_pan_content_del_cb(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Evas_Object *pobj = data;
+ EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
+
+ psd->content = NULL;
+ psd->content_w = psd->content_h = psd->px = psd->py = 0;
+ efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
+}
+
+static void
+_efl_ui_pan_content_resize_cb(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Evas_Object *pobj = data;
+ EFL_UI_PAN_DATA_GET_OR_RETURN(pobj, psd);
+
+ Eina_Size2D sz = efl_gfx_size_get(psd->content);
+ if ((sz.w != psd->content_w) || (sz.h != psd->content_h))
+ {
+ psd->content_w = sz.w;
+ psd->content_h = sz.h;
+ evas_object_smart_changed(pobj);
+ }
+ efl_event_callback_call(pobj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_pan_efl_content_content_set(Evas_Object *obj, Efl_Ui_Pan_Data *psd, Evas_Object *content)
+{
+ Eina_Size2D sz;
+
+ if (content == psd->content) return EINA_TRUE;
+ if (psd->content)
+ {
+ efl_canvas_group_member_del(obj, psd->content);
+ evas_object_event_callback_del_full
+ (psd->content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
+ evas_object_event_callback_del_full
+ (psd->content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb,
+ obj);
+ psd->content = NULL;
+ psd->content_w = psd->content_h = psd->px = psd->py = 0;
+ }
+ if (!content) goto end;
+
+ psd->content = content;
+ efl_canvas_group_member_add(obj, content);
+ sz = efl_gfx_size_get(psd->content);
+ psd->content_w = sz.w;
+ psd->content_h = sz.h;
+ evas_object_event_callback_add
+ (content, EVAS_CALLBACK_DEL, _efl_ui_pan_content_del_cb, obj);
+ evas_object_event_callback_add
+ (content, EVAS_CALLBACK_RESIZE, _efl_ui_pan_content_resize_cb, obj);
+
+ if (evas_object_visible_get(obj))
+ evas_object_show(psd->content);
+ else
+ evas_object_hide(psd->content);
+
+ evas_object_smart_changed(obj);
+
+end:
+ efl_event_callback_call(obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, NULL);
+ return EINA_TRUE;
+}
+
+EOLIAN static void
+_efl_ui_pan_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Efl_Ui_Pan_Data *psd)
+{
+ efl_gfx_position_set(psd->content, EINA_POSITION2D(psd->x - psd->px, psd->y - psd->py));
+}
+#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 @@
+class Efl.Ui.Pan (Efl.Canvas.Group,
+ Efl.Content)
+{
+ [[Elementary pan class]]
+ methods {
+ @property pan_position {
+ [[Position]]
+ set {
+ }
+ get {
+ }
+ values {
+ position: Eina.Position2D;
+ }
+ }
+ @property content_size {
+ [[Content size]]
+ get {
+ }
+ values {
+ size: Eina.Size2D;
+ }
+ }
+ @property pan_position_min {
+ [[The minimal position to scroll]]
+ get {
+ }
+ values {
+ pos: Eina.Position2D;
+ }
+ }
+ @property pan_position_max {
+ [[The maximal position to scroll]]
+ get {
+ }
+ values {
+ pos: Eina.Position2D;
+ }
+ }
+ }
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Efl.Gfx.visible { set; }
+ Efl.Gfx.position { set; }
+ Efl.Gfx.size { set; }
+ Efl.Content.content { set; }
+ Efl.Canvas.Group.group_calculate;
+ }
+ events {
+ content,changed; [[Called when pan content changed]]
+ viewport,changed; [[Called when pan viewport changed]]
+ position,changed; [[Called when pan position changed]]
+ }
+}
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 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define EFL_UI_SCROLL_MANAGER_PROTECTED
+#define EFL_UI_SCROLLBAR_PROTECTED
+#define EFL_UI_SCROLLBAR_BETA
+
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "efl_ui_widget_scroll_manager.h"
+
+#define MY_CLASS EFL_UI_SCROLL_MANAGER_CLASS
+#define MY_CLASS_NAME "Efl.Ui.Scroll.Manager"
+
+#define ELM_ANIMATOR_CONNECT(Obj, Bool, Callback, Data) \
+ efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
+ efl_event_callback_add(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
+ Bool = 1;
+
+#define ELM_ANIMATOR_DISCONNECT(Obj, Bool, Callback, Data) \
+ efl_event_callback_del(Obj, EFL_EVENT_ANIMATOR_TICK, Callback, Data); \
+ Bool = 0;
+
+
+static double
+_scroll_manager_linear_interp(void *data EINA_UNUSED, double progress)
+{
+ return progress;
+}
+static double
+_scroll_manager_accel_interp(void *data EINA_UNUSED, double progress)
+{
+ return progress * progress;
+}
+static double
+_scroll_manager_decel_interp(void *data EINA_UNUSED, double progress)
+{
+ return (1.0 - (1.0 - progress) * (1.0 - progress));
+}
+
+static Interpolator
+_scroll_manager_interp_get(InterpType interp)
+{
+ if (interp == ACCEL)
+ return _scroll_manager_accel_interp;
+ else if (interp == DECEL)
+ return _scroll_manager_decel_interp;
+ return _scroll_manager_linear_interp;
+}
+
+// Prototypes --- //
+
+// ANIMATORS - tick function
+static void _efl_ui_scroll_manager_hold_animator(void *data, const Efl_Event *event);
+static void _efl_ui_scroll_manager_on_hold_animator(void *data, const Efl_Event *event);
+static void _efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event);
+static void _efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event);
+static void _efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event);
+static void _efl_ui_scroll_manager_bounce_x_animator(void *data, const Efl_Event *event);
+
+// ANIMATORS - manipulate function
+static void _scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
+static Eina_Bool _scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+
+static void _scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
+static Eina_Bool _scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+
+/// Constant scrolling
+static 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);
+static Eina_Bool _scroll_manager_scrollto_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+static void _scroll_manager_scrollto_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cx, Evas_Coord x, double t, InterpType interp);
+static Eina_Bool _scroll_manager_scrollto_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+static void _scroll_manager_scrollto_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord cy, Evas_Coord y, double t, InterpType interp);
+static Eina_Bool _scroll_manager_scrollto_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+
+/// Flicking
+static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy);
+
+// Bounce
+static void _scroll_manager_bounce_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx);
+static Eina_Bool _scroll_manager_bounce_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+static void _scroll_manager_bounce_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vy);
+static Eina_Bool _scroll_manager_bounce_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd);
+
+// Util
+static void _scroll_manager_scrollto(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y);
+static void _scroll_manager_animators_drop(Evas_Object *obj);
+
+// ETC
+static void _efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x,Evas_Coord y);
+// --- Prototypes //
+
+static inline double
+_round(double value, int pos)
+{
+ double temp;
+
+ temp = value * pow( 10, pos );
+ temp = floor( temp + 0.5 );
+ temp *= pow( 10, -pos );
+
+ return temp;
+}
+
+#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(o, ptr) \
+ Efl_Ui_Scroll_Manager_Data *ptr = \
+ (!efl_isa(o, MY_CLASS) ? NULL : \
+ efl_data_scope_safe_get(o, MY_CLASS)); \
+ if (!ptr) \
+ { \
+ CRI("No interface data for object %p (%s)", \
+ o, evas_object_type_get(o)); \
+ return; \
+ }
+
+#define EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
+ Efl_Ui_Scroll_Manager_Data *ptr = \
+ (!efl_isa(o, MY_CLASS) ? NULL : \
+ efl_data_scope_safe_get(o, MY_CLASS)); \
+ if (!ptr) \
+ { \
+ CRI("No interface data for object %p (%s)", \
+ o, evas_object_type_get(o)); \
+ return val; \
+ }
+
+static void _efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj);
+
+#define LEFT 0
+#define RIGHT 1
+#define UP 2
+#define DOWN 3
+#define EVTIME 1
+//#define SCROLLDBG 1
+/* smoothness debug calls - for debugging how much smooth your app is */
+
+static inline Eina_Bool
+_scroll_manager_thumb_scrollable_get(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (!sd) return EINA_FALSE;
+ if ((sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) &&
+ (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL))
+ return EINA_FALSE;
+
+ if (!_elm_config->thumbscroll_enable) return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static inline Eina_Bool
+_scroll_manager_animating_get(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (!sd) return EINA_FALSE;
+ return ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
+ (sd->scrollto.x.animator) || (sd->scrollto.y.animator));
+}
+
+static void
+_efl_ui_scroll_manager_scroll_start(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ sd->scrolling = EINA_TRUE;
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_START, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_stop(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ sd->scrolling = EINA_FALSE;
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_STOP, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_drag_start(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
+ if (!sd->scrolling)
+ _efl_ui_scroll_manager_scroll_start(sd);
+}
+
+static void
+_efl_ui_scroll_manager_drag_stop(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_anim_start(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_START, NULL);
+ if (!sd->scrolling)
+ _efl_ui_scroll_manager_scroll_start(sd);
+}
+
+static void
+_efl_ui_scroll_manager_anim_stop(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_ANIM_STOP, NULL);
+ if (sd->scrolling)
+ _efl_ui_scroll_manager_scroll_stop(sd);
+}
+
+static void
+_efl_ui_scroll_manager_scroll(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_up(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_UP, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_down(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_DOWN, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_left(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_LEFT, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_right(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_SCROLL_RIGHT, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_edge_up(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_UP, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_edge_down(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_DOWN, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_edge_left(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_LEFT, NULL);
+}
+
+static void
+_efl_ui_scroll_manager_edge_right(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ efl_event_callback_call(sd->parent, EFL_UI_EVENT_EDGE_RIGHT, NULL);
+}
+
+EOLIAN static Eina_Size2D
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ return efl_ui_pan_content_size_get(sd->pan_obj);
+}
+
+EOLIAN static Eina_Rect
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_viewport_geometry_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (!sd->pan_obj) return EINA_RECT(0, 0, 0, 0);
+
+ return efl_gfx_geometry_get(sd->pan_obj);
+}
+
+EOLIAN static void
+_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)
+{
+ sd->match_content_w = !!w;
+ sd->match_content_h = !!h;
+}
+
+static Evas_Coord
+_efl_ui_scroll_manager_x_mirrored_get(const Evas_Object *obj,
+ Evas_Coord x)
+{
+ Evas_Coord ret;
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, x);
+
+ if (!sd->pan_obj) return 0;
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ ret = max.x - (x - min.x);
+
+ return (ret >= min.x) ? ret : min.x;
+}
+
+/* Update the wanted coordinates according to the x, y passed
+ * widget directionality, content size and etc. */
+static void
+_efl_ui_scroll_manager_wanted_coordinates_update(Efl_Ui_Scroll_Manager_Data *sd,
+ Evas_Coord x,
+ Evas_Coord y)
+{
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+
+ if (!sd->pan_obj) return;
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ /* Update wx/y/w/h - and if the requested positions aren't legal
+ * adjust a bit. */
+ Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+ sd->ww = r.w;
+ sd->wh = r.h;
+
+ if (x < min.x && !sd->is_mirrored)
+ {
+ if (!sd->loop_h) sd->wx = min.x;
+ else sd->wx = max.x;
+ }
+ else if (sd->is_mirrored)
+ sd->wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, x);
+ else if (!sd->loop_h && (x > max.x)) sd->wx = max.x;
+ else if (sd->loop_h && x >= (sd->ww + max.x)) sd->wx = min.x;
+ else sd->wx = x;
+
+ if (y < min.y)
+ {
+ if (!sd->loop_v) sd->wy = min.y;
+ else sd->wy = max.y;
+ }
+ else if (!sd->loop_v && (y > max.y)) sd->wy = max.y;
+ else if (sd->loop_v && y >= (sd->wh + max.y)) sd->wy = min.y;
+ else sd->wy = y;
+}
+
+static void
+_scroll_manager_animator_velocity_get(Efl_Ui_Scroll_Manager_Data *sd, double *velx, double *vely)
+{
+ Evas_Coord dx = 0, dy = 0;
+ double vx = 0.0, vy = 0.0;
+ double t = ecore_loop_time_get();
+ Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
+
+ if (t < sd->scrollto.x.start_t + sd->scrollto.x.dur)
+ {
+ dx = sd->scrollto.x.end - cur.x;
+ vx = (double)(dx /((sd->scrollto.x.start_t + sd->scrollto.x.dur) - t));
+
+ if (sd->scrollto.x.interp)
+ vx = sd->scrollto.x.interp(NULL, t/(sd->scrollto.x.start_t + sd->scrollto.x.dur)) * vx;
+ }
+ if (t < sd->scrollto.y.start_t + sd->scrollto.y.dur)
+ {
+ dy = sd->scrollto.y.end - cur.y;
+ vy = (double)(dy /((sd->scrollto.y.start_t + sd->scrollto.y.dur) - t));
+
+ if (sd->scrollto.y.interp)
+ vy = sd->scrollto.y.interp(NULL, t/(sd->scrollto.y.start_t + sd->scrollto.y.dur)) * vy;
+ }
+
+ if (velx) *velx = vx;
+ if (vely) *vely = vy;
+}
+
+static void
+_efl_ui_scroll_manager_bounce_eval(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ double vx = 0.0, vy = 0.0;
+ if (!sd->pan_obj) return;
+
+ if (sd->freeze) return;
+ if ((!sd->bouncemex) && (!sd->bouncemey)) return;
+ if (sd->down.now) return; // down bounce while still held down
+
+ _scroll_manager_on_hold_animator_del(sd);
+ _scroll_manager_hold_animator_del(sd);
+
+ _scroll_manager_animator_velocity_get(sd, &vx, &vy);
+ if (!sd->bounce.x.animator)
+ {
+ if (sd->bouncemex)
+ {
+ _scroll_manager_scrollto_x_animator_del(sd);
+ _scroll_manager_bounce_x_animator_add(sd,vx);
+ }
+ }
+ if (!sd->bounce.y.animator)
+ {
+ if (sd->bouncemey)
+ {
+ _scroll_manager_scrollto_y_animator_del(sd);
+ _scroll_manager_bounce_y_animator_add(sd,vy);
+ }
+ }
+}
+
+EOLIAN static Eina_Position2D
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (!sd->pan_obj) return EINA_POSITION2D(0, 0);
+
+ return efl_ui_pan_position_get(sd->pan_obj);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_content_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Position2D pos)
+{
+ Evas_Coord x = pos.x, y = pos.y;
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+ Eina_Size2D content = {0, 0};
+
+ if (!sd->pan_obj) return;
+
+ // FIXME: allow for bounce outsde of range
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ content = efl_ui_pan_content_size_get(sd->pan_obj);
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+
+ if (sd->loop_h && content.w > 0)
+ {
+ if (x < 0) x = content.w + (x % content.w);
+ else if (x >= content.w) x = (x % content.w);
+ }
+ if (sd->loop_v && content.h > 0)
+ {
+ if (y < 0) y = content.h + (y % content.h);
+ else if (y >= content.h) y = (y % content.h);
+ }
+
+ if (!_elm_config->thumbscroll_bounce_enable)
+ {
+
+ if (x < min.x) x = min.x;
+ if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
+ if (y < min.y) y = min.y;
+ if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
+ }
+
+ if (!sd->bounce_horiz)
+ {
+ if (x < min.x) x = min.x;
+ if (!sd->loop_h && (x - min.x) > max.x) x = max.x + min.x;
+ }
+ if (!sd->bounce_vert)
+ {
+ if (y < min.y) y = min.y;
+ if (!sd->loop_v && (y - min.y) > max.y) y = max.y + min.y;
+ }
+
+ efl_ui_pan_position_set(sd->pan_obj, EINA_POSITION2D(x, y));
+
+ if (!sd->loop_h && !sd->bounce.x.animator)
+ {
+ if ((x < min.x) ||(x > max.x + min.x))
+ {
+ sd->bouncemex = EINA_TRUE;
+ _efl_ui_scroll_manager_bounce_eval(sd);
+ }
+ else
+ sd->bouncemex = EINA_FALSE;
+ }
+ if (!sd->loop_v && !sd->bounce.y.animator)
+ {
+ if ((y < min.y) ||(y > max.y + min.y))
+ {
+ sd->bouncemey = EINA_TRUE;
+ _efl_ui_scroll_manager_bounce_eval(sd);
+ }
+ else
+ sd->bouncemey = EINA_FALSE;
+ }
+
+ {
+ if ((x != cur.x) || (y != cur.y))
+ {
+ _efl_ui_scroll_manager_scroll(sd);
+ if (x < cur.x)
+ {
+ _efl_ui_scroll_manager_scroll_left(sd);
+ }
+ if (x > cur.x)
+ {
+ _efl_ui_scroll_manager_scroll_right(sd);
+ }
+ if (y < cur.y)
+ {
+ _efl_ui_scroll_manager_scroll_up(sd);
+ }
+ if (y > cur.y)
+ {
+ _efl_ui_scroll_manager_scroll_down(sd);
+ }
+ }
+ if (x != cur.x)
+ {
+ if (x == min.x)
+ {
+ _efl_ui_scroll_manager_edge_left(sd);
+ }
+ if (x == (max.x + min.x))
+ {
+ _efl_ui_scroll_manager_edge_right(sd);
+ }
+ }
+ if (y != cur.y)
+ {
+ if (y == min.y)
+ {
+ _efl_ui_scroll_manager_edge_up(sd);
+ }
+ if (y == max.y + min.y)
+ {
+ _efl_ui_scroll_manager_edge_down(sd);
+ }
+ }
+ }
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_base_mirrored_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool mirrored)
+{
+ Evas_Coord wx;
+
+ mirrored = !!mirrored;
+
+ if (sd->is_mirrored == mirrored)
+ return;
+
+ sd->is_mirrored = mirrored;
+
+ if (sd->is_mirrored)
+ wx = _efl_ui_scroll_manager_x_mirrored_get(sd->obj, sd->wx);
+ else
+ wx = sd->wx;
+
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(wx, sd->wy));
+}
+
+static void
+_scroll_manager_animators_drop(Evas_Object *obj)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+ if ((sd->bounce.x.animator) || (sd->bounce.y.animator) ||
+ (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
+ {
+ if (_scroll_manager_scrollto_x_animator_del(sd))
+ {
+ }
+ if (_scroll_manager_scrollto_y_animator_del(sd))
+ {
+ }
+ if (_scroll_manager_bounce_x_animator_del(sd))
+ {
+ sd->bouncemex = EINA_FALSE;
+ if (sd->content_info.resized)
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ }
+ if (_scroll_manager_bounce_y_animator_del(sd))
+ {
+ sd->bouncemey = EINA_FALSE;
+ if (sd->content_info.resized)
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ }
+ _efl_ui_scroll_manager_anim_stop(sd);
+ }
+ if (_scroll_manager_hold_animator_del(sd))
+ {
+ _efl_ui_scroll_manager_drag_stop(sd);
+ if (sd->content_info.resized)
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ }
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_mode_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroll_Manager_Data *sd,
+ Efl_Ui_Scrollbar_Mode hmode,
+ Efl_Ui_Scrollbar_Mode vmode)
+{
+ sd->hbar_mode = hmode;
+ sd->vbar_mode = vmode;
+
+ if (sd->hbar_timer &&
+ hmode == EFL_UI_SCROLLBAR_MODE_ON)
+ ELM_SAFE_FREE(sd->hbar_timer, ecore_timer_del);
+ if (sd->vbar_timer &&
+ vmode == EFL_UI_SCROLLBAR_MODE_ON)
+ ELM_SAFE_FREE(sd->vbar_timer, ecore_timer_del);
+
+ efl_ui_scrollbar_bar_visibility_update(sd->obj);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_mode_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroll_Manager_Data *sd,
+ Efl_Ui_Scrollbar_Mode *hmode,
+ Efl_Ui_Scrollbar_Mode *vmode)
+{
+ *hmode = sd->hbar_mode;
+ *vmode = sd->vbar_mode;
+}
+
+/* returns TRUE when we need to move the scroller, FALSE otherwise.
+ * Updates w and h either way, so save them if you need them. */
+static Eina_Bool
+_efl_ui_scroll_manager_content_region_show_internal(Evas_Object *obj,
+ Evas_Coord *_x,
+ Evas_Coord *_y,
+ Evas_Coord w,
+ Evas_Coord h)
+{
+ Evas_Coord nx, ny, x = *_x, y = *_y;
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+ Eina_Size2D pan = {0, 0};
+
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
+
+ if (!sd->pan_obj) return EINA_FALSE;
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ pan = efl_gfx_size_get(sd->pan_obj);
+
+ nx = x;
+ if ((x > cur.x) && (w < pan.w))
+ {
+ if ((cur.x + pan.w) < (x + w)) nx = x - pan.w + w;
+ else nx = cur.x;
+ }
+ ny = y;
+ if ((y > cur.y) && (h < pan.h))
+ {
+ if ((cur.y + pan.h) < (y + h)) ny = y - pan.h + h;
+ else ny = cur.y;
+ }
+
+ x = nx;
+ y = ny;
+
+ if (!sd->loop_h)
+ {
+ if (x > max.x) x = max.x;
+ if (x < min.x) x = min.x;
+ }
+ if (!sd->loop_v)
+ {
+ if (y > max.y) y = max.y;
+ if (y < min.y) y = min.y;
+ }
+
+ if ((x == cur.x) && (y == cur.y)) return EINA_FALSE;
+ *_x = x;
+ *_y = y;
+ return EINA_TRUE;
+}
+
+static void
+_efl_ui_scroll_manager_content_region_set(Eo *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+
+ _scroll_manager_animators_drop(obj);
+ if (_efl_ui_scroll_manager_content_region_show_internal(obj, &x, &y, w, h))
+ {
+ efl_ui_scrollable_content_pos_set(obj, EINA_POSITION2D(x, y));
+ sd->down.sx = x;
+ sd->down.sy = y;
+ sd->down.x = sd->down.history[0].x;
+ sd->down.y = sd->down.history[0].y;
+ }
+}
+
+static void
+_efl_ui_scroll_manager_wanted_region_set(Evas_Object *obj)
+{
+ Evas_Coord ww, wh, wx;
+ Eina_Position2D max = {0, 0};
+
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+
+ wx = sd->wx;
+
+ if (_scroll_manager_animating_get(sd) || sd->down.now ||
+ sd->down.hold_animator || sd->down.onhold_animator) return;
+
+ sd->content_info.resized = EINA_FALSE;
+
+ /* Flip to RTL cords only if init in RTL mode */
+ if (sd->is_mirrored)
+ wx = _efl_ui_scroll_manager_x_mirrored_get(obj, sd->wx);
+
+ if (sd->ww == -1)
+ {
+ Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+ ww = r.w;
+ wh = r.h;
+ }
+ else
+ {
+ ww = sd->ww;
+ wh = sd->wh;
+ }
+
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ wx += (max.x - sd->prev_cw) * sd->gravity_x;
+ sd->wy += (max.y - sd->prev_ch) * sd->gravity_y;
+
+ sd->prev_cw = max.x;
+ sd->prev_ch = max.y;
+
+ _efl_ui_scroll_manager_content_region_set(obj, wx, sd->wy, ww, wh);
+}
+
+static Eina_Value
+_scroll_wheel_post_event_job(void *data, const Eina_Value v,
+ const Eina_Future *ev EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+
+ // Animations are disabled if we are here
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(sd->wx, sd->wy));
+
+ return v;
+}
+
+static inline void
+_scroll_wheel_post_event_go(Efl_Ui_Scroll_Manager_Data *sd, int x, int y)
+{
+ Eina_Position2D cur;
+ if (sd->hold || sd->freeze) return;
+ _efl_ui_scroll_manager_wanted_coordinates_update(sd, x, y);
+ if (_elm_config->scroll_animation_disable)
+ {
+ Eina_Future *f;
+
+ f = eina_future_then(efl_loop_job(efl_loop_get(sd->obj)),
+ _scroll_wheel_post_event_job, sd);
+ efl_future_Eina_FutureXXX_then(sd->obj, f);
+ }
+ else
+ {
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, x, y, 0.5, 0.5, LINEAR);
+ }
+}
+
+static Eina_Bool
+_scroll_wheel_post_event_cb(void *data, Evas *e EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Event_Mouse_Wheel *ev = sd->event_info;
+
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+ Eina_Size2D content = {0, 0};
+ Evas_Coord x = 0, y = 0, vw = 0, vh = 0;
+ Eina_Bool hold = EINA_FALSE;
+ Evas_Coord pwx, pwy;
+ double t;
+ int direction;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_TRUE);
+
+ sd->event_info = NULL;
+ direction = ev->direction;
+
+ pwx = sd->wx;
+ pwy = sd->wy;
+
+ if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
+ if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
+ direction = !direction;
+
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ x = cur.x;
+ y = cur.y;
+ if (sd->scrollto.x.animator) x = sd->scrollto.x.end;
+ if (sd->scrollto.y.animator) y = sd->scrollto.y.end;
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ if (x < min.x) x = min.x;
+ if (x > max.x) x = max.x;
+ if (y < min.y) y = min.y;
+ if (y > max.y) y = max.y;
+
+ t = ecore_loop_time_get();
+
+ _scroll_manager_animators_drop(sd->obj);
+
+ Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+ vw = r.w;
+ vh = r.h;
+
+ if (sd->pan_obj)
+ content = efl_ui_pan_content_size_get(sd->pan_obj);
+
+ int d = ev->z;
+ double delta_t = (double)(ev->timestamp - sd->last_wheel) / 1000.0;
+ double mul;
+
+ if (delta_t > 0.2) sd->last_wheel_mul = 0.0;
+ if (delta_t > 0.2) delta_t = 0.2;
+ mul = 1.0 + (_elm_config->scroll_accel_factor * ((0.2 - delta_t) / 0.2));
+ mul = mul * (1.0 + (0.15 * sd->last_wheel_mul));
+ d *= mul;
+ sd->last_wheel = ev->timestamp;
+ sd->last_wheel_mul = mul;
+
+ if (!direction)
+ {
+ if ((content.h > vh) || (content.w <= vw))
+ y += d * sd->step.y;
+ else
+ {
+ x += d * sd->step.x;
+ direction = 1;
+ }
+ }
+ else
+ {
+ if ((content.w > vw) || (content.h <= vh))
+ x += d * sd->step.x;
+ else
+ {
+ y += d * sd->step.y;
+ direction = 0;
+ }
+ }
+ _scroll_wheel_post_event_go(sd, x, y);
+
+ if (direction)
+ {
+ if ((sd->bounce_horiz) ||
+ (pwx != sd->wx) ||
+ (((t - sd->down.last_time_x_wheel) < 0.5) &&
+ (sd->down.last_hold_x_wheel)))
+ {
+ sd->down.last_hold_x_wheel = EINA_TRUE;
+ hold = EINA_TRUE;
+ }
+ else sd->down.last_hold_x_wheel = EINA_FALSE;
+ sd->down.last_time_x_wheel = t;
+ }
+ else
+ {
+ if ((sd->bounce_vert) ||
+ (pwy != sd->wy) ||
+ (((t - sd->down.last_time_y_wheel) < 0.5) &&
+ (sd->down.last_hold_y_wheel)))
+ {
+ sd->down.last_hold_y_wheel = EINA_TRUE;
+ hold = EINA_TRUE;
+ }
+ else sd->down.last_hold_y_wheel = EINA_FALSE;
+ sd->down.last_time_y_wheel = t;
+ }
+ return !hold;
+}
+
+static void
+_efl_ui_scroll_manager_wheel_event_cb(void *data,
+ Evas *e,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info)
+{
+ Efl_Ui_Scroll_Manager_Data *sd;
+ Evas_Event_Mouse_Wheel *ev;
+ int direction;
+
+ sd = data;
+ ev = event_info;
+ sd->event_info = event_info;
+ direction = ev->direction;
+
+ if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+ if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
+ (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
+ (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
+ (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
+ (evas_key_modifier_is_set(ev->modifiers, "Super")))
+ return;
+ if (direction)
+ {
+ if (sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL) return;
+ }
+ else
+ {
+ if (sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL) return;
+ }
+
+ evas_post_event_callback_push(e, _scroll_wheel_post_event_cb, sd);
+}
+
+static void
+_efl_ui_scroll_manager_scroll_to_x_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+ Evas_Coord nx = 0;
+ double t = 0.0, dt = 0.0, progx = 0.0, rx = 0.0;
+ Interpolator interp = NULL;
+ Eina_Bool no_bounce_x_end = EINA_FALSE;
+
+ t = ecore_loop_time_get();
+ dt = t - sd->scrollto.x.start_t;
+
+ if ( dt > sd->scrollto.x.dur) progx = 1.0;
+ else progx = dt / sd->scrollto.x.dur;
+
+ if (sd->scrollto.x.interp) interp = sd->scrollto.x.interp;
+ else interp = _scroll_manager_interp_get(LINEAR);
+
+ rx = interp(NULL, progx);
+ nx = sd->scrollto.x.start + (sd->scrollto.x.end - sd->scrollto.x.start) * rx;
+
+ Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
+ _efl_ui_scroll_manager_wanted_coordinates_update(sd, nx, cur.y);
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ if (!_elm_config->thumbscroll_bounce_enable || !sd->bounce_horiz)
+ {
+ if (nx < min.x) no_bounce_x_end = EINA_TRUE;
+ if (!sd->loop_h && (nx - min.x) > max.x) no_bounce_x_end = EINA_TRUE;
+ }
+ if (dt >= sd->scrollto.x.dur || no_bounce_x_end)
+ {
+ if ((!sd->scrollto.y.animator) &&
+ (!sd->bounce.y.animator))
+ _efl_ui_scroll_manager_anim_stop(sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_scroll_to_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+ Evas_Coord ny = 0;
+ double t = 0.0, dt = 0.0, progy = 0.0, ry = 0.0;
+ Interpolator interp = NULL;
+ Eina_Bool no_bounce_y_end = EINA_FALSE;
+
+ t = ecore_loop_time_get();
+ dt = t - sd->scrollto.y.start_t;
+
+ if ( dt > sd->scrollto.y.dur) progy = 1.0;
+ else progy = dt / sd->scrollto.y.dur;
+
+ if (sd->scrollto.y.interp) interp = sd->scrollto.y.interp;
+ else interp = _scroll_manager_interp_get(LINEAR);
+
+ ry = interp(NULL, progy);
+ ny = sd->scrollto.y.start + (sd->scrollto.y.end - sd->scrollto.y.start) * ry;
+
+ Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
+ _efl_ui_scroll_manager_wanted_coordinates_update(sd, cur.x, ny);
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ if (!_elm_config->thumbscroll_bounce_enable || !sd->bounce_vert)
+ {
+ if (ny < min.y) no_bounce_y_end = EINA_TRUE;
+ if (!sd->loop_v && (ny - min.y) > max.y) no_bounce_y_end = EINA_TRUE;
+ }
+ if (dt >= sd->scrollto.y.dur || no_bounce_y_end)
+ {
+ if ((!sd->scrollto.x.animator) &&
+ (!sd->bounce.x.animator))
+ _efl_ui_scroll_manager_anim_stop(sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_mouse_up_event_smooth(Efl_Ui_Scroll_Manager_Data *sd, double t, Evas_Coord *ox, Evas_Coord *oy, double *ot)
+{
+ static const unsigned int HISTORY_MAX = 60;
+ unsigned int i = 0;
+ double dt = 0, at = 0;
+ Evas_Coord ax = 0, ay = 0;
+
+ for (i = 0; i < HISTORY_MAX; i++)
+ {
+ dt = t - sd->down.history[i].timestamp;
+ if (dt > 0.2) break;
+#ifdef SCROLLDBG
+ DBG("H: %i %i @ %1.3f\n",
+ sd->down.history[i].x,
+ sd->down.history[i].y, dt);
+#endif
+ ax = sd->down.history[i].x;
+ ay = sd->down.history[i].y;
+ at = sd->down.history[i].timestamp;
+ }
+ if (ox) *ox = ax;
+ if (oy) *oy = ay;
+ if (ot) *ot = t - at;
+
+ return;
+ if (ox) *ox = (Evas_Coord)(ax / (i + 1));
+ if (oy) *oy = (Evas_Coord)(ay / (i + 1));
+ if (ot) *ot = (double)(at / (i + 1));
+}
+
+static void
+_efl_ui_scroll_manager_mouse_up_event_momentum_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Up *ev)
+{
+ double t, at;
+ Evas_Coord dx, dy, ax, ay, vel;
+ char sdx, sdy;
+
+#ifdef EVTIME
+ t = ev->timestamp / 1000.0;
+#else
+ t = ecore_loop_time_get();
+#endif
+
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+ ax = ev->canvas.x;
+ ay = ev->canvas.y;
+ at = 0.0;
+#ifdef SCROLLDBG
+ DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
+#endif
+ _efl_ui_scroll_manager_mouse_up_event_smooth(sd, t, &ax, &ay, &at);
+ dx = ev->canvas.x - ax;
+ dy = ev->canvas.y - ay;
+
+ sdx = (dx > 0) - (dx < 0);
+ sdy = (dy > 0) - (dy < 0);
+
+ dx = abs(dx);
+ dy = abs(dy);
+ if (at > 0)
+ {
+ vel = (Evas_Coord)(sqrt((dx * dx) + (dy * dy)) / at);
+ if ((_elm_config->thumbscroll_friction > 0.0) &&
+ (vel > _elm_config->thumbscroll_momentum_threshold))
+ {
+ _scroll_manager_momentum_animator_add(sd, -sdx*dx/at, -sdy*dy/at);
+ }
+ else if (!sd->bouncemex && !sd->bouncemey)
+ {
+ _efl_ui_scroll_manager_scroll_stop(sd);
+ }
+ }
+}
+
+static void
+_efl_ui_scroll_manager_mouse_up_event_cb(void *data,
+ Evas *e,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Event_Mouse_Up *ev;
+
+ if (!sd->pan_obj) return;
+ if (!_scroll_manager_thumb_scrollable_get(sd)) return;
+
+ ev = event_info;
+
+ if (ev->button == 1)
+ {
+ _scroll_manager_on_hold_animator_del(sd);
+
+ if (sd->down.dragged)
+ {
+ _efl_ui_scroll_manager_drag_stop(sd);
+ if ((!sd->hold) && (!sd->freeze))
+ {
+ _efl_ui_scroll_manager_mouse_up_event_momentum_eval(sd, ev);
+ }
+ evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
+ }
+
+ _scroll_manager_hold_animator_del(sd);
+
+ if (sd->down.scroll)
+ {
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
+ sd->down.scroll = EINA_FALSE;
+ }
+ if (sd->down.hold)
+ {
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+ sd->down.hold = EINA_FALSE;
+ }
+
+ sd->down.dragged_began = EINA_FALSE;
+ sd->down.dir_x = EINA_FALSE;
+ sd->down.dir_y = EINA_FALSE;
+ sd->down.dragged = EINA_FALSE;
+ sd->down.now = EINA_FALSE;
+
+ Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, cur);
+ _efl_ui_scroll_manager_wanted_coordinates_update(sd, cur.x, cur.y);
+
+ if (sd->content_info.resized)
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_mouse_down_event_cb(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info)
+{
+ Efl_Ui_Scroll_Manager_Data *sd;
+ Evas_Event_Mouse_Down *ev;
+ Eina_Position2D cur = {0, 0};
+
+ sd = data;
+ ev = event_info;
+
+ if (!_scroll_manager_thumb_scrollable_get(sd)) return;
+
+ sd->down.hold = EINA_FALSE;
+ if (_scroll_manager_animating_get(sd))
+ {
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
+ EVAS_EVENT_FLAG_ON_HOLD;
+ sd->down.scroll = EINA_TRUE;
+ sd->down.hold = EINA_TRUE;
+
+ _scroll_manager_animators_drop(sd->obj);
+ }
+
+ if (ev->button == 1)
+ {
+ sd->down.hist.est_timestamp_diff =
+ ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
+ sd->down.hist.tadd = 0.0;
+ sd->down.hist.dxsum = 0.0;
+ sd->down.hist.dysum = 0.0;
+ sd->down.now = EINA_TRUE;
+ sd->down.dragged = EINA_FALSE;
+ sd->down.dir_x = EINA_FALSE;
+ sd->down.dir_y = EINA_FALSE;
+ sd->down.x = ev->canvas.x;
+ sd->down.y = ev->canvas.y;
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ sd->down.sx = cur.x;
+ sd->down.sy = cur.y;
+ memset(&(sd->down.history[0]), 0,
+ sizeof(sd->down.history[0]) * 60);
+#ifdef EVTIME
+ sd->down.history[0].timestamp = ev->timestamp / 1000.0;
+ sd->down.history[0].localtimestamp = ecore_loop_time_get();
+#else
+ sd->down.history[0].timestamp = ecore_loop_time_get();
+#endif
+ sd->down.dragged_began_timestamp = sd->down.history[0].timestamp;
+ sd->down.history[0].x = ev->canvas.x;
+ sd->down.history[0].y = ev->canvas.y;
+ }
+ sd->down.dragged_began = EINA_FALSE;
+ if (sd->hold || sd->freeze)
+ sd->down.want_reset = EINA_TRUE;
+ else
+ sd->down.want_reset = EINA_FALSE;
+}
+
+static Eina_Bool
+_efl_ui_scroll_manager_can_scroll(Efl_Ui_Scroll_Manager_Data *sd,
+ int dir)
+{
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+
+ if (!sd->pan_obj) return EINA_FALSE;
+
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ switch (dir)
+ {
+ case LEFT:
+ if (cur.x > min.x) return EINA_TRUE;
+ break;
+
+ case RIGHT:
+ if ((cur.x - min.x) < max.x) return EINA_TRUE;
+ break;
+
+ case UP:
+ if (cur.y > min.y) return EINA_TRUE;
+ break;
+
+ case DOWN:
+ if ((cur.y - min.y) < max.y) return EINA_TRUE;
+ break;
+
+ default:
+ break;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_efl_ui_scroll_manager_bounce_weight_apply(Efl_Ui_Scroll_Manager_Data *sd,
+ Evas_Coord *x,
+ Evas_Coord *y)
+{
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ if (!sd->loop_h && *x < min.x)
+ *x += (min.x - *x) * _elm_config->thumbscroll_border_friction;
+ else if (!sd->loop_h && max.x <= 0)
+ *x += (sd->down.sx - *x) * _elm_config->thumbscroll_border_friction;
+ else if (!sd->loop_h && (max.x + min.x) < *x)
+ *x += (max.x + min.x - *x) *
+ _elm_config->thumbscroll_border_friction;
+
+ if (!sd->loop_v && *y < min.y)
+ *y += (min.y - *y) * _elm_config->thumbscroll_border_friction;
+ else if (!sd->loop_v && max.y <= 0)
+ *y += (sd->down.sy - *y) * _elm_config->thumbscroll_border_friction;
+ else if (!sd->loop_v && (max.y + min.y) < *y)
+ *y += (max.y + min.y - *y) *
+ _elm_config->thumbscroll_border_friction;
+}
+
+static inline double
+_scroll_manager_animation_duration_get(Evas_Coord dx, Evas_Coord dy)
+{
+ double dist = 0.0, vel = 0.0, dur = 0.0;
+ dist = sqrt(dx * dx + dy *dy);
+ vel = _elm_config->thumbscroll_friction_standard / _elm_config->thumbscroll_friction;
+ dur = dist / vel;
+ dur = (dur > _elm_config->thumbscroll_friction) ? _elm_config->thumbscroll_friction : dur;
+ return dur;
+}
+
+static Eina_Bool
+_scroll_manager_on_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->down.onhold_animator)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
+ if (sd->content_info.resized)
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_scroll_manager_on_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
+{
+ sd->down.onhold_vx = vx;
+ sd->down.onhold_vy = vy;
+ if (!sd->down.onhold_animator)
+ {
+ sd->down.onhold_vxe = 0.0;
+ sd->down.onhold_vye = 0.0;
+ sd->down.onhold_tlast = 0.0;
+
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
+ }
+}
+
+static void
+_scroll_manager_hold_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y)
+{
+ sd->down.hold_x = x;
+ sd->down.hold_y = y;
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
+}
+
+static Eina_Bool
+_scroll_manager_hold_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->down.hold_animator || sd->down.hold_enterer)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
+ ELM_SAFE_FREE(sd->down.hold_enterer, ecore_idle_enterer_del);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void _scroll_manager_momentum_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx, double vy)
+{
+ static const double friction = 5000;
+ static const double inverse_mass = 1;
+ static const double accel = friction * inverse_mass;
+ double dur = 0.0, vel = 0.0;
+ char sdx = 0, sdy = 0;
+ Evas_Coord dstx = 0, dsty = 0;
+
+/*
+ if (_scroll_manager_scrollto_animator_del(sd))
+ {
+ restore current veolocity
+ add to vx/vy
+ }
+*/
+ Eina_Position2D cur = efl_ui_pan_position_get(sd->pan_obj);
+
+ sdx = (vx > 0) - (vx < 0);
+ sdy = (vy > 0) - (vy < 0);
+
+ dstx = cur.x + sdx * (vx * vx) / (2 * accel);
+ dsty = cur.y + sdy * (vy * vy) / (2 * accel);
+
+ vel = sqrt(vx*vx + vy*vy);
+ dur = vel / accel;
+
+ _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, dstx, dsty, dur, dur, DECEL);
+}
+
+static void
+_efl_ui_scroll_manager_bounce_y_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Coord ny = 0;
+ Eina_Position2D cur = {0, 0};
+ double t = 0.0, dt = 0.0, r = 0.0;
+
+ t = ecore_loop_time_get();
+ if (sd->bounce.y.start_t + sd->bounce.y.t01 >= t)
+ {
+ dt = sd->bounce.y.start_t + sd->bounce.y.t01 - t;
+ r = 1.0 - (dt / sd->bounce.y.t01);
+ r = _scroll_manager_decel_interp(NULL, r);
+ ny = sd->bounce.y.p0 + (sd->bounce.y.p1 - sd->bounce.y.p0) * r;
+
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
+ }
+ else if (sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 >= t)
+ {
+ dt = sd->bounce.y.start_t + sd->bounce.y.t01 + sd->bounce.y.t12 - t;
+ r = 1.0 - (dt / sd->bounce.y.t12);
+ r = _scroll_manager_decel_interp(NULL, r);
+ ny = sd->bounce.y.p1 + (sd->bounce.y.p2 - sd->bounce.y.p1) * r;
+
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, ny));
+ }
+ else
+ {
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(cur.x, sd->bounce.y.p2));
+ if ((!sd->scrollto.x.animator) &&
+ (!sd->bounce.x.animator))
+ _efl_ui_scroll_manager_anim_stop(sd);
+ _scroll_manager_bounce_y_animator_del(sd);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_bounce_x_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Coord nx;
+ Eina_Position2D cur = {0, 0};
+ double t = 0.0, dt = 0.0, r = 0.0;
+
+ t = ecore_loop_time_get();
+
+ if (sd->bounce.x.start_t + sd->bounce.x.t01 >= t)
+ {
+ dt = sd->bounce.x.start_t + sd->bounce.x.t01 - t;
+ r = 1.0 - (dt / sd->bounce.x.t01);
+ r = _scroll_manager_decel_interp(NULL, r);
+ nx = sd->bounce.x.p0 + (sd->bounce.x.p1 - sd->bounce.x.p0) * r;
+
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
+ }
+ else if (sd->bounce.x.start_t + sd->bounce.x.t01 + sd->bounce.x.t12 >= t)
+ {
+ dt = sd->bounce.x.start_t + sd->bounce.x.t01 + sd->bounce.x.t12 - t;
+ r = 1.0 - (dt / sd->bounce.x.t12);
+ r = _scroll_manager_decel_interp(NULL, r);
+ nx = sd->bounce.x.p1 + (sd->bounce.x.p2 - sd->bounce.x.p1) * r;
+
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(nx, cur.y));
+ }
+ else
+ {
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(sd->bounce.x.p2, cur.y));
+ if ((!sd->scrollto.y.animator) &&
+ (!sd->bounce.y.animator))
+ _efl_ui_scroll_manager_anim_stop(sd);
+ _scroll_manager_bounce_x_animator_del(sd);
+ }
+}
+
+static void _scroll_manager_bounce_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vx)
+{
+ static const double spring_k = 1000;
+ static const double mass = 1;
+ char sign = (vx > 0) - (vx < 0);
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+
+ _scroll_manager_bounce_x_animator_del(sd);
+
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ double max_x = sqrt((mass * vx * vx) / spring_k);
+ sd->bounce.x.start_t = ecore_loop_time_get();
+ sd->bounce.x.vel = vx;
+ sd->bounce.x.p0 = cur.x;
+ if (fabs(vx) > 0.0)
+ sd->bounce.x.t01 = 0.2;
+ else
+ sd->bounce.x.t01 = 0.0;
+ sd->bounce.x.p1 = cur.x + sign * max_x;;
+ sd->bounce.x.t12 = 0.2;
+ if ( cur.x < min.x )
+ {
+ sd->bounce.x.p2 = min.x;
+ }
+ else if ( cur.x > max.x)
+ {
+ sd->bounce.x.p2 = max.x;
+ }
+
+ if ((!sd->bounce.y.animator) &&
+ (!sd->scrollto.y.animator))
+ _efl_ui_scroll_manager_anim_start(sd);
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->bounce.x.animator, _efl_ui_scroll_manager_bounce_x_animator, sd);
+}
+
+static Eina_Bool _scroll_manager_bounce_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->bounce.x.animator)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.x.animator, _efl_ui_scroll_manager_bounce_x_animator, sd);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void _scroll_manager_bounce_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, double vy)
+{
+ static const double spring_k = 1000;
+ static const double mass = 1;
+ char sign = (vy > 0) - (vy < 0);
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+
+ _scroll_manager_bounce_y_animator_del(sd);
+
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+
+ double max_y = sqrt((mass * vy * vy) / spring_k);
+ sd->bounce.y.start_t = ecore_loop_time_get();
+ sd->bounce.y.vel = vy;
+ sd->bounce.y.p0 = cur.y;
+ if (fabs(vy) > 0.0)
+ sd->bounce.y.t01 = 0.2;
+ else
+ sd->bounce.y.t01 = 0.0;
+
+ sd->bounce.y.p1 = cur.y + sign * max_y;
+ sd->bounce.y.t12 = 0.2;
+ if ( cur.y < min.y )
+ {
+ sd->bounce.y.p2 = min.y;
+ }
+ else if ( cur.y > max.y)
+ {
+ sd->bounce.y.p2 = max.y;
+ }
+
+ if ((!sd->bounce.x.animator) &&
+ (!sd->scrollto.x.animator))
+ _efl_ui_scroll_manager_anim_start(sd);
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->bounce.y.animator, _efl_ui_scroll_manager_bounce_y_animator, sd);
+}
+
+static Eina_Bool _scroll_manager_bounce_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->bounce.y.animator)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.y.animator, _efl_ui_scroll_manager_bounce_y_animator, sd);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_scroll_manager_scrollto_x_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord sx, Evas_Coord ex, double t, InterpType interp)
+{
+ sd->scrollto.x.start_t = ecore_loop_time_get();
+ sd->scrollto.x.dur = t;
+
+ sd->scrollto.x.start = sx;
+ sd->scrollto.x.end = ex;
+
+ sd->scrollto.x.interp = _scroll_manager_interp_get(interp);
+ if (!sd->scrollto.x.animator)
+ {
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
+ if (!sd->scrollto.y.animator) _efl_ui_scroll_manager_anim_start(sd);
+ }
+}
+
+static Eina_Bool
+_scroll_manager_scrollto_x_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->scrollto.x.animator)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_scroll_manager_scrollto_y_animator_add(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord sy, Evas_Coord ey, double t, InterpType interp)
+{
+ sd->scrollto.y.start_t = ecore_loop_time_get();
+ sd->scrollto.y.dur = t;
+
+ sd->scrollto.y.start = sy;
+ sd->scrollto.y.end = ey;
+
+ sd->scrollto.y.interp = _scroll_manager_interp_get(interp);
+ if (!sd->scrollto.y.animator)
+ {
+ ELM_ANIMATOR_CONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
+ if (!sd->scrollto.x.animator) _efl_ui_scroll_manager_anim_start(sd);
+ }
+}
+
+static Eina_Bool
+_scroll_manager_scrollto_y_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->scrollto.y.animator)
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_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)
+{
+ _scroll_manager_scrollto_animator_del(sd);
+
+ if (!sd->pan_obj) return;
+ if (sd->freeze) return;
+ _scroll_manager_scrollto_x_animator_add(sd, sx, x, tx, interp);
+ _scroll_manager_scrollto_y_animator_add(sd, sy, y, ty, interp);
+}
+
+static Eina_Bool
+_scroll_manager_scrollto_animator_del(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if ((sd->scrollto.x.animator) || (sd->scrollto.y.animator))
+ {
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_scroll_manager_scrollto(Efl_Ui_Scroll_Manager_Data *sd, Evas_Coord x, Evas_Coord y)
+{
+ double dur = 0.0;
+ Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ dur = _scroll_manager_animation_duration_get(x - cur.x, y - cur.y);
+ _scroll_manager_scrollto_animator_add(sd, cur.x, cur.y, x, y, dur, dur, LINEAR);
+}
+
+static void
+_efl_ui_scroll_manager_post_event_move_on_hold_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev)
+{
+ Evas_Coord x = 0, y = 0;
+ double vx = 0.0, vy = 0.0;
+ char sx = 0, sy = 0;
+
+ Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+
+ x = (r.x - ev->cur.canvas.x) > 0 ? (r.x - ev->cur.canvas.x) : 0;
+ y = (r.y - ev->cur.canvas.y) > 0 ? (r.y - ev->cur.canvas.y) : 0;
+ x = (ev->cur.canvas.x - (r.x + r.w)) > 0 ? (ev->cur.canvas.x - (r.x + r.w)) : x;
+ y = (ev->cur.canvas.y - (r.y + r.h)) > 0 ? (ev->cur.canvas.y - (r.y + r.h)) : y;
+ sx = r.x - ev->cur.canvas.x > 0 ? -1 : 1;
+ sy = r.y - ev->cur.canvas.y > 0 ? -1 : 1;
+
+ if (x > _elm_config->thumbscroll_hold_threshold)
+ {
+ vx = 1.0;
+ if (_elm_config->thumbscroll_hold_threshold > 0.0)
+ vx = (double)(x - _elm_config->thumbscroll_hold_threshold) /
+ _elm_config->thumbscroll_hold_threshold;
+ }
+
+ if (y > _elm_config->thumbscroll_hold_threshold)
+ {
+ vy = 1.0;
+ if (_elm_config->thumbscroll_hold_threshold > 0.0)
+ vy = (double)(y - _elm_config->thumbscroll_hold_threshold) /
+ _elm_config->thumbscroll_hold_threshold;
+ }
+
+ if ((vx != 0.0) || (vy != 0.0)) _scroll_manager_on_hold_animator_add(sd, vx*sx, vy*sy);
+ else _scroll_manager_on_hold_animator_del(sd);
+}
+
+
+static Eina_Bool
+_efl_ui_scroll_manager_post_event_move_direction_restrict_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev EINA_UNUSED,
+ Evas_Coord dx, Evas_Coord dy)
+{
+ if (sd->down.dragged) return EINA_FALSE;
+
+ sd->down.hdir = -1;
+ sd->down.vdir = -1;
+
+ if (dx > 0) sd->down.hdir = LEFT;
+ else if (dx < 0)
+ sd->down.hdir = RIGHT;
+ if (dy > 0) sd->down.vdir = UP;
+ else if (dy < 0)
+ sd->down.vdir = DOWN;
+
+ if (!(sd->block & EFL_UI_SCROLL_BLOCK_HORIZONTAL))
+ sd->down.dir_x = EINA_TRUE;
+
+ if (!(sd->block & EFL_UI_SCROLL_BLOCK_VERTICAL))
+ sd->down.dir_y = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_efl_ui_scroll_manager_post_event_move_hold_eval(Efl_Ui_Scroll_Manager_Data *sd, Evas_Event_Mouse_Move *ev,
+ Evas_Coord dx, Evas_Coord dy)
+{
+ if (!sd->down.dragged)
+ {
+ if(((dx * dx) + (dy * dy)) >
+ (_elm_config->thumbscroll_threshold * _elm_config->thumbscroll_threshold))
+ {
+ if (_elm_config->scroll_smooth_start_enable)
+ {
+ sd->down.x = ev->cur.canvas.x;
+ sd->down.y = ev->cur.canvas.y;
+#ifdef EVTIME
+ sd->down.dragged_began_timestamp = ev->timestamp / 1000.0;
+#else
+ sd->down.dragged_began_timestamp = ecore_loop_time_get();
+#endif
+ }
+ // TODO 다른조건들도 can_scroll 안쪽으로 넣는다?
+ if ((((_efl_ui_scroll_manager_can_scroll(sd, sd->down.hdir) || sd->bounce_horiz) && sd->down.dir_x) ||
+ ((_efl_ui_scroll_manager_can_scroll(sd, sd->down.vdir) || sd->bounce_vert) && sd->down.dir_y)))
+ {
+ _efl_ui_scroll_manager_drag_start(sd);
+ sd->down.dragged = EINA_TRUE;
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+ }
+ else if (!sd->down.dragged)
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+ }
+
+ if (sd->down.want_reset)
+ {
+ sd->down.x = ev->cur.canvas.x;
+ sd->down.y = ev->cur.canvas.y;
+ sd->down.want_reset = EINA_FALSE;
+ }
+
+ if (sd->down.dir_x) dx = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
+ else dx = sd->down.sx;
+ if (sd->down.dir_y) dy = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
+ else dy = sd->down.sy;
+
+ _efl_ui_scroll_manager_bounce_weight_apply(sd, &dx, &dy);
+ _scroll_manager_hold_animator_add(sd, dx, dy);
+
+ return EINA_TRUE;
+}
+
+
+static Eina_Bool
+_efl_ui_scroll_manager_post_event_move(void *data,
+ Evas *e EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Event_Mouse_Move *ev = sd->event_info;
+ sd->event_info = NULL;
+ Evas_Coord dx, dy;
+
+ dx = ev->cur.canvas.x - sd->down.x;
+ dy = ev->cur.canvas.y - sd->down.y;
+
+ _efl_ui_scroll_manager_post_event_move_direction_restrict_eval(sd, ev, dx, dy);
+
+ if (!sd->freeze)
+ {
+ if (!sd->hold)
+ {
+ if (!_efl_ui_scroll_manager_post_event_move_hold_eval(sd, ev, dx, dy))
+ return EINA_TRUE;
+ }
+ else
+ {
+ _efl_ui_scroll_manager_post_event_move_on_hold_eval(sd, ev);
+ }
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_efl_ui_scroll_manager_down_coord_eval(Efl_Ui_Scroll_Manager_Data *sd,
+ Evas_Coord *x,
+ Evas_Coord *y)
+{
+ if (!sd->pan_obj) return;
+
+ if (sd->down.dir_x) *x = sd->down.sx - (*x - sd->down.x);
+ else *x = sd->down.sx;
+ if (sd->down.dir_y) *y = sd->down.sy - (*y - sd->down.y);
+ else *y = sd->down.sy;
+
+ _efl_ui_scroll_manager_bounce_weight_apply(sd, x, y);
+}
+
+static Eina_Bool
+_efl_ui_scroll_manager_hold_enterer(void *data)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Coord fx = 0, fy = 0;
+
+ sd->down.hold_enterer = NULL;
+ fx = sd->down.hold_x;
+ fy = sd->down.hold_y;
+
+ if ((_elm_config->scroll_smooth_amount > 0.0) &&
+ (_elm_config->scroll_smooth_time_window > 0.0))
+ {
+ int i, count = 0;
+ Evas_Coord basex = 0, basey = 0, x, y;
+ double dt, tdiff, tnow, twin, ttot;
+ double xx, yy, tot;
+ struct
+ {
+ Evas_Coord x, y;
+ double t;
+ } pos[100];
+
+ tdiff = sd->down.hist.est_timestamp_diff;
+ tnow = ecore_loop_time_get();
+ twin = _elm_config->scroll_smooth_time_window;
+ for (i = 0; i < 60; i++)
+ {
+ if ((sd->down.history[i].timestamp - tdiff) > tnow)
+ continue;
+ if ((sd->down.history[i].timestamp >
+ sd->down.dragged_began_timestamp) || (count == 0))
+ {
+ x = sd->down.history[i].x;
+ y = sd->down.history[i].y;
+ _efl_ui_scroll_manager_down_coord_eval(sd, &x, &y);
+ if (count == 0)
+ {
+ basex = x;
+ basey = y;
+ }
+ dt = (tnow + tdiff) - sd->down.history[i].timestamp;
+ if ((dt > twin) && (count > 0)) break;
+ if ((dt > 0.0) && (count == 0))
+ {
+ pos[count].x = x - basex;
+ pos[count].y = y - basey;
+ pos[count].t = 0.0;
+ count++;
+ }
+ pos[count].x = x - basex;
+ pos[count].y = y - basey;
+ pos[count].t = dt;
+ count++;
+ }
+ }
+ if (count > 0)
+ {
+ xx = 0.0;
+ yy = 0.0;
+ tot = 0.0;
+ ttot = pos[count - 1].t;
+ for (i = 0; i < count; i++)
+ {
+ double wt;
+
+ if (ttot > 0.0)
+ {
+ if (i < (count - 1))
+ wt = (ttot - pos[i].t) * (pos[i + 1].t - pos[i].t);
+ else
+ wt = 0.0;
+ }
+ else wt = 1.0;
+
+ xx += ((double)(pos[i].x)) * wt;
+ yy += ((double)(pos[i].y)) * wt;
+ tot += wt;
+ }
+ if (tot > 0.0)
+ {
+ xx = basex + (xx / tot);
+ yy = basey + (yy / tot);
+ fx =
+ (_elm_config->scroll_smooth_amount * xx) +
+ ((1.0 - _elm_config->scroll_smooth_amount) * fx);
+ fy =
+ (_elm_config->scroll_smooth_amount * yy) +
+ ((1.0 - _elm_config->scroll_smooth_amount) * fy);
+ }
+ }
+ }
+
+ Eina_Position2D cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ if (sd->down.dir_x)
+ cur.x = fx;
+ if (sd->down.dir_y)
+ cur.y = fy;
+
+ efl_ui_scrollable_content_pos_set(sd->obj, cur);
+
+ return EINA_FALSE;
+}
+
+static void
+_efl_ui_scroll_manager_hold_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+
+ ecore_idle_enterer_del(sd->down.hold_enterer);
+ sd->down.hold_enterer =
+ ecore_idle_enterer_before_add(_efl_ui_scroll_manager_hold_enterer, sd);
+}
+
+static void
+_efl_ui_scroll_manager_on_hold_animator(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ double t, td;
+ double vx, vy;
+ Evas_Coord x, y;
+ Eina_Position2D cur = {0, 0};
+ Efl_Ui_Scroll_Manager_Data *sd;
+
+ sd = data;
+ t = ecore_loop_time_get();
+ if (sd->down.onhold_tlast > 0.0)
+ {
+ td = t - sd->down.onhold_tlast;
+ vx = sd->down.onhold_vx * td *
+ (double)_elm_config->thumbscroll_hold_threshold * 2.0;
+ vy = sd->down.onhold_vy * td *
+ (double)_elm_config->thumbscroll_hold_threshold * 2.0;
+ cur = efl_ui_scrollable_content_pos_get(sd->obj);
+ x = cur.x;
+ y = cur.y;
+
+ if (sd->down.dir_x)
+ {
+ sd->down.onhold_vxe += vx;
+ x = cur.x + (int)sd->down.onhold_vxe;
+ sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
+ }
+
+ if (sd->down.dir_y)
+ {
+ sd->down.onhold_vye += vy;
+ y = cur.y + (int)sd->down.onhold_vye;
+ sd->down.onhold_vye -= (int)sd->down.onhold_vye;
+ }
+
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(x, y));
+ }
+ sd->down.onhold_tlast = t;
+}
+
+static void
+_efl_ui_scroll_manager_mouse_move_event_cb(void *data,
+ Evas *e,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Evas_Event_Mouse_Move *ev;
+ Eina_Position2D cur = {0, 0};
+
+ if (!sd->pan_obj) return;
+ if (!_scroll_manager_thumb_scrollable_get(sd)) return;
+ if (!sd->down.now) return;
+
+ ev = event_info;
+
+ if ((!sd->hold) && (!sd->freeze))
+ {
+ if (_scroll_manager_animating_get(sd))
+ {
+ _scroll_manager_animators_drop(sd->obj);
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+ sd->down.sx = cur.x;
+ sd->down.sy = cur.y;
+ sd->down.x = sd->down.history[0].x;
+ sd->down.y = sd->down.history[0].y;
+ }
+ }
+
+#ifdef SCROLLDBG
+ DBG("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
+#endif
+ memmove(&(sd->down.history[1]), &(sd->down.history[0]),
+ sizeof(sd->down.history[0]) * (60 - 1));
+#ifdef EVTIME
+ sd->down.history[0].timestamp = ev->timestamp / 1000.0;
+ sd->down.history[0].localtimestamp = ecore_loop_time_get();
+#else
+ sd->down.history[0].timestamp = ecore_loop_time_get();
+#endif
+ sd->down.history[0].x = ev->cur.canvas.x;
+ sd->down.history[0].y = ev->cur.canvas.y;
+ sd->event_info = event_info;
+
+ if (!ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
+ evas_post_event_callback_push(e, _efl_ui_scroll_manager_post_event_move, sd);
+
+ if (sd->down.dragged)
+ ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+}
+
+static void
+_scroll_event_object_attach(Evas_Object *obj)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+
+ evas_object_event_callback_add
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _efl_ui_scroll_manager_wheel_event_cb,
+ sd);
+ evas_object_event_callback_add
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
+ _efl_ui_scroll_manager_mouse_down_event_cb, sd);
+ evas_object_event_callback_add
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_UP,
+ _efl_ui_scroll_manager_mouse_up_event_cb, sd);
+ evas_object_event_callback_add
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
+ _efl_ui_scroll_manager_mouse_move_event_cb, sd);
+}
+
+static void
+_scroll_event_object_detach(Evas_Object *obj)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+
+ evas_object_event_callback_del_full
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _efl_ui_scroll_manager_wheel_event_cb,
+ sd);
+ evas_object_event_callback_del_full
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
+ _efl_ui_scroll_manager_mouse_down_event_cb, sd);
+ evas_object_event_callback_del_full
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_UP,
+ _efl_ui_scroll_manager_mouse_up_event_cb, sd);
+ evas_object_event_callback_del_full
+ (sd->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
+ _efl_ui_scroll_manager_mouse_move_event_cb, sd);
+}
+
+static void
+_efl_ui_scroll_manager_pan_content_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+ Eina_Size2D content = {0, 0};
+
+ if (!sd->pan_obj) return;
+
+ content = efl_ui_pan_content_size_get(sd->pan_obj);
+ if ((content.w != sd->content_info.w) || (content.h != sd->content_info.h))
+ {
+ sd->content_info.w = content.w;
+ sd->content_info.h = content.h;
+
+ sd->content_info.resized = EINA_TRUE;
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED, NULL);
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED, NULL);
+ efl_ui_scrollbar_bar_visibility_update(sd->obj);
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_pan_viewport_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+
+ if (!sd->pan_obj) return;
+
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED, NULL);
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED, NULL);
+ efl_ui_scrollbar_bar_visibility_update(sd->obj);
+ _efl_ui_scroll_manager_wanted_region_set(sd->obj);
+}
+
+static void
+_efl_ui_scroll_manager_pan_position_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Efl_Ui_Scroll_Manager_Data *sd = data;
+
+ if (!sd->pan_obj) return;
+
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED, NULL);
+ efl_ui_scrollbar_bar_visibility_update(sd->obj);
+}
+
+static void
+_efl_ui_scroll_manager_pan_resized_cb(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Eo *manager = data;
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(manager, sd);
+
+ efl_gfx_size_set(sd->event_rect, efl_gfx_size_get(obj));
+}
+
+static void
+_efl_ui_scroll_manager_pan_moved_cb(void *data,
+ Evas *e EINA_UNUSED,
+ Evas_Object *obj EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Eo *manager = data;
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(manager, sd);
+
+ efl_gfx_position_set(sd->event_rect, efl_gfx_position_get(obj));
+}
+
+static void
+_efl_ui_scroll_manager_scrollbar_h_visibility_apply(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->hbar_visible)
+ {
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW, &type);
+ }
+ else
+ {
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE, &type);
+ }
+}
+
+static void
+_efl_ui_scroll_manager_scrollbar_v_visibility_apply(Efl_Ui_Scroll_Manager_Data *sd)
+{
+ if (sd->vbar_visible)
+ {
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW, &type);
+ }
+ else
+ {
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(sd->parent, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE, &type);
+ }
+}
+
+static void
+_efl_ui_scrollbar_h_visibility_adjust(Eo *obj)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+ int scroll_h_vis_change = 0;
+ Evas_Coord w;
+
+ w = sd->content_info.w;
+ Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+
+ switch (sd->hbar_mode)
+ {
+ case EFL_UI_SCROLLBAR_MODE_AUTO:
+ if (sd->hbar_visible)
+ {
+ if (w <= view.w)
+ {
+ scroll_h_vis_change = 1;
+ sd->hbar_visible = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (w > view.w)
+ {
+ scroll_h_vis_change = 1;
+ sd->hbar_visible = EINA_TRUE;
+ }
+ }
+ break;
+ case EFL_UI_SCROLLBAR_MODE_ON:
+ if (!sd->hbar_visible)
+ {
+ scroll_h_vis_change = 1;
+ sd->hbar_visible = EINA_TRUE;
+ }
+ break;
+ case EFL_UI_SCROLLBAR_MODE_OFF:
+ if (sd->hbar_visible)
+ {
+ scroll_h_vis_change = 1;
+ sd->hbar_visible = EINA_FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (scroll_h_vis_change) _efl_ui_scroll_manager_scrollbar_h_visibility_apply(sd);
+}
+
+static void
+_efl_ui_scrollbar_v_visibility_adjust(Eo *obj)
+{
+ EFL_UI_SCROLL_MANAGER_DATA_GET_OR_RETURN(obj, sd);
+ int scroll_v_vis_change = 0;
+ Evas_Coord h;
+
+ h = sd->content_info.h;
+ Eina_Rect view = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+
+ switch (sd->vbar_mode)
+ {
+ case EFL_UI_SCROLLBAR_MODE_AUTO:
+ if (sd->vbar_visible)
+ {
+ if (h <= view.h)
+ {
+ scroll_v_vis_change = 1;
+ sd->vbar_visible = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (h > view.h)
+ {
+ scroll_v_vis_change = 1;
+ sd->vbar_visible = EINA_TRUE;
+ }
+ }
+ break;
+ case EFL_UI_SCROLLBAR_MODE_ON:
+ if (!sd->vbar_visible)
+ {
+ scroll_v_vis_change = 1;
+ sd->vbar_visible = EINA_TRUE;
+ }
+ break;
+ case EFL_UI_SCROLLBAR_MODE_OFF:
+ if (sd->vbar_visible)
+ {
+ scroll_v_vis_change = 1;
+ sd->vbar_visible = EINA_FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ if (scroll_v_vis_change) _efl_ui_scroll_manager_scrollbar_v_visibility_apply(sd);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_visibility_update(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd EINA_UNUSED)
+{
+ _efl_ui_scrollbar_h_visibility_adjust(obj);
+ _efl_ui_scrollbar_v_visibility_adjust(obj);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_position_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, double posx, double posy)
+{
+ Evas_Coord x, y;
+ Eina_Position2D min = {0, 0}, max = {0, 0};
+
+ if (sd->down.dragged || _scroll_manager_animating_get(sd)) return;
+
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ x = _round(posx * (double)max.x + min.x, 1);
+ y = _round(posy * (double)max.y + min.y, 1);
+ efl_ui_scrollable_content_pos_set(sd->obj, EINA_POSITION2D(x, y));
+ _efl_ui_scroll_manager_wanted_coordinates_update(sd, x, y);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_position_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, double *posx, double *posy)
+{
+ if (!sd->pan_obj) return;
+
+ double vx = 0, vy = 0;
+ Eina_Position2D min = {0, 0}, max = {0, 0}, cur = {0, 0};
+
+ min = efl_ui_pan_position_min_get(sd->pan_obj);
+ max = efl_ui_pan_position_max_get(sd->pan_obj);
+ cur = efl_ui_pan_position_get(sd->pan_obj);
+
+ if (max.x > 0) vx = (double)(cur.x - min.x) / (double)max.x;
+ else vx = 0.0;
+
+ if (vx < 0.0) vx = 0.0;
+ else if (vx > 1.0)
+ vx = 1.0;
+
+ if (posx) *posx = vx;
+
+ if (max.y > 0) vy = (double)(cur.y - min.y) / (double)max.y;
+ else vy = 0.0;
+
+ if (vy < 0.0) vy = 0.0;
+ else if (vy > 1.0)
+ vy = 1.0;
+
+ if (posy) *posy = vy;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollbar_bar_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, double *width, double *height)
+{
+ if (!sd->pan_obj) return;
+
+ Evas_Coord w = 0, h = 0, vw = 0, vh = 0;
+ double size = 0.0;
+
+ Eina_Rect r = efl_ui_scrollable_viewport_geometry_get(sd->obj);
+ vw = r.w;
+ vh = r.h;
+
+ w = sd->content_info.w;
+ if (w < 1) w = 1;
+ size = (double)vw / (double)w;
+ if (size > 1.0) size = 1.0;
+
+ if (width) *width = size;
+
+ h = sd->content_info.h;
+ if (h < 1) h = 1;
+ size = (double)vh / (double)h;
+ if (size > 1.0) size = 1.0;
+
+ if (height) *height = size;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_pan_set(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd, Eo *pan)
+{
+ if (sd->pan_obj)
+ {
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, _efl_ui_scroll_manager_pan_content_changed_cb, sd);
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, _efl_ui_scroll_manager_pan_viewport_changed_cb, sd);
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, _efl_ui_scroll_manager_pan_position_changed_cb, sd);
+ }
+
+ if (!pan)
+ return;
+
+ sd->pan_obj = pan;
+
+ efl_event_callback_add
+ (sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, _efl_ui_scroll_manager_pan_content_changed_cb, sd);
+ efl_event_callback_add
+ (sd->pan_obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, _efl_ui_scroll_manager_pan_viewport_changed_cb, sd);
+ efl_event_callback_add
+ (sd->pan_obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, _efl_ui_scroll_manager_pan_position_changed_cb, sd);
+ evas_object_event_callback_add(sd->pan_obj, EVAS_CALLBACK_RESIZE,
+ _efl_ui_scroll_manager_pan_resized_cb, obj);
+ evas_object_event_callback_add(sd->pan_obj, EVAS_CALLBACK_MOVE,
+ _efl_ui_scroll_manager_pan_moved_cb, obj);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_scroll_hold_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ return sd->hold;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_scroll_hold_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool hold)
+{
+ sd->hold = hold;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_scroll_freeze_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ return sd->freeze;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_scroll_freeze_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool freeze)
+{
+ sd->freeze = freeze;
+ if (sd->freeze)
+ {
+ _scroll_manager_on_hold_animator_del(sd);
+ }
+ else
+ _efl_ui_scroll_manager_bounce_eval(sd);
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_bounce_enabled_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool horiz, Eina_Bool vert)
+{
+ sd->bounce_horiz = !!horiz;
+ sd->bounce_vert = !!vert;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_bounce_enabled_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool *horiz, Eina_Bool *vert)
+{
+ if (horiz) *horiz = sd->bounce_horiz;
+ if (vert) *vert = sd->bounce_vert;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_scroll(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd, Eina_Rect rect, Eina_Bool animation)
+{
+ _scroll_manager_animators_drop(obj);
+ if (animation)
+ {
+ if (_efl_ui_scroll_manager_content_region_show_internal(obj, &(rect.x), &(rect.y), rect.w, rect.h))
+ {
+ _scroll_manager_scrollto(sd, rect.x, rect.y);
+ }
+ }
+ else
+ {
+ sd->wx = (sd->is_mirrored ? _efl_ui_scroll_manager_x_mirrored_get(sd->obj, rect.x) : rect.x);
+ sd->wy = rect.y;
+ sd->ww = rect.w;
+ sd->wh = rect.h;
+ if (_efl_ui_scroll_manager_content_region_show_internal(obj, &(rect.x), &(rect.y), rect.w, rect.h))
+ {
+ efl_ui_scrollable_content_pos_set(obj, EINA_POSITION2D(rect.x, rect.y));
+ sd->down.sx = rect.x;
+ sd->down.sy = rect.y;
+ sd->down.x = sd->down.history[0].x;
+ sd->down.y = sd->down.history[0].y;
+ }
+ }
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_gravity_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, double x, double y)
+{
+ sd->gravity_x = x;
+ sd->gravity_y = y;
+ Eina_Position2D max = efl_ui_pan_position_max_get(sd->pan_obj);
+ sd->prev_cw = max.x;
+ sd->prev_ch = max.y;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_gravity_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, double *x, double *y)
+{
+ if (x) *x = sd->gravity_x;
+ if (y) *y = sd->gravity_y;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_movement_block_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Efl_Ui_Scroll_Block block)
+{
+ sd->block = block;
+}
+
+EOLIAN static Efl_Ui_Scroll_Block
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_movement_block_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ return sd->block;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_looping_set(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool loop_h, Eina_Bool loop_v)
+{
+ if (sd->loop_h == loop_h && sd->loop_v == loop_v) return;
+
+ sd->loop_h = loop_h;
+ sd->loop_v = loop_v;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_ui_scrollable_interactive_looping_get(Eo *obj EINA_UNUSED, Efl_Ui_Scroll_Manager_Data *sd, Eina_Bool *loop_h, Eina_Bool *loop_v)
+{
+ *loop_h = sd->loop_h;
+ *loop_v = sd->loop_v;
+}
+
+EOLIAN static Eo *
+_efl_ui_scroll_manager_efl_object_constructor(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+
+ memset(sd, 0, sizeof(*sd));
+
+ sd->parent = efl_parent_get(obj);
+
+ sd->obj = obj;
+
+ sd->step.x = 32 * elm_config_scale_get();
+ sd->step.y = 32 * elm_config_scale_get();
+ sd->page.x = -50;
+ sd->page.y = -50;
+ sd->loop_h = EINA_FALSE;
+ sd->loop_v = EINA_FALSE;
+
+ sd->hbar_mode = EFL_UI_SCROLLBAR_MODE_AUTO;
+ sd->vbar_mode = EFL_UI_SCROLLBAR_MODE_AUTO;
+ sd->hbar_visible = EINA_TRUE;
+ sd->vbar_visible = EINA_TRUE;
+
+ sd->bounce_horiz = _elm_config->thumbscroll_bounce_enable;
+ sd->bounce_vert = _elm_config->thumbscroll_bounce_enable;
+
+ sd->block = EFL_UI_SCROLL_BLOCK_NONE;
+ sd->scrolling = EINA_FALSE;
+
+ sd->event_rect = evas_object_rectangle_add(evas_object_evas_get(sd->parent));
+ efl_canvas_group_member_add(sd->parent, sd->event_rect);
+ efl_ui_widget_sub_object_add(sd->parent, sd->event_rect);
+
+ efl_gfx_color_set(sd->event_rect, 0, 0, 0, 0);
+ efl_gfx_visible_set(sd->event_rect, EINA_TRUE);
+ efl_canvas_object_repeat_events_set(sd->event_rect, EINA_TRUE);
+
+ _scroll_event_object_attach(obj);
+
+ efl_ui_scrollbar_bar_visibility_update(sd->obj);
+
+ return obj;
+}
+
+EOLIAN static void
+_efl_ui_scroll_manager_efl_object_destructor(Eo *obj, Efl_Ui_Scroll_Manager_Data *sd)
+{
+ ecore_idle_enterer_del(sd->down.hold_enterer);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.hold_animator, _efl_ui_scroll_manager_hold_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->down.onhold_animator, _efl_ui_scroll_manager_on_hold_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.x.animator, _efl_ui_scroll_manager_bounce_x_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->bounce.y.animator, _efl_ui_scroll_manager_bounce_y_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.x.animator, _efl_ui_scroll_manager_scroll_to_x_animator, sd);
+ ELM_ANIMATOR_DISCONNECT(sd->event_rect, sd->scrollto.y.animator, _efl_ui_scroll_manager_scroll_to_y_animator, sd);
+
+ evas_object_event_callback_del_full(sd->pan_obj, EVAS_CALLBACK_RESIZE,
+ _efl_ui_scroll_manager_pan_resized_cb, obj);
+ evas_object_event_callback_del_full(sd->pan_obj, EVAS_CALLBACK_MOVE,
+ _efl_ui_scroll_manager_pan_moved_cb, obj);
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_CONTENT_CHANGED, _efl_ui_scroll_manager_pan_content_changed_cb, sd);
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_VIEWPORT_CHANGED, _efl_ui_scroll_manager_pan_viewport_changed_cb, sd);
+ efl_event_callback_del
+ (sd->pan_obj, EFL_UI_PAN_EVENT_POSITION_CHANGED, _efl_ui_scroll_manager_pan_position_changed_cb, sd);
+
+ _scroll_event_object_detach(obj);
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+#include "efl_ui_scroll_manager.eo.c"
diff --git a/src/lib/elementary/efl_ui_scroll_manager.eo b/src/lib/elementary/efl_ui_scroll_manager.eo
new file mode 100644
index 0000000000..462b964511
--- /dev/null
+++ b/src/lib/elementary/efl_ui_scroll_manager.eo
@@ -0,0 +1,44 @@
+class Efl.Ui.Scroll.Manager (Efl.Object,
+ Efl.Ui.Base,
+ Efl.Ui.Scrollable.Interactive,
+ Efl.Ui.Scrollbar)
+{
+ [[Efl ui scroll manager class]]
+ event_prefix: efl_ui;
+ eo_prefix: efl_ui_scroll_manager;
+ methods {
+ @property pan @protected {
+ [[This is the internal canvas object managed by scroll manager.
+
+ This property is protected as it is meant for scrollable object
+ implementations only, to set and access the internal canvas object.
+ If pan is set to NULL, scrolling does not work.
+ ]]
+ set {
+ }
+ values {
+ pan: Efl.Canvas.Object @nullable; [[Pan object]]
+ }
+ }
+ }
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.destructor;
+ Efl.Ui.Base.mirrored { set; }
+ Efl.Ui.Scrollable.Interactive.content_pos { set; get; }
+ Efl.Ui.Scrollable.Interactive.content_size{ get; }
+ Efl.Ui.Scrollable.Interactive.viewport_geometry{ get; }
+ Efl.Ui.Scrollable.Interactive.bounce_enabled { set; get; }
+ Efl.Ui.Scrollable.Interactive.scroll_freeze { get; set; }
+ Efl.Ui.Scrollable.Interactive.scroll_hold { get; set; }
+ Efl.Ui.Scrollable.Interactive.looping { get; set; }
+ Efl.Ui.Scrollable.Interactive.movement_block { get; set; }
+ Efl.Ui.Scrollable.Interactive.gravity { get; set; }
+ Efl.Ui.Scrollable.Interactive.match_content { set; }
+ Efl.Ui.Scrollbar.bar_mode { get; set; }
+ Efl.Ui.Scrollbar.bar_size { get; }
+ Efl.Ui.Scrollbar.bar_position { get; set; }
+ Efl.Ui.Scrollbar.bar_visibility_update;
+ Efl.Ui.Scrollable.Interactive.scroll;
+ }
+}
diff --git a/src/lib/elementary/efl_ui_scroller.c b/src/lib/elementary/efl_ui_scroller.c
new file mode 100644
index 0000000000..e10d5b6cce
--- /dev/null
+++ b/src/lib/elementary/efl_ui_scroller.c
@@ -0,0 +1,638 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define ELM_LAYOUT_PROTECTED
+#define EFL_UI_SCROLL_MANAGER_PROTECTED
+#define EFL_UI_SCROLLBAR_PROTECTED
+#define EFL_UI_SCROLLBAR_BETA
+
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "efl_ui_widget_scroller.h"
+#include "elm_widget_layout.h"
+
+#define MY_CLASS EFL_UI_SCROLLER_CLASS
+#define MY_CLASS_PFX efl_ui_scroller
+
+#define MY_CLASS_NAME "Efl.Ui.Scroller"
+
+#define EFL_UI_SCROLLER_DATA_GET(o, sd) \
+ Efl_Ui_Scroller_Data * sd = efl_data_scope_safe_get(o, EFL_UI_SCROLLER_CLASS)
+
+#define EFL_UI_SCROLLER_DATA_GET_OR_RETURN(o, ptr, ...) \
+ EFL_UI_SCROLLER_DATA_GET(o, ptr); \
+ if (EINA_UNLIKELY(!ptr)) \
+ { \
+ CRI("No widget data for object %p (%s)", \
+ o, evas_object_type_get(o)); \
+ return __VA_ARGS__; \
+ }
+static void
+_efl_ui_scroller_content_del_cb(void *data,
+ const Efl_Event *event EINA_UNUSED)
+{
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(data, sd);
+
+ sd->content = NULL;
+ if (!sd->smanager) return;
+ efl_ui_scrollbar_bar_visibility_update(sd->smanager);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_scroller_efl_content_content_set(Eo *obj,
+ Efl_Ui_Scroller_Data *sd,
+ Evas_Object *content)
+{
+ if (sd->content)
+ {
+ efl_content_set(sd->pan_obj, NULL);
+ efl_event_callback_del(sd->content, EFL_EVENT_DEL,
+ _efl_ui_scroller_content_del_cb, obj);
+ }
+
+ sd->content = content;
+ if (!content) return EINA_TRUE;
+
+ efl_event_callback_add(sd->content, EFL_EVENT_DEL,
+ _efl_ui_scroller_content_del_cb, obj);
+
+ efl_content_set(sd->pan_obj, content);
+
+ elm_layout_sizing_eval(obj);
+
+ return EINA_TRUE;
+}
+
+static void
+_efl_ui_scroller_bar_read_and_update(Eo *obj)
+{
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ double vx, vy;
+
+ edje_object_part_drag_value_get
+ (wd->resize_obj, "elm.dragable.vbar", NULL, &vy);
+ edje_object_part_drag_value_get
+ (wd->resize_obj, "elm.dragable.hbar", &vx, NULL);
+
+ efl_ui_scrollbar_bar_position_set(sd->smanager, vx, vy);
+}
+
+static void
+_efl_ui_scroller_reload_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Eo *scroller = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(scroller, sd);
+
+ efl_ui_scrollbar_bar_visibility_update(sd->smanager);
+}
+
+static void
+_efl_ui_scroller_vbar_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_scroller_bar_read_and_update(data);
+
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
+}
+
+static void
+_efl_ui_scroller_vbar_press_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
+}
+
+static void
+_efl_ui_scroller_vbar_unpress_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_VERTICAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
+}
+
+static void
+_efl_ui_scroller_edje_drag_start_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Eo *scroller = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(scroller, sd);
+
+ _efl_ui_scroller_bar_read_and_update(scroller);
+
+ sd->freeze_want = efl_ui_scrollable_scroll_freeze_get(sd->smanager);
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, EINA_TRUE);
+ efl_event_callback_call(scroller, EFL_UI_EVENT_SCROLL_DRAG_START, NULL);
+}
+
+static void
+_efl_ui_scroller_edje_drag_stop_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Eo *scroller = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(scroller, sd);
+
+ _efl_ui_scroller_bar_read_and_update(scroller);
+
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, sd->freeze_want);
+ efl_event_callback_call(scroller, EFL_UI_EVENT_SCROLL_DRAG_STOP, NULL);
+}
+
+static void
+_efl_ui_scroller_edje_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_scroller_bar_read_and_update(data);
+}
+
+static void
+_efl_ui_scroller_hbar_drag_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ _efl_ui_scroller_bar_read_and_update(data);
+
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_DRAG, &type);
+}
+
+static void
+_efl_ui_scroller_hbar_press_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_PRESS, &type);
+}
+
+static void
+_efl_ui_scroller_hbar_unpress_cb(void *data,
+ Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED)
+{
+ Efl_Ui_Scrollbar_Direction type = EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL;
+ efl_event_callback_call(data, EFL_UI_SCROLLBAR_EVENT_BAR_UNPRESS, &type);
+}
+
+static void
+_efl_ui_scroller_bar_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Eo *obj = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ double width = 0.0, height = 0.0;
+
+ edje_object_calc_force(wd->resize_obj);
+ efl_ui_scrollbar_bar_size_get(sd->smanager, &width, &height);
+ edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.hbar", width, 1.0);
+ edje_object_part_drag_size_set(wd->resize_obj, "elm.dragable.vbar", 1.0, height);
+}
+
+static void
+_efl_ui_scroller_bar_pos_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
+{
+ Eo *obj = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ double posx = 0.0, posy = 0.0;
+
+ efl_ui_scrollbar_bar_position_get(sd->smanager, &posx, &posy);
+ edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.hbar", posx, 0.0);
+ edje_object_part_drag_value_set(wd->resize_obj, "elm.dragable.vbar", 0.0, posy);
+}
+
+static void
+_efl_ui_scroller_bar_show_cb(void *data, const Efl_Event *event)
+{
+ Eo *obj = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
+
+ if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,show,hbar", "elm");
+ else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,show,vbar", "elm");
+}
+
+static void
+_efl_ui_scroller_bar_hide_cb(void *data, const Efl_Event *event)
+{
+ Eo *obj = data;
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+ Efl_Ui_Scrollbar_Direction type = *(Efl_Ui_Scrollbar_Direction *)(event->info);
+
+ if (type == EFL_UI_SCROLLBAR_DIRECTION_HORIZONTAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,hide,hbar", "elm");
+ else if (type == EFL_UI_SCROLLBAR_DIRECTION_VERTICAL)
+ edje_object_signal_emit(wd->resize_obj, "elm,action,hide,vbar", "elm");
+}
+
+static void
+_scroll_edje_object_attach(Eo *obj)
+{
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+
+ efl_layout_signal_callback_add
+ (obj, "reload", "elm", _efl_ui_scroller_reload_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag", "elm.dragable.vbar", _efl_ui_scroller_vbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,set", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,start", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,stop", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,step", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,page", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,vbar,press", "elm",
+ _efl_ui_scroller_vbar_press_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,vbar,unpress", "elm",
+ _efl_ui_scroller_vbar_unpress_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag", "elm.dragable.hbar", _efl_ui_scroller_hbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,set", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,start", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,stop", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,step", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "drag,page", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,hbar,press", "elm",
+ _efl_ui_scroller_hbar_press_cb, obj);
+ efl_layout_signal_callback_add
+ (obj, "elm,hbar,unpress", "elm",
+ _efl_ui_scroller_hbar_unpress_cb, obj);
+}
+
+static void
+_scroll_edje_object_detach(Evas_Object *obj)
+{
+ EFL_UI_SCROLLER_DATA_GET_OR_RETURN(obj, sd);
+
+ efl_layout_signal_callback_del
+ (obj, "reload", "elm", _efl_ui_scroller_reload_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag", "elm.dragable.vbar", _efl_ui_scroller_vbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,set", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,start", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,stop", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,step", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,page", "elm.dragable.vbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,vbar,press", "elm",
+ _efl_ui_scroller_vbar_press_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,vbar,unpress", "elm",
+ _efl_ui_scroller_vbar_unpress_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag", "elm.dragable.hbar", _efl_ui_scroller_hbar_drag_cb,
+ obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,set", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,start", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_start_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,stop", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_stop_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,step", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "drag,page", "elm.dragable.hbar",
+ _efl_ui_scroller_edje_drag_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,hbar,press", "elm",
+ _efl_ui_scroller_hbar_press_cb, obj);
+ efl_layout_signal_callback_del
+ (obj, "elm,hbar,unpress", "elm",
+ _efl_ui_scroller_hbar_unpress_cb, obj);
+}
+
+static void
+_efl_ui_scroller_pan_resized_cb(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+ elm_layout_sizing_eval(data);
+}
+
+static void
+_efl_ui_scroller_resized_cb(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+ elm_layout_sizing_eval(data);
+}
+
+static void
+_efl_ui_scroller_size_hint_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+ elm_layout_sizing_eval(data);
+}
+
+EOLIAN static Eo *
+_efl_ui_scroller_efl_object_constructor(Eo *obj,
+ Efl_Ui_Scroller_Data *sd EINA_UNUSED)
+{
+ obj = efl_constructor(efl_super(obj, MY_CLASS));
+
+ return obj;
+}
+
+EOLIAN static Eo *
+_efl_ui_scroller_efl_object_finalize(Eo *obj,
+ Efl_Ui_Scroller_Data *sd EINA_UNUSED)
+{
+ obj = efl_finalize(efl_super(obj, MY_CLASS));
+
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
+
+ efl_ui_layout_theme_set(obj, "scroller", "base", efl_ui_widget_style_get(obj));
+
+ sd->smanager = efl_add(EFL_UI_SCROLL_MANAGER_CLASS, obj);
+ efl_ui_mirrored_set(sd->smanager, efl_ui_mirrored_get(obj));
+
+ sd->pan_obj = efl_add(EFL_UI_PAN_CLASS, obj);
+
+ efl_ui_scroll_manager_pan_set(sd->smanager, sd->pan_obj);
+ edje_object_part_swallow(wd->resize_obj, "elm.swallow.content", sd->pan_obj);
+
+ _scroll_edje_object_attach(obj);
+
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED,
+ _efl_ui_scroller_bar_size_changed_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED,
+ _efl_ui_scroller_bar_pos_changed_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW,
+ _efl_ui_scroller_bar_show_cb, obj);
+ efl_event_callback_add(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE,
+ _efl_ui_scroller_bar_hide_cb, obj);
+ efl_event_callback_add(obj, EFL_GFX_EVENT_RESIZE,
+ _efl_ui_scroller_resized_cb, obj);
+ efl_event_callback_add(obj, EFL_GFX_EVENT_CHANGE_SIZE_HINTS,
+ _efl_ui_scroller_size_hint_changed_cb, obj);
+ efl_event_callback_add(sd->pan_obj, EFL_GFX_EVENT_RESIZE,
+ _efl_ui_scroller_pan_resized_cb, obj);
+
+ return obj;
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_object_destructor(Eo *obj,
+ Efl_Ui_Scroller_Data *sd EINA_UNUSED)
+{
+ _scroll_edje_object_detach(obj);
+
+ efl_event_callback_del(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SIZE_CHANGED,
+ _efl_ui_scroller_bar_size_changed_cb, obj);
+ efl_event_callback_del(obj, EFL_UI_SCROLLBAR_EVENT_BAR_POS_CHANGED,
+ _efl_ui_scroller_bar_pos_changed_cb, obj);
+ efl_event_callback_del(obj, EFL_UI_SCROLLBAR_EVENT_BAR_SHOW,
+ _efl_ui_scroller_bar_show_cb, obj);
+ efl_event_callback_del(obj, EFL_UI_SCROLLBAR_EVENT_BAR_HIDE,
+ _efl_ui_scroller_bar_hide_cb, obj);
+ efl_event_callback_del(obj, EFL_GFX_EVENT_RESIZE,
+ _efl_ui_scroller_resized_cb, obj);
+ efl_event_callback_del(obj, EFL_GFX_EVENT_CHANGE_SIZE_HINTS,
+ _efl_ui_scroller_size_hint_changed_cb, obj);
+ efl_event_callback_del(sd->pan_obj, EFL_GFX_EVENT_RESIZE,
+ _efl_ui_scroller_pan_resized_cb, obj);
+ efl_del(sd->pan_obj);
+ sd->pan_obj = NULL;
+ efl_del(sd->smanager);
+ sd->smanager = NULL;
+
+ efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static void
+_efl_ui_scroller_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Scroller_Data *sd)
+{
+ Eina_Size2D min = {0, 0}, max = {0, 0}, size = {-1, -1};
+ Eina_Rect view = {};
+ Evas_Coord vmw = 0, vmh = 0;
+ double xw = 0.0, yw = 0.0;
+
+ ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+ if (sd->content)
+ {
+ min = efl_gfx_size_hint_combined_min_get(sd->content);
+ max = efl_gfx_size_hint_max_get(sd->content);
+ efl_gfx_size_hint_weight_get(sd->content, &xw, &yw);
+ }
+
+ if (sd->smanager)
+ view = efl_ui_scrollable_viewport_geometry_get(sd->smanager);
+
+ if (xw > 0.0)
+ {
+ if ((min.w > 0) && (view.w < min.w))
+ view.w = min.w;
+ else if ((max.w > 0) && (view.w > max.w))
+ view.w = max.w;
+ }
+ else if (min.w > 0)
+ view.w = min.w;
+
+ if (yw > 0.0)
+ {
+ if ((min.h > 0) && (view.h < min.h))
+ view.h = min.h;
+ else if ((max.h > 0) && (view.h > max.h))
+ view.h = max.h;
+ }
+ else if (min.h > 0)
+ view.h = min.h;
+
+ if (sd->content) efl_gfx_size_set(sd->content, EINA_SIZE2D(view.w, view.h));
+
+ edje_object_size_min_calc(wd->resize_obj, &vmw, &vmh);
+
+ if (sd->match_content_w) size.w = vmw + min.w;
+ if (sd->match_content_h) size.h = vmh + min.h;
+
+ max = efl_gfx_size_hint_max_get(obj);
+ if ((max.w > 0) && (size.w > max.w)) size.w = max.w;
+ if ((max.h > 0) && (size.h > max.h)) size.h = max.h;
+
+ efl_gfx_size_hint_min_set(obj, size);
+}
+
+EOLIAN static Efl_Ui_Theme_Apply
+_efl_ui_scroller_elm_widget_theme_apply(Eo *obj, Efl_Ui_Scroller_Data *sd)
+{
+ Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED;
+ int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
+ if (!int_ret) return EFL_UI_THEME_APPLY_FAILED;
+
+ efl_ui_mirrored_set(sd->smanager, efl_ui_mirrored_get(obj));
+
+ elm_layout_sizing_eval(obj);
+
+ return int_ret;
+}
+
+EOLIAN static Eina_Size2D
+_efl_ui_scroller_efl_ui_scrollable_interactive_content_size_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd)
+{
+ return efl_ui_scrollable_content_size_get(sd->smanager);
+}
+
+EOLIAN static Eina_Rect
+_efl_ui_scroller_efl_ui_scrollable_interactive_viewport_geometry_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd)
+{
+ return efl_ui_scrollable_viewport_geometry_get(sd->smanager);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_bounce_enabled_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Bool horiz,
+ Eina_Bool vert)
+{
+ efl_ui_scrollable_bounce_enabled_set(sd->smanager, horiz, vert);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_bounce_enabled_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Bool *horiz,
+ Eina_Bool *vert)
+{
+ efl_ui_scrollable_bounce_enabled_get(sd->smanager, horiz, vert);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_scroller_efl_ui_scrollable_interactive_scroll_hold_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd)
+{
+ return efl_ui_scrollable_scroll_hold_get(sd->smanager);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_scroll_hold_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Bool hold)
+{
+ efl_ui_scrollable_scroll_hold_set(sd->smanager, hold);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_scroller_efl_ui_scrollable_interactive_scroll_freeze_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd)
+{
+ return efl_ui_scrollable_scroll_freeze_get(sd->smanager);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_scroll_freeze_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Bool freeze)
+{
+ efl_ui_scrollable_scroll_freeze_set(sd->smanager, freeze);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_match_content_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Bool match_content_w,
+ Eina_Bool match_content_h)
+{
+ sd->match_content_w = !!match_content_w;
+ sd->match_content_h = !!match_content_h;
+
+ efl_ui_scrollable_match_content_set(sd->smanager, match_content_w, match_content_h);
+
+ elm_layout_sizing_eval(obj);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollbar_bar_mode_set(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Efl_Ui_Scrollbar_Mode hmode,
+ Efl_Ui_Scrollbar_Mode vmode)
+{
+ efl_ui_scrollbar_bar_mode_set(sd->smanager, hmode, vmode);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollbar_bar_mode_get(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Efl_Ui_Scrollbar_Mode *hmode,
+ Efl_Ui_Scrollbar_Mode *vmode)
+{
+ efl_ui_scrollbar_bar_mode_get(sd->smanager, hmode, vmode);
+}
+
+EOLIAN static void
+_efl_ui_scroller_efl_ui_scrollable_interactive_scroll(Eo *obj EINA_UNUSED,
+ Efl_Ui_Scroller_Data *sd,
+ Eina_Rect rc,
+ Eina_Bool animation)
+{
+ efl_ui_scrollable_scroll(sd->smanager, rc, animation);
+}
+
+/* Internal EO APIs and hidden overrides */
+
+#define EFL_UI_SCROLLER_EXTRA_OPS \
+ ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_scroller)
+
+#include "efl_ui_scroller.eo.c"
diff --git a/src/lib/elementary/efl_ui_scroller.eo b/src/lib/elementary/efl_ui_scroller.eo
new file mode 100644
index 0000000000..805e0de207
--- /dev/null
+++ b/src/lib/elementary/efl_ui_scroller.eo
@@ -0,0 +1,23 @@
+class Efl.Ui.Scroller (Efl.Ui.Layout,
+ Efl.Ui.Scrollable.Interactive,
+ Efl.Ui.Scrollbar,
+ Efl.Content,
+ Efl.Ui.Drag)
+{
+ [[Efl ui scroller class]]
+ implements {
+ Efl.Object.constructor;
+ Efl.Object.finalize;
+ Efl.Object.destructor;
+ Efl.Content.content { set; }
+ Elm.Widget.theme_apply;
+ Efl.Ui.Scrollable.Interactive.content_size{ get; }
+ Efl.Ui.Scrollable.Interactive.viewport_geometry{ get; }
+ Efl.Ui.Scrollable.Interactive.bounce_enabled { set; get; }
+ Efl.Ui.Scrollable.Interactive.scroll_freeze { get; set; }
+ Efl.Ui.Scrollable.Interactive.scroll_hold { get; set; }
+ Efl.Ui.Scrollable.Interactive.match_content { set; }
+ Efl.Ui.Scrollbar.bar_mode { get; set; }
+ Efl.Ui.Scrollable.Interactive.scroll;
+ }
+}
diff --git a/src/lib/elementary/efl_ui_widget_pan.h b/src/lib/elementary/efl_ui_widget_pan.h
new file mode 100644
index 0000000000..03275dcec8
--- /dev/null
+++ b/src/lib/elementary/efl_ui_widget_pan.h
@@ -0,0 +1,14 @@
+#ifndef EFL_UI_WIDGET_PAN_H
+#define EFL_UI_WIDGET_PAN_H
+
+#include "Elementary.h"
+
+typedef struct _Efl_Ui_Pan_Data Efl_Ui_Pan_Data;
+struct _Efl_Ui_Pan_Data
+{
+ Evas_Object *content;
+ Evas_Coord x, y, w, h;
+ Evas_Coord content_w, content_h, px, py;
+};
+
+#endif
diff --git a/src/lib/elementary/efl_ui_widget_scroll_manager.h b/src/lib/elementary/efl_ui_widget_scroll_manager.h
new file mode 100644
index 0000000000..07311910e0
--- /dev/null
+++ b/src/lib/elementary/efl_ui_widget_scroll_manager.h
@@ -0,0 +1,135 @@
+#ifndef EFL_UI_WIDGET_SCROLL_MANAGER_H
+#define EFL_UI_WIDGET_SCROLL_MANAGER_H
+
+#include "Elementary.h"
+
+typedef double (*Interpolator)(void *data, double progress);
+
+typedef enum {
+ LINEAR,
+ ACCEL,
+ DECEL,
+} InterpType;
+
+typedef struct _Efl_Ui_Scroll_Manager_Data
+{
+ Evas_Coord x, y, w, h;
+ Evas_Coord wx, wy, ww, wh; /**< Last "wanted" geometry */
+
+ Evas_Object *obj;
+ Evas_Object *pan_obj;
+ Evas_Object *event_rect;
+
+ Evas_Object *parent;
+
+ Efl_Ui_Scrollbar_Mode hbar_mode, vbar_mode;
+
+ Ecore_Timer *hbar_timer, *vbar_timer;
+ Efl_Ui_Scroll_Block block;
+
+ struct
+ {
+ Evas_Coord x, y;
+ Evas_Coord sx, sy;
+
+ struct
+ {
+ Evas_Coord x, y;
+ double timestamp, localtimestamp;
+ } history[60];
+
+ struct
+ {
+ double tadd, dxsum, dysum;
+ double est_timestamp_diff;
+ } hist;
+
+ double onhold_vx, onhold_vy;
+ double onhold_vxe, onhold_vye;
+ double onhold_tlast;
+
+ double last_time_x_wheel;
+ double last_time_y_wheel;
+
+ int hdir, vdir;
+
+ Evas_Coord hold_x, hold_y;
+ Ecore_Idle_Enterer *hold_enterer;
+
+ double dragged_began_timestamp;
+ Eina_Bool dragged : 1;
+ Eina_Bool dragged_began : 1;
+ Eina_Bool hold_animator : 1;
+ Eina_Bool onhold_animator : 1;
+ Eina_Bool last_hold_x_wheel : 1;
+ Eina_Bool last_hold_y_wheel : 1;
+ Eina_Bool dir_x : 1;
+ Eina_Bool dir_y : 1;
+
+ Eina_Bool scroll : 1;
+ Eina_Bool hold : 1;
+
+ Eina_Bool now : 1;
+ Eina_Bool want_reset : 1;
+ } down;
+
+ struct
+ {
+ Evas_Coord w, h;
+ Eina_Bool resized : 1;
+ } content_info;
+
+ struct
+ {
+ Evas_Coord x, y;
+ } step, page;
+
+ struct
+ {
+ struct
+ {
+ Evas_Coord start, end;
+ Eina_Bool animator;
+ Interpolator interp;
+ double start_t, dur;
+ } x, y;
+ } scrollto;
+
+ struct
+ {
+ struct
+ {
+ Evas_Coord p0, p1, p2;
+ double vel;
+ Eina_Bool animator;
+ double start_t;
+ double t01, t12;
+ } x, y;
+ } bounce;
+
+ double last_wheel_mul;
+ unsigned int last_wheel;
+
+ void *event_info;
+
+ double gravity_x, gravity_y;
+ Evas_Coord prev_cw, prev_ch;
+
+ Eina_Bool hbar_visible : 1;
+ Eina_Bool vbar_visible : 1;
+ Eina_Bool bounce_horiz : 1;
+ Eina_Bool bounce_vert : 1;
+ Eina_Bool is_mirrored : 1;
+ Eina_Bool bouncemey : 1;
+ Eina_Bool bouncemex : 1;
+ Eina_Bool freeze : 1;
+ Eina_Bool freeze_want : 1;
+ Eina_Bool hold : 1;
+ Eina_Bool match_content_w : 1;
+ Eina_Bool match_content_h : 1;
+ Eina_Bool loop_h : 1;
+ Eina_Bool loop_v : 1;
+ Eina_Bool scrolling : 1;
+} Efl_Ui_Scroll_Manager_Data;
+
+#endif
diff --git a/src/lib/elementary/efl_ui_widget_scroller.h b/src/lib/elementary/efl_ui_widget_scroller.h
new file mode 100644
index 0000000000..4fdfa32989
--- /dev/null
+++ b/src/lib/elementary/efl_ui_widget_scroller.h
@@ -0,0 +1,17 @@
+#ifndef EFL_UI_WIDGET_SCROLLER_H
+#define EFL_UI_WIDGET_SCROLLER_H
+
+#include "Elementary.h"
+
+typedef struct _Efl_Ui_Scroller_Data
+{
+ Eo *content;
+ Eo *pan_obj;
+ Eo *smanager;
+
+ Eina_Bool freeze_want : 1;
+ Eina_Bool match_content_w: 1;
+ Eina_Bool match_content_h: 1;
+} Efl_Ui_Scroller_Data;
+
+#endif