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"
63 struct menu_item
* items
;
64 int (*callback
)(int, int);
66 struct gui_buttonbar buttonbar
;
68 struct gui_synclist synclist
;
73 static struct menu menus
[MAX_MENUS
];
74 static bool inuse
[MAX_MENUS
] = { false };
76 static char * menu_get_itemname(int selected_item
, void * data
, char *buffer
)
78 struct menu
*local_menus
=(struct menu
*)data
;
80 return(P2STR(local_menus
->items
[selected_item
].desc
));
83 static int menu_find_free(void)
86 /* Tries to find an unused slot to put the new menu */
87 for ( i
=0; i
<MAX_MENUS
; i
++ ) {
93 if ( i
== MAX_MENUS
) {
94 DEBUGF("Out of menus!\n");
100 int menu_init(const struct menu_item
* mitems
, int count
, int (*callback
)(int, int),
101 const char *button1
, const char *button2
, const char *button3
)
103 int menu
=menu_find_free();
104 if(menu
==-1)/* Out of menus */
106 menus
[menu
].items
= (struct menu_item
*)mitems
; /* de-const */
107 gui_synclist_init(&(menus
[menu
].synclist
),
108 &menu_get_itemname
, &menus
[menu
], false, 1);
109 gui_synclist_set_icon_callback(&(menus
[menu
].synclist
), NULL
);
110 gui_synclist_set_nb_items(&(menus
[menu
].synclist
), count
);
111 menus
[menu
].callback
= callback
;
113 gui_buttonbar_init(&(menus
[menu
].buttonbar
));
114 gui_buttonbar_set_display(&(menus
[menu
].buttonbar
), &(screens
[SCREEN_MAIN
]) );
115 gui_buttonbar_set(&(menus
[menu
].buttonbar
), button1
, button2
, button3
);
124 void menu_exit(int m
)
132 gui_buttonbar_draw(&(menus
[m
].buttonbar
));
137 gui_synclist_draw(&(menus
[m
].synclist
));
138 gui_syncstatusbar_draw(&statusbars
, true);
139 menu_talk_selected(m
);
141 key
= get_action(CONTEXT_MAINMENU
,HZ
/2);
143 * "short-circuit" the default keypresses by running the
145 * The callback may return a new key value, often this will be
146 * BUTTON_NONE or the same key value, but it's perfectly legal
147 * to "simulate" key presses by returning another value.
149 if( menus
[m
].callback
!= NULL
)
150 key
= menus
[m
].callback(key
, m
);
151 /* If moved, "say" the entry under the cursor */
152 if(gui_synclist_do_button(&(menus
[m
].synclist
), key
,LIST_WRAP_UNLESS_HELD
))
153 menu_talk_selected(m
);
156 action_signalscreenchange();
157 return gui_synclist_get_sel_pos(&(menus
[m
].synclist
));
160 case ACTION_STD_CANCEL
:
161 case ACTION_STD_MENU
:
166 if(default_event_handler(key
) == SYS_USB_CONNECTED
)
167 return MENU_ATTACHED_USB
;
170 gui_syncstatusbar_draw(&statusbars
, false);
172 action_signalscreenchange();
173 return MENU_SELECTED_EXIT
;
181 switch (selected
=menu_show(m
))
183 case MENU_SELECTED_EXIT
:
186 case MENU_ATTACHED_USB
:
191 if (menus
[m
].items
[selected
].function
&&
192 menus
[m
].items
[selected
].function())
194 gui_syncstatusbar_draw(&statusbars
, true);
202 * Property function - return the current cursor for "menu"
205 int menu_cursor(int menu
)
207 return gui_synclist_get_sel_pos(&(menus
[menu
].synclist
));
211 * Property function - return the "menu" description at "position"
214 char* menu_description(int menu
, int position
)
216 return P2STR(menus
[menu
].items
[position
].desc
);
220 * Delete the element "position" from the menu items in "menu"
223 void menu_delete(int menu
, int position
)
226 int nb_items
=gui_synclist_get_nb_items(&(menus
[menu
].synclist
));
227 /* copy the menu item from the one below */
228 for( i
= position
; i
< nb_items
- 1; i
++)
229 menus
[menu
].items
[i
] = menus
[menu
].items
[i
+ 1];
231 gui_synclist_del_item(&(menus
[menu
].synclist
));
234 void menu_insert(int menu
, int position
, char *desc
, bool (*function
) (void))
237 int nb_items
=gui_synclist_get_nb_items(&(menus
[menu
].synclist
));
241 /* Move the items below one position forward */
242 for( i
= nb_items
; i
> position
; i
--)
243 menus
[menu
].items
[i
] = menus
[menu
].items
[i
- 1];
245 /* Update the current item */
246 menus
[menu
].items
[position
].desc
= (unsigned char *)desc
;
247 menus
[menu
].items
[position
].function
= function
;
248 gui_synclist_add_item(&(menus
[menu
].synclist
));
252 * Property function - return the "count" of menu items in "menu"
255 int menu_count(int menu
)
257 return gui_synclist_get_nb_items(&(menus
[menu
].synclist
));
261 * Allows to set the cursor position. Doesn't redraw by itself.
264 void menu_set_cursor(int menu
, int position
)
266 gui_synclist_select_item(&(menus
[menu
].synclist
), position
);
269 void menu_talk_selected(int m
)
271 if(global_settings
.talk_menu
)
273 int selected
=gui_synclist_get_sel_pos(&(menus
[m
].synclist
));
274 int voice_id
= P2ID(menus
[m
].items
[selected
].desc
);
275 if (voice_id
>= 0) /* valid ID given? */
276 talk_id(voice_id
, false); /* say it */
280 void menu_draw(int m
)
282 gui_synclist_draw(&(menus
[m
].synclist
));
285 /******************************************************************/
286 /* New menu stuff here!!
287 ******************************************************************/
290 /* used to allow for dynamic menus */
291 #define MAX_MENU_SUBITEMS 64
292 static int current_subitems
[MAX_MENU_SUBITEMS
];
293 static int current_subitems_count
= 0;
295 void get_menu_callback(const struct menu_item_ex
*m
,
296 menu_callback_type
*menu_callback
)
298 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
299 *menu_callback
= m
->callback_and_desc
->menu_callback
;
301 *menu_callback
= m
->menu_callback
;
304 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
306 int type
= (menu
->flags
&MENU_TYPE_MASK
);
307 if (type
== MT_MENU
&& (selected_item
<current_subitems_count
))
308 return current_subitems
[selected_item
];
309 return selected_item
;
311 static int find_menu_selection(int selected
)
314 for (i
=0; i
< current_subitems_count
; i
++)
315 if (current_subitems
[i
] == selected
)
319 static char * get_menu_item_name(int selected_item
,void * data
, char *buffer
)
321 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
322 int type
= (menu
->flags
&MENU_TYPE_MASK
);
323 selected_item
= get_menu_selection(selected_item
, menu
);
326 /* only MT_MENU or MT_RETURN_ID is allowed in here */
327 if (type
== MT_RETURN_ID
)
329 if (menu
->flags
&MENU_DYNAMIC_DESC
)
330 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
331 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
332 return (char*)menu
->strings
[selected_item
];
335 menu
= menu
->submenus
[selected_item
];
337 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
338 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
339 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
341 type
= (menu
->flags
&MENU_TYPE_MASK
);
342 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
344 const struct settings_list
*v
345 = find_setting(menu
->variable
, NULL
);
347 return str(v
->lang_id
);
348 else return "Not Done yet!";
350 return P2STR(menu
->callback_and_desc
->desc
);
352 #ifdef HAVE_LCD_BITMAP
353 static void menu_get_icon(int selected_item
, void * data
, ICON
* icon
)
355 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
356 int menu_icon
= Icon_NOICON
;
357 selected_item
= get_menu_selection(selected_item
, menu
);
359 menu
= menu
->submenus
[selected_item
];
360 if (menu
->flags
&MENU_HAS_DESC
)
361 menu_icon
= menu
->callback_and_desc
->icon_id
;
362 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
363 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
365 switch (menu
->flags
&MENU_TYPE_MASK
)
368 case MT_SETTING_W_TEXT
:
369 *icon
= bitmap_icons_6x8
[Icon_Menu_setting
];
372 if (menu_icon
== Icon_NOICON
)
373 *icon
= bitmap_icons_6x8
[Icon_Submenu
];
375 *icon
= bitmap_icons_6x8
[menu_icon
];
377 case MT_FUNCTION_CALL
:
378 case MT_FUNCTION_WITH_PARAM
:
379 case MT_RETURN_VALUE
:
380 if (menu_icon
== Icon_NOICON
)
381 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
383 *icon
= bitmap_icons_6x8
[menu_icon
];
391 static void init_menu_lists(const struct menu_item_ex
*menu
,
392 struct gui_synclist
*lists
, int selected
, bool callback
)
394 int i
, count
= (menu
->flags
&MENU_COUNT_MASK
)>>MENU_COUNT_SHIFT
;
395 menu_callback_type menu_callback
= NULL
;
397 current_subitems_count
= 0;
398 for (i
=0; i
<count
; i
++)
400 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
403 if (menu_callback(ACTION_REQUEST_MENUITEM
,menu
->submenus
[i
])
404 != ACTION_EXIT_MENUITEM
)
406 current_subitems
[current_subitems_count
] = i
;
407 current_subitems_count
++;
412 current_subitems
[current_subitems_count
] = i
;
413 current_subitems_count
++;
417 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1);
418 #ifdef HAVE_LCD_BITMAP
419 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
420 icon
= bitmap_icons_6x8
[Icon_Submenu_Entered
];
422 icon
= bitmap_icons_6x8
[menu
->callback_and_desc
->icon_id
];
423 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
424 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
427 gui_synclist_set_icon_callback(lists
, NULL
);
429 gui_synclist_set_nb_items(lists
,current_subitems_count
);
430 gui_synclist_limit_scroll(lists
,true);
431 gui_synclist_select_item(lists
, find_menu_selection(selected
));
433 get_menu_callback(menu
,&menu_callback
);
434 if (callback
&& menu_callback
)
435 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
438 static void talk_menu_item(const struct menu_item_ex
*menu
,
439 struct gui_synclist
*lists
)
445 if (global_settings
.talk_menu
)
447 int sel
= get_menu_selection(gui_synclist_get_sel_pos(lists
),menu
);
448 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
450 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
451 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
452 talk_setting(menu
->submenus
[sel
]->variable
);
455 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
458 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
459 list_get_name(sel
, menu
->submenus
[sel
]->
460 menu_get_name_and_icon
->
461 list_get_name_data
, buffer
);
465 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
472 #define MAX_OPTIONS 32
473 /* returns true if the menu needs to be redrwan */
474 bool do_setting_from_menu(const struct menu_item_ex
*temp
)
477 const struct settings_list
*setting
= find_setting(
480 bool ret_val
= false;
481 unsigned char *title
;
484 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
485 title
= temp
->callback_and_desc
->desc
;
487 title
= ID2P(setting
->lang_id
);
489 if ((setting
->flags
&F_BOOL_SETTING
) == F_BOOL_SETTING
)
492 bool show_icons
= global_settings
.show_icons
;
493 if (setting
->flags
&F_TEMPVAR
)
495 temp_var
= *(bool*)setting
->setting
;
500 var
= (bool*)setting
->setting
;
502 set_bool_options(P2STR(title
), var
,
503 STR(setting
->bool_setting
->lang_yes
),
504 STR(setting
->bool_setting
->lang_no
),
505 setting
->bool_setting
->option_callback
);
506 if (setting
->flags
&F_TEMPVAR
)
507 *(bool*)setting
->setting
= temp_var
;
508 if (show_icons
!= global_settings
.show_icons
)
511 else if (setting
->flags
&F_T_SOUND
)
513 set_sound(P2STR(title
), setting
->setting
,
514 setting
->sound_setting
->setting
);
516 else /* other setting, must be an INT type */
519 if (setting
->flags
&F_TEMPVAR
)
521 temp_var
= *(int*)setting
->setting
;
526 var
= (int*)setting
->setting
;
528 if (setting
->flags
&F_INT_SETTING
)
531 if (setting
->flags
&F_FLIPLIST
)
533 min
= setting
->int_setting
->max
;
534 max
= setting
->int_setting
->min
;
535 step
= -setting
->int_setting
->step
;
539 max
= setting
->int_setting
->max
;
540 min
= setting
->int_setting
->min
;
541 step
= setting
->int_setting
->step
;
543 set_int_ex(P2STR(title
), NULL
,
544 setting
->int_setting
->unit
,var
,
545 setting
->int_setting
->option_callback
,
547 setting
->int_setting
->formatter
,
548 setting
->int_setting
->get_talk_id
);
550 else if (setting
->flags
&F_CHOICE_SETTING
)
552 static struct opt_items options
[MAX_OPTIONS
];
554 char *buf_start
= buffer
;
556 int i
,j
, count
= setting
->choice_setting
->count
;
557 for (i
=0, j
=0; i
<count
&& i
<MAX_OPTIONS
; i
++)
559 if (setting
->flags
&F_CHOICETALKS
)
561 if (cfg_int_to_string(setting_id
, i
,
562 buf_start
, buf_free
))
564 int len
= strlen(buf_start
) +1;
565 options
[j
].string
= buf_start
;
568 options
[j
].voice_id
=
569 setting
->choice_setting
->talks
[i
];
577 choice_setting
->desc
[i
]);
578 options
[j
].voice_id
=
580 choice_setting
->desc
[i
]);
584 set_option(P2STR(title
), var
, INT
,
587 choice_setting
->option_callback
);
589 if (setting
->flags
&F_TEMPVAR
)
590 *(int*)setting
->setting
= temp_var
;
596 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
)
598 int selected
= start_selected
? *start_selected
: 0;
600 struct gui_synclist lists
;
601 const struct menu_item_ex
*temp
, *menu
;
604 struct gui_buttonbar buttonbar
;
607 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
608 int menu_stack_selected_item
[MAX_MENUS
];
611 menu_callback_type menu_callback
= NULL
;
612 if (start_menu
== NULL
)
614 else menu
= start_menu
;
616 gui_buttonbar_init(&buttonbar
);
617 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
618 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
619 gui_buttonbar_draw(&buttonbar
);
621 init_menu_lists(menu
,&lists
,selected
,true);
622 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
624 talk_menu_item(menu
, &lists
);
626 gui_synclist_draw(&lists
);
627 gui_syncstatusbar_draw(&statusbars
, true);
628 action_signalscreenchange();
630 /* load the callback, and only reload it if menu changes */
631 get_menu_callback(menu
, &menu_callback
);
635 action
= get_action(CONTEXT_MAINMENU
,HZ
);
636 /* HZ so the status bar redraws corectly */
637 if (action
== ACTION_NONE
)
639 gui_syncstatusbar_draw(&statusbars
, true);
646 int old_action
= action
;
647 action
= menu_callback(action
, menu
);
648 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
651 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
656 if (gui_synclist_do_button(&lists
,action
,LIST_WRAP_UNLESS_HELD
))
658 talk_menu_item(menu
, &lists
);
660 else if (action
== ACTION_MENU_WPS
)
662 ret
= GO_TO_PREVIOUS_MUSIC
;
664 else if (action
== ACTION_MENU_STOP
)
666 if (audio_status() && !global_settings
.party_mode
)
668 if (global_settings
.fade_on_stop
)
670 bookmark_autobookmark();
674 else if (action
== ACTION_STD_MENU
)
676 if (menu
!= &root_menu_
)
679 else if (action
== ACTION_STD_CANCEL
)
681 in_stringlist
= false;
683 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
688 menu
= menu_stack
[stack_top
];
689 init_menu_lists(menu
, &lists
,
690 menu_stack_selected_item
[stack_top
], false);
691 talk_menu_item(menu
, &lists
);
692 /* new menu, so reload the callback */
693 get_menu_callback(menu
, &menu_callback
);
695 else if (menu
!= &root_menu_
)
697 ret
= GO_TO_PREVIOUS
;
701 else if (action
== ACTION_STD_OK
)
705 gui_buttonbar_unset(&buttonbar
);
706 gui_buttonbar_draw(&buttonbar
);
708 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
709 temp
= menu
->submenus
[selected
];
711 type
= (menu
->flags
&MENU_TYPE_MASK
);
713 type
= (temp
->flags
&MENU_TYPE_MASK
);
714 get_menu_callback(temp
, &menu_callback
);
717 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
718 if (action
== ACTION_EXIT_MENUITEM
)
724 if (stack_top
< MAX_MENUS
)
726 menu_stack
[stack_top
] = menu
;
727 menu_stack_selected_item
[stack_top
] = selected
;
729 init_menu_lists(temp
, &lists
, 0, true);
731 talk_menu_item(menu
, &lists
);
734 case MT_FUNCTION_CALL
:
735 action_signalscreenchange();
738 case MT_FUNCTION_WITH_PARAM
:
739 action_signalscreenchange();
740 temp
->func_with_param
->function(
741 temp
->func_with_param
->param
);
744 case MT_SETTING_W_TEXT
:
746 if (do_setting_from_menu(temp
))
747 init_menu_lists(menu
, &lists
, 0, true);
753 action_signalscreenchange();
756 else if (stack_top
< MAX_MENUS
)
758 menu_stack
[stack_top
] = menu
;
759 menu_stack_selected_item
[stack_top
] = selected
;
762 init_menu_lists(menu
,&lists
,0,false);
763 in_stringlist
= true;
766 case MT_RETURN_VALUE
:
768 *start_selected
= selected
;
771 if (type
!= MT_MENU
&& menu_callback
)
772 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
773 /* callback was changed, so reload the menu's callback */
774 get_menu_callback(menu
, &menu_callback
);
776 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
777 gui_buttonbar_draw(&buttonbar
);
780 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
781 ret
= MENU_ATTACHED_USB
;
782 gui_syncstatusbar_draw(&statusbars
, true);
783 gui_synclist_draw(&lists
);
785 action_signalscreenchange();
787 *start_selected
= selected
;
793 return do_menu(NULL
, 0);