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
)
443 if (global_settings
.talk_menu
)
445 int sel
= get_menu_selection(gui_synclist_get_sel_pos(lists
),menu
);
446 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
448 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
449 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
450 talk_setting(menu
->submenus
[sel
]->variable
);
453 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
460 #define MAX_OPTIONS 32
461 /* returns true if the menu needs to be redrwan */
462 bool do_setting_from_menu(const struct menu_item_ex
*temp
)
465 const struct settings_list
*setting
= find_setting(
468 bool ret_val
= false;
469 unsigned char *title
;
472 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
473 title
= temp
->callback_and_desc
->desc
;
475 title
= ID2P(setting
->lang_id
);
477 if ((setting
->flags
&F_BOOL_SETTING
) == F_BOOL_SETTING
)
480 bool show_icons
= global_settings
.show_icons
;
481 if (setting
->flags
&F_TEMPVAR
)
483 temp_var
= *(bool*)setting
->setting
;
488 var
= (bool*)setting
->setting
;
490 set_bool_options(P2STR(title
), var
,
491 STR(setting
->bool_setting
->lang_yes
),
492 STR(setting
->bool_setting
->lang_no
),
493 setting
->bool_setting
->option_callback
);
494 if (setting
->flags
&F_TEMPVAR
)
495 *(bool*)setting
->setting
= temp_var
;
496 if (show_icons
!= global_settings
.show_icons
)
499 else if (setting
->flags
&F_T_SOUND
)
501 set_sound(P2STR(title
), setting
->setting
,
502 setting
->sound_setting
->setting
);
504 else /* other setting, must be an INT type */
507 if (setting
->flags
&F_TEMPVAR
)
509 temp_var
= *(int*)setting
->setting
;
514 var
= (int*)setting
->setting
;
516 if (setting
->flags
&F_INT_SETTING
)
519 if (setting
->flags
&F_FLIPLIST
)
521 min
= setting
->int_setting
->max
;
522 max
= setting
->int_setting
->min
;
523 step
= -setting
->int_setting
->step
;
527 max
= setting
->int_setting
->max
;
528 min
= setting
->int_setting
->min
;
529 step
= setting
->int_setting
->step
;
531 set_int_ex(P2STR(title
), NULL
,
532 setting
->int_setting
->unit
,var
,
533 setting
->int_setting
->option_callback
,
535 setting
->int_setting
->formatter
,
536 setting
->int_setting
->get_talk_id
);
538 else if (setting
->flags
&F_CHOICE_SETTING
)
540 static struct opt_items options
[MAX_OPTIONS
];
542 char *buf_start
= buffer
;
544 int i
,j
, count
= setting
->choice_setting
->count
;
545 for (i
=0, j
=0; i
<count
&& i
<MAX_OPTIONS
; i
++)
547 if (setting
->flags
&F_CHOICETALKS
)
549 if (cfg_int_to_string(setting_id
, i
,
550 buf_start
, buf_free
))
552 int len
= strlen(buf_start
) +1;
553 options
[j
].string
= buf_start
;
556 options
[j
].voice_id
=
557 setting
->choice_setting
->talks
[i
];
565 choice_setting
->desc
[i
]);
566 options
[j
].voice_id
=
568 choice_setting
->desc
[i
]);
572 set_option(P2STR(title
), var
, INT
,
575 choice_setting
->option_callback
);
577 if (setting
->flags
&F_TEMPVAR
)
578 *(int*)setting
->setting
= temp_var
;
584 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
)
586 int selected
= start_selected
? *start_selected
: 0;
588 struct gui_synclist lists
;
589 const struct menu_item_ex
*temp
, *menu
;
592 struct gui_buttonbar buttonbar
;
595 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
596 int menu_stack_selected_item
[MAX_MENUS
];
599 menu_callback_type menu_callback
= NULL
;
600 if (start_menu
== NULL
)
602 else menu
= start_menu
;
604 gui_buttonbar_init(&buttonbar
);
605 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
606 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
607 gui_buttonbar_draw(&buttonbar
);
609 init_menu_lists(menu
,&lists
,selected
,true);
610 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
612 talk_menu_item(menu
, &lists
);
614 gui_synclist_draw(&lists
);
615 gui_syncstatusbar_draw(&statusbars
, true);
616 action_signalscreenchange();
618 /* load the callback, and only reload it if menu changes */
619 get_menu_callback(menu
, &menu_callback
);
623 action
= get_action(CONTEXT_MAINMENU
,HZ
);
624 /* HZ so the status bar redraws corectly */
625 if (action
== ACTION_NONE
)
627 gui_syncstatusbar_draw(&statusbars
, true);
634 int old_action
= action
;
635 action
= menu_callback(action
, menu
);
636 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
639 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
644 if (gui_synclist_do_button(&lists
,action
,LIST_WRAP_UNLESS_HELD
))
646 talk_menu_item(menu
, &lists
);
648 else if (action
== ACTION_MENU_WPS
)
650 ret
= GO_TO_PREVIOUS_MUSIC
;
652 else if (action
== ACTION_MENU_STOP
)
654 if (audio_status() && !global_settings
.party_mode
)
656 if (global_settings
.fade_on_stop
)
658 bookmark_autobookmark();
662 else if (action
== ACTION_STD_MENU
)
664 if (menu
!= &root_menu_
)
667 else if (action
== ACTION_STD_CANCEL
)
669 in_stringlist
= false;
671 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
676 menu
= menu_stack
[stack_top
];
677 init_menu_lists(menu
, &lists
,
678 menu_stack_selected_item
[stack_top
], false);
679 talk_menu_item(menu
, &lists
);
680 /* new menu, so reload the callback */
681 get_menu_callback(menu
, &menu_callback
);
683 else if (menu
!= &root_menu_
)
685 ret
= GO_TO_PREVIOUS
;
689 else if (action
== ACTION_STD_OK
)
693 gui_buttonbar_unset(&buttonbar
);
694 gui_buttonbar_draw(&buttonbar
);
696 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
697 temp
= menu
->submenus
[selected
];
699 type
= (menu
->flags
&MENU_TYPE_MASK
);
701 type
= (temp
->flags
&MENU_TYPE_MASK
);
702 get_menu_callback(temp
, &menu_callback
);
705 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
706 if (action
== ACTION_EXIT_MENUITEM
)
712 if (stack_top
< MAX_MENUS
)
714 menu_stack
[stack_top
] = menu
;
715 menu_stack_selected_item
[stack_top
] = selected
;
717 init_menu_lists(temp
, &lists
, 0, true);
719 talk_menu_item(menu
, &lists
);
722 case MT_FUNCTION_CALL
:
723 action_signalscreenchange();
726 case MT_FUNCTION_WITH_PARAM
:
727 action_signalscreenchange();
728 temp
->func_with_param
->function(
729 temp
->func_with_param
->param
);
732 case MT_SETTING_W_TEXT
:
734 if (do_setting_from_menu(temp
))
735 init_menu_lists(menu
, &lists
, 0, true);
741 action_signalscreenchange();
744 else if (stack_top
< MAX_MENUS
)
746 menu_stack
[stack_top
] = menu
;
747 menu_stack_selected_item
[stack_top
] = selected
;
750 init_menu_lists(menu
,&lists
,0,false);
751 in_stringlist
= true;
754 case MT_RETURN_VALUE
:
756 *start_selected
= selected
;
759 if (type
!= MT_MENU
&& menu_callback
)
760 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
761 /* callback was changed, so reload the menu's callback */
762 get_menu_callback(menu
, &menu_callback
);
764 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
765 gui_buttonbar_draw(&buttonbar
);
768 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
769 ret
= MENU_ATTACHED_USB
;
770 gui_syncstatusbar_draw(&statusbars
, true);
771 gui_synclist_draw(&lists
);
773 action_signalscreenchange();
775 *start_selected
= selected
;
781 return do_menu(NULL
, 0);