summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-08-22 01:46:28 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-08-22 14:57:54 +0000
commitd1653bc4d89592f07206ad8f5b711fcf7d58a92d (patch)
treeb721d43277b8c3ebdd49aca524507c7b10bd053f
parent569b165cff2330c5c7dfd6b1aa175008729b4414 (diff)
downloadrockbox-d1653bc4d89592f07206ad8f5b711fcf7d58a92d.tar.gz
rockbox-d1653bc4d89592f07206ad8f5b711fcf7d58a92d.zip
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
-rw-r--r--apps/gui/bitmap/list.c57
-rw-r--r--apps/gui/list.c12
-rw-r--r--apps/gui/list.h6
3 files changed, 47 insertions, 28 deletions
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index db8e0504d7..ff0f5a29c1 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -50,7 +50,6 @@
50static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS]; 50static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS];
51 51
52#ifdef HAVE_TOUCHSCREEN 52#ifdef HAVE_TOUCHSCREEN
53static int y_offset;
54static bool hide_selection; 53static bool hide_selection;
55#endif 54#endif
56 55
@@ -170,12 +169,9 @@ void list_draw(struct screen *display, struct gui_synclist *list)
170 end = start + nb_lines; 169 end = start + nb_lines;
171 170
172#ifdef HAVE_TOUCHSCREEN 171#ifdef HAVE_TOUCHSCREEN
173 if (list->selected_item == 0 || (list->nb_items < nb_lines)) 172 int draw_offset = list_start_item * linedes.height - list->y_pos;
174 y_offset = 0; /* reset in case it's a new list */
175
176 int draw_offset = y_offset;
177 /* draw some extra items to not have empty lines at the top and bottom */ 173 /* draw some extra items to not have empty lines at the top and bottom */
178 if (y_offset > 0) 174 if (draw_offset > 0)
179 { 175 {
180 /* make it negative for more consistent apparence when switching 176 /* make it negative for more consistent apparence when switching
181 * directions */ 177 * directions */
@@ -183,7 +179,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
183 if (start > 0) 179 if (start > 0)
184 start--; 180 start--;
185 } 181 }
186 else if (y_offset < 0) 182 else if (draw_offset < 0)
187 end++; 183 end++;
188#else 184#else
189 #define draw_offset 0 185 #define draw_offset 0
@@ -367,7 +363,6 @@ static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
367 if (nb_lines < gui_list->nb_items) 363 if (nb_lines < gui_list->nb_items)
368 { 364 {
369 /* scrollbar scrolling is still line based */ 365 /* scrollbar scrolling is still line based */
370 y_offset = 0;
371 int scrollbar_size = nb_lines * gui_list->line_height[screen]; 366 int scrollbar_size = nb_lines * gui_list->line_height[screen];
372 int actual_y = y - list_text[screen].y; 367 int actual_y = y - list_text[screen].y;
373 int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size; 368 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)
379 start_item = gui_list->nb_items - nb_lines; 374 start_item = gui_list->nb_items - nb_lines;
380 375
381 gui_list->start_item[screen] = start_item; 376 gui_list->start_item[screen] = start_item;
377 gui_list->y_pos = start_item * gui_list->line_height[screen];
382 378
383 return ACTION_REDRAW; 379 return ACTION_REDRAW;
384 } 380 }
@@ -468,9 +464,11 @@ static void kinetic_force_stop(void)
468 464
469/* helper for gui/list.c to cancel scrolling if a normal button event comes 465/* helper for gui/list.c to cancel scrolling if a normal button event comes
470 * through dpad or keyboard or whatever */ 466 * through dpad or keyboard or whatever */
471void _gui_synclist_stop_kinetic_scrolling(void) 467void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list)
472{ 468{
473 y_offset = 0; 469 const enum screen_type screen = screens[SCREEN_MAIN].screen_type;
470 gui_list->y_pos = gui_list->start_item[screen] * gui_list->line_height[screen];
471
474 if (scroll_mode == SCROLL_KINETIC) 472 if (scroll_mode == SCROLL_KINETIC)
475 kinetic_force_stop(); 473 kinetic_force_stop();
476 scroll_mode = SCROLL_NONE; 474 scroll_mode = SCROLL_NONE;
@@ -512,22 +510,25 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
512 int new_start_item = -1; 510 int new_start_item = -1;
513 int line_diff = 0; 511 int line_diff = 0;
514 512
515 /* don't scroll at the edges of the list */ 513 /* Track whether we hit the end of the list for sake of kinetic scroll */
516 if ((old_start == 0 && difference > 0) 514 bool hit_end = true;
517 || (old_start == (gui_list->nb_items - nb_lines) && difference < 0))
518 {
519 y_offset = 0;
520 gui_list->start_item[screen] = old_start;
521 return scroll_mode != SCROLL_KINETIC; /* stop kinetic at the edges */
522 }
523 515
524 /* add up y_offset over time and translate to lines 516 /* Move the y position and clamp it (funny things happen otherwise...) */
525 * if scrolled enough */ 517 gui_list->y_pos -= difference;
526 y_offset += difference; 518 if(gui_list->y_pos < 0)
527 if (abs(y_offset) > line_height) 519 gui_list->y_pos = 0;
520 else if(gui_list->y_pos > (gui_list->nb_items - nb_lines) * line_height)
521 gui_list->y_pos = (gui_list->nb_items - nb_lines) * line_height;
522 else
523 hit_end = false;
524
525 /* Get the list y position. When pos_y differs by a line height or more,
526 * we need to scroll the list by adjusting the start item accordingly */
527 int cur_y = gui_list->start_item[screen] * line_height;
528 int diff_y = cur_y - gui_list->y_pos;
529 if (abs(diff_y) >= line_height)
528 { 530 {
529 line_diff = y_offset/line_height; 531 line_diff = diff_y/line_height;
530 y_offset -= line_diff * line_height;
531 } 532 }
532 533
533 if(line_diff != 0) 534 if(line_diff != 0)
@@ -548,7 +549,10 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
548 gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size); 549 gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size);
549 } 550 }
550 551
551 return true; 552 if(hit_end)
553 return scroll_mode != SCROLL_KINETIC;
554 else
555 return true;
552} 556}
553 557
554static int kinetic_callback(struct timeout *tmo) 558static int kinetic_callback(struct timeout *tmo)
@@ -729,7 +733,8 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
729 if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line)) 733 if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line))
730 { 734 {
731 /* selection needs to be corrected if items are only partially visible */ 735 /* selection needs to be corrected if items are only partially visible */
732 line = (adj_y - y_offset) / line_height; 736 int cur_y = list->start_item[screen] * line_height;
737 line = (adj_y - (cur_y - list->y_pos)) / line_height;
733 if (list_display_title(list, screen)) 738 if (list_display_title(list, screen))
734 line -= 1; /* adjust for the list title */ 739 line -= 1; /* adjust for the list title */
735 } 740 }
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 139dbaac18..13a850bd7b 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -152,6 +152,9 @@ void gui_synclist_init(struct gui_synclist * gui_list,
152 gui_list->callback_speak_item = NULL; 152 gui_list->callback_speak_item = NULL;
153 gui_list->nb_items = 0; 153 gui_list->nb_items = 0;
154 gui_list->selected_item = 0; 154 gui_list->selected_item = 0;
155#ifdef HAVE_TOUCHSCREEN
156 gui_list->y_pos = 0;
157#endif
155 FOR_NB_SCREENS(i) 158 FOR_NB_SCREENS(i)
156 { 159 {
157 gui_list->start_item[i] = 0; 160 gui_list->start_item[i] = 0;
@@ -282,6 +285,9 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
282 gui_list->start_item[screen] = bottom; 285 gui_list->start_item[screen] = bottom;
283 else 286 else
284 gui_list->start_item[screen] = new_start_item; 287 gui_list->start_item[screen] = new_start_item;
288#ifdef HAVE_TOUCHSCREEN
289 gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
290#endif
285} 291}
286 292
287static void edge_beep(struct gui_synclist * gui_list, bool wrap) 293static 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,
417 gui_list->selected_size); 423 gui_list->selected_size);
418 gui_list->selected_item = gui_list->start_item[i] + nb_lines; 424 gui_list->selected_item = gui_list->start_item[i] + nb_lines;
419 } 425 }
426
427#ifdef HAVE_TOUCHSCREEN
428 gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
429#endif
420 } 430 }
421 return; 431 return;
422 } 432 }
@@ -667,7 +677,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
667 action = *actionptr = gui_synclist_do_touchscreen(lists); 677 action = *actionptr = gui_synclist_do_touchscreen(lists);
668 else if (action > ACTION_TOUCHSCREEN_MODE) 678 else if (action > ACTION_TOUCHSCREEN_MODE)
669 /* cancel kinetic if we got a normal button event */ 679 /* cancel kinetic if we got a normal button event */
670 _gui_synclist_stop_kinetic_scrolling(); 680 _gui_synclist_stop_kinetic_scrolling(lists);
671#endif 681#endif
672 682
673 /* Disable the skin redraw callback */ 683 /* Disable the skin redraw callback */
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 3a613d0a67..64ff3e3fdd 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -118,6 +118,10 @@ struct gui_synclist
118 bool scroll_all; 118 bool scroll_all;
119 int nb_items; 119 int nb_items;
120 int selected_item; 120 int selected_item;
121#ifdef HAVE_TOUCHSCREEN
122 /* absolute Y coordinate, used for smooth scrolling */
123 int y_pos;
124#endif
121 int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */ 125 int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
122 /* the number of lines that are selected at the same time */ 126 /* the number of lines that are selected at the same time */
123 int selected_size; 127 int selected_size;
@@ -229,7 +233,7 @@ int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list);
229/* this needs to be fixed if we ever get more than 1 touchscreen on a target */ 233/* this needs to be fixed if we ever get more than 1 touchscreen on a target */
230extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list); 234extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list);
231/* only for private use in gui/list.c */ 235/* only for private use in gui/list.c */
232extern void _gui_synclist_stop_kinetic_scrolling(void); 236extern void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list);
233#endif 237#endif
234 238
235/* If the list has a pending postponed scheduled announcement, that 239/* If the list has a pending postponed scheduled announcement, that