mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-10 05:32:40 -05:00
touchscreen: fix smooth scrolling in lists
This fixes those annoying jumps that happen when you hit the end of a list while scrolling. Change-Id: I2e41111f9415dce1692b52a2600e7ce77c8f0291
This commit is contained in:
parent
569b165cff
commit
d1653bc4d8
3 changed files with 47 additions and 28 deletions
|
|
@ -50,7 +50,6 @@
|
||||||
static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS];
|
static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS];
|
||||||
|
|
||||||
#ifdef HAVE_TOUCHSCREEN
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
static int y_offset;
|
|
||||||
static bool hide_selection;
|
static bool hide_selection;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -170,12 +169,9 @@ void list_draw(struct screen *display, struct gui_synclist *list)
|
||||||
end = start + nb_lines;
|
end = start + nb_lines;
|
||||||
|
|
||||||
#ifdef HAVE_TOUCHSCREEN
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
if (list->selected_item == 0 || (list->nb_items < nb_lines))
|
int draw_offset = list_start_item * linedes.height - list->y_pos;
|
||||||
y_offset = 0; /* reset in case it's a new list */
|
|
||||||
|
|
||||||
int draw_offset = y_offset;
|
|
||||||
/* draw some extra items to not have empty lines at the top and bottom */
|
/* draw some extra items to not have empty lines at the top and bottom */
|
||||||
if (y_offset > 0)
|
if (draw_offset > 0)
|
||||||
{
|
{
|
||||||
/* make it negative for more consistent apparence when switching
|
/* make it negative for more consistent apparence when switching
|
||||||
* directions */
|
* directions */
|
||||||
|
|
@ -183,7 +179,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
|
||||||
if (start > 0)
|
if (start > 0)
|
||||||
start--;
|
start--;
|
||||||
}
|
}
|
||||||
else if (y_offset < 0)
|
else if (draw_offset < 0)
|
||||||
end++;
|
end++;
|
||||||
#else
|
#else
|
||||||
#define draw_offset 0
|
#define draw_offset 0
|
||||||
|
|
@ -367,7 +363,6 @@ static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
|
||||||
if (nb_lines < gui_list->nb_items)
|
if (nb_lines < gui_list->nb_items)
|
||||||
{
|
{
|
||||||
/* scrollbar scrolling is still line based */
|
/* scrollbar scrolling is still line based */
|
||||||
y_offset = 0;
|
|
||||||
int scrollbar_size = nb_lines * gui_list->line_height[screen];
|
int scrollbar_size = nb_lines * gui_list->line_height[screen];
|
||||||
int actual_y = y - list_text[screen].y;
|
int actual_y = y - list_text[screen].y;
|
||||||
int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size;
|
int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size;
|
||||||
|
|
@ -379,6 +374,7 @@ static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
|
||||||
start_item = gui_list->nb_items - nb_lines;
|
start_item = gui_list->nb_items - nb_lines;
|
||||||
|
|
||||||
gui_list->start_item[screen] = start_item;
|
gui_list->start_item[screen] = start_item;
|
||||||
|
gui_list->y_pos = start_item * gui_list->line_height[screen];
|
||||||
|
|
||||||
return ACTION_REDRAW;
|
return ACTION_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
@ -468,9 +464,11 @@ static void kinetic_force_stop(void)
|
||||||
|
|
||||||
/* helper for gui/list.c to cancel scrolling if a normal button event comes
|
/* helper for gui/list.c to cancel scrolling if a normal button event comes
|
||||||
* through dpad or keyboard or whatever */
|
* through dpad or keyboard or whatever */
|
||||||
void _gui_synclist_stop_kinetic_scrolling(void)
|
void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list)
|
||||||
{
|
{
|
||||||
y_offset = 0;
|
const enum screen_type screen = screens[SCREEN_MAIN].screen_type;
|
||||||
|
gui_list->y_pos = gui_list->start_item[screen] * gui_list->line_height[screen];
|
||||||
|
|
||||||
if (scroll_mode == SCROLL_KINETIC)
|
if (scroll_mode == SCROLL_KINETIC)
|
||||||
kinetic_force_stop();
|
kinetic_force_stop();
|
||||||
scroll_mode = SCROLL_NONE;
|
scroll_mode = SCROLL_NONE;
|
||||||
|
|
@ -512,22 +510,25 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
|
||||||
int new_start_item = -1;
|
int new_start_item = -1;
|
||||||
int line_diff = 0;
|
int line_diff = 0;
|
||||||
|
|
||||||
/* don't scroll at the edges of the list */
|
/* Track whether we hit the end of the list for sake of kinetic scroll */
|
||||||
if ((old_start == 0 && difference > 0)
|
bool hit_end = true;
|
||||||
|| (old_start == (gui_list->nb_items - nb_lines) && difference < 0))
|
|
||||||
{
|
|
||||||
y_offset = 0;
|
|
||||||
gui_list->start_item[screen] = old_start;
|
|
||||||
return scroll_mode != SCROLL_KINETIC; /* stop kinetic at the edges */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add up y_offset over time and translate to lines
|
/* Move the y position and clamp it (funny things happen otherwise...) */
|
||||||
* if scrolled enough */
|
gui_list->y_pos -= difference;
|
||||||
y_offset += difference;
|
if(gui_list->y_pos < 0)
|
||||||
if (abs(y_offset) > line_height)
|
gui_list->y_pos = 0;
|
||||||
|
else if(gui_list->y_pos > (gui_list->nb_items - nb_lines) * line_height)
|
||||||
|
gui_list->y_pos = (gui_list->nb_items - nb_lines) * line_height;
|
||||||
|
else
|
||||||
|
hit_end = false;
|
||||||
|
|
||||||
|
/* Get the list y position. When pos_y differs by a line height or more,
|
||||||
|
* we need to scroll the list by adjusting the start item accordingly */
|
||||||
|
int cur_y = gui_list->start_item[screen] * line_height;
|
||||||
|
int diff_y = cur_y - gui_list->y_pos;
|
||||||
|
if (abs(diff_y) >= line_height)
|
||||||
{
|
{
|
||||||
line_diff = y_offset/line_height;
|
line_diff = diff_y/line_height;
|
||||||
y_offset -= line_diff * line_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(line_diff != 0)
|
if(line_diff != 0)
|
||||||
|
|
@ -548,6 +549,9 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
|
||||||
gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size);
|
gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(hit_end)
|
||||||
|
return scroll_mode != SCROLL_KINETIC;
|
||||||
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -729,7 +733,8 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
|
||||||
if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line))
|
if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line))
|
||||||
{
|
{
|
||||||
/* selection needs to be corrected if items are only partially visible */
|
/* selection needs to be corrected if items are only partially visible */
|
||||||
line = (adj_y - y_offset) / line_height;
|
int cur_y = list->start_item[screen] * line_height;
|
||||||
|
line = (adj_y - (cur_y - list->y_pos)) / line_height;
|
||||||
if (list_display_title(list, screen))
|
if (list_display_title(list, screen))
|
||||||
line -= 1; /* adjust for the list title */
|
line -= 1; /* adjust for the list title */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,9 @@ void gui_synclist_init(struct gui_synclist * gui_list,
|
||||||
gui_list->callback_speak_item = NULL;
|
gui_list->callback_speak_item = NULL;
|
||||||
gui_list->nb_items = 0;
|
gui_list->nb_items = 0;
|
||||||
gui_list->selected_item = 0;
|
gui_list->selected_item = 0;
|
||||||
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
|
gui_list->y_pos = 0;
|
||||||
|
#endif
|
||||||
FOR_NB_SCREENS(i)
|
FOR_NB_SCREENS(i)
|
||||||
{
|
{
|
||||||
gui_list->start_item[i] = 0;
|
gui_list->start_item[i] = 0;
|
||||||
|
|
@ -282,6 +285,9 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
|
||||||
gui_list->start_item[screen] = bottom;
|
gui_list->start_item[screen] = bottom;
|
||||||
else
|
else
|
||||||
gui_list->start_item[screen] = new_start_item;
|
gui_list->start_item[screen] = new_start_item;
|
||||||
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
|
gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void edge_beep(struct gui_synclist * gui_list, bool wrap)
|
static void edge_beep(struct gui_synclist * gui_list, bool wrap)
|
||||||
|
|
@ -417,6 +423,10 @@ static void gui_list_select_at_offset(struct gui_synclist * gui_list,
|
||||||
gui_list->selected_size);
|
gui_list->selected_size);
|
||||||
gui_list->selected_item = gui_list->start_item[i] + nb_lines;
|
gui_list->selected_item = gui_list->start_item[i] + nb_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
|
gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -667,7 +677,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
|
||||||
action = *actionptr = gui_synclist_do_touchscreen(lists);
|
action = *actionptr = gui_synclist_do_touchscreen(lists);
|
||||||
else if (action > ACTION_TOUCHSCREEN_MODE)
|
else if (action > ACTION_TOUCHSCREEN_MODE)
|
||||||
/* cancel kinetic if we got a normal button event */
|
/* cancel kinetic if we got a normal button event */
|
||||||
_gui_synclist_stop_kinetic_scrolling();
|
_gui_synclist_stop_kinetic_scrolling(lists);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Disable the skin redraw callback */
|
/* Disable the skin redraw callback */
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,10 @@ struct gui_synclist
|
||||||
bool scroll_all;
|
bool scroll_all;
|
||||||
int nb_items;
|
int nb_items;
|
||||||
int selected_item;
|
int selected_item;
|
||||||
|
#ifdef HAVE_TOUCHSCREEN
|
||||||
|
/* absolute Y coordinate, used for smooth scrolling */
|
||||||
|
int y_pos;
|
||||||
|
#endif
|
||||||
int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
|
int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
|
||||||
/* the number of lines that are selected at the same time */
|
/* the number of lines that are selected at the same time */
|
||||||
int selected_size;
|
int selected_size;
|
||||||
|
|
@ -229,7 +233,7 @@ int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list);
|
||||||
/* this needs to be fixed if we ever get more than 1 touchscreen on a target */
|
/* this needs to be fixed if we ever get more than 1 touchscreen on a target */
|
||||||
extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list);
|
extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list);
|
||||||
/* only for private use in gui/list.c */
|
/* only for private use in gui/list.c */
|
||||||
extern void _gui_synclist_stop_kinetic_scrolling(void);
|
extern void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If the list has a pending postponed scheduled announcement, that
|
/* If the list has a pending postponed scheduled announcement, that
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue