1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
30 #include "screen_access.h"
32 #include "scrollbar.h"
33 #include "statusbar.h"
36 #ifdef HAVE_LCD_CHARCELLS
37 #define SCROLL_LIMIT 1
39 #define SCROLL_LIMIT 2
42 #ifdef HAVE_LCD_BITMAP
43 static int offset_step
= 16; /* pixels per screen scroll step */
44 /* should lines scroll out of the screen */
45 static bool offset_out_of_view
= false;
50 void gui_list_init(struct gui_list
* gui_list
,
51 list_get_name callback_get_item_name
,
57 gui_list
->callback_get_item_icon
= NULL
;
58 gui_list
->callback_get_item_name
= callback_get_item_name
;
59 gui_list
->display
= NULL
;
60 gui_list_set_nb_items(gui_list
, 0);
61 gui_list
->selected_item
= 0;
62 gui_list
->start_item
= 0;
63 gui_list
->limit_scroll
= false;
65 gui_list
->cursor_flash_state
=false;
66 #ifdef HAVE_LCD_BITMAP
67 gui_list
->offset_position
= 0;
69 gui_list
->scroll_all
=scroll_all
;
70 gui_list
->selected_size
=selected_size
;
71 gui_list
->title
= NULL
;
72 gui_list
->title_width
= 0;
73 gui_list
->title_icon
= NOICON
;
76 void gui_list_set_display(struct gui_list
* gui_list
, struct screen
* display
)
78 if(gui_list
->display
!= 0) /* we switched from a previous display */
79 gui_list
->display
->stop_scroll();
80 gui_list
->display
= display
;
81 #ifdef HAVE_LCD_CHARCELLS
82 display
->double_height(false);
84 gui_list_put_selection_in_screen(gui_list
, false);
87 void gui_list_flash(struct gui_list
* gui_list
)
89 struct screen
* display
=gui_list
->display
;
90 gui_list
->cursor_flash_state
=!gui_list
->cursor_flash_state
;
91 int selected_line
=gui_list
->selected_item
-gui_list
->start_item
;
92 #ifdef HAVE_LCD_BITMAP
93 int line_ypos
=display
->getymargin()+display
->char_height
*selected_line
;
94 if (global_settings
.invert_cursor
)
96 int line_xpos
=display
->getxmargin();
97 display
->set_drawmode(DRMODE_COMPLEMENT
);
98 display
->fillrect(line_xpos
, line_ypos
, display
->width
,
99 display
->char_height
);
100 display
->set_drawmode(DRMODE_SOLID
);
101 display
->invertscroll(0, selected_line
);
105 int cursor_xpos
=(global_settings
.scrollbar
&&
106 display
->nb_lines
< gui_list
->nb_items
)?1:0;
107 screen_put_cursorxy(display
, cursor_xpos
, selected_line
, gui_list
->cursor_flash_state
);
109 display
->update_rect(0, line_ypos
,display
->width
,
110 display
->char_height
);
112 screen_put_cursorxy(display
, 0, selected_line
, gui_list
->cursor_flash_state
);
113 gui_textarea_update(display
);
117 void gui_list_put_selection_in_screen(struct gui_list
* gui_list
,
120 #ifdef HAVE_LCD_BITMAP
121 gui_list
->display
->setfont(FONT_UI
);
123 gui_textarea_update_nblines(gui_list
->display
);
124 int nb_lines
=gui_list
->display
->nb_lines
;
129 int list_end
= gui_list
->selected_item
+ SCROLL_LIMIT
;
131 if(list_end
-1 == gui_list
->nb_items
)
133 if(list_end
> gui_list
->nb_items
)
135 gui_list
->start_item
= list_end
- nb_lines
;
139 int list_start
= gui_list
->selected_item
- SCROLL_LIMIT
+ 1;
140 if(list_start
+ nb_lines
> gui_list
->nb_items
)
141 list_start
= gui_list
->nb_items
- nb_lines
;
142 gui_list
->start_item
= list_start
;
144 if(gui_list
->start_item
< 0)
145 gui_list
->start_item
= 0;
148 #ifdef HAVE_LCD_BITMAP
149 int gui_list_get_item_offset(struct gui_list
* gui_list
, int item_width
,
152 struct screen
* display
=gui_list
->display
;
155 if (offset_out_of_view
)
157 item_offset
= gui_list
->offset_position
;
161 /* if text is smaller then view */
162 if (item_width
<= display
->width
- text_pos
)
168 /* if text got out of view */
169 if (gui_list
->offset_position
>
170 item_width
- (display
->width
- text_pos
))
171 item_offset
= item_width
- (display
->width
- text_pos
);
173 item_offset
= gui_list
->offset_position
;
181 void gui_list_draw(struct gui_list
* gui_list
)
183 struct screen
* display
=gui_list
->display
;
187 bool draw_icons
= (gui_list
->callback_get_item_icon
!= NULL
) ;
191 #ifdef HAVE_LCD_BITMAP
195 gui_textarea_clear(display
);
197 /* position and draw the list title & icon */
201 lines
= display
->nb_lines
- 1;
203 if (gui_list
->title_icon
!= NOICON
&& draw_icons
)
205 screen_put_iconxy(display
, 0, 0, gui_list
->title_icon
);
206 #ifdef HAVE_LCD_BITMAP
207 text_pos
= 8; /* pixels */
209 text_pos
= 1; /* chars */
217 #ifdef HAVE_LCD_BITMAP
218 screen_set_xmargin(display
, text_pos
); /* margin for title */
219 item_offset
= gui_list_get_item_offset(gui_list
, gui_list
->title_width
,
221 if (item_offset
> gui_list
->title_width
- (display
->width
- text_pos
))
222 display
->puts_offset(0, 0, gui_list
->title
, item_offset
);
224 display
->puts_scroll_offset(0, 0, gui_list
->title
, item_offset
);
226 display
->puts_scroll(text_pos
, 0, gui_list
->title
);
232 lines
= display
->nb_lines
;
235 /* Adjust the position of icon, cursor, text for the list */
236 #ifdef HAVE_LCD_BITMAP
237 display
->setfont(FONT_UI
);
238 gui_textarea_update_nblines(display
);
241 draw_scrollbar
= (global_settings
.scrollbar
&&
242 lines
< gui_list
->nb_items
);
244 draw_cursor
= !global_settings
.invert_cursor
;
245 text_pos
= 0; /* here it's in pixels */
246 if(draw_scrollbar
|| gui_list
->title
) /* indent if there's a title */
250 text_pos
+= SCROLLBAR_WIDTH
;
255 text_pos
+= CURSOR_WIDTH
;
262 text_pos
= 2; /* here it's in chars */
267 #ifdef HAVE_LCD_BITMAP
268 screen_set_xmargin(display
, text_pos
); /* margin for list */
271 while (i
< display
->nb_lines
)
273 char entry_buffer
[MAX_PATH
];
274 unsigned char *entry_name
;
275 int current_item
= gui_list
->start_item
+ (gui_list
->title
?i
-1:i
);
277 /* When there are less items to display than the
278 * current available space on the screen, we stop*/
279 if(current_item
>= gui_list
->nb_items
)
281 entry_name
= gui_list
->callback_get_item_name(current_item
,
284 #ifdef HAVE_LCD_BITMAP
285 /* position the string at the correct offset place */
287 display
->getstringsize(entry_name
, &item_width
, &h
);
288 item_offset
= gui_list_get_item_offset(gui_list
, item_width
, text_pos
);
291 if(current_item
>= gui_list
->selected_item
&&
292 current_item
< gui_list
->selected_item
+ gui_list
->selected_size
)
293 {/* The selected item must be displayed scrolling */
294 #ifdef HAVE_LCD_BITMAP
295 if (global_settings
.invert_cursor
)/* Display inverted-line-style*/
296 /* if text got out of view */
297 if (item_offset
> item_width
- (display
->width
- text_pos
))
299 display
->puts_style_offset(0, i
, entry_name
, STYLE_INVERT
,item_offset
);
301 display
->puts_scroll_style_offset(0, i
, entry_name
, STYLE_INVERT
,item_offset
);
303 else /* if (!global_settings.invert_cursor) */
304 if (item_offset
> item_width
- (display
->width
- text_pos
))
305 display
->puts_offset(0, i
, entry_name
,item_offset
);
307 display
->puts_scroll_offset(0, i
, entry_name
,item_offset
);
309 display
->puts_scroll(text_pos
, i
, entry_name
);
313 screen_put_cursorxy(display
, cursor_pos
, i
, true);
317 if(gui_list
->scroll_all
)
319 #ifdef HAVE_LCD_BITMAP
320 display
->puts_scroll_offset(0, i
, entry_name
,item_offset
);
322 display
->puts_scroll(text_pos
, i
, entry_name
);
327 #ifdef HAVE_LCD_BITMAP
328 display
->puts_offset(0, i
, entry_name
,item_offset
);
330 display
->puts(text_pos
, i
, entry_name
);
338 gui_list
->callback_get_item_icon(current_item
,
342 screen_put_iconxy(display
, icon_pos
, i
, icon
);
347 #ifdef HAVE_LCD_BITMAP
348 /* Draw the scrollbar if needed*/
351 int y_start
= gui_textarea_get_ystart(display
);
353 y_start
+= display
->char_height
;
354 int scrollbar_y_end
= display
->char_height
*
356 gui_scrollbar_draw(display
, 0, y_start
, SCROLLBAR_WIDTH
-1,
357 scrollbar_y_end
- y_start
, gui_list
->nb_items
,
358 gui_list
->start_item
,
359 gui_list
->start_item
+ display
->nb_lines
, VERTICAL
);
363 gui_textarea_update(display
);
366 void gui_list_select_item(struct gui_list
* gui_list
, int item_number
)
368 if( item_number
> gui_list
->nb_items
-1 || item_number
< 0 )
370 gui_list
->selected_item
= item_number
;
371 gui_list_put_selection_in_screen(gui_list
, false);
374 void gui_list_select_next(struct gui_list
* gui_list
)
376 if( gui_list
->selected_item
+gui_list
->selected_size
>= gui_list
->nb_items
)
378 if(gui_list
->limit_scroll
)
380 /* we have already reached the bottom of the list */
381 gui_list
->selected_item
= 0;
382 gui_list
->start_item
= 0;
386 gui_list
->selected_item
+=gui_list
->selected_size
;
387 int nb_lines
= gui_list
->display
->nb_lines
;
390 int item_pos
= gui_list
->selected_item
- gui_list
->start_item
;
391 int end_item
= gui_list
->start_item
+ nb_lines
;
393 if (global_settings
.scroll_paginated
)
395 /* When we reach the bottom of the list
396 * we jump to a new page if there are more items*/
397 if( item_pos
> nb_lines
-gui_list
->selected_size
&& end_item
< gui_list
->nb_items
)
399 gui_list
->start_item
= gui_list
->selected_item
;
400 if ( gui_list
->start_item
> gui_list
->nb_items
-nb_lines
)
401 gui_list
->start_item
= gui_list
->nb_items
-nb_lines
;
406 /* we start scrolling vertically when reaching the line
407 * (nb_lines-SCROLL_LIMIT)
408 * and when we are not in the last part of the list*/
409 if( item_pos
> nb_lines
-SCROLL_LIMIT
&& end_item
< gui_list
->nb_items
)
410 gui_list
->start_item
+=gui_list
->selected_size
;
415 void gui_list_select_previous(struct gui_list
* gui_list
)
417 int nb_lines
= gui_list
->display
->nb_lines
;
420 if( gui_list
->selected_item
-gui_list
->selected_size
< 0 )
422 if(gui_list
->limit_scroll
)
424 /* we have aleady reached the top of the list */
426 gui_list
->selected_item
= gui_list
->nb_items
-gui_list
->selected_size
;
427 start
= gui_list
->nb_items
-nb_lines
;
429 gui_list
->start_item
= 0;
431 gui_list
->start_item
= start
;
436 gui_list
->selected_item
-=gui_list
->selected_size
;
437 item_pos
= gui_list
->selected_item
- gui_list
->start_item
;
438 if (global_settings
.scroll_paginated
)
440 /* When we reach the top of the list
441 * we jump to a new page if there are more items*/
443 gui_list
->start_item
= gui_list
->selected_item
-nb_lines
+gui_list
->selected_size
;
447 /* we start scrolling vertically when reaching the line
448 * (nb_lines-SCROLL_LIMIT)
449 * and when we are not in the last part of the list*/
450 if( item_pos
< SCROLL_LIMIT
-1)
451 gui_list
->start_item
-=gui_list
->selected_size
;
453 if( gui_list
->start_item
< 0 )
454 gui_list
->start_item
= 0;
458 void gui_list_select_next_page(struct gui_list
* gui_list
, int nb_lines
)
460 if(gui_list
->selected_item
== gui_list
->nb_items
-gui_list
->selected_size
)
462 if(gui_list
->limit_scroll
)
464 gui_list
->selected_item
= 0;
470 nb_lines
-=nb_lines
%gui_list
->selected_size
;
471 gui_list
->selected_item
+= nb_lines
;
472 if(gui_list
->selected_item
> gui_list
->nb_items
-1)
473 gui_list
->selected_item
= gui_list
->nb_items
-1;
475 gui_list_put_selection_in_screen(gui_list
, true);
478 void gui_list_select_previous_page(struct gui_list
* gui_list
, int nb_lines
)
480 if(gui_list
->selected_item
== 0)
482 if(gui_list
->limit_scroll
)
484 gui_list
->selected_item
= gui_list
->nb_items
- gui_list
->selected_size
;
490 nb_lines
-=nb_lines
%gui_list
->selected_size
;
491 gui_list
->selected_item
-= nb_lines
;
492 if(gui_list
->selected_item
< 0)
493 gui_list
->selected_item
= 0;
495 gui_list_put_selection_in_screen(gui_list
, false);
498 void gui_list_add_item(struct gui_list
* gui_list
)
500 gui_list
->nb_items
++;
501 /* if only one item in the list, select it */
502 if(gui_list
->nb_items
== 1)
503 gui_list
->selected_item
= 0;
506 void gui_list_del_item(struct gui_list
* gui_list
)
508 if(gui_list
->nb_items
> 0)
510 gui_textarea_update_nblines(gui_list
->display
);
511 int nb_lines
= gui_list
->display
->nb_lines
;
513 int dist_selected_from_end
= gui_list
->nb_items
514 - gui_list
->selected_item
- 1;
515 int dist_start_from_end
= gui_list
->nb_items
516 - gui_list
->start_item
- 1;
517 if(dist_selected_from_end
== 0)
519 /* Oops we are removing the selected item,
520 select the previous one */
521 gui_list
->selected_item
--;
523 gui_list
->nb_items
--;
525 /* scroll the list if needed */
526 if( (dist_start_from_end
< nb_lines
) && (gui_list
->start_item
!= 0) )
527 gui_list
->start_item
--;
531 #ifdef HAVE_LCD_BITMAP
532 void gui_list_scroll_right(struct gui_list
* gui_list
)
534 /* FIXME: This is a fake right boundry limiter. there should be some
535 * callback function to find the longest item on the list in pixels,
536 * to stop the list from scrolling past that point */
537 gui_list
->offset_position
+=offset_step
;
538 if (gui_list
->offset_position
> 1000)
539 gui_list
->offset_position
= 1000;
542 void gui_list_scroll_left(struct gui_list
* gui_list
)
544 gui_list
->offset_position
-=offset_step
;
545 if (gui_list
->offset_position
< 0)
546 gui_list
->offset_position
= 0;
548 void gui_list_screen_scroll_step(int ofs
)
553 void gui_list_screen_scroll_out_of_view(bool enable
)
556 offset_out_of_view
= true;
558 offset_out_of_view
= false;
560 #endif /* HAVE_LCD_BITMAP */
562 void gui_list_set_title(struct gui_list
* gui_list
, char * title
, ICON icon
)
564 gui_list
->title
= title
;
565 gui_list
->title_icon
= icon
;
567 #ifdef HAVE_LCD_BITMAP
568 gui_list
->display
->getstringsize(title
, &gui_list
->title_width
, NULL
);
570 gui_list
->title_width
= strlen(title
);
573 gui_list
->title_width
= 0;
578 * Synchronized lists stuffs
580 void gui_synclist_init(
581 struct gui_synclist
* lists
,
582 list_get_name callback_get_item_name
,
591 gui_list_init(&(lists
->gui_list
[i
]),
592 callback_get_item_name
,
593 data
, scroll_all
, selected_size
);
594 gui_list_set_display(&(lists
->gui_list
[i
]), &(screens
[i
]));
598 void gui_synclist_set_nb_items(struct gui_synclist
* lists
, int nb_items
)
603 gui_list_set_nb_items(&(lists
->gui_list
[i
]), nb_items
);
604 #ifdef HAVE_LCD_BITMAP
605 lists
->gui_list
[i
].offset_position
= 0;
609 int gui_synclist_get_nb_items(struct gui_synclist
* lists
)
611 return gui_list_get_nb_items(&((lists
)->gui_list
[0]));
613 int gui_synclist_get_sel_pos(struct gui_synclist
* lists
)
615 return gui_list_get_sel_pos(&((lists
)->gui_list
[0]));
617 void gui_synclist_set_icon_callback(struct gui_synclist
* lists
, list_get_icon icon_callback
)
622 gui_list_set_icon_callback(&(lists
->gui_list
[i
]), icon_callback
);
626 void gui_synclist_draw(struct gui_synclist
* lists
)
630 gui_list_draw(&(lists
->gui_list
[i
]));
633 void gui_synclist_select_item(struct gui_synclist
* lists
, int item_number
)
637 gui_list_select_item(&(lists
->gui_list
[i
]), item_number
);
640 void gui_synclist_select_next(struct gui_synclist
* lists
)
644 gui_list_select_next(&(lists
->gui_list
[i
]));
647 void gui_synclist_select_previous(struct gui_synclist
* lists
)
651 gui_list_select_previous(&(lists
->gui_list
[i
]));
654 void gui_synclist_select_next_page(struct gui_synclist
* lists
,
655 enum screen_type screen
)
659 gui_list_select_next_page(&(lists
->gui_list
[i
]),
660 screens
[screen
].nb_lines
);
663 void gui_synclist_select_previous_page(struct gui_synclist
* lists
,
664 enum screen_type screen
)
668 gui_list_select_previous_page(&(lists
->gui_list
[i
]),
669 screens
[screen
].nb_lines
);
672 void gui_synclist_add_item(struct gui_synclist
* lists
)
676 gui_list_add_item(&(lists
->gui_list
[i
]));
679 void gui_synclist_del_item(struct gui_synclist
* lists
)
683 gui_list_del_item(&(lists
->gui_list
[i
]));
686 void gui_synclist_limit_scroll(struct gui_synclist
* lists
, bool scroll
)
690 gui_list_limit_scroll(&(lists
->gui_list
[i
]), scroll
);
693 void gui_synclist_set_title(struct gui_synclist
* lists
, char * title
, ICON icon
)
697 gui_list_set_title(&(lists
->gui_list
[i
]), title
, icon
);
700 void gui_synclist_flash(struct gui_synclist
* lists
)
704 gui_list_flash(&(lists
->gui_list
[i
]));
707 #ifdef HAVE_LCD_BITMAP
708 void gui_synclist_scroll_right(struct gui_synclist
* lists
)
712 gui_list_scroll_right(&(lists
->gui_list
[i
]));
715 void gui_synclist_scroll_left(struct gui_synclist
* lists
)
719 gui_list_scroll_left(&(lists
->gui_list
[i
]));
721 #endif /* HAVE_LCD_BITMAP */
723 unsigned gui_synclist_do_button(struct gui_synclist
* lists
, unsigned button
)
725 gui_synclist_limit_scroll(lists
, true);
728 case ACTION_STD_PREV
:
729 gui_synclist_limit_scroll(lists
, false);
731 case ACTION_STD_PREVREPEAT
:
732 gui_synclist_select_previous(lists
);
733 gui_synclist_draw(lists
);
735 return ACTION_STD_PREV
;
737 case ACTION_STD_NEXT
:
738 gui_synclist_limit_scroll(lists
, false);
740 case ACTION_STD_NEXTREPEAT
:
741 gui_synclist_select_next(lists
);
742 gui_synclist_draw(lists
);
744 return ACTION_STD_NEXT
;
746 #ifdef HAVE_LCD_BITMAP
747 case ACTION_TREE_PGRIGHT
:
748 gui_synclist_scroll_right(lists
);
749 gui_synclist_draw(lists
);
750 return ACTION_TREE_PGRIGHT
;
751 case ACTION_TREE_PGLEFT
:
752 gui_synclist_scroll_left(lists
);
753 gui_synclist_draw(lists
);
754 return ACTION_TREE_PGLEFT
;
757 /* for pgup / pgdown, we are obliged to have a different behaviour depending on the screen
758 * for which the user pressed the key since for example, remote and main screen doesn't
759 * have the same number of lines*/
760 case ACTION_LISTTREE_PGUP
:
761 gui_synclist_select_previous_page(lists
, SCREEN_MAIN
);
762 gui_synclist_draw(lists
);
764 return ACTION_STD_NEXT
;
766 case ACTION_LISTTREE_PGDOWN
:
767 gui_synclist_select_next_page(lists
, SCREEN_MAIN
);
768 gui_synclist_draw(lists
);
770 return ACTION_STD_PREV
;
771 #if (REMOTE_BUTTON != 0 )
772 case ACTION_LISTTREE_RC_PGUP
:
773 gui_synclist_select_previous_page(lists
, SCREEN_REMOTE
);
774 gui_synclist_draw(lists
);
776 return ACTION_STD_NEXT
;
778 case ACTION_LISTTREE_RC_PGDOWN
:
779 gui_synclist_select_next_page(lists
, SCREEN_REMOTE
);
780 gui_synclist_draw(lists
);
782 return ACTION_STD_PREV
;