From e61e3128b17912ba7bbf6b45f84f4781097a1412 Mon Sep 17 00:00:00 2001 From: raster Date: Thu, 9 Jun 2011 10:14:16 +0000 Subject: [PATCH] scroller smoothing stuff. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@60126 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- config/illume/base.src | 3 + config/standard/base.src | 3 + src/lib/elm_config.c | 12 ++++ src/lib/elm_priv.h | 3 + src/lib/els_scroller.c | 144 ++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 158 insertions(+), 7 deletions(-) diff --git a/config/illume/base.src b/config/illume/base.src index d5f558a..02a73c5 100644 --- a/config/illume/base.src +++ b/config/illume/base.src @@ -12,6 +12,9 @@ group "Elm_Config" struct { value "bring_in_scroll_friction" double: 0.5; value "zoom_friction" double: 0.5; value "thumbscroll_border_friction" double: 0.5; + value "scroll_smooth_amount" double: 1.0; + value "scroll_smooth_history_weight" double: 0.3; + value "scroll_smooth_future_time" double: 0.033; value "scale" double: 1.0; value "bgpixmap" int: 0; value "compositing" int: 1; diff --git a/config/standard/base.src b/config/standard/base.src index 3b18fa1..d87ce46 100644 --- a/config/standard/base.src +++ b/config/standard/base.src @@ -12,6 +12,9 @@ group "Elm_Config" struct { value "bring_in_scroll_friction" double: 0.5; value "zoom_friction" double: 0.5; value "thumbscroll_border_friction" double: 0.5; + value "scroll_smooth_amount" double: 0.0; + value "scroll_smooth_history_weight" double: 0.3; + value "scroll_smooth_future_time" double: 0.033; value "scale" double: 1.0; value "bgpixmap" int: 0; value "compositing" int: 1; diff --git a/src/lib/elm_config.c b/src/lib/elm_config.c index 3dad016..9465b9b 100644 --- a/src/lib/elm_config.c +++ b/src/lib/elm_config.c @@ -568,6 +568,9 @@ _desc_init(void) ELM_CONFIG_VAL(D, T, bring_in_scroll_friction, T_DOUBLE); ELM_CONFIG_VAL(D, T, zoom_friction, T_DOUBLE); ELM_CONFIG_VAL(D, T, thumbscroll_bounce_enable, T_UCHAR); + ELM_CONFIG_VAL(D, T, scroll_smooth_amount, T_DOUBLE); + ELM_CONFIG_VAL(D, T, scroll_smooth_history_weight, T_DOUBLE); + ELM_CONFIG_VAL(D, T, scroll_smooth_future_time, T_DOUBLE); ELM_CONFIG_VAL(D, T, scale, T_DOUBLE); ELM_CONFIG_VAL(D, T, bgpixmap, T_INT); ELM_CONFIG_VAL(D, T, compositing, T_INT); @@ -1118,6 +1121,9 @@ _config_load(void) _elm_config->bring_in_scroll_friction = 0.5; _elm_config->zoom_friction = 0.5; _elm_config->thumbscroll_border_friction = 0.5; + _elm_config->scroll_smooth_amount = 1.0; + _elm_config->scroll_smooth_history_weight = 0.3; + _elm_config->scroll_smooth_future_time = 2.0 / 60.0; _elm_config->scale = 1.0; _elm_config->bgpixmap = 0; _elm_config->compositing = 1; @@ -1469,6 +1475,12 @@ _env_get(void) _elm_config->thumbscroll_border_friction = friction; } + s = getenv("ELM_SCROLL_SMOOTH_AMOUNT"); + if (s) _elm_config->scroll_smooth_amount = atof(s); + s = getenv("ELM_SCROLL_SMOOTH_HISTORY_WEIGHT"); + if (s) _elm_config->scroll_smooth_history_weight = atof(s); + s = getenv("ELM_SCROLL_SMOOTH_FUTURE_TIME"); + if (s) _elm_config->scroll_smooth_future_time = atof(s); s = getenv("ELM_THEME"); if (s) eina_stringshare_replace(&_elm_config->theme, s); diff --git a/src/lib/elm_priv.h b/src/lib/elm_priv.h index af2d89e..4e02833 100644 --- a/src/lib/elm_priv.h +++ b/src/lib/elm_priv.h @@ -96,6 +96,9 @@ struct _Elm_Config double zoom_friction; unsigned char thumbscroll_bounce_enable; double thumbscroll_border_friction; + double scroll_smooth_amount; + double scroll_smooth_history_weight; + double scroll_smooth_future_time; double scale; int bgpixmap; int compositing; diff --git a/src/lib/els_scroller.c b/src/lib/els_scroller.c index 40721cb..bf51363 100644 --- a/src/lib/els_scroller.c +++ b/src/lib/els_scroller.c @@ -36,8 +36,12 @@ struct _Smart_Data Evas_Coord b2x, b2y; struct { Evas_Coord x, y; - double timestamp; - } history[20]; + double timestamp, localtimestamp; + } history[60]; + struct { + double tadd, dxsum, dysum; + double est_timestamp_diff; + } hist; double anim_start; double anim_start2; double anim_start3; @@ -1589,6 +1593,8 @@ _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSE } if (ev->button == 1) { + sd->down.hist.est_timestamp_diff = + ecore_loop_time_get() - ((double)ev->timestamp / 1000.0); sd->down.now = 1; sd->down.dragged = 0; sd->down.dir_x = 0; @@ -1599,9 +1605,10 @@ _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSE sd->down.sx = x; sd->down.sy = y; sd->down.locked = 0; - memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 20); + 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 @@ -1614,12 +1621,131 @@ _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSE } } +static void +_down_coord_eval(Smart_Data *sd, Evas_Coord *x, Evas_Coord *y) +{ + Evas_Coord minx, miny; + + 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; + + if ((sd->down.dir_x) || (sd->down.dir_y)) + { + if (!((sd->down.dir_x) && (sd->down.dir_y))) + { + if (sd->down.dir_x) *y = sd->down.locked_y; + else *x = sd->down.locked_x; + } + } + + sd->pan_func.min_get(sd->pan_obj, &minx, &miny); + + if (*x < minx) + *x += (minx - *x) * _elm_config->thumbscroll_border_friction; + else if (sd->child.w <= sd->w) + *x += (sd->down.sx - *x) * _elm_config->thumbscroll_border_friction; + else if ((sd->child.w - sd->w + minx) < *x) + *x += (sd->child.w - sd->w + minx - *x) * + _elm_config->thumbscroll_border_friction; + + if (*y < miny) + *y += (miny - *y) * _elm_config->thumbscroll_border_friction; + else if (sd->child.h <= sd->h) + *y += (sd->down.sy - *y) * _elm_config->thumbscroll_border_friction; + else if ((sd->child.h - sd->h + miny) < *y) + *y += (sd->child.h - sd->h + miny - *y) * + _elm_config->thumbscroll_border_friction; +} + static Eina_Bool _smart_hold_animator(void *data) { Smart_Data *sd = data; - Evas_Coord ox, oy; + Evas_Coord ox = 0, oy = 0, fx, fy; + + fx = sd->down.hold_x; + fy = sd->down.hold_y; + if (_elm_config->scroll_smooth_amount > 0.0) + { + int i, count = 0; + Evas_Coord basex, basey, x, y; + double dt, t, tdiff, tnow; + struct { + Evas_Coord x, y, dx, dy; + double t, dt; + } pos[60]; + + // FIXME: assume server and client have the same "timezone" + // (0 timepoint) for now. this needs to be figured out in advance + // though. + tdiff = sd->down.hist.est_timestamp_diff; + tnow = ecore_time_get() - tdiff; + t = tnow; + for (i = 0; i < 60; i++) + { + // oldest point is sd->down.history[i] + // newset is sd->down.history[0] + dt = t - sd->down.history[i].timestamp; + if (dt > 0.1) + { + i--; + break; + } + x = sd->down.history[i].x; + y = sd->down.history[i].y; + _down_coord_eval(sd, &x, &y); + if (i == 0) + { + basex = x; + basey = y; + } + pos[i].x = x - basex; + pos[i].y = y - basey; + pos[i].t = + sd->down.history[i].timestamp - sd->down.history[0].timestamp; + count++; + } + count = i; + if (count >= 2) + { + double dtsum = 0.0, tadd, maxdt; + double dxsum = 0.0, dysum = 0.0, xsum = 0.0, ysum = 0.0; + for (i = 0; i < (count - 1); i++) + { + pos[i].dx = pos[i].x - pos[i + 1].x; + pos[i].dy = pos[i].y - pos[i + 1].y; + pos[i].dt = pos[i].t - pos[i + 1].t; + dxsum += pos[i].dx; + dysum += pos[i].dy; + dtsum += pos[i].dt; + xsum += pos[i].x; + ysum += pos[i].y; + } + maxdt = pos[i].t; + dxsum /= (double)i; + dysum /= (double)i; + dtsum /= (double)i; + xsum /= (double)i; + ysum /= (double)i; + tadd = tnow - sd->down.history[0].timestamp + _elm_config->scroll_smooth_future_time; + tadd = tadd - (maxdt / 2); +#define WEIGHT(n, o, v) n = (o * (v - 1.0)) + (n * v) + WEIGHT(tadd, sd->down.hist.tadd, _elm_config->scroll_smooth_history_weight); + WEIGHT(dxsum, sd->down.hist.dxsum, _elm_config->scroll_smooth_history_weight); + WEIGHT(dysum, sd->down.hist.dysum, _elm_config->scroll_smooth_history_weight); + fx = basex + xsum + ((dxsum * tadd) / dtsum); + fy = basey + ysum + ((dysum * tadd) / dtsum); + sd->down.hist.tadd = tadd; + sd->down.hist.dxsum = dxsum; + sd->down.hist.dysum = dysum; + fx = WEIGHT(fx, sd->down.hold_x, _elm_config->scroll_smooth_amount); + fy = WEIGHT(fy, sd->down.hold_y, _elm_config->scroll_smooth_amount); + } + } + elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy); if (sd->down.dir_x) { @@ -1627,6 +1753,7 @@ _smart_hold_animator(void *data) (!elm_widget_drag_child_locked_x_get(sd->widget))) { ox = sd->down.hold_x; + ox = fx; } } if (sd->down.dir_y) @@ -1635,8 +1762,10 @@ _smart_hold_animator(void *data) (!elm_widget_drag_child_locked_y_get(sd->widget))) { oy = sd->down.hold_y; + oy = fy; } } + elm_smart_scroller_child_pos_set(sd->smart_obj, ox, oy); return ECORE_CALLBACK_RENEW; } @@ -1701,7 +1830,7 @@ _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *ev #ifdef SCROLLDBG printf("------ %i %i\n", ev->canvas.x, ev->canvas.y); #endif - for (i = 0; i < 20; i++) + for (i = 0; i < 60; i++) { dt = t - sd->down.history[i].timestamp; if (dt > 0.2) break; @@ -1994,9 +2123,10 @@ _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void * printf("::: %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]) * 19); + 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 @@ -2121,7 +2251,7 @@ _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void * x += (sd->child.w - sd->w + minx - x) * _elm_config->thumbscroll_border_friction; } - + sd->down.hold_x = x; sd->down.hold_y = y; if (!sd->down.hold_animator) -- 2.7.4