summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-09-23 00:02:32 +0000
committerThomas Martitz <kugel@rockbox.org>2010-09-23 00:02:32 +0000
commitac08e6942a6d74f949a3c61414dc7267573cf17e (patch)
treefed5dd04babc30c1e6c4a67befbed451db88e93d /apps
parentb2872c616c3decf521c8424db3cfcf4e7b095865 (diff)
downloadrockbox-ac08e6942a6d74f949a3c61414dc7267573cf17e.tar.gz
rockbox-ac08e6942a6d74f949a3c61414dc7267573cf17e.zip
Touchscreen: Improve scrolling in absolute point mode.
* Scrolling is now done by wiping over the screen. There's no acceleration or kinetic scrolling yet though. But it works rather well (previously you held the edges of the list to scroll). * Improve scrollbar scrolling so that it keeps scrolling even if you leave the scrollbar area. * Hide selection during scrolling * Prevent accidental hitting of the list title (which means go back) during scrolling * Don't go into context menu after scrolling when leaving the screen on an item In general, it's very much like scrolling in native lists in Android, except there's no kinetic scrolling and everything is still line based, but with the feature that the scrollbar enables jumping around in the list and very fast scrolling. Thanks to Dustin Skoracki for his ideas and half of the code for this. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28145 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/gui/bitmap/list.c181
-rw-r--r--apps/gui/list.h5
2 files changed, 127 insertions, 59 deletions
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 87d7107950..d892bff22b 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -40,6 +40,7 @@
40#include "misc.h" 40#include "misc.h"
41#include "viewport.h" 41#include "viewport.h"
42#include "statusbar-skinned.h" 42#include "statusbar-skinned.h"
43#include "debug.h"
43 44
44#define ICON_PADDING 1 45#define ICON_PADDING 1
45 46
@@ -230,8 +231,10 @@ void list_draw(struct screen *display, struct gui_synclist *list)
230 } 231 }
231 } 232 }
232#endif 233#endif
233 if(i >= list->selected_item && i < list->selected_item 234 /* draw the selected line */
234 + list->selected_size && list->show_selection_marker) 235 if(!list->hide_selection && i >= list->selected_item
236 && i < list->selected_item + list->selected_size
237 && list->show_selection_marker)
235 {/* The selected item must be displayed scrolling */ 238 {/* The selected item must be displayed scrolling */
236 if (global_settings.cursor_style == 1 239 if (global_settings.cursor_style == 1
237#ifdef HAVE_REMOTE_LCD 240#ifdef HAVE_REMOTE_LCD
@@ -308,7 +311,20 @@ void list_draw(struct screen *display, struct gui_synclist *list)
308 311
309#if defined(HAVE_TOUCHSCREEN) 312#if defined(HAVE_TOUCHSCREEN)
310/* This needs to be fixed if we ever get more than 1 touchscreen on a target. */ 313/* This needs to be fixed if we ever get more than 1 touchscreen on a target. */
311static bool scrolling=false; 314static enum {
315 SCROLL_NONE, /* no scrolling */
316 SCROLL_BAR, /* scroll by using the scrollbar */
317 SCROLL_SWIPE, /* scroll by wiping over the screen */
318} scroll_mode;
319
320static bool released = false;
321
322/* Used for kinetic scrolling as we need to know the last position to
323 * recognize the scroll direction.
324 * This gets reset to 0 at the end of scrolling
325 */
326static int last_position=0;
327
312 328
313static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list, 329static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
314 int y) 330 int y)
@@ -318,8 +334,7 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
318 334
319 if (nb_lines < gui_list->nb_items) 335 if (nb_lines < gui_list->nb_items)
320 { 336 {
321 scrolling = true; 337 scroll_mode = SCROLL_BAR;
322
323 int scrollbar_size = nb_lines* 338 int scrollbar_size = nb_lines*
324 font_get(gui_list->parent[screen]->font)->height; 339 font_get(gui_list->parent[screen]->font)->height;
325 int actual_y = y - list_text[screen].y; 340 int actual_y = y - list_text[screen].y;
@@ -334,7 +349,6 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
334 start_item = gui_list->nb_items - nb_lines; 349 start_item = gui_list->nb_items - nb_lines;
335 350
336 gui_list->start_item[screen] = start_item; 351 gui_list->start_item[screen] = start_item;
337 gui_synclist_select_item(gui_list, new_selection);
338 352
339 return ACTION_REDRAW; 353 return ACTION_REDRAW;
340 } 354 }
@@ -342,16 +356,44 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
342 return ACTION_NONE; 356 return ACTION_NONE;
343} 357}
344 358
359/*
360 * returns the number of scrolled items since the last call
361 **/
362static int gui_synclist_touchscreen_scrolling(struct gui_synclist * gui_list, int position)
363{
364 const int screen = screens[SCREEN_MAIN].screen_type;
365 const int difference = position - last_position;
366 const int nb_lines = viewport_get_nb_lines(&list_text[screen]);
367 if(nb_lines < gui_list->nb_items && difference != 0) // only scroll if needed
368 {
369 int new_start_item;
370 new_start_item = gui_list->start_item[screen] - difference;
371 // check if new_start_item is bigger than list item count
372 if(new_start_item > gui_list->nb_items - nb_lines)
373 new_start_item = gui_list->nb_items - nb_lines;
374 // set new_start_item to 0 if it's negative
375 if(new_start_item < 0)
376 new_start_item = 0;
377 gui_list->start_item[screen] = new_start_item;
378 }
379 return difference;
380}
381
345unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list) 382unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
346{ 383{
347 short x, y; 384 short x, y;
348 const int button = action_get_touchscreen_press(&x, &y); 385 const int button = action_get_touchscreen_press(&x, &y);
349 int line;
350 const int screen = SCREEN_MAIN; 386 const int screen = SCREEN_MAIN;
351 const int list_start_item = gui_list->start_item[screen]; 387 const int list_start_item = gui_list->start_item[screen];
352 const struct viewport *list_text_vp = &list_text[screen]; 388 const struct viewport *list_text_vp = &list_text[screen];
353 int list_width = list_text_vp->width; 389 const bool old_released = released;
390 int line, list_width = list_text_vp->width;
391
392 released = (button&BUTTON_REL) != 0;
393 gui_list->hide_selection = (scroll_mode != SCROLL_NONE);
394
354 395
396
355 if (global_settings.scrollbar == SCROLLBAR_RIGHT) 397 if (global_settings.scrollbar == SCROLLBAR_RIGHT)
356 list_width += SCROLLBAR_WIDTH; 398 list_width += SCROLLBAR_WIDTH;
357 399
@@ -364,7 +406,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
364 /* make sure it is inside the UI viewport */ 406 /* make sure it is inside the UI viewport */
365 if (list_display_title(gui_list, screen) && 407 if (list_display_title(gui_list, screen) &&
366 viewport_point_within_vp(&title_text[screen], x, y) && 408 viewport_point_within_vp(&title_text[screen], x, y) &&
367 button == BUTTON_REL) 409 button == BUTTON_REL && scroll_mode == SCROLL_NONE)
368 return ACTION_STD_CANCEL; 410 return ACTION_STD_CANCEL;
369 411
370 if (x < list_text_vp->x) 412 if (x < list_text_vp->x)
@@ -385,9 +427,26 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
385 } 427 }
386 else 428 else
387 { 429 {
388 if (x > list_text_vp->x + list_text_vp->width && 430 int line_height = font_get(gui_list->parent[screen]->font)->height;
389 global_settings.scrollbar == SCROLLBAR_RIGHT) 431 /* add a small margin to prevent accidental selection */
432 int x_end = list_text_vp->x + list_text_vp->width - line_height;
433
434 /* conditions for scrollbar scrolling:
435 * * pen is on the scrollbar (x > x_end-scrollbar width)
436 * AND scrollbar is on the right (left case is handled above)
437 * OR * pen is in the somewhere else but we did scrollbar scrolling before
438 *
439 * scrollbar scrolling must end if the pen is released
440 * scrollbar scrolling must not happen if we're currently scrolling
441 * via swiping the screen
442 **/
443
444 if (!released && scroll_mode != SCROLL_SWIPE
445 && ((scroll_mode == SCROLL_BAR
446 || (x > x_end && global_settings.scrollbar == SCROLLBAR_RIGHT))))
447 {
390 return gui_synclist_touchscreen_scrollbar(gui_list, y); 448 return gui_synclist_touchscreen_scrollbar(gui_list, y);
449 }
391 450
392 /* |--------------------------------------------------------| 451 /* |--------------------------------------------------------|
393 * | Description of the touchscreen list interface: | 452 * | Description of the touchscreen list interface: |
@@ -403,10 +462,9 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
403 */ 462 */
404 if (y > list_text_vp->y || button & BUTTON_REPEAT) 463 if (y > list_text_vp->y || button & BUTTON_REPEAT)
405 { 464 {
406 int line_height, actual_y; 465 int actual_y;
407 466
408 actual_y = y - list_text_vp->y; 467 actual_y = y - list_text_vp->y;
409 line_height = font_get(gui_list->parent[screen]->font)->height;
410 line = actual_y / line_height; 468 line = actual_y / line_height;
411 469
412 /* Pressed below the list*/ 470 /* Pressed below the list*/
@@ -416,59 +474,66 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
416 /* Pressed a border */ 474 /* Pressed a border */
417 if(UNLIKELY(actual_y % line_height == 0)) 475 if(UNLIKELY(actual_y % line_height == 0))
418 return ACTION_NONE; 476 return ACTION_NONE;
419 477
420 if (line != (gui_list->selected_item - list_start_item) 478 if (released)
421 && button ^ BUTTON_REL)
422 {
423 if(button & BUTTON_REPEAT)
424 scrolling = true;
425
426 gui_synclist_select_item(gui_list, list_start_item + line);
427
428 return ACTION_REDRAW;
429 }
430
431 /* This has the same effect as the icons do when the scrollbar
432 is on the left (ie eliminate the chances an user enters/starts
433 an item when he wanted to use the scrollbar, due to touchscreen
434 dead zones)
435 */
436 if(global_settings.scrollbar == SCROLLBAR_RIGHT &&
437 x > list_text_vp->x + list_text_vp->width -
438 get_icon_width(SCREEN_MAIN))
439 return ACTION_NONE;
440
441 if (button == (BUTTON_REPEAT|BUTTON_REL))
442 { 479 {
443 if(!scrolling) 480 /* Pen was released anywhere on the screen */
481 last_position = 0;
482 if (scroll_mode == SCROLL_NONE)
444 { 483 {
445 /* Pen was hold on the same line as the 484 gui_synclist_select_item(gui_list, list_start_item + line);
446 * previously selected one 485 /* If BUTTON_REPEAT is set, then the pen was hold on
447 * => simulate long button press 486 * the same line for some time
448 */ 487 * -> context menu
449 return ACTION_STD_CONTEXT; 488 * otherwise,
489 * -> select
490 **/
491 if (button & BUTTON_REPEAT)
492 return ACTION_STD_CONTEXT;
493 return ACTION_STD_OK;
450 } 494 }
451 else 495 else
452 { 496 {
453 /* Pen was moved across several lines and then released on 497 /* we were scrolling
454 * this one 498 * -> reset scrolling but do nothing else */
455 * => do nothing 499 scroll_mode = SCROLL_NONE;
456 */
457 scrolling = false;
458 return ACTION_NONE; 500 return ACTION_NONE;
459 } 501 }
460 } 502 }
461 else if(button == BUTTON_REL &&
462 line == gui_list->selected_item - list_start_item)
463 {
464 /* Pen was released on either the same line as the previously
465 * selected one or an other one
466 * => simulate short press
467 */
468 return ACTION_STD_OK;
469 }
470 else 503 else
471 return ACTION_NONE; 504 { /* pen is on the screen */
505 int result = 0;
506 bool redraw = false;
507
508 /* beginning of list interaction denoted by release in
509 * the previous call */
510 if (old_released)
511 {
512 scroll_mode = SCROLL_NONE;
513 redraw = true;
514 /* don't draw the selection during scrolling */
515 gui_list->hide_selection = false;
516 }
517
518 /* select current item */
519 gui_synclist_select_item(gui_list, list_start_item+line);
520 if (last_position == 0)
521 last_position = line;
522 else
523 result = gui_synclist_touchscreen_scrolling(gui_list, line);
524
525 /* Start scrolling once the pen is moved without
526 * releasing it inbetween */
527 if (result)
528 {
529 redraw = true;
530 scroll_mode = SCROLL_SWIPE;
531 }
532
533 last_position = line;
534
535 return redraw ? ACTION_REDRAW:ACTION_NONE;
536 }
472 } 537 }
473 } 538 }
474 return ACTION_NONE; 539 return ACTION_NONE;
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 965a46bfc6..57ca912800 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -94,7 +94,10 @@ struct gui_synclist
94 /* wether the text of the whole items of the list have to be 94 /* wether the text of the whole items of the list have to be
95 * scrolled or only for the selected item */ 95 * scrolled or only for the selected item */
96 bool scroll_all; 96 bool scroll_all;
97 97 /*
98 * if true the selection bar will not be drawn
99 */
100 bool hide_selection;
98 int nb_items; 101 int nb_items;
99 int selected_item; 102 int selected_item;
100 int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */ 103 int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */