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
;
66 int (*callback
)(int, int);
67 int current_selection
;
70 static struct menu menus
[MAX_MENUS
];
71 static bool inuse
[MAX_MENUS
] = { false };
72 static void init_oldmenu(const struct menu_item_ex
*menu
,
73 struct gui_synclist
*lists
, int selected
, bool callback
);
74 static void menu_talk_selected(int m
);
76 /* used to allow for dynamic menus */
77 #define MAX_MENU_SUBITEMS 64
78 static struct menu_item_ex
*current_submenus_menu
;
79 static int current_subitems
[MAX_MENU_SUBITEMS
];
80 static int current_subitems_count
= 0;
82 void get_menu_callback(const struct menu_item_ex
*m
,
83 menu_callback_type
*menu_callback
)
85 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
86 *menu_callback
= m
->callback_and_desc
->menu_callback
;
88 *menu_callback
= m
->menu_callback
;
91 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
93 int type
= (menu
->flags
&MENU_TYPE_MASK
);
94 if (type
== MT_MENU
&& (selected_item
<current_subitems_count
))
95 return current_subitems
[selected_item
];
98 static int find_menu_selection(int selected
)
101 for (i
=0; i
< current_subitems_count
; i
++)
102 if (current_subitems
[i
] == selected
)
106 static char * get_menu_item_name(int selected_item
,void * data
, char *buffer
)
108 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
109 int type
= (menu
->flags
&MENU_TYPE_MASK
);
110 selected_item
= get_menu_selection(selected_item
, menu
);
113 /* only MT_MENU or MT_RETURN_ID is allowed in here */
114 if (type
== MT_RETURN_ID
)
116 if (menu
->flags
&MENU_DYNAMIC_DESC
)
117 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
118 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
119 return (char*)menu
->strings
[selected_item
];
122 menu
= menu
->submenus
[selected_item
];
124 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
125 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
126 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
128 type
= (menu
->flags
&MENU_TYPE_MASK
);
129 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
131 const struct settings_list
*v
132 = find_setting(menu
->variable
, NULL
);
134 return str(v
->lang_id
);
135 else return "Not Done yet!";
137 return P2STR(menu
->callback_and_desc
->desc
);
139 #ifdef HAVE_LCD_BITMAP
140 static void menu_get_icon(int selected_item
, void * data
, ICON
* icon
)
142 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
143 int menu_icon
= Icon_NOICON
;
144 selected_item
= get_menu_selection(selected_item
, menu
);
146 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
148 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
151 menu
= menu
->submenus
[selected_item
];
152 if (menu
->flags
&MENU_HAS_DESC
)
153 menu_icon
= menu
->callback_and_desc
->icon_id
;
154 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
155 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
157 switch (menu
->flags
&MENU_TYPE_MASK
)
160 case MT_SETTING_W_TEXT
:
161 *icon
= bitmap_icons_6x8
[Icon_Menu_setting
];
164 if (menu_icon
== Icon_NOICON
)
165 *icon
= bitmap_icons_6x8
[Icon_Submenu
];
167 *icon
= bitmap_icons_6x8
[menu_icon
];
169 case MT_FUNCTION_CALL
:
170 case MT_RETURN_VALUE
:
171 if (menu_icon
== Icon_NOICON
)
172 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
174 *icon
= bitmap_icons_6x8
[menu_icon
];
182 static void init_menu_lists(const struct menu_item_ex
*menu
,
183 struct gui_synclist
*lists
, int selected
, bool callback
)
185 int i
, count
= MENU_GET_COUNT(menu
->flags
);
186 int type
= (menu
->flags
&MENU_TYPE_MASK
);
187 menu_callback_type menu_callback
= NULL
;
189 current_subitems_count
= 0;
191 if (type
== MT_OLD_MENU
)
193 init_oldmenu(menu
, lists
, selected
, callback
);
196 if (type
== MT_RETURN_ID
)
197 get_menu_callback(menu
, &menu_callback
);
199 for (i
=0; i
<count
; i
++)
201 if (type
!= MT_RETURN_ID
)
202 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
205 if (menu_callback(ACTION_REQUEST_MENUITEM
,
206 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
207 != ACTION_EXIT_MENUITEM
)
209 current_subitems
[current_subitems_count
] = i
;
210 current_subitems_count
++;
215 current_subitems
[current_subitems_count
] = i
;
216 current_subitems_count
++;
219 current_submenus_menu
= (struct menu_item_ex
*)menu
;
221 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1);
222 #ifdef HAVE_LCD_BITMAP
223 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
224 icon
= bitmap_icons_6x8
[Icon_Submenu_Entered
];
226 icon
= bitmap_icons_6x8
[menu
->callback_and_desc
->icon_id
];
227 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
228 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
231 gui_synclist_set_icon_callback(lists
, NULL
);
233 gui_synclist_set_nb_items(lists
,current_subitems_count
);
234 gui_synclist_limit_scroll(lists
,true);
235 gui_synclist_select_item(lists
, find_menu_selection(selected
));
237 get_menu_callback(menu
,&menu_callback
);
238 if (callback
&& menu_callback
)
239 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
242 static void talk_menu_item(const struct menu_item_ex
*menu
,
243 struct gui_synclist
*lists
)
250 if (global_settings
.talk_menu
)
252 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
254 menus
[menu
->value
].current_selection
=
255 gui_synclist_get_sel_pos(lists
);
256 menu_talk_selected(menu
->value
);
259 sel
= get_menu_selection(gui_synclist_get_sel_pos(lists
),menu
);
260 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
262 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
263 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
264 talk_setting(menu
->submenus
[sel
]->variable
);
267 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
270 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
271 list_get_name(sel
, menu
->submenus
[sel
]->
272 menu_get_name_and_icon
->
273 list_get_name_data
, buffer
);
277 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
284 #define MAX_OPTIONS 32
285 /* returns true if the menu needs to be redrwan */
286 bool do_setting_from_menu(const struct menu_item_ex
*temp
)
289 const struct settings_list
*setting
= find_setting(
292 bool ret_val
= false;
293 unsigned char *title
;
296 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
297 title
= temp
->callback_and_desc
->desc
;
299 title
= ID2P(setting
->lang_id
);
301 if ((setting
->flags
&F_BOOL_SETTING
) == F_BOOL_SETTING
)
304 bool show_icons
= global_settings
.show_icons
;
305 if (setting
->flags
&F_TEMPVAR
)
307 temp_var
= *(bool*)setting
->setting
;
312 var
= (bool*)setting
->setting
;
314 set_bool_options(P2STR(title
), var
,
315 STR(setting
->bool_setting
->lang_yes
),
316 STR(setting
->bool_setting
->lang_no
),
317 setting
->bool_setting
->option_callback
);
318 if (setting
->flags
&F_TEMPVAR
)
319 *(bool*)setting
->setting
= temp_var
;
320 if (show_icons
!= global_settings
.show_icons
)
323 else if (setting
->flags
&F_T_SOUND
)
325 set_sound(P2STR(title
), setting
->setting
,
326 setting
->sound_setting
->setting
);
328 else /* other setting, must be an INT type */
331 if (setting
->flags
&F_TEMPVAR
)
333 temp_var
= *(int*)setting
->setting
;
338 var
= (int*)setting
->setting
;
340 if (setting
->flags
&F_INT_SETTING
)
343 if (setting
->flags
&F_FLIPLIST
)
345 min
= setting
->int_setting
->max
;
346 max
= setting
->int_setting
->min
;
347 step
= -setting
->int_setting
->step
;
351 max
= setting
->int_setting
->max
;
352 min
= setting
->int_setting
->min
;
353 step
= setting
->int_setting
->step
;
355 set_int_ex(P2STR(title
), NULL
,
356 setting
->int_setting
->unit
,var
,
357 setting
->int_setting
->option_callback
,
359 setting
->int_setting
->formatter
,
360 setting
->int_setting
->get_talk_id
);
362 else if (setting
->flags
&F_CHOICE_SETTING
)
364 static struct opt_items options
[MAX_OPTIONS
];
366 char *buf_start
= buffer
;
368 int i
,j
, count
= setting
->choice_setting
->count
;
369 for (i
=0, j
=0; i
<count
&& i
<MAX_OPTIONS
; i
++)
371 if (setting
->flags
&F_CHOICETALKS
)
373 if (cfg_int_to_string(setting_id
, i
,
374 buf_start
, buf_free
))
376 int len
= strlen(buf_start
) +1;
377 options
[j
].string
= buf_start
;
380 options
[j
].voice_id
=
381 setting
->choice_setting
->talks
[i
];
389 choice_setting
->desc
[i
]);
390 options
[j
].voice_id
=
392 choice_setting
->desc
[i
]);
396 set_option(P2STR(title
), var
, INT
,
399 choice_setting
->option_callback
);
401 if (setting
->flags
&F_TEMPVAR
)
402 *(int*)setting
->setting
= temp_var
;
408 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
)
410 int selected
= start_selected
? *start_selected
: 0;
412 struct gui_synclist lists
;
413 const struct menu_item_ex
*temp
, *menu
;
416 struct gui_buttonbar buttonbar
;
419 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
420 int menu_stack_selected_item
[MAX_MENUS
];
422 bool in_stringlist
, done
= false;
423 menu_callback_type menu_callback
= NULL
;
424 if (start_menu
== NULL
)
426 else menu
= start_menu
;
428 gui_buttonbar_init(&buttonbar
);
429 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
430 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
431 gui_buttonbar_draw(&buttonbar
);
433 init_menu_lists(menu
,&lists
,selected
,true);
434 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
436 talk_menu_item(menu
, &lists
);
438 gui_synclist_draw(&lists
);
439 gui_syncstatusbar_draw(&statusbars
, true);
440 action_signalscreenchange();
442 /* load the callback, and only reload it if menu changes */
443 get_menu_callback(menu
, &menu_callback
);
447 action
= get_action(CONTEXT_MAINMENU
,HZ
);
448 /* HZ so the status bar redraws corectly */
449 if (action
== ACTION_NONE
)
451 gui_syncstatusbar_draw(&statusbars
, true);
458 int old_action
= action
;
459 action
= menu_callback(action
, menu
);
460 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
463 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
468 if (gui_synclist_do_button(&lists
,action
,LIST_WRAP_UNLESS_HELD
))
470 talk_menu_item(menu
, &lists
);
472 else if (action
== ACTION_TREE_WPS
)
474 ret
= GO_TO_PREVIOUS_MUSIC
;
477 else if (action
== ACTION_TREE_STOP
)
481 else if (action
== ACTION_STD_MENU
)
483 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
484 return MENU_SELECTED_EXIT
;
485 if (menu
!= &root_menu_
)
488 ret
= GO_TO_PREVIOUS
;
491 else if (action
== ACTION_STD_CANCEL
)
493 in_stringlist
= false;
495 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
500 menu
= menu_stack
[stack_top
];
501 init_menu_lists(menu
, &lists
,
502 menu_stack_selected_item
[stack_top
], false);
503 talk_menu_item(menu
, &lists
);
504 /* new menu, so reload the callback */
505 get_menu_callback(menu
, &menu_callback
);
507 else if (menu
!= &root_menu_
)
509 ret
= GO_TO_PREVIOUS
;
513 else if (action
== ACTION_STD_OK
)
517 gui_buttonbar_unset(&buttonbar
);
518 gui_buttonbar_draw(&buttonbar
);
520 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_OLD_MENU
)
522 selected
= gui_synclist_get_sel_pos(&lists
);
523 menus
[menu
->value
].current_selection
= selected
;
524 action_signalscreenchange();
527 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
528 temp
= menu
->submenus
[selected
];
530 type
= (menu
->flags
&MENU_TYPE_MASK
);
533 type
= (temp
->flags
&MENU_TYPE_MASK
);
534 get_menu_callback(temp
, &menu_callback
);
537 action
= menu_callback(ACTION_ENTER_MENUITEM
,temp
);
538 if (action
== ACTION_EXIT_MENUITEM
)
545 if (stack_top
< MAX_MENUS
)
547 menu_stack
[stack_top
] = menu
;
548 menu_stack_selected_item
[stack_top
] = selected
;
550 init_menu_lists(temp
, &lists
, 0, true);
552 talk_menu_item(menu
, &lists
);
555 case MT_FUNCTION_CALL
:
558 action_signalscreenchange();
559 if (temp
->flags
&MENU_FUNC_USEPARAM
)
560 return_value
= temp
->function
->function_w_param(
561 temp
->function
->param
);
563 return_value
= temp
->function
->function();
564 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
566 if (return_value
== 1)
575 case MT_SETTING_W_TEXT
:
577 if (do_setting_from_menu(temp
))
578 init_menu_lists(menu
, &lists
, 0, true);
584 action_signalscreenchange();
588 else if (stack_top
< MAX_MENUS
)
590 menu_stack
[stack_top
] = menu
;
591 menu_stack_selected_item
[stack_top
] = selected
;
594 init_menu_lists(menu
,&lists
,0,false);
595 in_stringlist
= true;
598 case MT_RETURN_VALUE
:
603 if (type
!= MT_MENU
&& menu_callback
)
604 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
605 if (current_submenus_menu
!= menu
)
606 init_menu_lists(menu
,&lists
,selected
,true);
607 /* callback was changed, so reload the menu's callback */
608 get_menu_callback(menu
, &menu_callback
);
610 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
611 gui_buttonbar_draw(&buttonbar
);
614 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
616 ret
= MENU_ATTACHED_USB
;
619 gui_syncstatusbar_draw(&statusbars
, true);
620 gui_synclist_draw(&lists
);
622 action_signalscreenchange();
624 *start_selected
= get_menu_selection(
625 gui_synclist_get_sel_pos(&lists
), menu
);
631 return do_menu(NULL
, 0) == MENU_ATTACHED_USB
;
634 /* wrappers for the old menu system to work with the new system */
637 static int menu_find_free(void)
640 /* Tries to find an unused slot to put the new menu */
641 for ( i
=0; i
<MAX_MENUS
; i
++ ) {
647 if ( i
== MAX_MENUS
) {
648 DEBUGF("Out of menus!\n");
654 int menu_init(const struct menu_item
* mitems
, int count
, int (*callback
)(int, int),
655 const char *button1
, const char *button2
, const char *button3
)
657 int menu
=menu_find_free();
658 if(menu
==-1)/* Out of menus */
660 menus
[menu
].items
= (struct menu_item
*)mitems
; /* de-const */
661 menus
[menu
].count
= count
;
662 menus
[menu
].callback
= callback
;
663 menus
[menu
].current_selection
= 0;
664 if ((button2
== NULL
) && (button3
== NULL
))
665 menus
[menu
].title
= (char*)button1
;
666 else menus
[menu
].title
= NULL
;
670 void menu_exit(int m
)
677 static int oldmenuwrapper_callback(int action
,
678 const struct menu_item_ex
*this_item
)
680 if (menus
[this_item
->value
].callback
)
682 int val
= menus
[this_item
->value
].callback(action
, this_item
->value
);
685 case MENU_SELECTED_EXIT
:
686 return ACTION_EXIT_MENUITEM
;
693 static char* oldmenuwrapper_getname(int selected_item
,
694 void * data
, char *buffer
)
697 unsigned char* desc
= menus
[(intptr_t)data
].items
[selected_item
].desc
;
701 #ifdef HAVE_LCD_BITMAP
702 static void oldmenu_get_icon(int selected_item
, void * data
, ICON
* icon
)
704 (void)data
; (void)selected_item
;
705 *icon
= bitmap_icons_6x8
[Icon_Menu_functioncall
];
709 static void init_oldmenu(const struct menu_item_ex
*menu
,
710 struct gui_synclist
*lists
, int selected
, bool callback
)
713 gui_synclist_init(lists
, oldmenuwrapper_getname
,
714 (void*)(intptr_t)menu
->value
, false, 1);
715 gui_synclist_set_nb_items(lists
, MENU_GET_COUNT(menu
->flags
));
716 gui_synclist_limit_scroll(lists
, true);
717 gui_synclist_select_item(lists
, selected
);
718 #ifdef HAVE_LCD_BITMAP
719 gui_synclist_set_title(lists
, menus
[menu
->value
].title
,
720 bitmap_icons_6x8
[Icon_Submenu_Entered
]);
721 gui_synclist_set_icon_callback(lists
, oldmenu_get_icon
);
725 static void menu_talk_selected(int m
)
727 int selected
= menus
[m
].current_selection
;
728 int voice_id
= P2ID(menus
[m
].items
[selected
].desc
);
729 if (voice_id
>= 0) /* valid ID given? */
730 talk_id(voice_id
, false); /* say it */
736 struct menu_item_ex menu
;
737 struct menu_get_name_and_icon menu_info
=
739 oldmenuwrapper_callback
,
740 oldmenuwrapper_getname
,
741 (void*)(intptr_t)m
, Icon_Submenu
744 menu
.flags
= (MENU_TYPE_MASK
&MT_OLD_MENU
) | MENU_DYNAMIC_DESC
|
745 MENU_ITEM_COUNT(menus
[m
].count
);
747 menu
.menu_get_name_and_icon
= &menu_info
;
748 value
= do_menu(&menu
, &menus
[m
].current_selection
);
751 case MENU_ATTACHED_USB
:
753 return MENU_ATTACHED_USB
;
755 return MENU_SELECTED_EXIT
;
758 return menus
[m
].current_selection
;
768 switch (selected
=menu_show(m
))
770 case MENU_SELECTED_EXIT
:
773 case MENU_ATTACHED_USB
:
778 if (selected
>= 0 && selected
< menus
[m
].count
)
780 if (menus
[m
].items
[selected
].function
&&
781 menus
[m
].items
[selected
].function())
784 gui_syncstatusbar_draw(&statusbars
, true);
792 * Property function - return the "count" of menu items in "menu"
795 int menu_count(int menu
)
797 return menus
[menu
].count
;