Speech enabled main menu config plugin

Patch by Igor Poretsky

Change-Id: Idffba2b1f1d225fc9278dcfab6a728fca5afe81d
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index b86feaf..da0f21b 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -15639,3 +15639,87 @@
     lowmem: none
   </voice>
 </phrase>
+<phrase>
+  id: LANG_TOGGLE_ITEM
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Toggle Item"
+  </source>
+  <dest>
+    *: "Toggle Item"
+  </dest>
+  <voice>
+    *: "Toggle Item"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MOVE_ITEM_UP
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Move Item Up"
+  </source>
+  <dest>
+    *: "Move Item Up"
+  </dest>
+  <voice>
+    *: "Move Item Up"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MOVE_ITEM_DOWN
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Move Item Down"
+  </source>
+  <dest>
+    *: "Move Item Down"
+  </dest>
+  <voice>
+    *: "Move Item Down"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_LOAD_DEFAULT_CONFIGURATION
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Load Default Configuration"
+  </source>
+  <dest>
+    *: "Load Default Configuration"
+  </dest>
+  <voice>
+    *: "Load Default Configuration"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_SAVE_EXIT
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Save and Exit"
+  </source>
+  <dest>
+    *: "Save and Exit"
+  </dest>
+  <voice>
+    *: "Save and Exit"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MAIN_MENU_ORDER
+  desc: main_menu_config plugin title
+  user: core
+  <source>
+    *: "Rockbox Main Menu Order"
+  </source>
+  <dest>
+    *: "Rockbox Main Menu Order"
+  </dest>
+  <voice>
+    *: ""
+  </voice>
+</phrase>
diff --git a/apps/lang/russian.lang b/apps/lang/russian.lang
index 632b0a1..9d28958 100644
--- a/apps/lang/russian.lang
+++ b/apps/lang/russian.lang
@@ -13700,3 +13700,87 @@
     charging: "Задержка перед возобновлением"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_TOGGLE_ITEM
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Toggle Item"
+  </source>
+  <dest>
+    *: "Сменить Статус"
+  </dest>
+  <voice>
+    *: "Сменить Статус"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MOVE_ITEM_UP
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Move Item Up"
+  </source>
+  <dest>
+    *: "Переместить вверх"
+  </dest>
+  <voice>
+    *: "Переместить вверх"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MOVE_ITEM_DOWN
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Move Item Down"
+  </source>
+  <dest>
+    *: "Переместить Вниз"
+  </dest>
+  <voice>
+    *: "Переместить Вниз"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_LOAD_DEFAULT_CONFIGURATION
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Load Default Configuration"
+  </source>
+  <dest>
+    *: "Загрузить Исходную Конфигурацию"
+  </dest>
+  <voice>
+    *: "Загрузить Исходную Конфигурацию"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_SAVE_EXIT
+  desc: in main_menu_config
+  user: core
+  <source>
+    *: "Save and Exit"
+  </source>
+  <dest>
+    *: "Сохранить и Выйти"
+  </dest>
+  <voice>
+    *: "Сохранить и Выйти"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_MAIN_MENU_ORDER
+  desc: main_menu_config plugin title
+  user: core
+  <source>
+    *: "Rockbox Main Menu Order"
+  </source>
+  <dest>
+    *: "Настройка Главного Меню Rockbox"
+  </dest>
+  <voice>
+    *: ""
+  </voice>
+</phrase>
diff --git a/apps/plugins/main_menu_config.c b/apps/plugins/main_menu_config.c
index 1015da7..f66165e 100644
--- a/apps/plugins/main_menu_config.c
+++ b/apps/plugins/main_menu_config.c
@@ -28,6 +28,7 @@
 #define MAX_ITEMS 16
 struct items
 {
+    unsigned char *name;
     char string[MAX_ITEM_NAME];
     bool enabled;
 };
@@ -41,8 +42,9 @@
     (void)data;
     (void)buffer;
     (void)buffer_len;
-
-    return menu_items[selected_item].string;
+    unsigned char *p = menu_items[selected_item].name;
+    int id = P2ID(p);
+    return (id != -1) ? rb->str(id) : p;
 }
 
 static enum themable_icons menu_get_icon(int selected_item, void * data)
@@ -52,6 +54,16 @@
     return menu_items[selected_item].enabled ? Icon_Config : Icon_NOICON;
 }
 
+static unsigned char *item_name(int n)
+{
+    const struct menu_item_ex *item = menu_table[n].item;
+    return (item->flags & MENU_HAS_DESC) ?
+      item->callback_and_desc->desc :
+      (rb->strcmp("wps", menu_table[n].string) ?
+       (unsigned char *)menu_table[n].string :
+       ID2P(LANG_RESUME_PLAYBACK));
+}
+
 void load_from_cfg(void)
 {
     char config_str[128];
@@ -60,20 +72,21 @@
     int i = 0;
     bool found = false;
 
+    config_str[0] = '\0';
     rb->root_menu_write_to_cfg(NULL, config_str, sizeof(config_str));
 
     token = rb->strtok_r(config_str, ", ", &save);
 
     while (token)
     {
-        i = 0;
-        found = false;
-        for (i = 0, found = false; i < menu_item_count && !found; i++)
+        for (i = 0, found = false; i < menu_item_count; i++)
         {
             found = rb->strcmp(token, menu_table[i].string) == 0;
+            if (found) break;
         }
         if (found)
         {
+            menu_items[done].name = item_name(i);
             rb->strcpy(menu_items[done].string, token);
             menu_items[done].enabled = true;
             done++;
@@ -93,6 +106,7 @@
 
             if (!found)
             {
+                menu_items[done].name = item_name(i);
                 rb->strcpy(menu_items[done].string, menu_table[i].string);
                 menu_items[done].enabled = false;
                 done++;
@@ -120,18 +134,36 @@
 
 static void swap_items(int a, int b)
 {
+    unsigned char *name;
     char temp[MAX_ITEM_NAME];
     bool enabled;
-    
+
+    name = menu_items[a].name;
     rb->strcpy(temp, menu_items[a].string);
     enabled = menu_items[a].enabled;
+    menu_items[a].name = menu_items[b].name;
     rb->strcpy(menu_items[a].string,
             menu_items[b].string);
     menu_items[a].enabled = menu_items[b].enabled;
+    menu_items[b].name = name;
     rb->strcpy(menu_items[b].string, temp);
     menu_items[b].enabled = enabled;
 }
 
+static int menu_speak_item(int selected_item, void *data)
+{
+    (void) data;
+    int id = P2ID(menu_items[selected_item].name);
+
+    if (id != -1)
+    {
+        rb->talk_id(id, false);
+        rb->talk_id(menu_items[selected_item].enabled ? LANG_ON : LANG_OFF, true);
+    }
+
+    return 0;
+}
+
 /* this is the plugin entry point */
 enum plugin_status plugin_start(const void* parameter)
 {
@@ -144,13 +176,16 @@
     load_from_cfg();
 
     rb->gui_synclist_init(&list, menu_get_name, NULL, false, 1, NULL);
+    if (rb->global_settings->talk_menu)
+        rb->gui_synclist_set_voice_callback(&list, menu_speak_item);
     rb->gui_synclist_set_icon_callback(&list, menu_get_icon);
     rb->gui_synclist_set_nb_items(&list, menu_item_count);
-    rb->gui_synclist_set_title(&list, "Rockbox Main Menu Order", Icon_Rockbox);
+    rb->gui_synclist_set_title(&list, rb->str(LANG_MAIN_MENU_ORDER), Icon_Rockbox);
+    rb->gui_synclist_draw(&list);
+    rb->gui_synclist_speak_item(&list);
 
     while (!done)
     {
-        rb->gui_synclist_draw(&list);
         cur_sel = rb->gui_synclist_get_sel_pos(&list);
         action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
         if (rb->gui_synclist_do_button(&list,&action,LIST_WRAP_UNLESS_HELD))
@@ -161,10 +196,12 @@
             case ACTION_STD_OK:
             {
                 MENUITEM_STRINGLIST(menu, "Main Menu Editor", NULL,
-                                        "Toggle Item",
-                                        "Move Item Up", "Move Item down",
-                                        "----------",
-                                        "Load Default Configuration", "Exit");
+                                    ID2P(LANG_TOGGLE_ITEM),
+                                    ID2P(LANG_MOVE_ITEM_UP),
+                                    ID2P(LANG_MOVE_ITEM_DOWN),
+                                    "----------",
+                                    ID2P(LANG_LOAD_DEFAULT_CONFIGURATION),
+                                    ID2P(LANG_SAVE_EXIT));
                 switch (rb->do_menu(&menu, NULL, NULL, false))
                 {
                     case 0:
@@ -191,6 +228,11 @@
                         rb->settings_save();
                         break;
                 }
+                if (!done)
+                {
+                    rb->gui_synclist_draw(&list);
+                    rb->gui_synclist_speak_item(&list);
+                }
                 break;
             }
             case ACTION_STD_CANCEL: