PP502x: Make RAM physical addresses uncached. Cache the flash ROM on targets with...
[Rockbox.git] / apps / gui / list.c
blob107ce5a71aa46ed3f3fc6336b91357e5fb181edf
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Kevin Ferrare
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include "lcd.h"
22 #include "font.h"
23 #include "button.h"
24 #include "sprintf.h"
25 #include "string.h"
26 #include "settings.h"
27 #include "kernel.h"
28 #include "system.h"
30 #include "action.h"
31 #include "screen_access.h"
32 #include "list.h"
33 #include "scrollbar.h"
34 #include "statusbar.h"
35 #include "textarea.h"
36 #include "lang.h"
37 #include "sound.h"
38 #include "misc.h"
40 #ifdef HAVE_LCD_CHARCELLS
41 #define SCROLL_LIMIT 1
42 #else
43 #define SCROLL_LIMIT (nb_lines<3?1:2)
44 #endif
46 /* The minimum number of pending button events in queue before starting
47 * to limit list drawing interval.
49 #define FRAMEDROP_TRIGGER 6
51 #ifdef HAVE_LCD_BITMAP
52 static int offset_step = 16; /* pixels per screen scroll step */
53 /* should lines scroll out of the screen */
54 static bool offset_out_of_view = false;
55 #endif
56 static struct gui_list* last_list_displayed[NB_SCREENS];
58 #define SHOW_LIST_TITLE ((gui_list->title != NULL) && \
59 (gui_list->display->nb_lines > 2))
61 static void gui_list_select_at_offset(struct gui_list * gui_list, int offset);
64 * Initializes a scrolling list
65 * - gui_list : the list structure to initialize
66 * - callback_get_item_name : pointer to a function that associates a label
67 * to a given item number
68 * - data : extra data passed to the list callback
69 * - scroll_all :
70 * - selected_size :
72 static void gui_list_init(struct gui_list * gui_list,
73 list_get_name callback_get_item_name,
74 void * data,
75 bool scroll_all,
76 int selected_size
79 gui_list->callback_get_item_icon = NULL;
80 gui_list->callback_get_item_name = callback_get_item_name;
81 gui_list->display = NULL;
82 gui_list_set_nb_items(gui_list, 0);
83 gui_list->selected_item = 0;
84 gui_list->start_item = 0;
85 gui_list->limit_scroll = false;
86 gui_list->data=data;
87 gui_list->cursor_flash_state=false;
88 #ifdef HAVE_LCD_BITMAP
89 gui_list->offset_position = 0;
90 #endif
91 gui_list->scroll_all=scroll_all;
92 gui_list->selected_size=selected_size;
93 gui_list->title = NULL;
94 gui_list->title_width = 0;
95 gui_list->title_icon = Icon_NOICON;
97 gui_list->last_displayed_selected_item = -1 ;
98 gui_list->last_displayed_start_item = -1 ;
99 gui_list->show_selection_marker = true;
101 #ifdef HAVE_LCD_COLOR
102 gui_list->title_color = -1;
103 gui_list->callback_get_item_color = NULL;
104 #endif
107 /* this toggles the selection bar or cursor */
108 void gui_synclist_hide_selection_marker(struct gui_synclist * lists, bool hide)
110 int i;
111 FOR_NB_SCREENS(i)
112 lists->gui_list[i].show_selection_marker = !hide;
116 * Attach the scrolling list to a screen
117 * (The previous screen attachement is lost)
118 * - gui_list : the list structure
119 * - display : the screen to attach
121 static void gui_list_set_display(struct gui_list * gui_list, struct screen * display)
123 if(gui_list->display != 0) /* we switched from a previous display */
124 gui_list->display->stop_scroll();
125 gui_list->display = display;
126 #ifdef HAVE_LCD_CHARCELLS
127 display->double_height(false);
128 #endif
129 gui_list_select_at_offset(gui_list, 0);
133 * One call on 2, the selected lune will either blink the cursor or
134 * invert/display normal the selected line
135 * - gui_list : the list structure
137 static void gui_list_flash(struct gui_list * gui_list)
139 struct screen * display=gui_list->display;
140 gui_list->cursor_flash_state=!gui_list->cursor_flash_state;
141 int selected_line=gui_list->selected_item-gui_list->start_item+SHOW_LIST_TITLE;
142 #ifdef HAVE_LCD_BITMAP
143 int line_ypos=display->getymargin()+display->char_height*selected_line;
144 if (global_settings.cursor_style)
146 int line_xpos=display->getxmargin();
147 display->set_drawmode(DRMODE_COMPLEMENT);
148 display->fillrect(line_xpos, line_ypos, display->width,
149 display->char_height);
150 display->set_drawmode(DRMODE_SOLID);
151 display->invertscroll(0, selected_line);
153 else
155 int cursor_xpos=(global_settings.scrollbar &&
156 display->nb_lines < gui_list->nb_items)?1:0;
157 screen_put_cursorxy(display, cursor_xpos, selected_line,
158 gui_list->cursor_flash_state);
160 display->update_rect(0, line_ypos,display->width,
161 display->char_height);
162 #else
163 screen_put_cursorxy(display, 0, selected_line,
164 gui_list->cursor_flash_state);
165 gui_textarea_update(display);
166 #endif
170 #ifdef HAVE_LCD_BITMAP
171 static int gui_list_get_item_offset(struct gui_list * gui_list, int item_width,
172 int text_pos)
174 struct screen * display=gui_list->display;
175 int item_offset;
177 if (offset_out_of_view)
179 item_offset = gui_list->offset_position;
181 else
183 /* if text is smaller then view */
184 if (item_width <= display->width - text_pos)
186 item_offset = 0;
188 else
190 /* if text got out of view */
191 if (gui_list->offset_position >
192 item_width - (display->width - text_pos))
193 item_offset = item_width - (display->width - text_pos);
194 else
195 item_offset = gui_list->offset_position;
199 return item_offset;
201 #endif
204 * Draws the list on the attached screen
205 * - gui_list : the list structure
207 static void gui_list_draw_smart(struct gui_list *gui_list)
209 struct screen * display=gui_list->display;
210 int text_pos;
211 bool draw_icons = (gui_list->callback_get_item_icon != NULL && global_settings.show_icons);
212 bool draw_cursor;
213 int i;
214 int lines;
215 static int last_lines[NB_SCREENS] = {0};
216 #ifdef HAVE_LCD_BITMAP
217 int item_offset;
218 int old_margin = display->getxmargin();
219 #endif
220 int start, end;
221 bool partial_draw = false;
223 #ifdef HAVE_LCD_BITMAP
224 display->setfont(FONT_UI);
225 gui_textarea_update_nblines(display);
226 #endif
227 /* Speed up UI by drawing the changed contents only. */
228 if (gui_list == last_list_displayed[gui_list->display->screen_type]
229 && gui_list->last_displayed_start_item == gui_list->start_item
230 && gui_list->selected_size == 1)
232 partial_draw = true;
235 lines = display->nb_lines - SHOW_LIST_TITLE;
236 if (last_lines[display->screen_type] != lines)
238 gui_list_select_at_offset(gui_list, 0);
239 last_lines[display->screen_type] = lines;
242 if (partial_draw)
244 end = gui_list->last_displayed_selected_item - gui_list->start_item;
245 i = gui_list->selected_item - gui_list->start_item;
246 if (i < end )
248 start = i;
249 end++;
251 else
253 start = end;
254 end = i + 1;
257 else
259 gui_textarea_clear(display);
260 start = 0;
261 end = display->nb_lines;
262 gui_list->last_displayed_start_item = gui_list->start_item;
263 last_list_displayed[gui_list->display->screen_type] = gui_list;
266 gui_list->last_displayed_selected_item = gui_list->selected_item;
268 /* position and draw the list title & icon */
269 if (SHOW_LIST_TITLE && !partial_draw)
271 if (gui_list->title_icon != NOICON && draw_icons)
273 screen_put_icon(display, 0, 0, gui_list->title_icon);
274 #ifdef HAVE_LCD_BITMAP
275 text_pos = get_icon_width(display->screen_type)+2; /* pixels */
276 #else
277 text_pos = 1; /* chars */
278 #endif
280 else
282 text_pos = 0;
285 #ifdef HAVE_LCD_BITMAP
286 int title_style = STYLE_DEFAULT;
287 #ifdef HAVE_LCD_COLOR
288 if (gui_list->title_color >= 0)
290 title_style |= STYLE_COLORED;
291 title_style |= gui_list->title_color;
293 #endif
294 screen_set_xmargin(display, text_pos); /* margin for title */
295 item_offset = gui_list_get_item_offset(gui_list, gui_list->title_width,
296 text_pos);
297 if (item_offset > gui_list->title_width - (display->width - text_pos))
298 display->puts_style_offset(0, 0, gui_list->title,
299 title_style, item_offset);
300 else
301 display->puts_scroll_style_offset(0, 0, gui_list->title,
302 title_style, item_offset);
303 #else
304 display->puts_scroll(text_pos, 0, gui_list->title);
305 #endif
308 /* Adjust the position of icon, cursor, text for the list */
309 #ifdef HAVE_LCD_BITMAP
310 gui_textarea_update_nblines(display);
311 bool draw_scrollbar;
313 draw_scrollbar = (global_settings.scrollbar &&
314 lines < gui_list->nb_items);
316 draw_cursor = !global_settings.cursor_style &&
317 gui_list->show_selection_marker;
318 text_pos = 0; /* here it's in pixels */
319 if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's
320 a title */
322 text_pos += SCROLLBAR_WIDTH;
324 if(draw_cursor)
325 text_pos += get_icon_width(display->screen_type) + 2;
327 if(draw_icons)
328 text_pos += get_icon_width(display->screen_type) + 2;
329 #else
330 draw_cursor = true;
331 if(draw_icons)
332 text_pos = 2; /* here it's in chars */
333 else
334 text_pos = 1;
335 #endif
337 #ifdef HAVE_LCD_BITMAP
338 screen_set_xmargin(display, text_pos); /* margin for list */
339 #endif
341 if (SHOW_LIST_TITLE)
343 start++;
344 if (end < display->nb_lines)
345 end++;
348 for (i = start; i < end; i++)
350 unsigned char *s;
351 char entry_buffer[MAX_PATH];
352 unsigned char *entry_name;
353 int current_item = gui_list->start_item +
354 (SHOW_LIST_TITLE ? i-1 : i);
356 /* When there are less items to display than the
357 * current available space on the screen, we stop*/
358 if(current_item >= gui_list->nb_items)
359 break;
360 s = gui_list->callback_get_item_name(current_item,
361 gui_list->data,
362 entry_buffer);
363 entry_name = P2STR(s);
365 #ifdef HAVE_LCD_BITMAP
366 int style = STYLE_DEFAULT;
367 /* position the string at the correct offset place */
368 int item_width,h;
369 display->getstringsize(entry_name, &item_width, &h);
370 item_offset = gui_list_get_item_offset(gui_list, item_width, text_pos);
371 #endif
373 #ifdef HAVE_LCD_COLOR
374 /* if the list has a color callback */
375 if (gui_list->callback_get_item_color)
377 int color = gui_list->callback_get_item_color(current_item,
378 gui_list->data);
379 /* if color selected */
380 if (color >= 0)
382 style |= STYLE_COLORED;
383 style |= color;
386 #endif
388 if(gui_list->show_selection_marker &&
389 current_item >= gui_list->selected_item &&
390 current_item < gui_list->selected_item + gui_list->selected_size)
391 {/* The selected item must be displayed scrolling */
392 #ifdef HAVE_LCD_BITMAP
393 if (global_settings.cursor_style == 1
394 #ifdef HAVE_REMOTE_LCD
395 || display->screen_type == SCREEN_REMOTE
396 #endif
399 /* Display inverted-line-style */
400 style |= STYLE_INVERT;
402 #ifdef HAVE_LCD_COLOR
403 else if (global_settings.cursor_style == 2)
405 /* Display colour line selector */
406 style |= STYLE_COLORBAR;
408 else if (global_settings.cursor_style == 3)
410 /* Display gradient line selector */
411 style = STYLE_GRADIENT;
413 /* Make the lcd driver know how many lines the gradient should
414 cover and only draw it for the first selected item. */
415 if (current_item == gui_list->selected_item)
416 style |= gui_list->selected_size & STYLE_COLOR_MASK;
418 #endif
419 else /* if (!global_settings.cursor_style) */
421 if (current_item % gui_list->selected_size != 0)
422 draw_cursor = false;
424 /* if the text is smaller than the viewport size */
425 if (item_offset > item_width - (display->width - text_pos))
427 /* don't scroll */
428 display->puts_style_offset(0, i, entry_name,
429 style, item_offset);
431 else
433 display->puts_scroll_style_offset(0, i, entry_name,
434 style, item_offset);
436 #else
437 display->puts_scroll(text_pos, i, entry_name);
438 #endif
440 if (draw_cursor)
442 screen_put_icon_with_offset(display, 0, i,
443 (draw_scrollbar || SHOW_LIST_TITLE)?
444 SCROLLBAR_WIDTH: 0,
445 0, Icon_Cursor);
448 else
449 {/* normal item */
450 if(gui_list->scroll_all)
452 #ifdef HAVE_LCD_BITMAP
453 display->puts_scroll_style_offset(0, i, entry_name,
454 style, item_offset);
455 #else
456 display->puts_scroll(text_pos, i, entry_name);
457 #endif
459 else
461 #ifdef HAVE_LCD_BITMAP
462 display->puts_style_offset(0, i, entry_name,
463 style, item_offset);
464 #else
465 display->puts(text_pos, i, entry_name);
466 #endif
469 /* Icons display */
470 if(draw_icons)
472 enum themable_icons icon;
473 icon = gui_list->callback_get_item_icon(current_item, gui_list->data);
474 if(icon > Icon_NOICON)
476 #ifdef HAVE_LCD_BITMAP
477 int x = draw_cursor?1:0;
478 int x_off = (draw_scrollbar || SHOW_LIST_TITLE) ? SCROLLBAR_WIDTH: 0;
479 screen_put_icon_with_offset(display, x, i,
480 x_off, 0, icon);
481 #else
482 screen_put_icon(display, 1, i, icon);
483 #endif
488 #ifdef HAVE_LCD_BITMAP
489 /* Draw the scrollbar if needed*/
490 if(draw_scrollbar)
492 int y_start = gui_textarea_get_ystart(display);
493 if (SHOW_LIST_TITLE)
494 y_start += display->char_height;
495 int scrollbar_y_end = display->char_height *
496 lines + y_start;
497 gui_scrollbar_draw(display, 0, y_start, SCROLLBAR_WIDTH-1,
498 scrollbar_y_end - y_start, gui_list->nb_items,
499 gui_list->start_item,
500 gui_list->start_item + lines, VERTICAL);
503 screen_set_xmargin(display, old_margin);
504 #endif
506 gui_textarea_update(display);
510 * Force a full screen update.
512 static void gui_list_draw(struct gui_list *gui_list)
514 last_list_displayed[gui_list->display->screen_type] = NULL;
515 return gui_list_draw_smart(gui_list);
519 * Selects an item in the list
520 * - gui_list : the list structure
521 * - item_number : the number of the item which will be selected
523 static void gui_list_select_item(struct gui_list * gui_list, int item_number)
525 if( item_number > gui_list->nb_items-1 || item_number < 0 )
526 return;
527 gui_list->selected_item = item_number;
528 gui_list_select_at_offset(gui_list, 0);
531 /* select an item above the current one */
532 static void gui_list_select_above(struct gui_list * gui_list,
533 int items, int nb_lines)
535 gui_list->selected_item -= items;
537 /* in bottom "3rd" of the screen, so dont move the start item.
538 by 3rd I mean above SCROLL_LIMIT lines above the end of the screen */
539 if (items && gui_list->start_item + SCROLL_LIMIT < gui_list->selected_item)
541 if (gui_list->show_selection_marker == false)
543 gui_list->start_item -= items;
544 if (gui_list->start_item < 0)
545 gui_list->start_item = 0;
547 return;
549 if (gui_list->selected_item < 0)
551 if(gui_list->limit_scroll)
553 gui_list->selected_item = 0;
554 gui_list->start_item = 0;
556 else
558 gui_list->selected_item += gui_list->nb_items;
559 if (global_settings.scroll_paginated)
561 gui_list->start_item = gui_list->nb_items - nb_lines;
565 if (gui_list->nb_items > nb_lines)
567 if (global_settings.scroll_paginated)
569 if (gui_list->start_item > gui_list->selected_item)
570 gui_list->start_item = MAX(0, gui_list->start_item - nb_lines);
572 else
574 int top_of_screen = gui_list->selected_item - SCROLL_LIMIT;
575 int temp = MIN(top_of_screen, gui_list->nb_items - nb_lines);
576 gui_list->start_item = MAX(0, temp);
579 else gui_list->start_item = 0;
580 if (gui_list->selected_size > 1)
582 if (gui_list->start_item + nb_lines == gui_list->selected_item)
583 gui_list->start_item++;
586 /* select an item below the current one */
587 static void gui_list_select_below(struct gui_list * gui_list,
588 int items, int nb_lines)
590 int bottom;
592 gui_list->selected_item += items;
593 bottom = gui_list->nb_items - nb_lines;
595 /* always move the screen if selection isnt "visible" */
596 if (items && gui_list->show_selection_marker == false)
598 if (bottom < 0)
599 bottom = 0;
600 gui_list->start_item = MIN(bottom, gui_list->start_item +
601 items);
602 return;
604 /* in top "3rd" of the screen, so dont move the start item */
605 if (items &&
606 (gui_list->start_item + nb_lines - SCROLL_LIMIT > gui_list->selected_item)
607 && (gui_list->selected_item < gui_list->nb_items))
609 if (gui_list->show_selection_marker == false)
611 if (bottom < 0)
612 bottom = 0;
613 gui_list->start_item = MIN(bottom,
614 gui_list->start_item + items);
616 return;
619 if (gui_list->selected_item >= gui_list->nb_items)
621 if(gui_list->limit_scroll)
623 gui_list->selected_item = gui_list->nb_items-gui_list->selected_size;
624 gui_list->start_item = MAX(0,gui_list->nb_items - nb_lines);
626 else
628 gui_list->selected_item = 0;
629 gui_list->start_item = 0;
631 return;
634 if (gui_list->nb_items > nb_lines)
636 if (global_settings.scroll_paginated)
638 if (gui_list->start_item + nb_lines <= gui_list->selected_item)
639 gui_list->start_item = MIN(bottom, gui_list->selected_item);
641 else
643 int top_of_screen = gui_list->selected_item + SCROLL_LIMIT - nb_lines;
644 int temp = MAX(0, top_of_screen);
645 gui_list->start_item = MIN(bottom, temp);
648 else gui_list->start_item = 0;
651 static void gui_list_select_at_offset(struct gui_list * gui_list, int offset)
653 /* do this here instead of in both select_above and select_below */
654 int nb_lines = gui_list->display->nb_lines;
655 if (SHOW_LIST_TITLE)
656 nb_lines--;
658 if (gui_list->selected_size > 1)
660 offset *= gui_list->selected_size;
661 /* always select the first item of multi-line lists */
662 offset -= offset%gui_list->selected_size;
664 if (offset == 0 && global_settings.scroll_paginated &&
665 (gui_list->nb_items > nb_lines))
667 int bottom = gui_list->nb_items - nb_lines;
668 gui_list->start_item = MIN(gui_list->selected_item, bottom);
670 else if (offset < 0)
671 gui_list_select_above(gui_list, -offset, nb_lines);
672 else
673 gui_list_select_below(gui_list, offset, nb_lines);
677 * Adds an item to the list (the callback will be asked for one more item)
678 * - gui_list : the list structure
680 static void gui_list_add_item(struct gui_list * gui_list)
682 gui_list->nb_items++;
683 /* if only one item in the list, select it */
684 if(gui_list->nb_items == 1)
685 gui_list->selected_item = 0;
689 * Removes an item to the list (the callback will be asked for one less item)
690 * - gui_list : the list structure
692 static void gui_list_del_item(struct gui_list * gui_list)
694 if(gui_list->nb_items > 0)
696 gui_textarea_update_nblines(gui_list->display);
697 int nb_lines = gui_list->display->nb_lines;
699 int dist_selected_from_end = gui_list->nb_items
700 - gui_list->selected_item - 1;
701 int dist_start_from_end = gui_list->nb_items
702 - gui_list->start_item - 1;
703 if(dist_selected_from_end == 0)
705 /* Oops we are removing the selected item,
706 select the previous one */
707 gui_list->selected_item--;
709 gui_list->nb_items--;
711 /* scroll the list if needed */
712 if( (dist_start_from_end < nb_lines) && (gui_list->start_item != 0) )
713 gui_list->start_item--;
717 #ifdef HAVE_LCD_BITMAP
720 * Makes all the item in the list scroll by one step to the right.
721 * Should stop increasing the value when reaching the widest item value
722 * in the list.
724 static void gui_list_scroll_right(struct gui_list * gui_list)
726 /* FIXME: This is a fake right boundry limiter. there should be some
727 * callback function to find the longest item on the list in pixels,
728 * to stop the list from scrolling past that point */
729 gui_list->offset_position+=offset_step;
730 if (gui_list->offset_position > 1000)
731 gui_list->offset_position = 1000;
735 * Makes all the item in the list scroll by one step to the left.
736 * stops at starting position.
738 static void gui_list_scroll_left(struct gui_list * gui_list)
740 gui_list->offset_position-=offset_step;
741 if (gui_list->offset_position < 0)
742 gui_list->offset_position = 0;
744 void gui_list_screen_scroll_step(int ofs)
746 offset_step = ofs;
749 void gui_list_screen_scroll_out_of_view(bool enable)
751 if (enable)
752 offset_out_of_view = true;
753 else
754 offset_out_of_view = false;
756 #endif /* HAVE_LCD_BITMAP */
759 * Set the title and title icon of the list. Setting title to NULL disables
760 * both the title and icon. Use NOICON if there is no icon.
762 static void gui_list_set_title(struct gui_list * gui_list,
763 char * title, enum themable_icons icon)
765 gui_list->title = title;
766 gui_list->title_icon = icon;
767 if (title) {
768 #ifdef HAVE_LCD_BITMAP
769 gui_list->display->getstringsize(title, &gui_list->title_width, NULL);
770 #else
771 gui_list->title_width = strlen(title);
772 #endif
773 } else {
774 gui_list->title_width = 0;
779 * Synchronized lists stuffs
781 void gui_synclist_init(
782 struct gui_synclist * lists,
783 list_get_name callback_get_item_name,
784 void * data,
785 bool scroll_all,
786 int selected_size
789 int i;
790 FOR_NB_SCREENS(i)
792 gui_list_init(&(lists->gui_list[i]),
793 callback_get_item_name,
794 data, scroll_all, selected_size);
795 gui_list_set_display(&(lists->gui_list[i]), &(screens[i]));
799 void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items)
801 int i;
802 FOR_NB_SCREENS(i)
804 gui_list_set_nb_items(&(lists->gui_list[i]), nb_items);
805 #ifdef HAVE_LCD_BITMAP
806 lists->gui_list[i].offset_position = 0;
807 #endif
810 int gui_synclist_get_nb_items(struct gui_synclist * lists)
812 return gui_list_get_nb_items(&((lists)->gui_list[0]));
814 int gui_synclist_get_sel_pos(struct gui_synclist * lists)
816 return gui_list_get_sel_pos(&((lists)->gui_list[0]));
818 void gui_synclist_set_icon_callback(struct gui_synclist * lists,
819 list_get_icon icon_callback)
821 int i;
822 FOR_NB_SCREENS(i)
824 gui_list_set_icon_callback(&(lists->gui_list[i]), icon_callback);
828 void gui_synclist_draw(struct gui_synclist * lists)
830 int i;
831 FOR_NB_SCREENS(i)
832 gui_list_draw(&(lists->gui_list[i]));
835 void gui_synclist_select_item(struct gui_synclist * lists, int item_number)
837 int i;
838 FOR_NB_SCREENS(i)
839 gui_list_select_item(&(lists->gui_list[i]), item_number);
842 static void gui_synclist_select_next_page(struct gui_synclist * lists,
843 enum screen_type screen)
845 int i;
846 FOR_NB_SCREENS(i)
847 gui_list_select_at_offset(&(lists->gui_list[i]),
848 screens[screen].nb_lines);
851 static void gui_synclist_select_previous_page(struct gui_synclist * lists,
852 enum screen_type screen)
854 int i;
855 FOR_NB_SCREENS(i)
856 gui_list_select_at_offset(&(lists->gui_list[i]),
857 -screens[screen].nb_lines);
860 void gui_synclist_add_item(struct gui_synclist * lists)
862 int i;
863 FOR_NB_SCREENS(i)
864 gui_list_add_item(&(lists->gui_list[i]));
867 void gui_synclist_del_item(struct gui_synclist * lists)
869 int i;
870 FOR_NB_SCREENS(i)
871 gui_list_del_item(&(lists->gui_list[i]));
874 void gui_synclist_limit_scroll(struct gui_synclist * lists, bool scroll)
876 int i;
877 FOR_NB_SCREENS(i)
878 gui_list_limit_scroll(&(lists->gui_list[i]), scroll);
881 void gui_synclist_set_title(struct gui_synclist * lists,
882 char * title, enum themable_icons icon)
884 int i;
885 FOR_NB_SCREENS(i)
886 gui_list_set_title(&(lists->gui_list[i]), title, icon);
889 void gui_synclist_flash(struct gui_synclist * lists)
891 int i;
892 FOR_NB_SCREENS(i)
893 gui_list_flash(&(lists->gui_list[i]));
896 #ifdef HAVE_LCD_BITMAP
897 static void gui_synclist_scroll_right(struct gui_synclist * lists)
899 int i;
900 FOR_NB_SCREENS(i)
901 gui_list_scroll_right(&(lists->gui_list[i]));
904 static void gui_synclist_scroll_left(struct gui_synclist * lists)
906 int i;
907 FOR_NB_SCREENS(i)
908 gui_list_scroll_left(&(lists->gui_list[i]));
910 #endif /* HAVE_LCD_BITMAP */
912 extern intptr_t get_action_data(void);
914 bool gui_synclist_do_button(struct gui_synclist * lists,
915 unsigned *actionptr, enum list_wrap wrap)
917 int action = *actionptr;
918 #ifdef HAVE_LCD_BITMAP
919 static bool scrolling_left = false;
920 #endif
921 int i;
923 #ifdef HAVE_SCROLLWHEEL
924 int next_item_modifier = button_apply_acceleration(get_action_data(),
925 WHEEL_ACCELERATION_FACTOR);
926 #else
927 static int next_item_modifier = 1;
928 static int last_accel_tick = 0;
930 if (global_settings.list_accel_start_delay)
932 int start_delay = global_settings.list_accel_start_delay * (HZ/2);
933 int accel_wait = global_settings.list_accel_wait * HZ/2;
935 if (get_action_statuscode(NULL)&ACTION_REPEAT)
937 if (!last_accel_tick)
938 last_accel_tick = current_tick + start_delay;
939 else if (current_tick >=
940 last_accel_tick + accel_wait)
942 last_accel_tick = current_tick;
943 next_item_modifier++;
946 else if (last_accel_tick)
948 next_item_modifier = 1;
949 last_accel_tick = 0;
952 #endif
954 switch (wrap)
956 case LIST_WRAP_ON:
957 gui_synclist_limit_scroll(lists, false);
958 break;
959 case LIST_WRAP_OFF:
960 gui_synclist_limit_scroll(lists, true);
961 break;
962 case LIST_WRAP_UNLESS_HELD:
963 if (action == ACTION_STD_PREVREPEAT ||
964 action == ACTION_STD_NEXTREPEAT ||
965 action == ACTION_LISTTREE_PGUP ||
966 action == ACTION_LISTTREE_PGDOWN)
967 gui_synclist_limit_scroll(lists, true);
968 else gui_synclist_limit_scroll(lists, false);
969 break;
972 switch (action)
974 #ifdef HAVE_VOLUME_IN_LIST
975 case ACTION_LIST_VOLUP:
976 global_settings.volume += 2;
977 /* up two because the falthrough brings it down one */
978 case ACTION_LIST_VOLDOWN:
979 global_settings.volume--;
980 setvol();
981 return true;
982 #endif
983 case ACTION_STD_PREV:
984 case ACTION_STD_PREVREPEAT:
985 FOR_NB_SCREENS(i)
986 gui_list_select_at_offset(&(lists->gui_list[i]), -next_item_modifier);
987 #ifndef HAVE_SCROLLWHEEL
988 if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
989 #endif
991 gui_synclist_draw(lists);
993 yield();
994 *actionptr = ACTION_STD_PREV;
995 return true;
997 case ACTION_STD_NEXT:
998 case ACTION_STD_NEXTREPEAT:
999 FOR_NB_SCREENS(i)
1000 gui_list_select_at_offset(&(lists->gui_list[i]), next_item_modifier);
1001 #ifndef HAVE_SCROLLWHEEL
1002 if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
1003 #endif
1005 gui_synclist_draw(lists);
1007 yield();
1008 *actionptr = ACTION_STD_NEXT;
1009 return true;
1011 #ifdef HAVE_LCD_BITMAP
1012 case ACTION_TREE_PGRIGHT:
1013 gui_synclist_scroll_right(lists);
1014 gui_synclist_draw(lists);
1015 return true;
1016 case ACTION_TREE_ROOT_INIT:
1017 /* After this button press ACTION_TREE_PGLEFT is allowed
1018 to skip to root. ACTION_TREE_ROOT_INIT must be defined in the
1019 keymaps as a repeated button press (the same as the repeated
1020 ACTION_TREE_PGLEFT) with the pre condition being the non-repeated
1021 button press */
1022 if (lists->gui_list[0].offset_position == 0)
1024 scrolling_left = false;
1025 *actionptr = ACTION_STD_CANCEL;
1026 return true;
1028 *actionptr = ACTION_TREE_PGLEFT;
1029 case ACTION_TREE_PGLEFT:
1030 if(!scrolling_left && (lists->gui_list[0].offset_position == 0))
1032 *actionptr = ACTION_STD_CANCEL;
1033 return false;
1035 gui_synclist_scroll_left(lists);
1036 gui_synclist_draw(lists);
1037 scrolling_left = true; /* stop ACTION_TREE_PAGE_LEFT
1038 skipping to root */
1039 return true;
1040 #endif
1042 /* for pgup / pgdown, we are obliged to have a different behaviour depending
1043 * on the screen for which the user pressed the key since for example, remote
1044 * and main screen doesn't have the same number of lines */
1045 case ACTION_LISTTREE_PGUP:
1047 int screen =
1048 #ifdef HAVE_REMOTE_LCD
1049 get_action_statuscode(NULL)&ACTION_REMOTE ?
1050 SCREEN_REMOTE :
1051 #endif
1052 SCREEN_MAIN;
1053 gui_synclist_select_previous_page(lists, screen);
1054 gui_synclist_draw(lists);
1055 yield();
1056 *actionptr = ACTION_STD_NEXT;
1058 return true;
1060 case ACTION_LISTTREE_PGDOWN:
1062 int screen =
1063 #ifdef HAVE_REMOTE_LCD
1064 get_action_statuscode(NULL)&ACTION_REMOTE ?
1065 SCREEN_REMOTE :
1066 #endif
1067 SCREEN_MAIN;
1068 gui_synclist_select_next_page(lists, screen);
1069 gui_synclist_draw(lists);
1070 yield();
1071 *actionptr = ACTION_STD_PREV;
1073 return true;
1075 return false;