On 04/02/07, Jonathan Gordon <[EMAIL PROTECTED]> wrote:
OK,
I was alot lazier than expecting last week, but the first step is
ready for inclusion (attached .patch)

I know you dont like the heavy use of macros but I think these can be
exceptions, without them there will be plenty of places for copy/paste
errors and other bad stuff.

now, before I forget, I just did a compile for the fm rec, the binary
size increases about about 1Kb, but this is expected because only the
main menu uses the new system (it bassicaly does exactly the same as
before, but with more code.)

The plan is to fix the wiki page
(http://www.rockbox.org/twiki/bin/view/Main/SettingsRecode) to explain
how interested people can help, then commit this, then work through
the menu, 1 submenu at a time to convert the existing code to this new
system. This will mean moving code out of apps/*_menu.c to
apps/menus/*_menu.c in a neat manner so adding items later or
rearranging items will be simple.

Doing it this way instead of in 1 big hit means it will probably take
the same amount of time (a few weeks if its only me doing it), but
bugs will be found more quickly and there is more chance others' will
chip in.

any objections or comments?
(if there isnt I'll nag everyone in IRC in the next few days before I
commit.. not doing that without an ok)

woops, forgot to attach the patch
Index: apps/main_menu.c
===================================================================
--- apps/main_menu.c	(revision 12190)
+++ apps/main_menu.c	(working copy)
@@ -340,7 +340,7 @@
 }
 #endif
 
-static bool info_menu(void)
+bool info_menu(void)
 {
     int m;
     bool result;
@@ -375,7 +375,7 @@
     return false;
 }
 #endif
-
+#if 0
 bool main_menu(void)
 {
     int m;
@@ -445,7 +445,7 @@
 
     return result;
 }
-
+#endif
 /* -----------------------------------------------------------------
  * vim: et sw=4 ts=8 sts=4 tw=78
  */
Index: apps/action.h
===================================================================
--- apps/action.h	(revision 12190)
+++ apps/action.h	(working copy)
@@ -154,6 +154,10 @@
     ACTION_REC_F3,
     
     /* main menu */
+    ACTION_REQUEST_MENUITEM,
+    ACTION_EXIT_MENUITEM,
+    ACTION_ENTER_MENUITEM,
+    ACTION_MENU_WPS,
     
     /* id3db */
     
Index: apps/settings.c
===================================================================
--- apps/settings.c	(revision 12190)
+++ apps/settings.c	(working copy)
@@ -904,7 +904,79 @@
 }
 
 /** Changing setting values **/
+const struct settings_list* find_setting(void* variable)
+{
+    int i;
+    for(i=0;i<nb_settings;i++)
+    {
+        if (settings[i].setting == variable)
+            return &settings[i];
+    }
+    return NULL;
+}
 
+void talk_setting(void *global_settings_variable)
+{
+    const struct settings_list *setting;
+    if (global_settings.talk_menu == 0)
+        return;
+    setting = find_setting(global_settings_variable);
+    if (setting == NULL)
+        return;
+    if (setting->lang_id)
+        talk_id(setting->lang_id,false);
+}
+static int selected_setting; /* Used by the callback */
+#define abs(x) ((x)>0?(x):-(x))
+static void dec_sound_formatter(char *buffer, int buffer_size, int val, const char *unit)
+{
+    val = sound_val2phys(selected_setting, val);
+    char sign = ' ';
+    if(val < 0)
+    {
+        sign = '-';
+        val = abs(val);
+    }
+    int integer = val / 10;
+    int dec = val % 10;
+    snprintf(buffer, buffer_size, "%c%d.%d %s", sign, integer, dec, unit);
+}
+bool set_sound(const unsigned char * string,
+               int* variable,
+               int setting)
+{
+    int talkunit = UNIT_INT;
+    const char* unit = sound_unit(setting);
+    int numdec = sound_numdecimals(setting);
+    int steps = sound_steps(setting);
+    int min = sound_min(setting);
+    int max = sound_max(setting);
+    sound_set_type* sound_callback = sound_get_fn(setting);
+    if (*unit == 'd') /* crude reconstruction */
+        talkunit = UNIT_DB;
+    else if (*unit == '%')
+        talkunit = UNIT_PERCENT;
+    else if (*unit == 'H')
+        talkunit = UNIT_HERTZ;
+    if(!numdec)
+#if CONFIG_CODEC == SWCODEC
+        /* We need to hijack this one and send it off to apps/dsp.c instead of
+           firmware/sound.c */
+        if (setting == SOUND_STEREO_WIDTH)
+            return set_int(string, unit, talkunit,  variable, &stereo_width_set,
+                           steps, min, max, NULL );
+        else
+#endif   
+        return set_int(string, unit, talkunit,  variable, sound_callback,
+                       steps, min, max, NULL );
+    else
+    {/* Decimal number */
+        selected_setting=setting;
+        return set_int(string, unit, talkunit,  variable, sound_callback,
+                       steps, min, max, &dec_sound_formatter );
+    }
+}
+
 bool set_bool(const char* string, bool* variable )
 {
     return set_bool_options(string, variable,
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang	(revision 12190)
+++ apps/lang/english.lang	(working copy)
@@ -10487,3 +10487,17 @@
     *: "Charge During U S B Connection"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_MAIN_MENU
+  desc: in main menu
+  user:
+  <source>
+    *: "Rockbox Main Menu"
+  </source>
+  <dest>
+    *: "Rockbox Main Menu"
+  </dest>
+  <voice>
+    *: "Rockbox Main Menu"
+  </voice>
+</phrase>
Index: apps/menu.c
===================================================================
--- apps/menu.c	(revision 12190)
+++ apps/menu.c	(working copy)
@@ -35,12 +35,14 @@
 #include "usb.h"
 #include "panic.h"
 #include "settings.h"
+#include "settings_list.h"
 #include "status.h"
 #include "screens.h"
 #include "talk.h"
 #include "lang.h"
 #include "misc.h"
 #include "action.h"
+#include "menus/exported_menus.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
@@ -356,3 +358,336 @@
 #endif
     }
 }
+
+/******************************************************************/
+/*              New menu stuff here!!
+ ******************************************************************/
+
+
+/* used to allow for dynamic menus */
+#define MAX_MENU_SUBITEMS 64
+static int current_subitems[MAX_MENU_SUBITEMS];
+static int current_subitems_count = 0;
+
+void get_menu_callback(const struct menu_item_ex *m,
+						menu_callback_type menu_callback) 
+{
+    if (m->flags&MENU_HAS_DESC)
+        menu_callback= m->callback_and_desc->menu_callback;
+    else menu_callback = m->menu_callback;
+}
+
+static int get_menu_selection(int selected_item, const struct menu_item_ex *menu)
+{
+    int type = (menu->flags&MENU_TYPE_MASK);
+    if (type == MT_MENU && (selected_item<current_subitems_count))
+        return current_subitems[selected_item];
+    return selected_item;
+}
+
+static char * get_menu_item_name(int selected_item,void * data, char *buffer)
+{
+    const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
+    int type = (menu->flags&MENU_TYPE_MASK);
+    selected_item = get_menu_selection(selected_item, menu);
+    
+    (void)buffer;
+    /* only MT_MENU or MT_RETURN_ID is allowed in here */
+    if (type == MT_RETURN_ID)
+    {
+        return (char*)menu->strings[selected_item];
+    }
+    
+    menu = menu->submenus[selected_item];
+    type = (menu->flags&MENU_TYPE_MASK);
+    if (type == MT_SETTING)
+    {
+        const struct settings_list *v
+                = find_setting(menu->variable);
+        if (v)
+            return str(v->lang_id);
+        else return "Not Done yet!";
+    }
+    return P2STR(menu->callback_and_desc->desc);
+}
+
+static void init_menu_lists(const struct menu_item_ex *menu,
+                     struct gui_synclist *lists, int selected, bool callback)
+{
+    int i, count = (menu->flags&MENU_COUNT_MASK)>>MENU_COUNT_SHIFT;
+    menu_callback_type menu_callback = NULL;
+    current_subitems_count = 0;
+    for (i=0; i<count; i++)
+    {
+        get_menu_callback(menu->submenus[i],menu_callback);
+        if (menu_callback)
+        {
+            if (menu_callback(ACTION_REQUEST_MENUITEM,menu->submenus[i])
+                    != ACTION_EXIT_MENUITEM)
+            {
+                current_subitems[current_subitems_count] = i;
+                current_subitems_count++;
+            }
+        }
+        else 
+        {
+            current_subitems[current_subitems_count] = i;
+            current_subitems_count++;
+        }
+    }
+    
+    gui_synclist_init(lists,get_menu_item_name,(void*)menu,false,1);
+    gui_synclist_set_title(lists, P2STR(menu->callback_and_desc->desc), NOICON);
+    gui_synclist_set_icon_callback(lists,NULL);
+    gui_synclist_set_nb_items(lists,current_subitems_count);
+    gui_synclist_limit_scroll(lists,true);
+    gui_synclist_select_item(lists, selected);
+    
+    get_menu_callback(menu,menu_callback);
+    if (callback && menu_callback)
+        menu_callback(ACTION_ENTER_MENUITEM,menu);
+}
+
+static void talk_menu_item(const struct menu_item_ex *menu,
+                    struct gui_synclist *lists)
+{
+    int id = -1;
+    if (global_settings.talk_menu)
+    {
+        int sel = get_menu_selection(gui_synclist_get_sel_pos(lists),menu);
+        if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
+        {
+           if ((menu->submenus[sel]->flags&MENU_TYPE_MASK) == MT_SETTING)
+               talk_setting(menu->submenus[sel]->variable);
+           else 
+           {
+               id = P2ID(menu->submenus[sel]->callback_and_desc->desc);
+               if (id != -1)
+                   talk_id(id,false);
+           }
+        }
+    }
+}
+#define MAX_OPTIONS 32
+int do_menu(const struct menu_item_ex *start_menu)
+{
+    int action;
+    int selected = 0;
+    struct gui_synclist lists;
+    const struct menu_item_ex *temp, *menu;
+    int ret = 0;
+    
+    const struct menu_item_ex *menu_stack[MAX_MENUS];
+    int menu_stack_selected_item[MAX_MENUS];
+    int stack_top = 0;
+    bool in_stringlist;
+    menu_callback_type menu_callback = NULL;
+    if (start_menu == NULL)
+        menu = &main_menu_;
+    else menu = start_menu;
+
+    init_menu_lists(menu,&lists,selected,true);
+    in_stringlist = ((menu->flags&MENU_TYPE_MASK) == MT_RETURN_ID);
+    
+    talk_menu_item(menu, &lists);
+    
+    gui_synclist_draw(&lists);
+    gui_syncstatusbar_draw(&statusbars, true);
+    action_signalscreenchange();
+    
+    while (ret == 0)
+    {
+        action = get_action(CONTEXT_MAINMENU,HZ); 
+        /* HZ so the status bar redraws corectly */
+        if (action == ACTION_NONE)
+        {
+            gui_syncstatusbar_draw(&statusbars, true);
+            continue;
+        }
+
+        get_menu_callback(menu,menu_callback);
+        if (menu_callback)
+        {
+            action = menu_callback(action,menu);
+        }
+
+        if (gui_synclist_do_button(&lists,action,LIST_WRAP_UNLESS_HELD))
+        {
+            talk_menu_item(menu, &lists);
+        }
+        else if (action == ACTION_MENU_WPS)
+        {
+            ret = MENU_RETURN_TO_WPS;
+        }
+        else if ((action == ACTION_STD_CANCEL) ||
+                 (action == ACTION_STD_MENU))
+        {
+            if (in_stringlist)
+                in_stringlist = false;
+            if (stack_top > 0)
+            {
+                get_menu_callback(menu,menu_callback);
+                if (menu_callback)
+                {
+                    if (menu_callback(action,menu) ==
+                            ACTION_EXIT_MENUITEM)
+                        break;
+                }
+                stack_top--;
+                menu = menu_stack[stack_top];
+                init_menu_lists(menu,&lists,menu_stack_selected_item[stack_top],false);
+                talk_menu_item(menu, &lists);
+            }
+            else 
+            {
+                break;
+            }
+        }
+        else if (action == ACTION_STD_OK)
+        {
+            int type;
+            selected = get_menu_selection(gui_synclist_get_sel_pos(&lists),menu);
+            temp = menu->submenus[selected];
+            if (in_stringlist)
+                type = (menu->flags&MENU_TYPE_MASK);
+            else type = (temp->flags&MENU_TYPE_MASK);
+            get_menu_callback(temp,menu_callback);
+            if (menu_callback)
+            {
+                action = menu_callback(ACTION_ENTER_MENUITEM,temp);
+                if (action == ACTION_EXIT_MENUITEM)
+                    break;
+            }
+            switch (type)
+            {
+                case MT_MENU:
+                    if (stack_top < MAX_MENUS)
+                    {
+                        menu_stack[stack_top] = menu;
+                        menu_stack_selected_item[stack_top]
+                                = gui_synclist_get_sel_pos(&lists);
+                        stack_top++;
+                        init_menu_lists(temp,&lists,0,true);
+                        menu = temp;
+                        talk_menu_item(menu, &lists);
+                    }
+                    break;
+                case MT_FUNCTION_CALL:
+                    action_signalscreenchange();
+                    temp->function();
+                    break;
+                case MT_FUNCTION_WITH_PARAM:
+                    action_signalscreenchange();
+                    temp->func_with_param->function(
+                                    temp->func_with_param->param);
+                    break;
+                case MT_SETTING:
+                {
+                    const struct settings_list *setting = find_setting(
+                                temp->variable);
+                    if (setting)
+                    {
+                        if ((setting->flags&F_BOOL_SETTING) == F_BOOL_SETTING)
+                        {
+							bool temp_var, *var;
+							if (setting->flags&F_TEMPVAR)
+							{
+								temp_var = *(bool*)setting->setting;
+								var = &temp_var;
+							}
+							else
+							{
+								var = (bool*)setting->setting;
+							}
+                            set_bool_options(str(setting->lang_id),var,
+                                        STR(setting->bool_setting->lang_yes),
+                                        STR(setting->bool_setting->lang_no),
+                                        setting->bool_setting->option_callback);
+							if (setting->flags&F_TEMPVAR)
+								*(bool*)setting->setting = temp_var;
+                        }
+                        else if (setting->flags&F_T_SOUND)
+                        {
+                            set_sound(str(setting->lang_id),setting->setting,
+                                        setting->sound_setting->setting);
+                        }
+						else /* other setting, must be an INT type */
+						{
+							int temp_var, *var;
+							if (setting->flags&F_TEMPVAR)
+							{
+								temp_var = *(int*)setting->setting;
+								var = &temp_var;
+							}
+							else
+							{
+								var = (int*)setting->setting;
+							}
+							DEBUGF("%x\n",setting->flags);
+							if (setting->flags&F_INT_SETTING)
+							{DEBUGF("boo");
+								set_int(str(setting->lang_id),
+										str(setting->int_setting->unit),
+										setting->int_setting->unit,var,
+										setting->int_setting->option_callback,
+										setting->int_setting->step,
+										setting->int_setting->min,
+										setting->int_setting->max,
+										setting->int_setting->formatter);
+							}
+							else if (setting->flags&F_CHOICE_SETTING)
+							{
+								static struct opt_items options[MAX_OPTIONS];
+								int i,j, count = setting->choice_setting->count;
+								for (i=0, j=0; i<count && i<MAX_OPTIONS; i++)
+								{
+									options[j].string =
+										P2STR(setting->choice_setting->desc[i]);
+									options[j].voice_id = 
+										P2ID(setting->choice_setting->desc[i]);
+									j++;
+								}
+								set_option(str(setting->lang_id), var, INT,
+											options,count,
+											setting->choice_setting->option_callback);
+							}
+							if (setting->flags&F_TEMPVAR)
+								*(int*)setting->setting = temp_var;
+						}
+                    }
+                    break;
+                }
+                case MT_RETURN_ID:
+                    if (in_stringlist)
+                    {
+                        action_signalscreenchange();
+                        return selected;
+                    }
+                    else if (stack_top < MAX_MENUS)
+                    {
+                        menu_stack[stack_top] = menu;
+                        menu_stack_selected_item[stack_top] = selected;
+                        stack_top++;
+                        menu = temp;
+                        init_menu_lists(menu,&lists,0,false);
+                        in_stringlist = true;
+                    }
+                    break;
+            }
+            get_menu_callback(temp,menu_callback);
+            if (type != MT_MENU && menu_callback)
+                menu_callback(ACTION_EXIT_MENUITEM,temp);
+        }
+        else if(default_event_handler(action) == SYS_USB_CONNECTED)
+            ret = MENU_ATTACHED_USB;
+        gui_syncstatusbar_draw(&statusbars, true);
+        gui_synclist_draw(&lists);
+    }
+    action_signalscreenchange();
+    return ret;
+}
+
+int main_menu(void)
+{
+    return do_menu(NULL);
+}
Index: apps/settings.h
===================================================================
--- apps/settings.h	(revision 12190)
+++ apps/settings.h	(working copy)
@@ -224,6 +224,10 @@
     unsigned const char* string;
     long voice_id;
 };
+const struct settings_list* find_setting(void* variable);
+void talk_setting(void *global_settings_variable);
+bool set_sound(const unsigned char * string,
+               int* variable, int setting);
 bool set_bool_options(const char* string, bool* variable,
                       const char* yes_str, int yes_voice,
                       const char* no_str, int no_voice,
Index: apps/menus/exported_menus.h
===================================================================
--- apps/menus/exported_menus.h	(revision 0)
+++ apps/menus/exported_menus.h	(revision 0)
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _EXPORTED_MENUS_H
+#define _EXPORTED_MENUS_H
+
+#include "menu.h"
+/* not needed for plugins and just causes compile error, possibly fix proberly later */
+#ifndef PLUGIN 
+#include "playlist.h"
+#if 0
+int main_menu(void);        /* apps/menu.c      */
+bool recording_menu(void);  /* recording_menu.c */
+bool sound_menu(void);      /* sound_menu.c     */
+bool set_sound(const unsigned char * string, 
+               int* variable, int setting);               /* sound_menu.c */
+int save_playlist_screen(struct playlist_info* playlist); /* playlist_menu.c */
+#endif
+extern const struct menu_item_ex 
+        main_menu_;
+#if 0
+ ,                 /* main_menu.c      */
+        display_menu,               /* display_menu.c   */
+        playback_settings,          /* playback_menu.c  */
+#ifdef HAVE_RECORDING
+        recording_settings_menu,    /* recording_menu.c */
+#endif
+        sound_settings,             /* sound_menu.c     */
+        playlist_menu;              /* playlist_menu.c  */
+#endif
+#if CONFIG_CODEC == SWCODEC
+/* in playback_menu.c, used by many settings to set crossfade 
+   after retrning from option screen */
+//int setcrossfadeonexit_callback(int action,const struct menu_item_ex *this_item);
+#endif /* CONFIG_CODEC == SWCODEC */
+
+
+#endif /* ! PLUGIN */
+#endif /*_EXPORTED_MENUS_H */
Index: apps/menus/main_menu.c
===================================================================
--- apps/menus/main_menu.c	(revision 0)
+++ apps/menus/main_menu.c	(revision 0)
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2007 Jonathan Gordon
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <limits.h>
+#include "config.h"
+#include "lang.h"
+#include "action.h"
+#include "settings.h"
+#include "menu.h"
+#include "settings_menu.h"
+#include "tree.h"
+#include "radio.h"
+#include "recording.h"
+#include "bookmark.h"
+
+/* lazy coders can use this function if the needed callback 
+	is just to say if the item is shown or not */
+int dynamicitem_callback(int action,const struct menu_item_ex *this_item);
+
+/***********************************/
+/*    MAIN MENU                    */
+
+
+/* these two will be replaced when sound_menu.c is moved to menus/sound_menu.c */
+#include "sound_menu.h"
+MAKE_FUNCTION_CALL(sound_menu_item, ID2P(LANG_SOUND_SETTINGS),
+                   (menu_function)sound_menu, NULL);
+/* these two will be replaced when playlist_menu.c is moved to menus/playlist_menu.c */
+#include "playlist_menu.h"
+MAKE_FUNCTION_CALL(playlist_menu_item, ID2P(LANG_PLAYLIST_MENU),
+                   (menu_function)playlist_menu, NULL);
+/* these three will be replaced when settings_menu.c is moved to menus/setting_menu.c */
+#include "settings_menu.h"
+MAKE_FUNCTION_CALL(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS),
+                   (menu_function)settings_menu, NULL);
+MAKE_FUNCTION_CALL(manage_settings_menu_item, ID2P(LANG_MANAGE_MENU),
+                   (menu_function)manage_settings_menu, NULL);
+bool info_menu(void); /* from apps/main_menu.c TEMP*/
+MAKE_FUNCTION_CALL(info_menu_item, ID2P(LANG_INFO),
+                   (menu_function)info_menu, NULL);
+
+struct browse_folder_info {
+	const char* dir;
+	int show_options;
+};
+static struct browse_folder_info theme = {THEME_DIR, SHOW_CFG};
+static struct browse_folder_info rocks = {PLUGIN_DIR, SHOW_PLUGINS};
+static int browse_folder(void *param)
+{
+	const struct browse_folder_info *info =
+		(const struct browse_folder_info*)param;
+    return rockbox_browse(info->dir, info->show_options);
+}
+MAKE_FUNCTION_CALL_WPARAM(browse_themes, ID2P(LANG_CUSTOM_THEME), 
+		browse_folder, (void*)&theme, NULL);
+MAKE_FUNCTION_CALL_WPARAM(browse_plugins, ID2P(LANG_PLUGINS),
+		browse_folder, (void*)&rocks, NULL);
+
+#ifdef CONFIG_TUNER
+MAKE_FUNCTION_CALL(load_radio_screen, ID2P(LANG_FM_RADIO),
+                   (menu_function)radio_screen, dynamicitem_callback);
+#endif
+
+#ifdef HAVE_RECORDING
+MAKE_FUNCTION_CALL(rec_menu_recording_screen_item, ID2P(LANG_RECORDING_MENU),
+			(menu_function)recording_screen, NULL);
+/* TEMP */
+bool recording_menu(bool no_source); /* from apps/sound_menu.h */
+MAKE_FUNCTION_CALL_WPARAM(recording_settings_menu, ID2P(LANG_RECORDING_MENU),
+			(int (*)(void*))recording_menu,0, NULL);
+
+MAKE_MENU(rec_menu_item,ID2P(LANG_RECORDING),0,
+			&rec_menu_recording_screen_item, &recording_settings_menu);
+#endif
+
+MAKE_FUNCTION_CALL(mrb_bookmarks, ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS),
+                   (menu_function)bookmark_mrb_load, NULL);
+				   
+#ifdef HAVE_LCD_CHARCELLS
+static int do_shutdown(void)
+{
+    sys_poweroff();
+    return false;
+}
+MAKE_FUNCTION_CALL(do_shutdown_item, ID2P(LANG_SHUTDOWN), do_shutdown_item, NULL);
+#endif
+
+MAKE_MENU(main_menu_, ID2P(LANG_MAIN_MENU), NULL,
+		&mrb_bookmarks, &sound_menu_item,
+		&settings_menu_item, &manage_settings_menu_item, &browse_themes,
+#ifdef CONFIG_TUNER
+		&load_radio_screen,
+#endif
+#ifdef HAVE_RECORDING
+		&rec_menu_item,
+#endif
+        &playlist_menu_item, &browse_plugins, &info_menu_item
+#ifdef HAVE_LCD_CHARCELLS
+        ,&do_shutdown_item
+#endif
+		);
+/*    MAIN MENU                    */
+/***********************************/
+
+/* lazy coders can use this function if the needed callback is just to say if the item is shown or not */
+int dynamicitem_callback(int action,const struct menu_item_ex *this_item)
+{
+    if (action != ACTION_ENTER_MENUITEM)
+        return action;
+	
+#ifdef CONFIG_TUNER
+    if (this_item == &load_radio_screen)
+    {
+        if (radio_hardware_present() == 0)
+            return ACTION_EXIT_MENUITEM;
+    }
+#else
+    (void)this_item;
+#endif
+	
+    return action;
+}
Index: apps/menu.h
===================================================================
--- apps/menu.h	(revision 12190)
+++ apps/menu.h	(working copy)
@@ -22,94 +22,6 @@
 
 #include <stdbool.h>
 
-/* button definitions */
-#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
-    (CONFIG_KEYPAD == IRIVER_H300_PAD)
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT2      BUTTON_OFF
-#define MENU_EXIT_MENU  BUTTON_MODE
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_SELECT
-
-#define MENU_RC_EXIT        BUTTON_RC_STOP
-#define MENU_RC_EXIT_MENU   BUTTON_RC_MODE
-#define MENU_RC_ENTER       BUTTON_RC_ON
-#define MENU_RC_ENTER2      BUTTON_RC_MENU
-
-
-#elif CONFIG_KEYPAD == RECORDER_PAD
-
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT2      BUTTON_OFF
-#define MENU_EXIT_MENU  BUTTON_F1
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_PLAY
-
-#define MENU_RC_EXIT    BUTTON_RC_STOP
-#define MENU_RC_ENTER   BUTTON_RC_PLAY
-
-#elif CONFIG_KEYPAD == PLAYER_PAD
-#define MENU_EXIT       BUTTON_STOP
-#define MENU_EXIT_MENU  BUTTON_MENU
-#define MENU_ENTER      BUTTON_PLAY
-
-#define MENU_RC_EXIT    BUTTON_RC_STOP
-#define MENU_RC_ENTER   BUTTON_RC_PLAY
-
-#elif CONFIG_KEYPAD == ONDIO_PAD
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT_MENU  BUTTON_MENU
-#define MENU_ENTER      BUTTON_RIGHT
-
-#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
-
-/* TODO: Check menu button assignments */
-
-#define MENU_NEXT       BUTTON_DOWN
-#define MENU_PREV       BUTTON_UP
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT_MENU  BUTTON_MENU
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_SELECT
-
-#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
-
-#define MENU_NEXT       BUTTON_DOWN
-#define MENU_PREV       BUTTON_UP
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT_MENU  BUTTON_PLAY
-#define MENU_ENTER      BUTTON_RIGHT
-
-#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
-
-#define MENU_NEXT       BUTTON_DOWN
-#define MENU_PREV       BUTTON_UP
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT_MENU  BUTTON_REC
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_SELECT
-
-#elif CONFIG_KEYPAD == GIGABEAT_PAD
-
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT2      BUTTON_A
-#define MENU_EXIT_MENU  BUTTON_MENU
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_SELECT
-#define MENU_NEXT       BUTTON_DOWN
-#define MENU_PREV       BUTTON_UP
-
-#elif CONFIG_KEYPAD == IRIVER_H10_PAD
-
-#define MENU_NEXT       BUTTON_SCROLL_DOWN
-#define MENU_PREV       BUTTON_SCROLL_UP
-#define MENU_EXIT       BUTTON_LEFT
-#define MENU_EXIT_MENU  BUTTON_REW
-#define MENU_ENTER      BUTTON_RIGHT
-#define MENU_ENTER2     BUTTON_FF
-
-#endif
-
 struct menu_item {
     unsigned char *desc; /* string or ID */
     bool (*function) (void); /* return true if USB was connected */
@@ -125,6 +37,8 @@
 int menu_show(int m);
 #define MENU_ATTACHED_USB -1
 #define MENU_SELECTED_EXIT -2
+#define MENU_EXIT_ALL -3
+#define MENU_RETURN_TO_WPS -4
 
 bool menu_run(int menu);
 int menu_cursor(int menu);
@@ -138,4 +52,80 @@
 void menu_set_cursor(int menu, int position);
 void menu_talk_selected(int m);
 
+
+enum menu_item_type {
+    MT_MENU = 0,
+    MT_SETTING,
+    MT_FUNCTION_CALL, /* used when the standard code wont work */
+    MT_FUNCTION_WITH_PARAM,
+    MT_RETURN_ID, /* returns the position of the selected item on selection (starting at 0)*/
+};
+
+typedef int (*menu_function)(void);
+struct menu_func_with_param {
+    int (*function)(void* param);
+    void *param;
+};
+
+#define MENU_TYPE_MASK 0xF /* MT_* type */
+#define MENU_HAS_DESC   0x10
+#define MENU_COUNT_MASK (~(MENU_TYPE_MASK|MENU_HAS_DESC)) /* unless we need more flags*/
+#define MENU_COUNT_SHIFT 5
+
+struct menu_item_ex {
+    int flags; /* above defines */
+    union {
+        const struct menu_item_ex **submenus; /* used with MT_MENU */
+        void *variable; /* used with MT_SETTING,
+                           must be in the settings_list.c list */
+        int (*function)(void); /* used with MT_FUNCTION_CALL */
+        const struct menu_func_with_param *func_with_param; /* MT_FUNCTION_WITH_PARAM */
+        const char **strings; /* used with MT_RETURN_ID */
+    };
+    union {
+        int (*menu_callback)(int action, const struct menu_item_ex *this_item);
+        const struct menu_callback_with_desc {
+            int (*menu_callback)(int action, const struct menu_item_ex *this_item);
+            unsigned char *desc; /* string or ID */
+        } *callback_and_desc;
+    };
+};
+
+typedef int (*menu_callback_type)(int action, const struct menu_item_ex *this_item);
+int do_menu(const struct menu_item_ex *menu);
+
+#define MENU_ITEM_COUNT(c) (c<<MENU_COUNT_SHIFT)
+
+#define MAKE_SETTING_OPT(name,var,callback)                  \
+    static const struct menu_item_ex name =                     \
+        {MT_SETTING, {.variable = (void*)var},{callback}};
+
+#define MAKE_MENU( name, str, cb, ... )                                 \
+    static const struct menu_item_ex *name##_[]  = {__VA_ARGS__};              \
+    static const struct menu_callback_with_desc name##__ = {cb,str};           \
+    const struct menu_item_ex name =                                    \
+        {MT_MENU|MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_))|MENU_HAS_DESC,    \
+            { (void*)name##_},{.callback_and_desc = & name##__}};
+
+#define MAKE_STRINGLIST(name, str, callback, ... )                          \
+    static const char *name##_[] = {__VA_ARGS__};                                  \
+    static const struct menu_callback_with_desc name##__ = {cb,str};               \
+    static const struct menu_item_ex name =                                        \
+        {MT_RETURN_ID|MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_))|MENU_HAS_DESC,   \
+            { .submenus = name##_},{.callback_and_desc = & name##__}};
+
+#define MAKE_FUNCTION_CALL(name, str, func, cb)               \
+    static const struct menu_callback_with_desc name##_ = {cb,str};        \
+    static const struct menu_item_ex name   =                              \
+        { MT_FUNCTION_CALL|MENU_HAS_DESC, { .function = func},                    \
+        {.callback_and_desc = & name##_}};
+
+#define MAKE_FUNCTION_CALL_WPARAM(name, str, func, param, callback) \
+    static const struct menu_callback_with_desc name##_ = {callback,str};   \
+    static const struct menu_func_with_param name##__ = {func, param};     \
+    static const struct menu_item_ex name   =                              \
+        { MT_FUNCTION_WITH_PARAM|MENU_HAS_DESC, { .func_with_param = &name##__},         \
+        {.callback_and_desc = & name##_}};
+
+
 #endif /* End __MENU_H__ */
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c	(revision 12190)
+++ apps/settings_list.c	(working copy)
@@ -21,10 +21,12 @@
 #include <stdbool.h>
 
 #include "lang.h"
+#include "talk.h"
 #include "lcd.h"
 #include "settings.h"
 #include "settings_list.h"
 #include "sound.h"
+#include "dsp.h"
 
 /* some sets of values which are used more than once, to save memory */
 static const char off_on[] = "off,on";
@@ -92,24 +94,39 @@
 #define NODEFAULT INT(0)
 
 #define SOUND_SETTING(flags,var,lang_id,setting) \
-        {flags|F_T_INT|F_T_SOUND, GS(var),lang_id, NODEFAULT,#var,NULL,\
-            {.sound_setting=(struct sound_setting[]){{setting}}} }
+			{flags|F_T_INT|F_T_SOUND, GS(var),lang_id, NODEFAULT,#var,NULL,\
+				{.sound_setting=(struct sound_setting[]){{setting}}} }
 
 #define BOOL_SETTING(flags,var,lang_id,default,name,cfgvals,yes,no,opt_cb) \
-        {flags|F_T_BOOL, GS(var),lang_id, BOOL(default),name,cfgvals,  \
-            {.bool_setting=(struct bool_setting[]){{opt_cb,yes,no}}} }
+			{flags|F_BOOL_SETTING, GS(var),lang_id, BOOL(default),name,cfgvals,\
+				{.bool_setting=(struct bool_setting[]){{opt_cb,yes,no}}} }
 
 #define OFFON_SETTING(flags,var,lang_id,default,name,cb) \
-        {flags|F_T_BOOL, GS(var),lang_id, BOOL(default),name,off_on,  \
-            {.bool_setting=(struct bool_setting[])             \
-            {{cb,LANG_SET_BOOL_YES,LANG_SET_BOOL_NO}}} }
+			{flags|F_BOOL_SETTING, GS(var),lang_id, BOOL(default),name,off_on, \
+				{.bool_setting=(struct bool_setting[])             \
+				{{cb,LANG_SET_BOOL_YES,LANG_SET_BOOL_NO}}} }
 
 #define SYSTEM_SETTING(flags,var,default) \
-        {flags|F_T_INT, &global_status.var,-1, INT(default), NULL, NULL, UNUSED}
+			{flags|F_T_INT, &global_status.var,-1, INT(default),	\
+				NULL, NULL, UNUSED}
         
 #define FILENAME_SETTING(flags,var,name,default,prefix,suffix,len) \
-        {flags|F_T_UCHARPTR, GS(var),-1, CHARPTR(default),name,NULL,\
-            {.filename_setting=(struct filename_setting[]){{prefix,suffix,len}}} }
+			{flags|F_T_UCHARPTR, GS(var),-1, CHARPTR(default),name,NULL,\
+				{.filename_setting=										\
+					(struct filename_setting[]){{prefix,suffix,len}}} }
+					
+#define CHOICE_SETTING(flags,var,lang_id,default,name,cfg_vals,cb,count,...)  \
+			{flags|F_CHOICE_SETTING|F_T_INT,  GS(var), lang_id,   \
+				INT(default), name, cfg_vals, 					\
+				{.choice_setting = (struct choice_setting[]){	\
+					{cb,count,(unsigned char*[]){__VA_ARGS__}}}}}
+
+#define INT_SETTING(flags, var, lang_id, default, name, cfg_vals, \
+					unit, min, max, step, formatter, cb)  \
+			{flags|F_INT_SETTING|F_T_INT, GS(var), lang_id, INT(default),   \
+				name, cfg_vals, {.int_setting = (struct int_setting[]){	\
+					{cb, unit, min, max, step, formatter}}}}
+					
 const struct settings_list settings[] = {
     /* sound settings */
     SOUND_SETTING(0,volume, LANG_VOLUME, SOUND_VOLUME),
@@ -122,10 +139,17 @@
          "off,20ms,2,4,8", UNUSED },
     OFFON_SETTING(0,superbass,LANG_SUPERBASS,false,"superbass",NULL),
 #endif
-    { F_T_INT, GS(channel_config), LANG_CHANNEL, INT(0), "channels",
-         "stereo,mono,custom,mono left,mono right,karaoke", UNUSED },
-    { F_T_INT, GS(stereo_width),LANG_STEREO_WIDTH,
-         INT(100), "stereo width", NULL, UNUSED },
+	CHOICE_SETTING(0,channel_config,LANG_CHANNEL,0,"channels",
+         "stereo,mono,custom,mono left,mono right,karaoke", 
+#if CONFIG_CODEC == SWCODEC
+		 channels_set,
+#else
+		 sound_set_channels,
+#endif
+		 6, ID2P(LANG_CHANNEL_STEREO), ID2P(LANG_CHANNEL_MONO),
+			ID2P(LANG_CHANNEL_CUSTOM), ID2P(LANG_CHANNEL_LEFT),
+			ID2P(LANG_CHANNEL_RIGHT), ID2P(LANG_CHANNEL_KARAOKE)),
+	SOUND_SETTING(0,stereo_width, LANG_STEREO_WIDTH, SOUND_STEREO_WIDTH),
     /* playback */
     OFFON_SETTING(0, resume, LANG_RESUME, false, "resume", NULL),
     OFFON_SETTING(0, playlist_shuffle, LANG_SHUFFLE, false, "shuffle", NULL),
@@ -174,8 +198,8 @@
     SYSTEM_SETTING(NVRAM(4),runtime,0),
     SYSTEM_SETTING(NVRAM(4),topruntime,0),
 #if MEM > 1
-    {F_T_INT,GS(max_files_in_playlist),LANG_MAX_FILES_IN_PLAYLIST, 
-        INT(10000),"max files in playlist",NULL,UNUSED},
+    INT_SETTING(0,max_files_in_playlist,LANG_MAX_FILES_IN_PLAYLIST,10000,
+				"max files in playlist", NULL, UNIT_INT,1000,20000,1000,NULL,NULL),
     {F_T_INT,GS(max_files_in_dir),LANG_MAX_FILES_IN_DIR,
         INT(400),"max files in dir",NULL,UNUSED},
 #else
Index: apps/settings_list.h
===================================================================
--- apps/settings_list.h	(revision 12190)
+++ apps/settings_list.h	(working copy)
@@ -53,7 +53,7 @@
     int lang_yes;
     int lang_no;
 };
-#define F_BOOL_SETTING F_T_BOOL|0x10
+#define F_BOOL_SETTING (F_T_BOOL|0x10)
 #define F_RGB 0x20
 
 struct filename_setting {
@@ -65,28 +65,41 @@
 
 struct int_setting {
     void (*option_callback)(int);
+	int unit;
     int min;
     int max;
     int step;
+	void (*formatter)(char*, int, int, const char*);
 };
+#define F_INT_SETTING 0x80
+
+struct choice_setting {
+	void (*option_callback)(int);
+	int count;
+	unsigned char **desc;
+};
+#define F_CHOICE_SETTING 0x100
 /* these use the _isfunc_type type for the function */
 /* typedef int (*_isfunc_type)(void); */
 #define F_MIN_ISFUNC    0x100000 /* min(above) is function pointer to above type */
 #define F_MAX_ISFUNC    0x200000 /* max(above) is function pointer to above type */
 #define F_DEF_ISFUNC    0x400000 /* default_val is function pointer to above type */
 
-#define F_NVRAM_BYTES_MASK     0xE00 /*0-4 bytes can be stored */
-#define F_NVRAM_MASK_SHIFT     9
+#define F_NVRAM_BYTES_MASK     0xE000 /*0-4 bytes can be stored */
+#define F_NVRAM_MASK_SHIFT     13
 #define NVRAM_CONFIG_VERSION 2
 /* Above define should be bumped if
 - a new NVRAM setting is added between 2 other NVRAM settings
 - number of bytes for a NVRAM setting is changed
 - a NVRAM setting is removed
 */
+
+#define F_TEMPVAR	0x200 /* used if the setting should be set using a temp var */
 #define F_THEMESETTING	0x800000
 
+
 struct settings_list {
-    uint32_t             flags;   /* ____ ____ TFFF ____ ____ NNN_ IFRB STTT */
+    uint32_t             flags;   /* ____ ____ TFFF ____ NNN_ __TC IFRB STTT */
     void                *setting;
     int                  lang_id; /* -1 for none */
     union storage_type   default_val;
@@ -98,6 +111,8 @@
         struct sound_setting *sound_setting; /* use F_T_SOUND for this */
         struct bool_setting  *bool_setting; /* F_BOOL_SETTING */
         struct filename_setting *filename_setting; /* use F_FILENAME */
+		struct int_setting *int_setting; /* use F_INT_SETTING */
+		struct choice_setting *choice_setting; /* F_CHOICE_SETTING */
     };
 };
 
Index: apps/SOURCES
===================================================================
--- apps/SOURCES	(revision 12190)
+++ apps/SOURCES	(working copy)
@@ -11,6 +11,7 @@
 main.c
 main_menu.c
 menu.c
+menus/main_menu.c
 misc.c
 onplay.c
 playlist.c
Index: apps/sound_menu.c
===================================================================
--- apps/sound_menu.c	(revision 12190)
+++ apps/sound_menu.c	(working copy)
@@ -61,57 +61,6 @@
 #endif
 #include "action.h"
 
-static int selected_setting; /* Used by the callback */
-static void dec_sound_formatter(char *buffer, int buffer_size, int val, const char *unit)
-{
-    val = sound_val2phys(selected_setting, val);
-    char sign = ' ';
-    if(val < 0)
-    {
-        sign = '-';
-        val = abs(val);
-    }
-    int integer = val / 10;
-    int dec = val % 10;
-    snprintf(buffer, buffer_size, "%c%d.%d %s", sign, integer, dec, unit);
-}
-
-bool set_sound(const unsigned char * string,
-               int* variable,
-               int setting)
-{
-    int talkunit = UNIT_INT;
-    const char* unit = sound_unit(setting);
-    int numdec = sound_numdecimals(setting);
-    int steps = sound_steps(setting);
-    int min = sound_min(setting);
-    int max = sound_max(setting);
-    sound_set_type* sound_callback = sound_get_fn(setting);
-    if (*unit == 'd') /* crude reconstruction */
-        talkunit = UNIT_DB;
-    else if (*unit == '%')
-        talkunit = UNIT_PERCENT;
-    else if (*unit == 'H')
-        talkunit = UNIT_HERTZ;
-    if(!numdec)
-#if CONFIG_CODEC == SWCODEC
-        /* We need to hijack this one and send it off to apps/dsp.c instead of
-           firmware/sound.c */
-        if (setting == SOUND_STEREO_WIDTH)
-            return set_int(string, unit, talkunit,  variable, &stereo_width_set,
-                           steps, min, max, NULL );
-        else
-#endif   
-        return set_int(string, unit, talkunit,  variable, sound_callback,
-                       steps, min, max, NULL );
-    else
-    {/* Decimal number */
-        selected_setting=setting;
-        return set_int(string, unit, talkunit,  variable, sound_callback,
-                       steps, min, max, &dec_sound_formatter );
-    }
-}
-
 static bool volume(void)
 {
     return set_sound(str(LANG_VOLUME), &global_settings.volume, SOUND_VOLUME);
Index: apps/sound_menu.h
===================================================================
--- apps/sound_menu.h	(revision 12190)
+++ apps/sound_menu.h	(working copy)
@@ -24,6 +24,5 @@
 bool sound_menu(void);
 bool recording_menu(bool no_source);
 bool rectrigger(void);
-bool set_sound(const unsigned char * string, int* variable, int setting);
 
 #endif

Reply via email to