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"
40 #include "option_select.h"
47 #include "menus/exported_menus.h"
49 #include "root_menu.h"
51 #include "gwps-common.h" /* for fade() */
55 #ifdef HAVE_LCD_BITMAP
61 #include "statusbar.h"
62 #include "buttonbar.h"
65 /* used to allow for dynamic menus */
66 #define MAX_MENU_SUBITEMS 64
67 static struct menu_item_ex
*current_submenus_menu
;
68 static int current_subitems
[MAX_MENU_SUBITEMS
];
69 static int current_subitems_count
= 0;
70 static int talk_menu_item(int selected_item
, void *data
);
72 static void get_menu_callback(const struct menu_item_ex
*m
,
73 menu_callback_type
*menu_callback
)
75 if (m
->flags
&(MENU_HAS_DESC
|MENU_DYNAMIC_DESC
))
76 *menu_callback
= m
->callback_and_desc
->menu_callback
;
78 *menu_callback
= m
->menu_callback
;
81 static int get_menu_selection(int selected_item
, const struct menu_item_ex
*menu
)
83 int type
= (menu
->flags
&MENU_TYPE_MASK
);
84 if (type
== MT_MENU
&& (selected_item
<current_subitems_count
))
85 return current_subitems
[selected_item
];
88 static int find_menu_selection(int selected
)
91 for (i
=0; i
< current_subitems_count
; i
++)
92 if (current_subitems
[i
] == selected
)
96 static char * get_menu_item_name(int selected_item
,void * data
, char *buffer
)
98 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
99 int type
= (menu
->flags
&MENU_TYPE_MASK
);
100 selected_item
= get_menu_selection(selected_item
, menu
);
103 /* only MT_MENU or MT_RETURN_ID is allowed in here */
104 if (type
== MT_RETURN_ID
)
106 if (menu
->flags
&MENU_DYNAMIC_DESC
)
107 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
108 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
109 return (char*)menu
->strings
[selected_item
];
112 menu
= menu
->submenus
[selected_item
];
114 if ((menu
->flags
&MENU_DYNAMIC_DESC
) && (type
!= MT_SETTING_W_TEXT
))
115 return menu
->menu_get_name_and_icon
->list_get_name(selected_item
,
116 menu
->menu_get_name_and_icon
->list_get_name_data
, buffer
);
118 type
= (menu
->flags
&MENU_TYPE_MASK
);
119 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
121 const struct settings_list
*v
122 = find_setting(menu
->variable
, NULL
);
124 return str(v
->lang_id
);
125 else return "Not Done yet!";
127 return P2STR(menu
->callback_and_desc
->desc
);
129 #ifdef HAVE_LCD_BITMAP
130 static int menu_get_icon(int selected_item
, void * data
)
132 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
133 int menu_icon
= Icon_NOICON
;
134 selected_item
= get_menu_selection(selected_item
, menu
);
136 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
)
138 return Icon_Menu_functioncall
;
140 menu
= menu
->submenus
[selected_item
];
141 if (menu
->flags
&MENU_HAS_DESC
)
142 menu_icon
= menu
->callback_and_desc
->icon_id
;
143 else if (menu
->flags
&MENU_DYNAMIC_DESC
)
144 menu_icon
= menu
->menu_get_name_and_icon
->icon_id
;
146 if (menu_icon
== Icon_NOICON
)
148 switch (menu
->flags
&MENU_TYPE_MASK
)
151 case MT_SETTING_W_TEXT
:
152 menu_icon
= Icon_Menu_setting
;
155 menu_icon
= Icon_Submenu
;
157 case MT_FUNCTION_CALL
:
158 case MT_RETURN_VALUE
:
159 menu_icon
= Icon_Menu_functioncall
;
167 static void init_menu_lists(const struct menu_item_ex
*menu
,
168 struct gui_synclist
*lists
, int selected
, bool callback
,
169 struct viewport parent
[NB_SCREENS
])
171 int i
, count
= MENU_GET_COUNT(menu
->flags
);
172 int type
= (menu
->flags
&MENU_TYPE_MASK
);
173 menu_callback_type menu_callback
= NULL
;
175 current_subitems_count
= 0;
177 if (type
== MT_RETURN_ID
)
178 get_menu_callback(menu
, &menu_callback
);
180 for (i
=0; i
<count
; i
++)
182 if (type
!= MT_RETURN_ID
)
183 get_menu_callback(menu
->submenus
[i
],&menu_callback
);
186 if (menu_callback(ACTION_REQUEST_MENUITEM
,
187 type
==MT_RETURN_ID
? (void*)(intptr_t)i
: menu
->submenus
[i
])
188 != ACTION_EXIT_MENUITEM
)
190 current_subitems
[current_subitems_count
] = i
;
191 current_subitems_count
++;
196 current_subitems
[current_subitems_count
] = i
;
197 current_subitems_count
++;
200 current_submenus_menu
= (struct menu_item_ex
*)menu
;
202 gui_synclist_init(lists
,get_menu_item_name
,(void*)menu
,false,1, parent
);
203 #ifdef HAVE_LCD_BITMAP
204 if (menu
->callback_and_desc
->icon_id
== Icon_NOICON
)
205 icon
= Icon_Submenu_Entered
;
207 icon
= menu
->callback_and_desc
->icon_id
;
208 gui_synclist_set_title(lists
, P2STR(menu
->callback_and_desc
->desc
), icon
);
209 gui_synclist_set_icon_callback(lists
, menu_get_icon
);
212 gui_synclist_set_icon_callback(lists
, NULL
);
214 if(global_settings
.talk_menu
)
215 gui_synclist_set_voice_callback(lists
, talk_menu_item
);
216 gui_synclist_set_nb_items(lists
,current_subitems_count
);
217 gui_synclist_limit_scroll(lists
,true);
218 gui_synclist_select_item(lists
, find_menu_selection(selected
));
220 get_menu_callback(menu
,&menu_callback
);
221 if (callback
&& menu_callback
)
222 menu_callback(ACTION_ENTER_MENUITEM
,menu
);
223 gui_synclist_draw(lists
);
224 gui_synclist_speak_item(lists
);
227 static int talk_menu_item(int selected_item
, void *data
)
229 const struct menu_item_ex
*menu
= (const struct menu_item_ex
*)data
;
233 int sel
= get_menu_selection(selected_item
, menu
);
235 if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
237 type
= menu
->submenus
[sel
]->flags
&MENU_TYPE_MASK
;
238 if ((type
== MT_SETTING
) || (type
== MT_SETTING_W_TEXT
))
239 talk_setting(menu
->submenus
[sel
]->variable
);
242 if (menu
->submenus
[sel
]->flags
&(MENU_DYNAMIC_DESC
))
244 int (*list_speak_item
)(int selected_item
, void * data
)
245 = menu
->submenus
[sel
]->menu_get_name_and_icon
->
248 list_speak_item(sel
, menu
->submenus
[sel
]->
249 menu_get_name_and_icon
->
254 str
= menu
->submenus
[sel
]->menu_get_name_and_icon
->
255 list_get_name(sel
, menu
->submenus
[sel
]->
256 menu_get_name_and_icon
->
257 list_get_name_data
, buffer
);
262 id
= P2ID(menu
->submenus
[sel
]->callback_and_desc
->desc
);
267 else if(((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
))
269 if ((menu
->flags
&MENU_DYNAMIC_DESC
) == 0)
271 unsigned char *s
= (unsigned char *)menu
->strings
[sel
];
272 /* string list, try to talk it if ID2P was used */
280 /* this is used to reload the default menu viewports when the
281 theme changes. nothing happens if the menu is using a supplied parent vp */
282 void init_default_menu_viewports(struct viewport parent
[NB_SCREENS
], bool hide_bars
)
287 viewport_set_defaults(&parent
[i
], i
);
288 /* viewport_set_defaults() fixes the vp for the bars, so resize */
291 if (global_settings
.statusbar
)
293 parent
[i
].y
-= STATUSBAR_HEIGHT
;
294 parent
[i
].height
+= STATUSBAR_HEIGHT
;
299 if (!hide_bars
&& global_settings
.buttonbar
)
300 parent
[0].height
-= BUTTONBAR_HEIGHT
;
304 bool do_setting_from_menu(const struct menu_item_ex
*temp
)
306 int setting_id
, oldval
;
307 const struct settings_list
*setting
= find_setting(
311 char padded_title
[MAX_PATH
];
312 int var_type
= setting
->flags
&F_T_MASK
;
313 if (var_type
== F_T_INT
|| var_type
== F_T_UINT
)
315 oldval
= *(int*)setting
->setting
;
317 else if (var_type
== F_T_BOOL
)
319 oldval
= *(bool*)setting
->setting
;
323 if ((temp
->flags
&MENU_TYPE_MASK
) == MT_SETTING_W_TEXT
)
324 title
= temp
->callback_and_desc
->desc
;
326 title
= ID2P(setting
->lang_id
);
328 /* Pad the title string by repeating it. This is needed
329 so the scroll settings title can actually be used to
331 if (setting
->flags
&F_PADTITLE
)
334 if (setting
->lang_id
== -1)
335 title
= (char*)setting
->cfg_vals
;
337 title
= P2STR((unsigned char*)title
);
339 while (i
< MAX_PATH
-1)
341 int padlen
= MIN(len
, MAX_PATH
-1-i
);
342 strncpy(&padded_title
[i
], title
, padlen
);
345 padded_title
[i
++] = ' ';
347 padded_title
[i
] = '\0';
348 title
= padded_title
;
351 option_screen((struct settings_list
*)setting
,
352 setting
->flags
&F_TEMPVAR
, title
);
353 if (var_type
== F_T_INT
|| var_type
== F_T_UINT
)
355 return oldval
!= *(int*)setting
->setting
;
357 else if (var_type
== F_T_BOOL
)
359 return oldval
!= *(bool*)setting
->setting
;
365 int do_menu(const struct menu_item_ex
*start_menu
, int *start_selected
,
366 struct viewport parent
[NB_SCREENS
], bool hide_bars
)
368 int selected
= start_selected
? *start_selected
: 0;
370 struct gui_synclist lists
;
371 const struct menu_item_ex
*temp
, *menu
;
375 const struct menu_item_ex
*menu_stack
[MAX_MENUS
];
376 int menu_stack_selected_item
[MAX_MENUS
];
378 bool in_stringlist
, done
= false;
380 struct viewport
*vps
, menu_vp
[NB_SCREENS
]; /* menu_vp will hopefully be phased out */
382 struct gui_buttonbar buttonbar
;
383 gui_buttonbar_init(&buttonbar
);
384 gui_buttonbar_set_display(&buttonbar
, &(screens
[SCREEN_MAIN
]) );
385 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
388 menu_callback_type menu_callback
= NULL
;
389 if (start_menu
== NULL
)
391 else menu
= start_menu
;
396 /* if hide_bars == true we assume the viewport is correctly sized */
401 init_default_menu_viewports(vps
, hide_bars
);
405 screens
[i
].set_viewport(&vps
[i
]);
406 screens
[i
].clear_viewport();
407 screens
[i
].set_viewport(NULL
);
409 init_menu_lists(menu
, &lists
, selected
, true, vps
);
410 in_stringlist
= ((menu
->flags
&MENU_TYPE_MASK
) == MT_RETURN_ID
);
412 /* load the callback, and only reload it if menu changes */
413 get_menu_callback(menu
, &menu_callback
);
419 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
420 gui_buttonbar_draw(&buttonbar
);
425 redraw_lists
= false;
428 gui_syncstatusbar_draw(&statusbars
, true);
430 action
= get_action(CONTEXT_MAINMENU
,
431 list_do_action_timeout(&lists
, HZ
));
432 /* HZ so the status bar redraws corectly */
434 if (action
!= ACTION_NONE
&& menu_callback
)
436 int old_action
= action
;
437 action
= menu_callback(action
, menu
);
438 if (action
== ACTION_EXIT_AFTER_THIS_MENUITEM
)
441 ret
= MENU_SELECTED_EXIT
; /* will exit after returning
444 else if (action
== ACTION_REDRAW
)
451 if (gui_synclist_do_button(&lists
, &action
, LIST_WRAP_UNLESS_HELD
))
453 if (action
== ACTION_NONE
)
456 #ifdef HAVE_RECORDING
457 if (action
== ACTION_STD_REC
)
459 ret
= GO_TO_RECSCREEN
;
464 if (action
== ACTION_TREE_WPS
)
466 ret
= GO_TO_PREVIOUS_MUSIC
;
469 else if (action
== ACTION_TREE_STOP
)
471 redraw_lists
= list_stop_handler();
473 else if (action
== ACTION_STD_CONTEXT
&&
476 ret
= GO_TO_ROOTITEM_CONTEXT
;
479 else if (action
== ACTION_STD_MENU
)
481 if (menu
!= &root_menu_
)
484 ret
= GO_TO_PREVIOUS
;
487 else if (action
== ACTION_STD_CANCEL
)
489 bool exiting_menu
= false;
490 in_stringlist
= false;
492 menu_callback(ACTION_EXIT_MENUITEM
, menu
);
494 if (menu
->flags
&MENU_EXITAFTERTHISMENU
)
496 else if ((menu
->flags
&MENU_TYPE_MASK
) == MT_MENU
)
501 menu
= menu_stack
[stack_top
];
502 if (!exiting_menu
&& (menu
->flags
&MENU_EXITAFTERTHISMENU
))
505 init_menu_lists(menu
, &lists
,
506 menu_stack_selected_item
[stack_top
], false, vps
);
507 /* new menu, so reload the callback */
508 get_menu_callback(menu
, &menu_callback
);
510 else if (menu
!= &root_menu_
)
512 ret
= GO_TO_PREVIOUS
;
516 else if (action
== ACTION_STD_OK
)
522 gui_buttonbar_unset(&buttonbar
);
523 gui_buttonbar_draw(&buttonbar
);
526 selected
= get_menu_selection(gui_synclist_get_sel_pos(&lists
), menu
);
527 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, vps
);
551 redraw_lists
= false; /* above does the redraw */
555 case MT_FUNCTION_CALL
:
558 if (temp
->flags
&MENU_FUNC_USEPARAM
)
559 return_value
= temp
->function
->function_w_param(
560 temp
->function
->param
);
562 return_value
= temp
->function
->function();
564 init_default_menu_viewports(menu_vp
, hide_bars
);
565 init_menu_lists(menu
, &lists
, selected
, true, vps
);
567 if (temp
->flags
&MENU_FUNC_CHECK_RETVAL
)
569 if (return_value
== 1)
578 case MT_SETTING_W_TEXT
:
580 if (do_setting_from_menu(temp
))
582 init_default_menu_viewports(menu_vp
, hide_bars
);
583 init_menu_lists(menu
, &lists
, selected
, true,vps
);
584 redraw_lists
= false; /* above does the redraw */
594 else if (stack_top
< MAX_MENUS
)
596 menu_stack
[stack_top
] = menu
;
597 menu_stack_selected_item
[stack_top
] = selected
;
600 init_menu_lists(menu
,&lists
,0,false, vps
);
601 redraw_lists
= false; /* above does the redraw */
602 in_stringlist
= true;
605 case MT_RETURN_VALUE
:
613 menu_callback(ACTION_EXIT_MENUITEM
,temp
);
615 if (current_submenus_menu
!= menu
)
616 init_menu_lists(menu
,&lists
,selected
,true,vps
);
617 /* callback was changed, so reload the menu's callback */
618 get_menu_callback(menu
, &menu_callback
);
619 if ((menu
->flags
&MENU_EXITAFTERTHISMENU
) &&
620 !(temp
->flags
&MENU_EXITAFTERTHISMENU
))
628 gui_buttonbar_set(&buttonbar
, "<<<", "", "");
629 gui_buttonbar_draw(&buttonbar
);
633 else if(default_event_handler(action
) == SYS_USB_CONNECTED
)
635 ret
= MENU_ATTACHED_USB
;
639 if (redraw_lists
&& !done
)
641 gui_synclist_draw(&lists
);
642 gui_synclist_speak_item(&lists
);
647 /* make sure the start_selected variable is set to
648 the selected item from the menu do_menu() was called from */
651 menu
= menu_stack
[0];
652 init_menu_lists(menu
,&lists
,menu_stack_selected_item
[0],true, vps
);
654 *start_selected
= get_menu_selection(
655 gui_synclist_get_sel_pos(&lists
), menu
);