elm - thumbscroll finger scrolling - make it far smoother

smooth out scrolling and simplifyconfig as well as expose config apis
to configure it all and elm config ui sliders and checkboxes for
related config values etc. etc. - with this it is much smoother if you
use the default values, though latency is a bit worse. it looks nicer
though.

@feature
This commit is contained in:
Carsten Haitzler 2015-09-11 23:24:51 +09:00
parent 9d5b9872fb
commit 33e55d512d
8 changed files with 313 additions and 83 deletions

View File

@ -20,12 +20,9 @@ group "Elm_Config" struct {
value "zoom_friction" double: 0.5;
value "thumbscroll_border_friction" double: 0.5;
value "thumbscroll_sensitivity_friction" double: 0.25;
value "scroll_smooth_start_enable" uchar: 0;
value "scroll_smooth_time_interval" double: 0.0;
value "scroll_smooth_amount" double: 0.0;
value "scroll_smooth_history_weight" double: 0.1;
value "scroll_smooth_future_time" double: 0.0;
value "scroll_smooth_time_window" double: 0.01;
value "scroll_smooth_start_enable" uchar: 1;
value "scroll_smooth_amount" double: 1.0;
value "scroll_smooth_time_window" double: 0.15;
value "focus_autoscroll_mode" uchar: 0;
value "slider_indicator_visible_mode" int: 0;
value "scale" double: 1.0;

View File

@ -21,11 +21,8 @@ group "Elm_Config" struct {
value "thumbscroll_border_friction" double: 0.5;
value "thumbscroll_sensitivity_friction" double: 0.7;
value "scroll_smooth_start_enable" uchar: 1;
value "scroll_smooth_time_interval" double: 0;
value "scroll_smooth_amount" double: 1.0;
value "scroll_smooth_history_weight" double: 0.1;
value "scroll_smooth_future_time" double: 0.0;
value "scroll_smooth_time_window" double: 0.01;
value "scroll_smooth_time_window" double: 0.15;
value "focus_autoscroll_mode" uchar: 0;
value "slider_indicator_visible_mode" int: 0;
value "scale" double: 1.0;

View File

@ -20,12 +20,9 @@ group "Elm_Config" struct {
value "zoom_friction" double: 0.5;
value "thumbscroll_border_friction" double: 0.5;
value "thumbscroll_sensitivity_friction" double: 0.25;
value "scroll_smooth_start_enable" uchar: 0;
value "scroll_smooth_time_interval" double: 0.0;
value "scroll_smooth_amount" double: 0.0;
value "scroll_smooth_history_weight" double: 0.1;
value "scroll_smooth_future_time" double: 0.0;
value "scroll_smooth_time_window" double: 0.01;
value "scroll_smooth_start_enable" uchar: 1;
value "scroll_smooth_amount" double: 1.0;
value "scroll_smooth_time_window" double: 0.15;
value "focus_autoscroll_mode" uchar: 0;
value "slider_indicator_visible_mode" int: 0;
value "scale" double: 1.0;

View File

@ -165,6 +165,19 @@ sb_change(void *data EINA_UNUSED,
/*TODO: enable/disable subordinate sliders (make 'em support it 1st)*/
}
static void
ss_change(void *data EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
Eina_Bool val = elm_check_state_get(obj);
Eina_Bool ss = elm_config_scroll_thumbscroll_smooth_start_get();
if (val == ss) return;
elm_config_scroll_thumbscroll_smooth_start_set(val);
elm_config_all_flush();
}
static void
bf_round(void *data EINA_UNUSED,
Evas_Object *obj,
@ -265,6 +278,56 @@ zf_change(void *data EINA_UNUSED,
elm_config_all_flush();
}
static void
smooth_round(void *data EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
double val = elm_slider_value_get(obj);
double v;
v = ((double)((int)(val * 100.0))) / 100.0;
if (v != val) elm_slider_value_set(obj, v);
}
static void
smooth_change(void *data EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
double zf = elm_config_scroll_thumbscroll_smooth_amount_get();
double val = elm_slider_value_get(obj);
if (zf == val) return;
elm_config_scroll_thumbscroll_smooth_amount_set(val);
elm_config_all_flush();
}
static void
smooth_win_round(void *data EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
double val = elm_slider_value_get(obj);
double v;
v = ((double)((int)(val * 100.0))) / 100.0;
if (v != val) elm_slider_value_set(obj, v);
}
static void
smooth_win_change(void *data EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
double zf = elm_config_scroll_thumbscroll_smooth_time_window_get();
double val = elm_slider_value_get(obj);
if (zf == val) return;
elm_config_scroll_thumbscroll_smooth_time_window_set(val);
elm_config_all_flush();
}
static void
ts_change(void *data EINA_UNUSED,
Evas_Object *obj,
@ -1191,9 +1254,10 @@ _config_display_update(Evas_Object *win)
ts_min_friction, ts_friction_standard, ts_border_friction,
ts_sensitivity_friction, ts_acceleration_threshold,
ts_acceleration_time_limit, ts_acceleration_weight, page_friction,
bring_in_friction, zoom_friction, transition_duration;
bring_in_friction, zoom_friction, transition_duration,
smooth_amount, smooth_time_window;
const char *curr_theme;
Eina_Bool s_bounce, ts;
Eina_Bool s_bounce, ts, smooth_start;
Elm_Theme *th;
int fs;
@ -1224,6 +1288,9 @@ _config_display_update(Evas_Object *win)
page_friction = elm_config_scroll_page_scroll_friction_get();
bring_in_friction = elm_config_scroll_bring_in_scroll_friction_get();
zoom_friction = elm_config_scroll_zoom_friction_get();
smooth_start = elm_config_scroll_thumbscroll_smooth_start_get();
smooth_amount = elm_config_scroll_thumbscroll_smooth_amount_get();
smooth_time_window = elm_config_scroll_thumbscroll_smooth_time_window_get();
/* gotta update root windows' atoms */
elm_slider_value_set(evas_object_data_get(win, "scale_slider"), scale);
@ -1288,6 +1355,15 @@ _config_display_update(Evas_Object *win)
"zoom_scroll_friction_slider"),
zoom_friction);
elm_check_state_set(evas_object_data_get(win, "scroll_smooth_start"),
smooth_start);
elm_slider_value_set(evas_object_data_get(win,
"scroll_smooth_amount"),
smooth_amount);
elm_slider_value_set(evas_object_data_get(win,
"scroll_smooth_time_window"),
smooth_time_window);
curr_theme = _elm_theme_current_get(elm_theme_get(NULL));
th = elm_theme_new();
@ -3355,7 +3431,7 @@ static void
_status_config_scrolling(Evas_Object *win,
Evas_Object *naviframe)
{
Evas_Object *lb, *pd, *bx, *sl, *sc;
Evas_Object *lb, *pd, *bx, *sl, *sc, *ck;
bx = elm_box_add(win);
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0);
@ -3440,6 +3516,55 @@ _status_config_scrolling(Evas_Object *win,
evas_object_smart_callback_add(sl, "changed", zf_round, NULL);
evas_object_smart_callback_add(sl, "delay,changed", zf_change, NULL);
/* Enable Scroll Bounce */
CHECK_ADD("Enable smooth start",
"Set whether scrollers start smoothly on thumb<br/>"
"scroll",
ss_change, NULL);
evas_object_data_set(win, "scroll_smooth_start", ck);
elm_check_state_set(ck, elm_config_scroll_thumbscroll_smooth_start_get());
/* Scroll Smooth Amount */
LABEL_FRAME_ADD("<hilight>Scroll Smooth Amount</>");
sl = elm_slider_add(win);
elm_object_tooltip_text_set(sl, "This is the amount smoothing to apply<br/>"
"to thumbscroll to avoid jerky input");
evas_object_data_set(win, "scroll_smooth_amount", sl);
evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5);
elm_slider_span_size_set(sl, 120);
elm_slider_unit_format_set(sl, "%1.2f");
elm_slider_indicator_format_set(sl, "%1.2f");
elm_slider_min_max_set(sl, 0.0, 1.0);
elm_slider_value_set(sl, elm_config_scroll_thumbscroll_smooth_amount_get());
elm_box_pack_end(bx, sl);
evas_object_show(sl);
evas_object_smart_callback_add(sl, "changed", smooth_round, NULL);
evas_object_smart_callback_add(sl, "delay,changed", smooth_change, NULL);
/* Scroll Smooth Time Window */
LABEL_FRAME_ADD("<hilight>Scroll Smooth Amount</>");
sl = elm_slider_add(win);
elm_object_tooltip_text_set(sl, "This is the amount smoothing to apply<br/>"
"to thumbscroll to avoid jerky input");
evas_object_data_set(win, "scroll_smooth_time_window", sl);
evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5);
elm_slider_span_size_set(sl, 120);
elm_slider_unit_format_set(sl, "%1.2f");
elm_slider_indicator_format_set(sl, "%1.2f");
elm_slider_min_max_set(sl, 0.0, 1.0);
elm_slider_value_set(sl, elm_config_scroll_thumbscroll_smooth_time_window_get());
elm_box_pack_end(bx, sl);
evas_object_show(sl);
evas_object_smart_callback_add(sl, "changed", smooth_win_round, NULL);
evas_object_smart_callback_add(sl, "delay,changed", smooth_win_change, NULL);
evas_object_data_set(win, "scrolling", sc);
elm_naviframe_item_simple_push(naviframe, sc);

View File

@ -343,10 +343,10 @@ _desc_init(void)
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_start_enable, T_UCHAR);
ELM_CONFIG_VAL(D, T, scroll_smooth_time_interval, T_DOUBLE);
// ELM_CONFIG_VAL(D, T, scroll_smooth_time_interval, T_DOUBLE); // not used anymore
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, scroll_smooth_history_weight, T_DOUBLE); // not used anymore
// ELM_CONFIG_VAL(D, T, scroll_smooth_future_time, T_DOUBLE); // not used anymore
ELM_CONFIG_VAL(D, T, scroll_smooth_time_window, T_DOUBLE);
ELM_CONFIG_VAL(D, T, scale, T_DOUBLE);
ELM_CONFIG_VAL(D, T, bgpixmap, T_INT);
@ -1373,12 +1373,12 @@ _config_load(void)
_elm_config->zoom_friction = 0.5;
_elm_config->thumbscroll_border_friction = 0.5;
_elm_config->thumbscroll_sensitivity_friction = 0.25; // magic number! just trial and error shows this makes it behave "nicer" and not run off at high speed all the time
_elm_config->scroll_smooth_start_enable = EINA_FALSE;
_elm_config->scroll_smooth_time_interval = 0.008;
_elm_config->scroll_smooth_start_enable = EINA_TRUE;
// _elm_config->scroll_smooth_time_interval = 0.008; // not used anymore
_elm_config->scroll_smooth_amount = 1.0;
_elm_config->scroll_smooth_history_weight = 0.3;
_elm_config->scroll_smooth_future_time = 0.0;
_elm_config->scroll_smooth_time_window = 0.2;
// _elm_config->scroll_smooth_history_weight = 0.3; // not used anymore
// _elm_config->scroll_smooth_future_time = 0.0; // not used anymore
_elm_config->scroll_smooth_time_window = 0.15;
_elm_config->scale = 1.0;
_elm_config->bgpixmap = 0;
_elm_config->compositing = 1;
@ -1930,14 +1930,14 @@ _env_get(void)
}
s = getenv("ELM_SCROLL_SMOOTH_START_ENABLE");
if (s) _elm_config->scroll_smooth_start_enable = !!atoi(s);
s = getenv("ELM_SCROLL_SMOOTH_TIME_INTERVAL");
if (s) _elm_config->scroll_smooth_time_interval = atof(s);
// s = getenv("ELM_SCROLL_SMOOTH_TIME_INTERVAL"); // not used anymore
// if (s) _elm_config->scroll_smooth_time_interval = atof(s); // not used anymore
s = getenv("ELM_SCROLL_SMOOTH_AMOUNT");
if (s) _elm_config->scroll_smooth_amount = _elm_atof(s);
s = getenv("ELM_SCROLL_SMOOTH_HISTORY_WEIGHT");
if (s) _elm_config->scroll_smooth_history_weight = _elm_atof(s);
s = getenv("ELM_SCROLL_SMOOTH_FUTURE_TIME");
if (s) _elm_config->scroll_smooth_future_time = _elm_atof(s);
// s = getenv("ELM_SCROLL_SMOOTH_HISTORY_WEIGHT"); // not used anymore
// if (s) _elm_config->scroll_smooth_history_weight = _elm_atof(s); // not used anymore
// s = getenv("ELM_SCROLL_SMOOTH_FUTURE_TIME"); // not used anymore
// if (s) _elm_config->scroll_smooth_future_time = _elm_atof(s); // not used anymore
s = getenv("ELM_SCROLL_SMOOTH_TIME_WINDOW");
if (s) _elm_config->scroll_smooth_time_window = _elm_atof(s);
s = getenv("ELM_FOCUS_AUTOSCROLL_MODE");
@ -2886,6 +2886,46 @@ elm_config_scroll_thumbscroll_sensitivity_friction_set(double friction)
_elm_config->thumbscroll_sensitivity_friction = friction;
}
EAPI Eina_Bool
elm_config_scroll_thumbscroll_smooth_start_get(void)
{
return _elm_config->scroll_smooth_start_enable;
}
EAPI void
elm_config_scroll_thumbscroll_smooth_start_set(Eina_Bool enable)
{
_elm_config->scroll_smooth_start_enable = enable;
}
EAPI void
elm_config_scroll_thumbscroll_smooth_amount_set(double amount)
{
if (amount < 0.0) amount = 0.0;
if (amount > 1.0) amount = 1.0;
_elm_config->scroll_smooth_amount = amount;
}
EAPI double
elm_config_scroll_thumbscroll_smooth_amount_get(void)
{
return _elm_config->scroll_smooth_amount;
}
EAPI void
elm_config_scroll_thumbscroll_smooth_time_window_set(double amount)
{
if (amount < 0.0) amount = 0.0;
if (amount > 1.0) amount = 1.0;
_elm_config->scroll_smooth_time_window = amount;
}
EAPI double
elm_config_scroll_thumbscroll_smooth_time_window_get(void)
{
return _elm_config->scroll_smooth_time_window;
}
EAPI double
elm_config_scroll_thumbscroll_acceleration_threshold_get(void)
{

View File

@ -489,6 +489,90 @@ EAPI double elm_config_scroll_thumbscroll_sensitivity_friction_get(void);
*/
EAPI void elm_config_scroll_thumbscroll_sensitivity_friction_set(double friction);
/**
* Get the smooth start mode for scrolling with your finger
*
* @return smooth scroll flag
*
* @see elm_config_scroll_thumbscroll_smooth_start_set()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI Eina_Bool elm_config_scroll_thumbscroll_smooth_start_get(void);
/**
* Set the smooth start mode for scrolling with your finger
*
* This enabled finger scrolling to scroll from the currunt point rather than
* jumping and playing catch-up to make start of scrolling look smoother once
* the finger or mouse goes past the threshold.
*
* @param enable The enabled state of the smooth scroller
*
* @see elm_config_scroll_thumbscroll_smooth_start_get()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI void elm_config_scroll_thumbscroll_smooth_start_set(Eina_Bool enable);
/**
* Get the amount of smoothing to apply to scrolling
*
* @return the amount of smoothing to apply from 0.0 to 1.0
*
* @see elm_config_scroll_thumbscroll_smooth_amount_set()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI double elm_config_scroll_thumbscroll_smooth_amount_get(void);
/**
* Set the amount of smoothing to apply to scrolling
*
* Scrolling with your finger can be smoothed out and the amount to smooth
* is determined by this parameter. 0.0 means to not smooth at all and
* 1.0 is to smoth as much as possible.
*
* @param the amount to smooth from 0.0 to 1.0 with 0.0 being none
*
* @see elm_config_thumbscroll_acceleration_threshold_set()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI void elm_config_scroll_thumbscroll_smooth_amount_set(double amount);
/**
* Get the time window to look back at for events for smoothing
*
* @return the time window in seconds (between 0.0 and 1.0)
*
* @see elm_config_scroll_thumbscroll_smooth_time_window_set()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI double elm_config_scroll_thumbscroll_smooth_time_window_get(void);
/**
* Set the time window to look back at for events for smoothing
*
* Scrolling with your finger can be smoothed out and the window of time
* to look at is determined by this config. The value is in seconds and
* is from 0.0 to 1.0
*
* @param the time window in seconds (between 0.0 and 1.0)
*
* @see elm_config_scroll_thumbscroll_smooth_time_window_get()
*
* @since 1.16
* @ingroup Scrolling
*/
EAPI void elm_config_scroll_thumbscroll_smooth_time_window_set(double amount);
/**
* Get the minimum speed of mouse cursor movement which will accelerate
* scrolling velocity after a mouse up event

View File

@ -2964,12 +2964,17 @@ _elm_scroll_hold_enterer(void *data)
fx = sid->down.hold_x;
fy = sid->down.hold_y;
// printf("%1.5f %i ",
// ecore_loop_time_get() - sid->down.dragged_began_timestamp,
// fy);
if (_elm_config->scroll_smooth_amount > 0.0)
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, t, tdiff, tnow, twin;
double xx, yy, tot;
struct
{
Evas_Coord x, y, dx, dy;
@ -2977,76 +2982,61 @@ _elm_scroll_hold_enterer(void *data)
} pos[60];
tdiff = sid->down.hist.est_timestamp_diff;
tnow = ecore_time_get() - tdiff;
tnow = ecore_loop_time_get();
t = tnow;
twin = _elm_config->scroll_smooth_time_window;
for (i = 0; i < 60; i++)
{
if (sid->down.history[i].timestamp >
sid->down.dragged_began_timestamp)
if ((sid->down.history[i].timestamp - tdiff) > tnow)
{
continue;
}
if ((sid->down.history[i].timestamp >
sid->down.dragged_began_timestamp) || (count == 0))
{
// oldest point is sd->down.history[i]
// newset is sd->down.history[0]
dt = t - sid->down.history[i].timestamp;
if (dt > twin)
{
i--;
count--;
break;
}
x = sid->down.history[i].x;
y = sid->down.history[i].y;
_elm_scroll_down_coord_eval(sid, &x, &y);
if (i == 0)
{
basex = x;
basey = y;
}
dt = t - sid->down.history[i].timestamp;
if ((dt > twin) && (count > 0)) break;
_elm_scroll_down_coord_eval(sid, &x, &y);
pos[i].x = x - basex;
pos[i].y = y - basey;
pos[i].t = sid->down.history[i].timestamp - sid->down.history[0].timestamp;
pos[i].t = sid->down.history[0].timestamp - sid->down.history[i].timestamp;
count++;
}
}
if (count >= 2)
if (count > 0)
{
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++)
xx = 0.0;
yy = 0.0;
tot = 0.0;
for (i = 0; i < count; 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;
double wt = (twin - pos[i].t) / twin;
xx += ((double)(pos[i].x)) * wt;
yy += ((double)(pos[i].y)) * wt;
tot += wt;
}
maxdt = pos[i].t;
dxsum /= (double)i;
dysum /= (double)i;
dtsum /= (double)i;
if (dtsum > 0)
if (tot > 0.0)
{
xsum /= (double)i;
ysum /= (double)i;
tadd = tnow - sid->down.history[0].timestamp + _elm_config->scroll_smooth_future_time;
tadd = tadd - (maxdt / 2);
#define WEIGHT(n, o, v) n = (((double)o * (1.0 - v)) + ((double)n * v))
WEIGHT(tadd, sid->down.hist.tadd, _elm_config->scroll_smooth_history_weight);
WEIGHT(dxsum, sid->down.hist.dxsum, _elm_config->scroll_smooth_history_weight);
WEIGHT(dysum, sid->down.hist.dysum, _elm_config->scroll_smooth_history_weight);
fx = basex + xsum + ((dxsum * tadd) / dtsum);
fy = basey + ysum + ((dysum * tadd) / dtsum);
sid->down.hist.tadd = tadd;
sid->down.hist.dxsum = dxsum;
sid->down.hist.dysum = dysum;
WEIGHT(fx, sid->down.hold_x, _elm_config->scroll_smooth_amount);
WEIGHT(fy, sid->down.hold_y, _elm_config->scroll_smooth_amount);
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);
}
}
}
// printf("%i\n", fy);
eo_do(sid->obj, elm_interface_scrollable_content_pos_get(&ox, &oy));
if (sid->down.dir_x)

View File

@ -204,10 +204,10 @@ struct _Elm_Config
double thumbscroll_border_friction;
double thumbscroll_sensitivity_friction;
unsigned char scroll_smooth_start_enable;
double scroll_smooth_time_interval;
// double scroll_smooth_time_interval;; // not used anymore
double scroll_smooth_amount;
double scroll_smooth_history_weight;
double scroll_smooth_future_time;
// double scroll_smooth_history_weight;; // not used anymore
// double scroll_smooth_future_time;; // not used anymore
double scroll_smooth_time_window;
double scale;
int bgpixmap;