1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Robert E. Hak
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 ****************************************************************************/
21 - Multi screen support
22 - Rewrote/removed a lot of code now useless with the new gui API
31 #include "backlight.h"
39 #include "settings_list.h"
46 #include "menus/exported_menus.h"
48 #include "root_menu.h"
50 #include "gwps-common.h" /* for fade() */
53 #ifdef HAVE_LCD_BITMAP
59 #include "statusbar.h"
60 #include "buttonbar.h"
61 /* needed for the old menu system */
63 struct menu_item
* items
;
65 int (*callback
)(int, int);
66 int current_selection
;
69 static struct menu menus
[MAX_MENUS
];
70 static bool inuse
[MAX_MENUS
] = { false };
71 static void init_oldmenu(const struct menu_item_ex
*menu
,
72 struct gui_synclist
*lists
, int selected
, bool callback
);
73 static void menu_talk_selected(int m
);
75 /* used to allow for dynamic menus */
76 #define MAX_MENU_SUBITEMS 64
77 static struct menu_item_ex
*current_submenus_menu
;
78 static int current_subitems
[MAX_MENU_SUBITEMS
];
79 static int current_subitems_count
= 0;
81 void get_menu_callback(const struct menu_item_ex
*m
,
82 menu_callback_type
*menu_callback
)
84 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
85 *menu_callback
= m
->callback_and_desc
->menu_callback
;
87 *menu_callback
= m
->menu_callback
;
90 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
92 int type
= (menu
->flags
&MENU_TYPE_MASK
);
93 if (type
== MT_MENU
&& (selected_item
<current_subitems_count
))
94 return current_subitems
[selected_item
];
97 static int find_menu_selection(int selected
)
100 for (i
=0; i
< current_subitems_count
; i
++)
101 if (current_subitems
[i
] == selected
)
105 static char * get_menu_item_name(int selected_item
,void * data
, char *buffer
)
107 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
108 int type
= (menu
->flags
&MENU_TYPE_MASK
);
109 selected_item
= get_menu_selection(selected_item
, menu
);
112 /* only MT_MENU or MT_RETURN_ID is allowed in here */
113 if (type
== MT_RETURN_ID
)
115 if (menu
->flags
&MENU_DYNAMIC_DESC
)
116 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
117 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
118 return (char*)menu
->strings
[selected_item
];
121 menu
= menu
->submenus
[selected_item
];
123 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
124 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
125 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
127 type
= (menu
->flags
&MENU_TYPE_MASK
);
128 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
130 const struct settings_list
*v
131 = find_setting(menu
->variable
, NULL
);
133 return str(v
->lang_id
);
134 else return "Not Done yet!";
136 return P2STR(menu
->callback_and_desc
->desc
);
138 #ifdef HAVE_LCD_BITMAP
139 static void menu_get_icon(int selected_item
, void * data
, ICON
* icon
)
141 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
142 int menu_icon
= Icon_NOICON
;
143 selected_item
= get_menu_selection(selected_item
, menu
);
145 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
147 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
150 menu
= menu
->submenus
[selected_item
];
151 if (menu
->flags
&MENU_HAS_DESC
)
152 menu_icon
= menu
->callback_and_desc
->icon_id
;
153 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
154 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
156 switch (menu
->flags
&MENU_TYPE_MASK
)
159 case MT_SETTING_W_TEXT
:
160 *icon
= bitmap_icons_6x8
[Icon_Menu_setting
];
163 if (menu_icon
== Icon_NOICON
)
164 *icon
= bitmap_icons_6x8
[Icon_Submenu
];
166 *icon
= bitmap_icons_6x8
[menu_icon
];
168 case MT_FUNCTION_CALL
:
169 case MT_RETURN_VALUE
:
170 if (menu_icon
== Icon_NOICON
)
171 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
173 *icon
= bitmap_icons_6x8
[menu_icon
];
181 static void init_menu_lists(const struct menu_item_ex
*menu
,
182 struct gui_synclist
*lists
, int selected
, bool callback
)
184 int i
, count
= MENU_GET_COUNT(menu
->flags
);
185 int type
= (menu
->flags
&MENU_TYPE_MASK
);
186 menu_callback_type menu_callback
= NULL
;
188 current_subitems_count
= 0;
190 if (type
== MT_OLD_MENU
)
192 init_oldmenu(menu
, lists
, selected
, callback
);
195 if (type
== MT_RETURN_ID
)
196 get_menu_callback(menu
, &menu_callback
);
198 for (i
=0; i
<count
; i
++)
200 if (type
!= MT_RETURN_ID
)
201 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
204 if (menu_callback(ACTION_REQUEST_MENUITEM
,
205 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
206 != ACTION_EXIT_MENUITEM
)
208 current_subitems
[current_subitems_count
] = i
;
209 current_subitems_count
++;
214 current_subitems
[current_subitems_count
] = i
;
215 current_subitems_count
++;
218 current_submenus_menu
= (struct menu_item_ex
*)menu
;
220 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1);
221 #ifdef HAVE_LCD_BITMAP
222 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
223 icon
= bitmap_icons_6x8
[Icon_Submenu_Entered
];
225 icon
= bitmap_icons_6x8
[menu
->callback_and_desc
->icon_id
];
226 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
227 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
230 gui_synclist_set_icon_callback(lists
, NULL
);
232 gui_synclist_set_nb_items(lists
,current_subitems_count
);
233 gui_synclist_limit_scroll(lists
,true);
234 gui_synclist_select_item(lists
, find_menu_selection(selected
));
236 get_menu_callback(menu
,&menu_callback
);
237 if (callback
&& menu_callback
)
238 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
241 static void talk_menu_item(const struct menu_item_ex
*menu
,
242 struct gui_synclist
*lists
)
249 if (global_settings
.talk_menu
)
251 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
253 menus
[menu
->value
].current_selection
=
254 gui_synclist_get_sel_pos(lists
);
255 menu_talk_selected(menu
->value
);
258 sel
= get_menu_selection(gui_synclist_get_sel_pos(lists
),menu
);
259 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
261 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
262 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
263 talk_setting(menu
->submenus
[sel
]->variable
);
266 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
269 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
270 list_get_name(sel
, menu
->submenus
[sel
]->
271 menu_get_name_and_icon
->
272 list_get_name_data
, buffer
);
276 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
283 #define MAX_OPTIONS 32
284 /* returns true if the menu needs to be redrwan */
285 bool do_setting_from_menu(const struct menu_item_ex
*temp
)
288 const struct settings_list
*setting
= find_setting(
291 bool ret_val
= false;
292 unsigned char *title
;
295 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
296 title
= temp
->callback_and_desc
->desc
;
298 title
= ID2P(setting
->lang_id
);
300 if ((setting
->flags
&F_BOOL_SETTING
) == F_BOOL_SETTING
)
303 bool show_icons
= global_settings
.show_icons
;
304 if (setting
->flags
&F_TEMPVAR
)
306 temp_var
= *(bool*)setting
->setting
;
311 var
= (bool*)setting
->setting
;
313 set_bool_options(P2STR(title
), var
,
314 STR(setting
->bool_setting
->lang_yes
),
315 STR(setting
->bool_setting
->lang_no
),
316 setting
->bool_setting
->option_callback
);
317 if (setting
->flags
&F_TEMPVAR
)
318 *(bool*)setting
->setting
= temp_var
;
319 if (show_icons
!= global_settings
.show_icons
)
322 else if (setting
->flags
&F_T_SOUND
)
324 set_sound(P2STR(title
), setting
->setting
,
325 setting
->sound_setting
->setting
);
327 else /* other setting, must be an INT type */
330 if (setting
->flags
&F_TEMPVAR
)
332 temp_var
= *(int*)setting
->setting
;
337 var
= (int*)setting
->setting
;
339 if (setting
->flags
&F_INT_SETTING
)
342 if (setting
->flags
&F_FLIPLIST
)
344 min
= setting
->int_setting
->max
;
345 max
= setting
->int_setting
->min
;
346 step
= -setting
->int_setting
->step
;
350 max
= setting
->int_setting
->max
;
351 min
= setting
->int_setting
->min
;
352 step
= setting
->int_setting
->step
;
354 set_int_ex(P2STR(title
), NULL
,
355 setting
->int_setting
->unit
,var
,
356 setting
->int_setting
->option_callback
,
358 setting
->int_setting
->formatter
,
359 setting
->int_setting
->get_talk_id
);
361 else if (setting
->flags
&F_CHOICE_SETTING
)
363 static struct opt_items options
[MAX_OPTIONS
];
365 char *buf_start
= buffer
;
367 int i
,j
, count
= setting
->choice_setting
->count
;
368 for (i
=0, j
=0; i
<count
&& i
<MAX_OPTIONS
; i
++)
370 if (setting
->flags
&F_CHOICETALKS
)
372 if (cfg_int_to_string(setting_id
, i
,
373 buf_start
, buf_free
))
375 int len
= strlen(buf_start
) +1;
376 options
[j
].string
= buf_start
;
379 options
[j
].voice_id
=
380 setting
->choice_setting
->talks
[i
];
388 choice_setting
->desc
[i
]);
389 options
[j
].voice_id
=
391 choice_setting
->desc
[i
]);
395 set_option(P2STR(title
), var
, INT
,
398 choice_setting
->option_callback
);
400 if (setting
->flags
&F_TEMPVAR
)
401 *(int*)setting
->setting
= temp_var
;
407 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
)
409 int selected
= start_selected
? *start_selected
: 0;
411 struct gui_synclist lists
;
412 const struct menu_item_ex
*temp
, *menu
;
415 struct gui_buttonbar buttonbar
;
418 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
419 int menu_stack_selected_item
[MAX_MENUS
];
421 bool in_stringlist
, done
= false;
422 menu_callback_type menu_callback
= NULL
;
423 if (start_menu
== NULL
)
425 else menu
= start_menu
;
427 gui_buttonbar_init(&buttonbar
);
428 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
429 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
430 gui_buttonbar_draw(&buttonbar
);
432 init_menu_lists(menu
,&lists
,selected
,true);
433 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
435 talk_menu_item(menu
, &lists
);
437 gui_synclist_draw(&lists
);
438 gui_syncstatusbar_draw(&statusbars
, true);
439 action_signalscreenchange();
441 /* load the callback, and only reload it if menu changes */
442 get_menu_callback(menu
, &menu_callback
);
446 action
= get_action(CONTEXT_MAINMENU
,HZ
);
447 /* HZ so the status bar redraws corectly */
448 if (action
== ACTION_NONE
)
450 gui_syncstatusbar_draw(&statusbars
, true);
457 int old_action
= action
;
458 action
= menu_callback(action
, menu
);
459 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
462 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
467 if (gui_synclist_do_button(&lists
,action
,LIST_WRAP_UNLESS_HELD
))
469 talk_menu_item(menu
, &lists
);
471 else if (action
== ACTION_MENU_WPS
)
473 ret
= GO_TO_PREVIOUS_MUSIC
;
476 else if (action
== ACTION_MENU_STOP
)
478 if (audio_status() && !global_settings
.party_mode
)
480 if (global_settings
.fade_on_stop
)
482 bookmark_autobookmark();
486 else if (action
== ACTION_STD_MENU
)
488 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
489 return MENU_SELECTED_EXIT
;
490 if (menu
!= &root_menu_
)
493 ret
= GO_TO_PREVIOUS
;
496 else if (action
== ACTION_STD_CANCEL
)
498 in_stringlist
= false;
500 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
505 menu
= menu_stack
[stack_top
];
506 init_menu_lists(menu
, &lists
,
507 menu_stack_selected_item
[stack_top
], false);
508 talk_menu_item(menu
, &lists
);
509 /* new menu, so reload the callback */
510 get_menu_callback(menu
, &menu_callback
);
512 else if (menu
!= &root_menu_
)
514 ret
= GO_TO_PREVIOUS
;
518 else if (action
== ACTION_STD_OK
)
522 gui_buttonbar_unset(&buttonbar
);
523 gui_buttonbar_draw(&buttonbar
);
525 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
527 selected
= gui_synclist_get_sel_pos(&lists
);
528 menus
[menu
->value
].current_selection
= selected
;
529 action_signalscreenchange();
532 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
533 temp
= menu
->submenus
[selected
];
535 type
= (menu
->flags
&MENU_TYPE_MASK
);
538 type
= (temp
->flags
&MENU_TYPE_MASK
);
539 get_menu_callback(temp
, &menu_callback
);
542 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
543 if (action
== ACTION_EXIT_MENUITEM
)
550 if (stack_top
< MAX_MENUS
)
552 menu_stack
[stack_top
] = menu
;
553 menu_stack_selected_item
[stack_top
] = selected
;
555 init_menu_lists(temp
, &lists
, 0, true);
557 talk_menu_item(menu
, &lists
);
560 case MT_FUNCTION_CALL
:
563 action_signalscreenchange();
564 if (temp
->flags
&MENU_FUNC_USEPARAM
)
565 return_value
= temp
->function
->function_w_param(
566 temp
->function
->param
);
568 return_value
= temp
->function
->function();
569 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
571 if (return_value
== 1)
580 case MT_SETTING_W_TEXT
:
582 if (do_setting_from_menu(temp
))
583 init_menu_lists(menu
, &lists
, 0, true);
589 action_signalscreenchange();
593 else if (stack_top
< MAX_MENUS
)
595 menu_stack
[stack_top
] = menu
;
596 menu_stack_selected_item
[stack_top
] = selected
;
599 init_menu_lists(menu
,&lists
,0,false);
600 in_stringlist
= true;
603 case MT_RETURN_VALUE
:
608 if (type
!= MT_MENU
&& menu_callback
)
609 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
610 if (current_submenus_menu
!= menu
)
611 init_menu_lists(menu
,&lists
,selected
,true);
612 /* callback was changed, so reload the menu's callback */
613 get_menu_callback(menu
, &menu_callback
);
615 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
616 gui_buttonbar_draw(&buttonbar
);
619 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
620 ret
= MENU_ATTACHED_USB
;
621 gui_syncstatusbar_draw(&statusbars
, true);
622 gui_synclist_draw(&lists
);
624 action_signalscreenchange();
626 *start_selected
= get_menu_selection(
627 gui_synclist_get_sel_pos(&lists
), menu
);
633 return do_menu(NULL
, 0) == MENU_ATTACHED_USB
;
636 /* wrappers for the old menu system to work with the new system */
639 static int menu_find_free(void)
642 /* Tries to find an unused slot to put the new menu */
643 for ( i
=0; i
<MAX_MENUS
; i
++ ) {
649 if ( i
== MAX_MENUS
) {
650 DEBUGF("Out of menus!\n");
656 int menu_init(const struct menu_item
* mitems
, int count
, int (*callback
)(int, int),
657 const char *button1
, const char *button2
, const char *button3
)
662 int menu
=menu_find_free();
663 if(menu
==-1)/* Out of menus */
665 menus
[menu
].items
= (struct menu_item
*)mitems
; /* de-const */
666 menus
[menu
].count
= count
;
667 menus
[menu
].callback
= callback
;
668 menus
[menu
].current_selection
= 0;
672 void menu_exit(int m
)
679 static int oldmenuwrapper_callback(int action
,
680 const struct menu_item_ex
*this_item
)
682 if (menus
[this_item
->value
].callback
)
684 int val
= menus
[this_item
->value
].callback(action
, this_item
->value
);
687 case MENU_SELECTED_EXIT
:
688 return ACTION_EXIT_MENUITEM
;
695 static char* oldmenuwrapper_getname(int selected_item
,
696 void * data
, char *buffer
)
699 unsigned char* desc
= menus
[(intptr_t)data
].items
[selected_item
].desc
;
702 static void init_oldmenu(const struct menu_item_ex
*menu
,
703 struct gui_synclist
*lists
, int selected
, bool callback
)
706 gui_synclist_init(lists
, oldmenuwrapper_getname
,
707 (void*)(intptr_t)menu
->value
, false, 1);
708 gui_synclist_set_nb_items(lists
, MENU_GET_COUNT(menu
->flags
));
709 gui_synclist_limit_scroll(lists
, true);
710 gui_synclist_select_item(lists
, selected
);
713 static void menu_talk_selected(int m
)
715 int selected
= menus
[m
].current_selection
;
716 int voice_id
= P2ID(menus
[m
].items
[selected
].desc
);
717 if (voice_id
>= 0) /* valid ID given? */
718 talk_id(voice_id
, false); /* say it */
724 struct menu_item_ex menu
;
725 struct menu_get_name_and_icon menu_info
=
727 oldmenuwrapper_callback
,
728 oldmenuwrapper_getname
,
729 (void*)(intptr_t)m
, Icon_NOICON
732 menu
.flags
= (MENU_TYPE_MASK
&MT_OLD_MENU
) | MENU_DYNAMIC_DESC
|
733 MENU_ITEM_COUNT(menus
[m
].count
);
735 menu
.menu_get_name_and_icon
= &menu_info
;
736 value
= do_menu(&menu
, &menus
[m
].current_selection
);
739 case MENU_ATTACHED_USB
:
741 return MENU_ATTACHED_USB
;
743 return MENU_SELECTED_EXIT
;
746 return menus
[m
].current_selection
;
756 switch (selected
=menu_show(m
))
758 case MENU_SELECTED_EXIT
:
761 case MENU_ATTACHED_USB
:
766 if (selected
>= 0 && selected
< menus
[m
].count
)
768 if (menus
[m
].items
[selected
].function
&&
769 menus
[m
].items
[selected
].function())
772 gui_syncstatusbar_draw(&statusbars
, true);
780 * Property function - return the "count" of menu items in "menu"
783 int menu_count(int menu
)
785 return menus
[menu
].count
;