summaryrefslogtreecommitdiffstats
path: root/apps/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/menu.c')
-rw-r--r--apps/menu.c251
1 files changed, 149 insertions, 102 deletions
diff --git a/apps/menu.c b/apps/menu.c
index 6279ec10a6..df2284be12 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -67,8 +67,14 @@ static int current_subitems[MAX_MENU_SUBITEMS];
static int current_subitems_count = 0;
static int talk_menu_item(int selected_item, void *data);
+struct menu_data_t
+{
+ const struct menu_item_ex *menu;
+ int selected;
+};
+
static void get_menu_callback(const struct menu_item_ex *m,
- menu_callback_type *menu_callback)
+ menu_callback_type *menu_callback)
{
if (m->flags&(MENU_HAS_DESC|MENU_DYNAMIC_DESC))
*menu_callback= m->callback_and_desc->menu_callback;
@@ -76,6 +82,19 @@ static void get_menu_callback(const struct menu_item_ex *m,
*menu_callback = m->menu_callback;
}
+static bool query_audio_status(int *old_audio_status)
+{
+ bool redraw_list = false;
+ /* query audio status to see if it changed */
+ int new_audio_status = audio_status();
+ if (*old_audio_status != new_audio_status)
+ { /* force a redraw if anything changed the audio status from outside */
+ *old_audio_status = new_audio_status;
+ redraw_list = true;
+ }
+ return redraw_list;
+}
+
static int get_menu_selection(int selected_item, const struct menu_item_ex *menu)
{
int type = (menu->flags&MENU_TYPE_MASK);
@@ -128,8 +147,7 @@ static const char* get_menu_item_name(int selected_item,
type = (menu->flags&MENU_TYPE_MASK);
if ((type == MT_SETTING) || (type == MT_SETTING_W_TEXT))
{
- const struct settings_list *v
- = find_setting(menu->variable, NULL);
+ const struct settings_list *v = find_setting(menu->variable);
if (v)
return str(v->lang_id);
else return "Not Done yet!";
@@ -158,29 +176,29 @@ static enum themable_icons menu_get_icon(int selected_item, void * data)
if (menu_icon == Icon_NOICON)
{
- switch (menu->flags&MENU_TYPE_MASK)
- {
- case MT_SETTING:
- case MT_SETTING_W_TEXT:
- menu_icon = Icon_Menu_setting;
- break;
- case MT_MENU:
- menu_icon = Icon_Submenu;
- break;
- case MT_FUNCTION_CALL:
- case MT_RETURN_VALUE:
- menu_icon = Icon_Menu_functioncall;
- break;
- }
+ unsigned int flags = (menu->flags&MENU_TYPE_MASK);
+ if(flags == MT_MENU)
+ menu_icon = Icon_Submenu;
+ else if (flags == MT_SETTING || flags == MT_SETTING_W_TEXT)
+ menu_icon = Icon_Menu_setting;
+ else if (flags == MT_FUNCTION_CALL || flags == MT_RETURN_VALUE)
+ menu_icon = Icon_Menu_functioncall;
}
return menu_icon;
}
-static void init_menu_lists(const struct menu_item_ex *menu,
+static int init_menu_lists(const struct menu_item_ex *menu,
struct gui_synclist *lists, int selected, bool callback,
struct viewport parent[NB_SCREENS])
{
+ if (!menu || !lists)
+ {
+ panicf("init_menu_lists, NULL pointer");
+ return 0;
+ }
+
int i;
+ int start_action = ACTION_ENTER_MENUITEM;
int count = MIN(MENU_GET_COUNT(menu->flags), MAX_MENU_SUBITEMS);
int type = (menu->flags&MENU_TYPE_MASK);
menu_callback_type menu_callback = NULL;
@@ -242,12 +260,13 @@ static void init_menu_lists(const struct menu_item_ex *menu,
if(global_settings.talk_menu)
gui_synclist_set_voice_callback(lists, talk_menu_item);
gui_synclist_set_nb_items(lists,current_subitems_count);
- gui_synclist_limit_scroll(lists,true);
gui_synclist_select_item(lists, find_menu_selection(selected));
get_menu_callback(menu,&menu_callback);
if (callback && menu_callback)
- menu_callback(ACTION_ENTER_MENUITEM, menu, lists);
+ start_action = menu_callback(start_action, menu, lists);
+
+ return start_action;
}
static int talk_menu_item(int selected_item, void *data)
@@ -314,10 +333,7 @@ void do_setting_screen(const struct settings_list *setting, const char * title,
if (setting->flags&F_PADTITLE)
{
int i = 0, len;
- if (setting->lang_id == -1)
- title = (char*)setting->cfg_vals;
- else
- title = P2STR((unsigned char*)title);
+ title = P2STR((unsigned char*)title);
len = strlen(title);
while (i < MAX_PATH-1)
{
@@ -334,19 +350,24 @@ void do_setting_screen(const struct settings_list *setting, const char * title,
option_screen((struct settings_list *)setting, parent,
setting->flags&F_TEMPVAR, (char*)title);
}
-
+
void do_setting_from_menu(const struct menu_item_ex *temp,
struct viewport parent[NB_SCREENS])
{
char *title;
- int setting_id;
- const struct settings_list *setting =
- find_setting(temp->variable, &setting_id);
- if (temp && ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT))
+ if (!temp)
+ {
+ panicf("do_setting_from_menu, NULL pointer");
+ return;
+ }
+ const struct settings_list *setting = find_setting(temp->variable);
+
+ if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
title = temp->callback_and_desc->desc;
else
title = ID2P(setting->lang_id);
+
do_setting_screen(setting, title, parent);
}
@@ -355,33 +376,39 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
struct viewport parent[NB_SCREENS], bool hide_theme)
{
int selected = start_selected? *start_selected : 0;
+ int ret = 0;
int action;
+ int start_action;
struct gui_synclist lists;
const struct menu_item_ex *temp = NULL;
const struct menu_item_ex *menu = start_menu;
- int ret = 0;
+
+ bool in_stringlist, done = false;
bool redraw_lists;
+
int old_audio_status = audio_status();
#ifdef HAVE_TOUCHSCREEN
/* plugins possibly have grid mode active. force global settings in lists */
enum touchscreen_mode tsm = touchscreen_get_mode();
+ enum touchscreen_mode old_global_mode = global_settings.touch_mode;
touchscreen_set_mode(global_settings.touch_mode);
#endif
FOR_NB_SCREENS(i)
viewportmanager_theme_enable(i, !hide_theme, NULL);
- const struct menu_item_ex *menu_stack[MAX_MENUS];
- int menu_stack_selected_item[MAX_MENUS];
+ struct menu_data_t mstack[MAX_MENUS]; /* menu, selected */
int stack_top = 0;
- bool in_stringlist, done = false;
+
struct viewport *vps = NULL;
menu_callback_type menu_callback = NULL;
/* if hide_theme is true, assume parent has been fixed before passed into
- * this function, e.g. with viewport_set_defaults(parent, screen) */
- init_menu_lists(menu, &lists, selected, true, parent);
+ * this function, e.g. with viewport_set_defaults(parent, screen)
+ * start_action allows an action to be processed
+ * by menu logic by bypassing get_action on the initial run */
+ start_action = init_menu_lists(menu, &lists, selected, true, parent);
vps = *(lists.parent);
in_stringlist = ((menu->flags&MENU_TYPE_MASK) == MT_RETURN_ID);
/* load the callback, and only reload it if menu changes */
@@ -389,54 +416,56 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
gui_synclist_draw(&lists);
gui_synclist_speak_item(&lists);
+
while (!done)
{
- int new_audio_status;
- redraw_lists = false;
keyclick_set_callback(gui_synclist_keyclick_callback, &lists);
- action = get_action(CONTEXT_MAINMENU|ALLOW_SOFTLOCK,
- list_do_action_timeout(&lists, HZ));
- /* query audio status to see if it changed */
- new_audio_status = audio_status();
- if (old_audio_status != new_audio_status)
- { /* force a redraw if anything changed the audio status
- * from outside */
- redraw_lists = true;
- old_audio_status = new_audio_status;
+ if (UNLIKELY(start_action != ACTION_ENTER_MENUITEM))
+ {
+ action = start_action;
+ start_action = ACTION_ENTER_MENUITEM;
}
- /* HZ so the status bar redraws corectly */
+ else
+ action = get_action(CONTEXT_MAINMENU|ALLOW_SOFTLOCK,
+ list_do_action_timeout(&lists, HZ));
+ /* HZ so the status bar redraws corectly */
+
+ /* query audio status to see if it changed */
+ redraw_lists = query_audio_status(&old_audio_status);
if (menu_callback)
{
- int old_action = action;
- action = menu_callback(action, menu, &lists);
- if (action == ACTION_EXIT_AFTER_THIS_MENUITEM)
- {
- action = old_action;
- ret = MENU_SELECTED_EXIT; /* will exit after returning
- from selection */
- }
- else if (action == ACTION_REDRAW)
- {
- action = old_action;
+ int new_action = menu_callback(action, menu, &lists);
+ if (new_action == ACTION_EXIT_AFTER_THIS_MENUITEM)
+ ret = MENU_SELECTED_EXIT; /* exit after return from selection */
+ else if (new_action == ACTION_REDRAW)
redraw_lists = true;
- }
+ else
+ action = new_action;
}
- if (gui_synclist_do_button(&lists, &action, LIST_WRAP_UNLESS_HELD))
+ if (LIKELY(gui_synclist_do_button(&lists, &action)))
continue;
#ifdef HAVE_QUICKSCREEN
else if (action == ACTION_STD_QUICKSCREEN)
{
- if (global_settings.shortcuts_replaces_qs)
+ if (global_settings.shortcuts_replaces_qs ||
+ quick_screen_quick(action) == QUICKSCREEN_GOTO_SHORTCUTS_MENU)
{
+ int last_screen = global_status.last_screen;
global_status.last_screen = GO_TO_SHORTCUTMENU;
- ret = quick_screen_quick(action);
- done = true;
+ int shortcut_ret = do_shortcut_menu(NULL);
+ if (shortcut_ret == GO_TO_PREVIOUS)
+ global_status.last_screen = last_screen;
+ else
+ {
+ ret = shortcut_ret;
+ done = true;
+ }
}
- else
- quick_screen_quick(action);
+ if (!done)
+ init_menu_lists(menu, &lists, lists.selected_item, false, vps);
redraw_lists = true;
}
#endif
@@ -487,20 +516,22 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
ID2P(LANG_RIGHT_QS_ITEM),
ID2P(LANG_ADD_TO_FAVES));
#endif
- MENUITEM_STRINGLIST(notquickscreen_able_option,
+ MENUITEM_STRINGLIST(notquickscreen_able_option,
ID2P(LANG_ONPLAY_MENU_TITLE), NULL,
ID2P(LANG_RESET_SETTING));
- const struct menu_item_ex *menu;
- int menu_selection = 0;
- const struct settings_list *setting =
- find_setting(temp->variable, NULL);
+ const struct menu_item_ex *context_menu;
+ const struct settings_list *setting =
+ find_setting(temp->variable);
#ifdef HAVE_QUICKSCREEN
if (is_setting_quickscreenable(setting))
- menu = &quickscreen_able_option;
+ context_menu = &quickscreen_able_option;
else
#endif
- menu = &notquickscreen_able_option;
- switch (do_menu(menu, &menu_selection, NULL, false))
+ context_menu = &notquickscreen_able_option;
+
+ int msel = do_menu(context_menu, NULL, NULL, false);
+
+ switch (msel)
{
case GO_TO_PREVIOUS:
break;
@@ -511,16 +542,16 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
break;
#ifdef HAVE_QUICKSCREEN
case 1: /* set as top QS item */
- set_as_qs_item(setting, QUICKSCREEN_TOP);
+ global_settings.qs_items[QUICKSCREEN_TOP] = setting;
break;
case 2: /* set as left QS item */
- set_as_qs_item(setting, QUICKSCREEN_LEFT);
+ global_settings.qs_items[QUICKSCREEN_LEFT] = setting;
break;
case 3: /* set as bottom QS item */
- set_as_qs_item(setting, QUICKSCREEN_BOTTOM);
+ global_settings.qs_items[QUICKSCREEN_BOTTOM] = setting;
break;
case 4: /* set as right QS item */
- set_as_qs_item(setting, QUICKSCREEN_RIGHT);
+ global_settings.qs_items[QUICKSCREEN_RIGHT] = setting;
break;
case 5: /* Add to faves. Same limitation on which can be
added to the shortcuts menu as the quickscreen */
@@ -542,10 +573,12 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
}
else if (action == ACTION_STD_CANCEL)
{
- bool exiting_menu = false;
- in_stringlist = false;
/* might be leaving list, so stop scrolling */
gui_synclist_scroll_stop(&lists);
+
+ bool exiting_menu = false;
+ in_stringlist = false;
+
if (menu_callback)
menu_callback(ACTION_EXIT_MENUITEM, menu, &lists);
@@ -553,15 +586,16 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
done = true;
else if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
exiting_menu = true;
+
if (stack_top > 0)
{
stack_top--;
- menu = menu_stack[stack_top];
+ menu = mstack[stack_top].menu;
+ int msel = mstack[stack_top].selected;
if (!exiting_menu && (menu->flags&MENU_EXITAFTERTHISMENU))
done = true;
else
- init_menu_lists(menu, &lists,
- menu_stack_selected_item[stack_top], false, vps);
+ init_menu_lists(menu, &lists, msel, false, vps);
redraw_lists = true;
/* new menu, so reload the callback */
get_menu_callback(menu, &menu_callback);
@@ -574,19 +608,18 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
}
else if (action == ACTION_STD_OK)
{
- int type = (menu->flags&MENU_TYPE_MASK);
/* entering an item that may not be a list, so stop scrolling */
gui_synclist_scroll_stop(&lists);
+ redraw_lists = true;
+
+ int type = (menu->flags&MENU_TYPE_MASK);
selected = get_menu_selection(gui_synclist_get_sel_pos(&lists), menu);
if (type == MT_MENU)
temp = menu->submenus[selected];
- else
+ else if (!in_stringlist)
type = -1;
- redraw_lists = true;
- if (in_stringlist)
- type = (menu->flags&MENU_TYPE_MASK);
- else if (temp)
+ if (!in_stringlist && temp)
{
type = (temp->flags&MENU_TYPE_MASK);
get_menu_callback(temp, &menu_callback);
@@ -602,25 +635,31 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
case MT_MENU:
if (stack_top < MAX_MENUS)
{
- menu_stack[stack_top] = menu;
- menu_stack_selected_item[stack_top] = selected;
+ mstack[stack_top].menu = menu;
+ mstack[stack_top].selected = selected;
stack_top++;
menu = temp;
init_menu_lists(menu, &lists, 0, true, vps);
}
break;
+ case MT_FUNCTION_CALL_W_PARAM:
case MT_FUNCTION_CALL:
{
int return_value;
- if (temp->flags&MENU_FUNC_USEPARAM)
- return_value = temp->function->function_w_param(
- temp->function->param);
+ if (type == MT_FUNCTION_CALL_W_PARAM)
+ {
+ return_value = temp->function_param->function_w_param(
+ temp->function_param->param);
+ }
else
+ {
return_value = temp->function->function();
+ }
if (!(menu->flags&MENU_EXITAFTERTHISMENU) ||
(temp->flags&MENU_EXITAFTERTHISMENU))
{
- init_menu_lists(menu, &lists, selected, true, vps);
+ /* Reload menu but don't run the calback again FS#8117 */
+ init_menu_lists(menu, &lists, selected, false, vps);
}
if (temp->flags&MENU_FUNC_CHECK_RETVAL)
{
@@ -636,7 +675,9 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
case MT_SETTING_W_TEXT:
{
do_setting_from_menu(temp, vps);
- send_event(GUI_EVENT_ACTIONUPDATE, (void*)1); /* force a redraw */
+ init_menu_lists(menu, &lists, selected, false, vps);
+ redraw_lists = true;
+
break;
}
case MT_RETURN_ID:
@@ -647,8 +688,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
}
else if (stack_top < MAX_MENUS)
{
- menu_stack[stack_top] = menu;
- menu_stack_selected_item[stack_top] = selected;
+ mstack[stack_top].menu = menu;
+ mstack[stack_top].selected = selected;
stack_top++;
menu = temp;
init_menu_lists(menu,&lists,0,false, vps);
@@ -674,7 +715,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
init_menu_lists(menu,&lists,selected,true,vps);
/* callback was changed, so reload the menu's callback */
get_menu_callback(menu, &menu_callback);
- if ((menu->flags&MENU_EXITAFTERTHISMENU) &&
+ if ((menu->flags&MENU_EXITAFTERTHISMENU) &&
!(temp->flags&MENU_EXITAFTERTHISMENU))
{
done = true;
@@ -706,6 +747,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
if (menu_callback(ACTION_REDRAW, menu, &lists) != ACTION_REDRAW)
continue;
+
+ gui_synclist_set_title(&lists, lists.title, lists.title_icon);
gui_synclist_draw(&lists);
gui_synclist_speak_item(&lists);
}
@@ -717,8 +760,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
the selected item from the menu do_menu() was called from */
if (stack_top > 0)
{
- menu = menu_stack[0];
- init_menu_lists(menu,&lists,menu_stack_selected_item[0],true, vps);
+ menu = mstack[0].menu;
+ init_menu_lists(menu,&lists,mstack[0].selected,true, vps);
}
*start_selected = get_menu_selection(
gui_synclist_get_sel_pos(&lists), menu);
@@ -727,8 +770,12 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
FOR_NB_SCREENS(i)
viewportmanager_theme_undo(i, false);
#ifdef HAVE_TOUCHSCREEN
- touchscreen_set_mode(tsm);
+ /* This is needed because this function runs the settings menu and we do
+ * not want to switch back to the old mode if the user intentionally went
+ * to a different one. This is a very hacky way to do this... */
+ if(!(global_settings.touch_mode != (int)old_global_mode &&
+ tsm == old_global_mode))
+ touchscreen_set_mode(tsm);
#endif
-
return ret;
}