1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Kevin Ferrare
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
33 #include "screen_access.h"
35 #include "scrollbar.h"
36 #include "statusbar.h"
44 #ifdef HAVE_LCD_CHARCELLS
45 #define SCROLL_LIMIT 1
47 #define SCROLL_LIMIT (nb_lines<3?1:2)
50 /* The minimum number of pending button events in queue before starting
51 * to limit list drawing interval.
53 #define FRAMEDROP_TRIGGER 6
55 #ifdef HAVE_LCD_BITMAP
56 static int offset_step
= 16; /* pixels per screen scroll step */
57 /* should lines scroll out of the screen */
58 static bool offset_out_of_view
= false;
60 static int force_list_reinit
= false;
62 static void gui_list_select_at_offset(struct gui_synclist
* gui_list
,
64 void list_draw(struct screen
*display
, struct viewport
*parent
, struct gui_synclist
*list
);
66 #ifdef HAVE_LCD_BITMAP
67 static struct viewport parent
[NB_SCREENS
];
68 void list_init_viewports(struct gui_synclist
*list
)
76 viewport_set_defaults(vp
, i
);
77 else if (list
->parent
[i
] == vp
)
79 viewport_set_defaults(vp
, i
);
80 list
->parent
[i
]->y
= gui_statusbar_height();
81 list
->parent
[i
]->height
= screens
[i
].lcdheight
- list
->parent
[i
]->y
;
85 if (list
&& (list
->parent
[0] == &parent
[0]) && global_settings
.buttonbar
)
86 list
->parent
[0]->height
-= BUTTONBAR_HEIGHT
;
88 force_list_reinit
= false;
91 static struct viewport parent
[NB_SCREENS
] =
101 void list_init_viewports(struct gui_synclist
*list
)
104 force_list_reinit
= false;
108 #ifdef HAVE_LCD_BITMAP
109 bool list_display_title(struct gui_synclist
*list
, struct viewport
*vp
)
111 return list
->title
!= NULL
&& viewport_get_nb_lines(vp
)>2;
114 #define list_display_title(l,v) false
118 * Initializes a scrolling list
119 * - gui_list : the list structure to initialize
120 * - callback_get_item_name : pointer to a function that associates a label
121 * to a given item number
122 * - data : extra data passed to the list callback
125 * - parent : the parent viewports to use. NULL means the full screen minus
126 * statusbar if enabled. NOTE: new screens should NOT set this to NULL.
128 void gui_synclist_init(struct gui_synclist
* gui_list
,
129 list_get_name callback_get_item_name
,
132 int selected_size
, struct viewport list_parent
[NB_SCREENS
]
136 gui_list
->callback_get_item_icon
= NULL
;
137 gui_list
->callback_get_item_name
= callback_get_item_name
;
138 gui_list
->callback_speak_item
= NULL
;
139 gui_list
->nb_items
= 0;
140 gui_list
->selected_item
= 0;
143 gui_list
->start_item
[i
] = 0;
144 gui_list
->last_displayed_start_item
[i
] = -1 ;
145 #ifdef HAVE_LCD_BITMAP
146 gui_list
->offset_position
[i
] = 0;
149 gui_list
->parent
[i
] = &list_parent
[i
];
152 gui_list
->parent
[i
] = &parent
[i
];
155 list_init_viewports(gui_list
);
156 gui_list
->limit_scroll
= false;
158 gui_list
->scroll_all
=scroll_all
;
159 gui_list
->selected_size
=selected_size
;
160 gui_list
->title
= NULL
;
161 gui_list
->title_width
= 0;
162 gui_list
->title_icon
= Icon_NOICON
;
164 gui_list
->scheduled_talk_tick
= gui_list
->last_talked_tick
= 0;
165 gui_list
->show_selection_marker
= true;
166 gui_list
->last_displayed_selected_item
= -1 ;
168 #ifdef HAVE_LCD_COLOR
169 gui_list
->title_color
= -1;
170 gui_list
->callback_get_item_color
= NULL
;
172 force_list_reinit
= true;
175 /* this toggles the selection bar or cursor */
176 void gui_synclist_hide_selection_marker(struct gui_synclist
* lists
, bool hide
)
178 lists
->show_selection_marker
= !hide
;
182 #ifdef HAVE_LCD_BITMAP
183 int list_title_height(struct gui_synclist
*list
, struct viewport
*vp
);
185 int gui_list_get_item_offset(struct gui_synclist
* gui_list
, int item_width
,
186 int text_pos
, struct screen
* display
, struct viewport
*vp
)
190 if (offset_out_of_view
)
192 item_offset
= gui_list
->offset_position
[display
->screen_type
];
196 /* if text is smaller then view */
197 if (item_width
<= vp
->width
- text_pos
)
203 /* if text got out of view */
204 if (gui_list
->offset_position
[display
->screen_type
] >
205 item_width
- (vp
->width
- text_pos
))
206 item_offset
= item_width
- (vp
->width
- text_pos
);
208 item_offset
= gui_list
->offset_position
[display
->screen_type
];
216 * Force a full screen update.
219 void gui_synclist_draw(struct gui_synclist
*gui_list
)
222 static struct gui_synclist
*last_list
= NULL
;
223 static int last_count
= -1;
224 #ifdef HAVE_BUTTONBAR
225 static bool last_buttonbar
= false;
227 if (force_list_reinit
||
228 #ifdef HAVE_BUTTONBAR
229 last_buttonbar
!= screens
[SCREEN_MAIN
].has_buttonbar
||
231 last_list
!= gui_list
||
232 gui_list
->nb_items
!= last_count
)
234 list_init_viewports(gui_list
);
235 gui_synclist_select_item(gui_list
, gui_list
->selected_item
);
237 #ifdef HAVE_BUTTONBAR
238 last_buttonbar
= screens
[SCREEN_MAIN
].has_buttonbar
;
240 last_count
= gui_list
->nb_items
;
241 last_list
= gui_list
;
244 list_draw(&screens
[i
], gui_list
->parent
[i
], gui_list
);
248 /* sets up the list so the selection is shown correctly on the screen */
249 static void gui_list_put_selection_on_screen(struct gui_synclist
* gui_list
,
250 enum screen_type screen
)
253 int difference
= gui_list
->selected_item
- gui_list
->start_item
[screen
];
254 struct viewport vp
= *gui_list
->parent
[screen
];
255 #ifdef HAVE_LCD_BITMAP
256 if (list_display_title(gui_list
, gui_list
->parent
[screen
]))
257 vp
.height
-= list_title_height(gui_list
,gui_list
->parent
[screen
]);
259 nb_lines
= viewport_get_nb_lines(&vp
);
261 /* edge case,, selected last item */
262 if (gui_list
->selected_item
== gui_list
->nb_items
-1)
264 gui_list
->start_item
[screen
] = MAX(0, gui_list
->nb_items
- nb_lines
);
266 /* selected first item */
267 else if (gui_list
->selected_item
== 0)
269 gui_list
->start_item
[screen
] = 0;
271 else if (difference
< SCROLL_LIMIT
) /* list moved up */
273 if (global_settings
.scroll_paginated
)
275 if (gui_list
->start_item
[screen
] > gui_list
->selected_item
)
276 gui_list
->start_item
[screen
] = (gui_list
->selected_item
/nb_lines
)*nb_lines
;
277 if (gui_list
->nb_items
<= nb_lines
)
278 gui_list
->start_item
[screen
] = 0;
282 int top_of_screen
= gui_list
->selected_item
- SCROLL_LIMIT
+ 1;
283 int temp
= MIN(top_of_screen
, gui_list
->nb_items
- nb_lines
);
284 gui_list
->start_item
[screen
] = MAX(0, temp
);
287 else if (difference
> nb_lines
- SCROLL_LIMIT
) /* list moved down */
289 int bottom
= gui_list
->nb_items
- nb_lines
;
290 /* always move the screen if selection isnt "visible" */
291 if (gui_list
->show_selection_marker
== false)
295 gui_list
->start_item
[screen
] = MIN(bottom
, gui_list
->start_item
[screen
] +
296 2*gui_list
->selected_size
);
298 else if (global_settings
.scroll_paginated
)
300 if (gui_list
->start_item
[screen
] + nb_lines
<= gui_list
->selected_item
)
301 gui_list
->start_item
[screen
] = MIN(bottom
, gui_list
->selected_item
);
305 int top_of_screen
= gui_list
->selected_item
+ SCROLL_LIMIT
- nb_lines
;
306 int temp
= MAX(0, top_of_screen
);
307 gui_list
->start_item
[screen
] = MIN(bottom
, temp
);
312 * Selects an item in the list
313 * - gui_list : the list structure
314 * - item_number : the number of the item which will be selected
316 void gui_synclist_select_item(struct gui_synclist
* gui_list
, int item_number
)
319 if( item_number
> gui_list
->nb_items
-1 || item_number
< 0 )
321 gui_list
->selected_item
= item_number
;
323 gui_list_put_selection_on_screen(gui_list
, i
);
326 static void gui_list_select_at_offset(struct gui_synclist
* gui_list
,
330 if (gui_list
->selected_size
> 1)
332 offset
*= gui_list
->selected_size
;
333 /* always select the first item of multi-line lists */
334 offset
-= offset
%gui_list
->selected_size
;
336 new_selection
= gui_list
->selected_item
+ offset
;
337 if (new_selection
>= gui_list
->nb_items
)
339 gui_list
->selected_item
= gui_list
->limit_scroll
?
340 gui_list
->nb_items
- gui_list
->selected_size
: 0;
342 else if (new_selection
< 0)
344 gui_list
->selected_item
= gui_list
->limit_scroll
?
345 0 : gui_list
->nb_items
- gui_list
->selected_size
;
347 else if (gui_list
->show_selection_marker
== false)
349 int i
, nb_lines
, screen_top
;
352 struct viewport vp
= *gui_list
->parent
[i
];
353 #ifdef HAVE_LCD_BITMAP
354 if (list_display_title(gui_list
, gui_list
->parent
[i
]))
355 vp
.height
-= list_title_height(gui_list
,gui_list
->parent
[i
]);
357 nb_lines
= viewport_get_nb_lines(&vp
);
360 screen_top
= gui_list
->nb_items
-nb_lines
;
363 gui_list
->start_item
[i
] = MIN(screen_top
, gui_list
->start_item
[i
] +
364 gui_list
->selected_size
);
365 gui_list
->selected_item
= gui_list
->start_item
[i
];
369 gui_list
->start_item
[i
] = MAX(0, gui_list
->start_item
[i
] -
370 gui_list
->selected_size
);
371 gui_list
->selected_item
= gui_list
->start_item
[i
] + nb_lines
;
376 else gui_list
->selected_item
+= offset
;
377 gui_synclist_select_item(gui_list
, gui_list
->selected_item
);
381 * Adds an item to the list (the callback will be asked for one more item)
382 * - gui_list : the list structure
384 void gui_synclist_add_item(struct gui_synclist
* gui_list
)
386 gui_list
->nb_items
++;
387 /* if only one item in the list, select it */
388 if(gui_list
->nb_items
== 1)
389 gui_list
->selected_item
= 0;
393 * Removes an item to the list (the callback will be asked for one less item)
394 * - gui_list : the list structure
396 void gui_synclist_del_item(struct gui_synclist
* gui_list
)
398 if(gui_list
->nb_items
> 0)
400 if (gui_list
->selected_item
== gui_list
->nb_items
-1)
401 gui_list
->selected_item
--;
402 gui_list
->nb_items
--;
403 gui_synclist_select_item(gui_list
, gui_list
->selected_item
);
407 #ifdef HAVE_LCD_BITMAP
408 void gui_list_screen_scroll_step(int ofs
)
413 void gui_list_screen_scroll_out_of_view(bool enable
)
416 offset_out_of_view
= true;
418 offset_out_of_view
= false;
420 #endif /* HAVE_LCD_BITMAP */
423 * Set the title and title icon of the list. Setting title to NULL disables
424 * both the title and icon. Use NOICON if there is no icon.
426 void gui_synclist_set_title(struct gui_synclist
* gui_list
,
427 char * title
, enum themable_icons icon
)
429 gui_list
->title
= title
;
430 gui_list
->title_icon
= icon
;
432 #ifdef HAVE_LCD_BITMAP
435 screens
[i
].getstringsize(title
, &gui_list
->title_width
, NULL
);
437 gui_list
->title_width
= strlen(title
);
440 gui_list
->title_width
= 0;
442 force_list_reinit
= true;
446 void gui_synclist_set_nb_items(struct gui_synclist
* lists
, int nb_items
)
448 #ifdef HAVE_LCD_BITMAP
451 lists
->nb_items
= nb_items
;
452 #ifdef HAVE_LCD_BITMAP
455 lists
->offset_position
[i
] = 0;
459 int gui_synclist_get_nb_items(struct gui_synclist
* lists
)
461 return lists
->nb_items
;
463 int gui_synclist_get_sel_pos(struct gui_synclist
* lists
)
465 return lists
->selected_item
;
467 void gui_synclist_set_icon_callback(struct gui_synclist
* lists
,
468 list_get_icon icon_callback
)
470 lists
->callback_get_item_icon
= icon_callback
;
473 void gui_synclist_set_voice_callback(struct gui_synclist
* lists
,
474 list_speak_item voice_callback
)
476 lists
->callback_speak_item
= voice_callback
;
479 #ifdef HAVE_LCD_COLOR
480 void gui_synclist_set_color_callback(struct gui_synclist
* lists
,
481 list_get_color color_callback
)
483 lists
->callback_get_item_color
= color_callback
;
487 static void gui_synclist_select_next_page(struct gui_synclist
* lists
,
488 enum screen_type screen
)
490 int nb_lines
= viewport_get_nb_lines(lists
->parent
[screen
]);
491 gui_list_select_at_offset(lists
, nb_lines
);
494 static void gui_synclist_select_previous_page(struct gui_synclist
* lists
,
495 enum screen_type screen
)
497 int nb_lines
= viewport_get_nb_lines(lists
->parent
[screen
]);
498 gui_list_select_at_offset(lists
, -nb_lines
);
501 void gui_synclist_limit_scroll(struct gui_synclist
* lists
, bool scroll
)
503 lists
->limit_scroll
= scroll
;
506 #ifdef HAVE_LCD_BITMAP
508 * Makes all the item in the list scroll by one step to the right.
509 * Should stop increasing the value when reaching the widest item value
512 static void gui_synclist_scroll_right(struct gui_synclist
* lists
)
517 /* FIXME: This is a fake right boundry limiter. there should be some
518 * callback function to find the longest item on the list in pixels,
519 * to stop the list from scrolling past that point */
520 lists
->offset_position
[i
]+=offset_step
;
521 if (lists
->offset_position
[i
] > 1000)
522 lists
->offset_position
[i
] = 1000;
527 * Makes all the item in the list scroll by one step to the left.
528 * stops at starting position.
530 static void gui_synclist_scroll_left(struct gui_synclist
* lists
)
535 lists
->offset_position
[i
]-=offset_step
;
536 if (lists
->offset_position
[i
] < 0)
537 lists
->offset_position
[i
] = 0;
540 #endif /* HAVE_LCD_BITMAP */
542 static void _gui_synclist_speak_item(struct gui_synclist
*lists
, bool repeating
)
544 list_speak_item
*cb
= lists
->callback_speak_item
;
545 if(cb
&& gui_synclist_get_nb_items(lists
) != 0)
547 int sel
= gui_synclist_get_sel_pos(lists
);
549 /* If we got a repeating key action, or we have just very
550 recently started talking, then we want to stay silent for a
551 while until things settle. Likewise if we already had a
552 pending scheduled announcement not yet due: we need to
555 || (lists
->scheduled_talk_tick
556 && TIME_BEFORE(current_tick
, lists
->scheduled_talk_tick
))
557 || (lists
->last_talked_tick
558 && TIME_BEFORE(current_tick
, lists
->last_talked_tick
+HZ
/4)))
560 lists
->scheduled_talk_tick
= current_tick
+HZ
/4;
563 lists
->scheduled_talk_tick
= 0; /* work done */
564 cb(sel
, lists
->data
);
565 lists
->last_talked_tick
= current_tick
;
569 void gui_synclist_speak_item(struct gui_synclist
* lists
)
570 /* The list user should call this to speak the first item on entering
571 the list, and whenever the list is updated. */
573 if(gui_synclist_get_nb_items(lists
) == 0 && global_settings
.talk_menu
)
574 talk_id(VOICE_EMPTY_LIST
, true);
575 else _gui_synclist_speak_item(lists
, false);
578 extern intptr_t get_action_data(void);
579 #if defined(HAVE_TOUCHSCREEN)
580 /* this needs to be fixed if we ever get more than 1 touchscreen on a target */
581 unsigned gui_synclist_do_touchscreen(struct gui_synclist
* gui_list
, struct viewport
*parent
);
584 bool gui_synclist_do_button(struct gui_synclist
* lists
,
585 unsigned *actionptr
, enum list_wrap wrap
)
587 int action
= *actionptr
;
588 #ifdef HAVE_LCD_BITMAP
589 static bool scrolling_left
= false;
592 #ifdef HAVE_SCROLLWHEEL
593 int next_item_modifier
= button_apply_acceleration(get_action_data());
595 static int next_item_modifier
= 1;
596 static int last_accel_tick
= 0;
598 if (global_settings
.list_accel_start_delay
)
600 int start_delay
= global_settings
.list_accel_start_delay
* (HZ
/2);
601 int accel_wait
= global_settings
.list_accel_wait
* HZ
/2;
603 if (get_action_statuscode(NULL
)&ACTION_REPEAT
)
605 if (!last_accel_tick
)
606 last_accel_tick
= current_tick
+ start_delay
;
607 else if (current_tick
>=
608 last_accel_tick
+ accel_wait
)
610 last_accel_tick
= current_tick
;
611 next_item_modifier
++;
614 else if (last_accel_tick
)
616 next_item_modifier
= 1;
622 #if defined(HAVE_TOUCHSCREEN)
623 if (action
== ACTION_TOUCHSCREEN
)
624 action
= *actionptr
= gui_synclist_do_touchscreen(lists
, &parent
[SCREEN_MAIN
]);
630 gui_synclist_limit_scroll(lists
, false);
633 gui_synclist_limit_scroll(lists
, true);
635 case LIST_WRAP_UNLESS_HELD
:
636 if (action
== ACTION_STD_PREVREPEAT
||
637 action
== ACTION_STD_NEXTREPEAT
||
638 action
== ACTION_LISTTREE_PGUP
||
639 action
== ACTION_LISTTREE_PGDOWN
)
640 gui_synclist_limit_scroll(lists
, true);
641 else gui_synclist_limit_scroll(lists
, false);
648 gui_synclist_draw(lists
);
651 #ifdef HAVE_VOLUME_IN_LIST
652 case ACTION_LIST_VOLUP
:
653 global_settings
.volume
+= 2;
654 /* up two because the falthrough brings it down one */
655 case ACTION_LIST_VOLDOWN
:
656 global_settings
.volume
--;
660 case ACTION_STD_PREV
:
661 case ACTION_STD_PREVREPEAT
:
662 gui_list_select_at_offset(lists
, -next_item_modifier
);
663 #ifndef HAVE_SCROLLWHEEL
664 if (button_queue_count() < FRAMEDROP_TRIGGER
)
666 gui_synclist_draw(lists
);
667 _gui_synclist_speak_item(lists
,
668 action
== ACTION_STD_PREVREPEAT
669 || next_item_modifier
>1);
671 *actionptr
= ACTION_STD_PREV
;
674 case ACTION_STD_NEXT
:
675 case ACTION_STD_NEXTREPEAT
:
676 gui_list_select_at_offset(lists
, next_item_modifier
);
677 #ifndef HAVE_SCROLLWHEEL
678 if (button_queue_count() < FRAMEDROP_TRIGGER
)
680 gui_synclist_draw(lists
);
681 _gui_synclist_speak_item(lists
,
682 action
== ACTION_STD_NEXTREPEAT
683 || next_item_modifier
>1);
685 *actionptr
= ACTION_STD_NEXT
;
688 #ifdef HAVE_LCD_BITMAP
689 case ACTION_TREE_PGRIGHT
:
690 gui_synclist_scroll_right(lists
);
691 gui_synclist_draw(lists
);
693 case ACTION_TREE_ROOT_INIT
:
694 /* After this button press ACTION_TREE_PGLEFT is allowed
695 to skip to root. ACTION_TREE_ROOT_INIT must be defined in the
696 keymaps as a repeated button press (the same as the repeated
697 ACTION_TREE_PGLEFT) with the pre condition being the non-repeated
699 if (lists
->offset_position
[0] == 0)
701 scrolling_left
= false;
702 *actionptr
= ACTION_STD_CANCEL
;
705 *actionptr
= ACTION_TREE_PGLEFT
;
706 case ACTION_TREE_PGLEFT
:
707 if(!scrolling_left
&& (lists
->offset_position
[0] == 0))
709 *actionptr
= ACTION_STD_CANCEL
;
712 gui_synclist_scroll_left(lists
);
713 gui_synclist_draw(lists
);
714 scrolling_left
= true; /* stop ACTION_TREE_PAGE_LEFT
718 /* for pgup / pgdown, we are obliged to have a different behaviour depending
719 * on the screen for which the user pressed the key since for example, remote
720 * and main screen doesn't have the same number of lines */
721 case ACTION_LISTTREE_PGUP
:
724 #ifdef HAVE_REMOTE_LCD
725 get_action_statuscode(NULL
)&ACTION_REMOTE
?
729 gui_synclist_select_previous_page(lists
, screen
);
730 gui_synclist_draw(lists
);
731 _gui_synclist_speak_item(lists
, false);
733 *actionptr
= ACTION_STD_NEXT
;
737 case ACTION_LISTTREE_PGDOWN
:
740 #ifdef HAVE_REMOTE_LCD
741 get_action_statuscode(NULL
)&ACTION_REMOTE
?
745 gui_synclist_select_next_page(lists
, screen
);
746 gui_synclist_draw(lists
);
747 _gui_synclist_speak_item(lists
, false);
749 *actionptr
= ACTION_STD_PREV
;
753 if(lists
->scheduled_talk_tick
754 && TIME_AFTER(current_tick
, lists
->scheduled_talk_tick
))
755 /* scheduled postponed item announcement is due */
756 _gui_synclist_speak_item(lists
, false);
760 int list_do_action_timeout(struct gui_synclist
*lists
, int timeout
)
761 /* Returns the lowest of timeout or the delay until a postponed
762 scheduled announcement is due (if any). */
764 if(lists
->scheduled_talk_tick
)
766 long delay
= lists
->scheduled_talk_tick
-current_tick
+1;
767 /* +1 because the trigger condition uses TIME_AFTER(), which
768 is implemented as strictly greater than. */
771 if(timeout
> delay
|| timeout
== TIMEOUT_BLOCK
)
777 bool list_do_action(int context
, int timeout
,
778 struct gui_synclist
*lists
, int *action
,
780 /* Combines the get_action() (with possibly overridden timeout) and
781 gui_synclist_do_button() calls. Returns the list action from
782 do_button, and places the action from get_action in *action. */
784 timeout
= list_do_action_timeout(lists
, timeout
);
785 *action
= get_action(context
, timeout
);
786 return gui_synclist_do_button(lists
, action
, wrap
);
789 bool gui_synclist_item_is_onscreen(struct gui_synclist
*lists
,
790 enum screen_type screen
, int item
)
792 struct viewport vp
= *lists
->parent
[screen
];
793 #ifdef HAVE_LCD_BITMAP
794 if (list_display_title(lists
, lists
->parent
[screen
]))
795 vp
.height
-= list_title_height(lists
, lists
->parent
[screen
]);
797 return item
<= (lists
->start_item
[screen
] + viewport_get_nb_lines(&vp
));
800 /* Simple use list implementation */
801 static int simplelist_line_count
= 0;
802 static char simplelist_text
[SIMPLELIST_MAX_LINES
][SIMPLELIST_MAX_LINELENGTH
];
803 /* set the amount of lines shown in the list */
804 void simplelist_set_line_count(int lines
)
807 simplelist_line_count
= 0;
808 else if (lines
>= SIMPLELIST_MAX_LINES
)
809 simplelist_line_count
= SIMPLELIST_MAX_LINES
;
811 simplelist_line_count
= lines
;
813 /* get the current amount of lines shown */
814 int simplelist_get_line_count(void)
816 return simplelist_line_count
;
818 /* add/edit a line in the list.
819 if line_number > number of lines shown it adds the line, else it edits the line */
820 void simplelist_addline(int line_number
, const char *fmt
, ...)
824 if (line_number
> simplelist_line_count
)
826 if (simplelist_line_count
< SIMPLELIST_MAX_LINES
)
827 line_number
= simplelist_line_count
++;
832 vsnprintf(simplelist_text
[line_number
], SIMPLELIST_MAX_LINELENGTH
, fmt
, ap
);
836 static char* simplelist_static_getname(int item
,
841 (void)data
; (void)buffer
; (void)buffer_len
;
842 return simplelist_text
[item
];
845 bool simplelist_show_list(struct simplelist_info
*info
)
847 struct gui_synclist lists
;
848 struct viewport vp
[NB_SCREENS
];
849 int action
, old_line_count
= simplelist_line_count
,i
;
850 char* (*getname
)(int item
, void * data
, char *buffer
, size_t buffer_len
);
851 int wrap
= LIST_WRAP_UNLESS_HELD
;
853 getname
= info
->get_name
;
855 getname
= simplelist_static_getname
;
858 viewport_set_defaults(&vp
[i
], i
);
860 gui_synclist_init(&lists
, getname
, info
->callback_data
,
861 info
->scroll_all
, info
->selection_size
, vp
);
864 gui_synclist_set_title(&lists
, info
->title
, NOICON
);
866 gui_synclist_set_icon_callback(&lists
, info
->get_icon
);
868 gui_synclist_set_voice_callback(&lists
, info
->get_talk
);
870 if (info
->hide_selection
)
872 gui_synclist_hide_selection_marker(&lists
, true);
873 wrap
= LIST_WRAP_OFF
;
876 if (info
->action_callback
)
877 info
->action_callback(ACTION_REDRAW
, &lists
);
879 if (info
->get_name
== NULL
)
880 gui_synclist_set_nb_items(&lists
, simplelist_line_count
*info
->selection_size
);
882 gui_synclist_set_nb_items(&lists
, info
->count
*info
->selection_size
);
884 gui_synclist_select_item(&lists
, info
->selection
);
886 gui_synclist_draw(&lists
);
887 gui_synclist_speak_item(&lists
);
891 gui_syncstatusbar_draw(&statusbars
, true);
892 list_do_action(CONTEXT_STD
, info
->timeout
,
893 &lists
, &action
, wrap
);
895 /* We must yield in this case or no other thread can run */
896 if (info
->timeout
== TIMEOUT_NOBLOCK
)
899 if (info
->action_callback
)
901 bool stdok
= action
==ACTION_STD_OK
;
902 action
= info
->action_callback(action
, &lists
);
903 if (stdok
&& action
== ACTION_STD_CANCEL
) /* callback asked us to exit */
905 info
->selection
= gui_synclist_get_sel_pos(&lists
);
909 if (info
->get_name
== NULL
)
910 gui_synclist_set_nb_items(&lists
, simplelist_line_count
*info
->selection_size
);
912 if (action
== ACTION_STD_CANCEL
)
914 info
->selection
= -1;
917 else if ((action
== ACTION_REDRAW
) ||
918 (old_line_count
!= simplelist_line_count
))
920 if (info
->get_name
== NULL
)
921 gui_synclist_set_nb_items(&lists
, simplelist_line_count
*info
->selection_size
);
922 gui_synclist_draw(&lists
);
923 old_line_count
= simplelist_line_count
;
925 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
932 void simplelist_info_init(struct simplelist_info
*info
, char* title
,
933 int count
, void* data
)
937 info
->selection_size
= 1;
938 info
->hide_selection
= false;
939 info
->scroll_all
= false;
940 info
->timeout
= HZ
/10;
942 info
->action_callback
= NULL
;
943 info
->get_icon
= NULL
;
944 info
->get_name
= NULL
;
945 info
->get_talk
= NULL
;
946 info
->callback_data
= data
;