summaryrefslogtreecommitdiff
path: root/apps/gui
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui')
-rw-r--r--apps/gui/list.c239
-rw-r--r--apps/gui/list.h5
2 files changed, 165 insertions, 79 deletions
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 448c7da7f0..f3a151ccc6 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -40,11 +40,17 @@
40#define SCROLL_LIMIT 2 40#define SCROLL_LIMIT 2
41#endif 41#endif
42 42
43/* The minimum number of pending button events in queue before starting
44 * to limit list drawing interval.
45 */
46#define FRAMEDROP_TRIGGER 6
47
43#ifdef HAVE_LCD_BITMAP 48#ifdef HAVE_LCD_BITMAP
44static int offset_step = 16; /* pixels per screen scroll step */ 49static int offset_step = 16; /* pixels per screen scroll step */
45/* should lines scroll out of the screen */ 50/* should lines scroll out of the screen */
46static bool offset_out_of_view = false; 51static bool offset_out_of_view = false;
47#endif 52#endif
53static struct gui_list* last_list_displayed[NB_SCREENS];
48 54
49#define SHOW_LIST_TITLE ((gui_list->title != NULL) && \ 55#define SHOW_LIST_TITLE ((gui_list->title != NULL) && \
50 (gui_list->display->nb_lines > 1)) 56 (gui_list->display->nb_lines > 1))
@@ -86,6 +92,9 @@ static void gui_list_init(struct gui_list * gui_list,
86 gui_list->title = NULL; 92 gui_list->title = NULL;
87 gui_list->title_width = 0; 93 gui_list->title_width = 0;
88 gui_list->title_icon = NOICON; 94 gui_list->title_icon = NOICON;
95
96 gui_list->last_displayed_selected_item = -1 ;
97 gui_list->last_displayed_start_item = -1 ;
89} 98}
90 99
91/* 100/*
@@ -162,7 +171,7 @@ static void gui_list_put_selection_in_screen(struct gui_list * gui_list,
162 if(put_from_end) 171 if(put_from_end)
163 { 172 {
164 int list_end = gui_list->selected_item + SCROLL_LIMIT; 173 int list_end = gui_list->selected_item + SCROLL_LIMIT;
165 174
166 if(list_end-1 == gui_list->nb_items) 175 if(list_end-1 == gui_list->nb_items)
167 list_end--; 176 list_end--;
168 if(list_end > gui_list->nb_items) 177 if(list_end > gui_list->nb_items)
@@ -186,7 +195,7 @@ static int gui_list_get_item_offset(struct gui_list * gui_list, int item_width,
186{ 195{
187 struct screen * display=gui_list->display; 196 struct screen * display=gui_list->display;
188 int item_offset; 197 int item_offset;
189 198
190 if (offset_out_of_view) 199 if (offset_out_of_view)
191 { 200 {
192 item_offset = gui_list->offset_position; 201 item_offset = gui_list->offset_position;
@@ -201,7 +210,7 @@ static int gui_list_get_item_offset(struct gui_list * gui_list, int item_width,
201 else 210 else
202 { 211 {
203 /* if text got out of view */ 212 /* if text got out of view */
204 if (gui_list->offset_position > 213 if (gui_list->offset_position >
205 item_width - (display->width - text_pos)) 214 item_width - (display->width - text_pos))
206 item_offset = item_width - (display->width - text_pos); 215 item_offset = item_width - (display->width - text_pos);
207 else 216 else
@@ -217,7 +226,7 @@ static int gui_list_get_item_offset(struct gui_list * gui_list, int item_width,
217 * Draws the list on the attached screen 226 * Draws the list on the attached screen
218 * - gui_list : the list structure 227 * - gui_list : the list structure
219 */ 228 */
220static void gui_list_draw(struct gui_list * gui_list) 229static void gui_list_draw_smart(struct gui_list *gui_list)
221{ 230{
222 struct screen * display=gui_list->display; 231 struct screen * display=gui_list->display;
223 int cursor_pos = 0; 232 int cursor_pos = 0;
@@ -231,15 +240,51 @@ static void gui_list_draw(struct gui_list * gui_list)
231 int item_offset; 240 int item_offset;
232 int old_margin = display->getxmargin(); 241 int old_margin = display->getxmargin();
233#endif 242#endif
243 int start, end;
244 bool partial_draw = false;
234 245
235 gui_textarea_clear(display); 246 /* Speed up UI by drawing the changed contents only. */
247 if (gui_list == last_list_displayed[gui_list->display->screen_type]
248 && gui_list->last_displayed_start_item == gui_list->start_item
249 && gui_list->selected_size == 1)
250 {
251 partial_draw = true;
252 }
236 253
237 /* position and draw the list title & icon */
238 if (SHOW_LIST_TITLE) 254 if (SHOW_LIST_TITLE)
239 {
240 i = 1;
241 lines = display->nb_lines - 1; 255 lines = display->nb_lines - 1;
256 else
257 lines = display->nb_lines;
242 258
259 if (partial_draw)
260 {
261 end = gui_list->last_displayed_selected_item - gui_list->start_item;
262 i = gui_list->selected_item - gui_list->start_item;
263 if (i < end )
264 {
265 start = i;
266 end++;
267 }
268 else
269 {
270 start = end;
271 end = i + 1;
272 }
273 }
274 else
275 {
276 gui_textarea_clear(display);
277 start = 0;
278 end = display->nb_lines;
279 gui_list->last_displayed_start_item = gui_list->start_item;
280 last_list_displayed[gui_list->display->screen_type] = gui_list;
281 }
282
283 gui_list->last_displayed_selected_item = gui_list->selected_item;
284
285 /* position and draw the list title & icon */
286 if (SHOW_LIST_TITLE && !partial_draw)
287 {
243 if (gui_list->title_icon != NOICON && draw_icons) 288 if (gui_list->title_icon != NOICON && draw_icons)
244 { 289 {
245 screen_put_iconxy(display, 0, 0, gui_list->title_icon); 290 screen_put_iconxy(display, 0, 0, gui_list->title_icon);
@@ -266,11 +311,6 @@ static void gui_list_draw(struct gui_list * gui_list)
266 display->puts_scroll(text_pos, 0, gui_list->title); 311 display->puts_scroll(text_pos, 0, gui_list->title);
267#endif 312#endif
268 } 313 }
269 else
270 {
271 i = 0;
272 lines = display->nb_lines;
273 }
274 314
275 /* Adjust the position of icon, cursor, text for the list */ 315 /* Adjust the position of icon, cursor, text for the list */
276#ifdef HAVE_LCD_BITMAP 316#ifdef HAVE_LCD_BITMAP
@@ -280,7 +320,7 @@ static void gui_list_draw(struct gui_list * gui_list)
280 320
281 draw_scrollbar = (global_settings.scrollbar && 321 draw_scrollbar = (global_settings.scrollbar &&
282 lines < gui_list->nb_items); 322 lines < gui_list->nb_items);
283 323
284 draw_cursor = !global_settings.invert_cursor; 324 draw_cursor = !global_settings.invert_cursor;
285 text_pos = 0; /* here it's in pixels */ 325 text_pos = 0; /* here it's in pixels */
286 if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's 326 if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's
@@ -309,12 +349,19 @@ static void gui_list_draw(struct gui_list * gui_list)
309 screen_set_xmargin(display, text_pos); /* margin for list */ 349 screen_set_xmargin(display, text_pos); /* margin for list */
310#endif 350#endif
311 351
312 while (i < display->nb_lines) 352 if (SHOW_LIST_TITLE)
353 {
354 start++;
355 if (end < display->nb_lines)
356 end++;
357 }
358
359 for (i = start; i < end; i++)
313 { 360 {
314 unsigned char *s; 361 unsigned char *s;
315 char entry_buffer[MAX_PATH]; 362 char entry_buffer[MAX_PATH];
316 unsigned char *entry_name; 363 unsigned char *entry_name;
317 int current_item = gui_list->start_item + 364 int current_item = gui_list->start_item +
318 (SHOW_LIST_TITLE ? i-1 : i); 365 (SHOW_LIST_TITLE ? i-1 : i);
319 366
320 /* When there are less items to display than the 367 /* When there are less items to display than the
@@ -338,26 +385,33 @@ static void gui_list_draw(struct gui_list * gui_list)
338 {/* The selected item must be displayed scrolling */ 385 {/* The selected item must be displayed scrolling */
339#ifdef HAVE_LCD_BITMAP 386#ifdef HAVE_LCD_BITMAP
340 if (global_settings.invert_cursor)/* Display inverted-line-style*/ 387 if (global_settings.invert_cursor)/* Display inverted-line-style*/
388 {
341 /* if text got out of view */ 389 /* if text got out of view */
342 if (item_offset > item_width - (display->width - text_pos)) 390 if (item_offset > item_width - (display->width - text_pos))
391 {
343 /* don't scroll */ 392 /* don't scroll */
344 display->puts_style_offset(0, i, entry_name, 393 display->puts_style_offset(0, i, entry_name,
345 STYLE_INVERT,item_offset); 394 STYLE_INVERT,item_offset);
395 }
346 else 396 else
397 {
347 display->puts_scroll_style_offset(0, i, entry_name, 398 display->puts_scroll_style_offset(0, i, entry_name,
348 STYLE_INVERT, 399 STYLE_INVERT,
349 item_offset); 400 item_offset);
350 401 }
402 }
351 else /* if (!global_settings.invert_cursor) */ 403 else /* if (!global_settings.invert_cursor) */
404 {
352 if (item_offset > item_width - (display->width - text_pos)) 405 if (item_offset > item_width - (display->width - text_pos))
353 display->puts_offset(0, i, entry_name,item_offset); 406 display->puts_offset(0, i, entry_name,item_offset);
354 else 407 else
355 display->puts_scroll_offset(0, i, entry_name,item_offset); 408 display->puts_scroll_offset(0, i, entry_name,item_offset);
409 }
356#else 410#else
357 display->puts_scroll(text_pos, i, entry_name); 411 display->puts_scroll(text_pos, i, entry_name);
358#endif 412#endif
359 413
360 if(draw_cursor) 414 if (draw_cursor)
361 screen_put_cursorxy(display, cursor_pos, i, true); 415 screen_put_cursorxy(display, cursor_pos, i, true);
362 } 416 }
363 else 417 else
@@ -389,10 +443,9 @@ static void gui_list_draw(struct gui_list * gui_list)
389 if(icon) 443 if(icon)
390 screen_put_iconxy(display, icon_pos, i, icon); 444 screen_put_iconxy(display, icon_pos, i, icon);
391 } 445 }
392 i++;
393 } 446 }
394 447
395#ifdef HAVE_LCD_BITMAP 448#ifdef HAVE_LCD_BITMAP
396 /* Draw the scrollbar if needed*/ 449 /* Draw the scrollbar if needed*/
397 if(draw_scrollbar) 450 if(draw_scrollbar)
398 { 451 {
@@ -414,6 +467,15 @@ static void gui_list_draw(struct gui_list * gui_list)
414} 467}
415 468
416/* 469/*
470 * Force a full screen update.
471 */
472static void gui_list_draw(struct gui_list *gui_list)
473{
474 last_list_displayed[gui_list->display->screen_type] = NULL;
475 return gui_list_draw_smart(gui_list);
476}
477
478/*
417 * Selects an item in the list 479 * Selects an item in the list
418 * - gui_list : the list structure 480 * - gui_list : the list structure
419 * - item_number : the number of the item which will be selected 481 * - item_number : the number of the item which will be selected
@@ -426,6 +488,64 @@ static void gui_list_select_item(struct gui_list * gui_list, int item_number)
426 gui_list_put_selection_in_screen(gui_list, false); 488 gui_list_put_selection_in_screen(gui_list, false);
427} 489}
428 490
491static void scroll_down(struct gui_list *gui_list, bool paginate)
492{
493 int nb_lines = gui_list->display->nb_lines;
494 if (SHOW_LIST_TITLE)
495 nb_lines--;
496 int item_pos = gui_list->selected_item - gui_list->start_item;
497 int end_item = gui_list->start_item + nb_lines;
498
499 if (paginate)
500 {
501 /* When we reach the bottom of the list
502 * we jump to a new page if there are more items*/
503 if ((item_pos > nb_lines-gui_list->selected_size) &&
504 (end_item < gui_list->nb_items) )
505 {
506 gui_list->start_item = gui_list->selected_item;
507 if ( gui_list->start_item > gui_list->nb_items-nb_lines )
508 gui_list->start_item = gui_list->nb_items-nb_lines;
509 }
510 }
511 else
512 {
513 /* we start scrolling vertically when reaching the line
514 * (nb_lines-SCROLL_LIMIT)
515 * and when we are not in the last part of the list*/
516 if( (item_pos > nb_lines-SCROLL_LIMIT) &&
517 (end_item < gui_list->nb_items) )
518 {
519 gui_list->start_item+=gui_list->selected_size;
520 }
521 }
522}
523
524static void scroll_up(struct gui_list *gui_list, bool paginate)
525{
526 int item_pos = gui_list->selected_item - gui_list->start_item;
527 int nb_lines = gui_list->display->nb_lines;
528
529 if (paginate)
530 {
531 /* When we reach the top of the list
532 * we jump to a new page if there are more items*/
533 if( item_pos < 0)
534 gui_list->start_item = gui_list->selected_item - nb_lines +
535 gui_list->selected_size;
536 }
537 else
538 {
539 /* we start scrolling vertically when reaching the line
540 * (nb_lines-SCROLL_LIMIT)
541 * and when we are not in the last part of the list*/
542 if( item_pos < SCROLL_LIMIT-1)
543 gui_list->start_item-=gui_list->selected_size;
544 }
545 if( gui_list->start_item < 0 )
546 gui_list->start_item = 0;
547}
548
429/* 549/*
430 * Selects the next item in the list 550 * Selects the next item in the list
431 * (Item 0 gets selected if the end of the list is reached) 551 * (Item 0 gets selected if the end of the list is reached)
@@ -444,33 +564,7 @@ static void gui_list_select_next(struct gui_list * gui_list)
444 else 564 else
445 { 565 {
446 gui_list->selected_item+=gui_list->selected_size; 566 gui_list->selected_item+=gui_list->selected_size;
447 int nb_lines = gui_list->display->nb_lines; 567 scroll_down(gui_list, global_settings.scroll_paginated);
448 if (SHOW_LIST_TITLE)
449 nb_lines--;
450 int item_pos = gui_list->selected_item - gui_list->start_item;
451 int end_item = gui_list->start_item + nb_lines;
452
453 if (global_settings.scroll_paginated)
454 {
455 /* When we reach the bottom of the list
456 * we jump to a new page if there are more items*/
457 if( (item_pos > nb_lines-gui_list->selected_size) &&
458 (end_item < gui_list->nb_items) )
459 {
460 gui_list->start_item = gui_list->selected_item;
461 if ( gui_list->start_item > gui_list->nb_items-nb_lines )
462 gui_list->start_item = gui_list->nb_items-nb_lines;
463 }
464 }
465 else
466 {
467 /* we start scrolling vertically when reaching the line
468 * (nb_lines-SCROLL_LIMIT)
469 * and when we are not in the last part of the list*/
470 if( (item_pos > nb_lines-SCROLL_LIMIT) &&
471 (end_item < gui_list->nb_items) )
472 gui_list->start_item+=gui_list->selected_size;
473 }
474 } 568 }
475} 569}
476 570
@@ -481,7 +575,7 @@ static void gui_list_select_next(struct gui_list * gui_list)
481 */ 575 */
482static void gui_list_select_previous(struct gui_list * gui_list) 576static void gui_list_select_previous(struct gui_list * gui_list)
483{ 577{
484 int nb_lines = gui_list->display->nb_lines; 578 int nb_lines = gui_list->display->nb_lines;
485 if (SHOW_LIST_TITLE) 579 if (SHOW_LIST_TITLE)
486 nb_lines--; 580 nb_lines--;
487 if( gui_list->selected_item-gui_list->selected_size < 0 ) 581 if( gui_list->selected_item-gui_list->selected_size < 0 )
@@ -499,27 +593,8 @@ static void gui_list_select_previous(struct gui_list * gui_list)
499 } 593 }
500 else 594 else
501 { 595 {
502 int item_pos; 596 gui_list->selected_item -= gui_list->selected_size;
503 gui_list->selected_item-=gui_list->selected_size; 597 scroll_up(gui_list, global_settings.scroll_paginated);
504 item_pos = gui_list->selected_item - gui_list->start_item;
505 if (global_settings.scroll_paginated)
506 {
507 /* When we reach the top of the list
508 * we jump to a new page if there are more items*/
509 if( item_pos < 0)
510 gui_list->start_item = gui_list->selected_item - nb_lines +
511 gui_list->selected_size;
512 }
513 else
514 {
515 /* we start scrolling vertically when reaching the line
516 * (nb_lines-SCROLL_LIMIT)
517 * and when we are not in the last part of the list*/
518 if( item_pos < SCROLL_LIMIT-1)
519 gui_list->start_item-=gui_list->selected_size;
520 }
521 if( gui_list->start_item < 0 )
522 gui_list->start_item = 0;
523 } 598 }
524} 599}
525 600
@@ -623,9 +698,9 @@ static void gui_list_del_item(struct gui_list * gui_list)
623 */ 698 */
624static void gui_list_scroll_right(struct gui_list * gui_list) 699static void gui_list_scroll_right(struct gui_list * gui_list)
625{ 700{
626 /* FIXME: This is a fake right boundry limiter. there should be some 701 /* FIXME: This is a fake right boundry limiter. there should be some
627 * callback function to find the longest item on the list in pixels, 702 * callback function to find the longest item on the list in pixels,
628 * to stop the list from scrolling past that point */ 703 * to stop the list from scrolling past that point */
629 gui_list->offset_position+=offset_step; 704 gui_list->offset_position+=offset_step;
630 if (gui_list->offset_position > 1000) 705 if (gui_list->offset_position > 1000)
631 gui_list->offset_position = 1000; 706 gui_list->offset_position = 1000;
@@ -844,20 +919,26 @@ unsigned gui_synclist_do_button(struct gui_synclist * lists,
844 else gui_synclist_limit_scroll(lists, false); 919 else gui_synclist_limit_scroll(lists, false);
845 break; 920 break;
846 }; 921 };
847 922
848 switch(button) 923 switch(button)
849 { 924 {
850 case ACTION_STD_PREV: 925 case ACTION_STD_PREV:
851 case ACTION_STD_PREVREPEAT: 926 case ACTION_STD_PREVREPEAT:
852 gui_synclist_select_previous(lists); 927 gui_synclist_select_previous(lists);
853 gui_synclist_draw(lists); 928#ifndef SIMULATOR
929 if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
930#endif
931 gui_synclist_draw(lists);
854 yield(); 932 yield();
855 return ACTION_STD_PREV; 933 return ACTION_STD_PREV;
856 934
857 case ACTION_STD_NEXT: 935 case ACTION_STD_NEXT:
858 case ACTION_STD_NEXTREPEAT: 936 case ACTION_STD_NEXTREPEAT:
859 gui_synclist_select_next(lists); 937 gui_synclist_select_next(lists);
860 gui_synclist_draw(lists); 938#ifndef SIMULATOR
939 if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
940#endif
941 gui_synclist_draw(lists);
861 yield(); 942 yield();
862 return ACTION_STD_NEXT; 943 return ACTION_STD_NEXT;
863 944
diff --git a/apps/gui/list.h b/apps/gui/list.h
index f6e4a5d615..26f58761b6 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -91,6 +91,10 @@ struct gui_list
91 int selected_size; 91 int selected_size;
92 /* The data that will be passed to the callback function YOU implement */ 92 /* The data that will be passed to the callback function YOU implement */
93 void * data; 93 void * data;
94 /* These are used to calculate how much of the screen content we need
95 to redraw. */
96 int last_displayed_selected_item;
97 int last_displayed_start_item;
94 /* The optional title, set to NULL for none */ 98 /* The optional title, set to NULL for none */
95 char *title; 99 char *title;
96 /* Cache the width of the title string in pixels/characters */ 100 /* Cache the width of the title string in pixels/characters */
@@ -162,6 +166,7 @@ extern void gui_list_screen_scroll_out_of_view(bool enable);
162struct gui_synclist 166struct gui_synclist
163{ 167{
164 struct gui_list gui_list[NB_SCREENS]; 168 struct gui_list gui_list[NB_SCREENS];
169 struct gui_list *last_displayed[NB_SCREENS];
165}; 170};
166 171
167extern void gui_synclist_init( 172extern void gui_synclist_init(