summaryrefslogtreecommitdiff
path: root/apps/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/menu.c')
-rw-r--r--apps/menu.c390
1 files changed, 168 insertions, 222 deletions
diff --git a/apps/menu.c b/apps/menu.c
index 62cce5a721..bc9ceea7b6 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -58,234 +58,19 @@
58#include "list.h" 58#include "list.h"
59#include "statusbar.h" 59#include "statusbar.h"
60#include "buttonbar.h" 60#include "buttonbar.h"
61 61/* needed for the old menu system */
62struct menu { 62struct menu {
63 struct menu_item* items; 63 struct menu_item* items;
64 int count;
64 int (*callback)(int, int); 65 int (*callback)(int, int);
65#ifdef HAS_BUTTONBAR 66 int current_selection;
66 struct gui_buttonbar buttonbar;
67#endif
68 struct gui_synclist synclist;
69}; 67};
70
71#define MAX_MENUS 6 68#define MAX_MENUS 6
72
73static struct menu menus[MAX_MENUS]; 69static struct menu menus[MAX_MENUS];
74static bool inuse[MAX_MENUS] = { false }; 70static bool inuse[MAX_MENUS] = { false };
75 71static void init_oldmenu(const struct menu_item_ex *menu,
76static char * menu_get_itemname(int selected_item, void * data, char *buffer) 72 struct gui_synclist *lists, int selected, bool callback);
77{ 73static void menu_talk_selected(int m);
78 struct menu *local_menus=(struct menu *)data;
79 (void)buffer;
80 return(P2STR(local_menus->items[selected_item].desc));
81}
82
83static int menu_find_free(void)
84{
85 int i;
86 /* Tries to find an unused slot to put the new menu */
87 for ( i=0; i<MAX_MENUS; i++ ) {
88 if ( !inuse[i] ) {
89 inuse[i] = true;
90 break;
91 }
92 }
93 if ( i == MAX_MENUS ) {
94 DEBUGF("Out of menus!\n");
95 return -1;
96 }
97 return(i);
98}
99
100int menu_init(const struct menu_item* mitems, int count, int (*callback)(int, int),
101 const char *button1, const char *button2, const char *button3)
102{
103 int menu=menu_find_free();
104 if(menu==-1)/* Out of menus */
105 return -1;
106 menus[menu].items = (struct menu_item*)mitems; /* de-const */
107 gui_synclist_init(&(menus[menu].synclist),
108 &menu_get_itemname, &menus[menu], false, 1);
109 gui_synclist_set_icon_callback(&(menus[menu].synclist), NULL);
110 gui_synclist_set_nb_items(&(menus[menu].synclist), count);
111 menus[menu].callback = callback;
112#ifdef HAS_BUTTONBAR
113 gui_buttonbar_init(&(menus[menu].buttonbar));
114 gui_buttonbar_set_display(&(menus[menu].buttonbar), &(screens[SCREEN_MAIN]) );
115 gui_buttonbar_set(&(menus[menu].buttonbar), button1, button2, button3);
116#else
117 (void)button1;
118 (void)button2;
119 (void)button3;
120#endif
121 return menu;
122}
123
124void menu_exit(int m)
125{
126 inuse[m] = false;
127}
128
129int menu_show(int m)
130{
131#ifdef HAS_BUTTONBAR
132 gui_buttonbar_draw(&(menus[m].buttonbar));
133#endif
134 bool exit = false;
135 int key;
136
137 gui_synclist_draw(&(menus[m].synclist));
138 gui_syncstatusbar_draw(&statusbars, true);
139 menu_talk_selected(m);
140 while (!exit) {
141 key = get_action(CONTEXT_MAINMENU,HZ/2);
142 /*
143 * "short-circuit" the default keypresses by running the
144 * callback function
145 * The callback may return a new key value, often this will be
146 * BUTTON_NONE or the same key value, but it's perfectly legal
147 * to "simulate" key presses by returning another value.
148 */
149 if( menus[m].callback != NULL )
150 key = menus[m].callback(key, m);
151 /* If moved, "say" the entry under the cursor */
152 if(gui_synclist_do_button(&(menus[m].synclist), key,LIST_WRAP_UNLESS_HELD))
153 menu_talk_selected(m);
154 switch( key ) {
155 case ACTION_STD_OK:
156 action_signalscreenchange();
157 return gui_synclist_get_sel_pos(&(menus[m].synclist));
158
159
160 case ACTION_STD_CANCEL:
161 case ACTION_STD_MENU:
162 exit = true;
163 break;
164
165 default:
166 if(default_event_handler(key) == SYS_USB_CONNECTED)
167 return MENU_ATTACHED_USB;
168 break;
169 }
170 gui_syncstatusbar_draw(&statusbars, false);
171 }
172 action_signalscreenchange();
173 return MENU_SELECTED_EXIT;
174}
175
176
177bool menu_run(int m)
178{
179 int selected;
180 while (1) {
181 switch (selected=menu_show(m))
182 {
183 case MENU_SELECTED_EXIT:
184 return false;
185
186 case MENU_ATTACHED_USB:
187 return true;
188
189 default:
190 {
191 if (menus[m].items[selected].function &&
192 menus[m].items[selected].function())
193 return true;
194 gui_syncstatusbar_draw(&statusbars, true);
195 }
196 }
197 }
198 return false;
199}
200
201/*
202 * Property function - return the current cursor for "menu"
203 */
204
205int menu_cursor(int menu)
206{
207 return gui_synclist_get_sel_pos(&(menus[menu].synclist));
208}
209
210/*
211 * Property function - return the "menu" description at "position"
212 */
213
214char* menu_description(int menu, int position)
215{
216 return P2STR(menus[menu].items[position].desc);
217}
218
219/*
220 * Delete the element "position" from the menu items in "menu"
221 */
222
223void menu_delete(int menu, int position)
224{
225 int i;
226 int nb_items=gui_synclist_get_nb_items(&(menus[menu].synclist));
227 /* copy the menu item from the one below */
228 for( i = position; i < nb_items - 1; i++)
229 menus[menu].items[i] = menus[menu].items[i + 1];
230
231 gui_synclist_del_item(&(menus[menu].synclist));
232}
233
234void menu_insert(int menu, int position, char *desc, bool (*function) (void))
235{
236 int i;
237 int nb_items=gui_synclist_get_nb_items(&(menus[menu].synclist));
238 if(position < 0)
239 position = nb_items;
240
241 /* Move the items below one position forward */
242 for( i = nb_items; i > position; i--)
243 menus[menu].items[i] = menus[menu].items[i - 1];
244
245 /* Update the current item */
246 menus[menu].items[position].desc = (unsigned char *)desc;
247 menus[menu].items[position].function = function;
248 gui_synclist_add_item(&(menus[menu].synclist));
249}
250
251/*
252 * Property function - return the "count" of menu items in "menu"
253 */
254
255int menu_count(int menu)
256{
257 return gui_synclist_get_nb_items(&(menus[menu].synclist));
258}
259
260/*
261 * Allows to set the cursor position. Doesn't redraw by itself.
262 */
263
264void menu_set_cursor(int menu, int position)
265{
266 gui_synclist_select_item(&(menus[menu].synclist), position);
267}
268
269void menu_talk_selected(int m)
270{
271 if(global_settings.talk_menu)
272 {
273 int selected=gui_synclist_get_sel_pos(&(menus[m].synclist));
274 int voice_id = P2ID(menus[m].items[selected].desc);
275 if (voice_id >= 0) /* valid ID given? */
276 talk_id(voice_id, false); /* say it */
277 }
278}
279
280void menu_draw(int m)
281{
282 gui_synclist_draw(&(menus[m].synclist));
283}
284
285/******************************************************************/
286/* New menu stuff here!!
287 ******************************************************************/
288
289 74
290/* used to allow for dynamic menus */ 75/* used to allow for dynamic menus */
291#define MAX_MENU_SUBITEMS 64 76#define MAX_MENU_SUBITEMS 64
@@ -395,6 +180,13 @@ static void init_menu_lists(const struct menu_item_ex *menu,
395 menu_callback_type menu_callback = NULL; 180 menu_callback_type menu_callback = NULL;
396 ICON icon = NOICON; 181 ICON icon = NOICON;
397 current_subitems_count = 0; 182 current_subitems_count = 0;
183
184 if ((menu->flags&MENU_TYPE_MASK) == MT_OLD_MENU)
185 {
186 init_oldmenu(menu, lists, selected, callback);
187 return;
188 }
189
398 for (i=0; i<count; i++) 190 for (i=0; i<count; i++)
399 { 191 {
400 get_menu_callback(menu->submenus[i],&menu_callback); 192 get_menu_callback(menu->submenus[i],&menu_callback);
@@ -441,10 +233,18 @@ static void talk_menu_item(const struct menu_item_ex *menu,
441 int id = -1; 233 int id = -1;
442 int type; 234 int type;
443 unsigned char *str; 235 unsigned char *str;
236 int sel;
444 237
445 if (global_settings.talk_menu) 238 if (global_settings.talk_menu)
446 { 239 {
447 int sel = get_menu_selection(gui_synclist_get_sel_pos(lists),menu); 240 if ((menu->flags&MENU_TYPE_MASK) == MT_OLD_MENU)
241 {
242 menus[menu->value].current_selection =
243 gui_synclist_get_sel_pos(lists);
244 menu_talk_selected(menu->value);
245 return;
246 }
247 sel = get_menu_selection(gui_synclist_get_sel_pos(lists),menu);
448 if ((menu->flags&MENU_TYPE_MASK) == MT_MENU) 248 if ((menu->flags&MENU_TYPE_MASK) == MT_MENU)
449 { 249 {
450 type = menu->submenus[sel]->flags&MENU_TYPE_MASK; 250 type = menu->submenus[sel]->flags&MENU_TYPE_MASK;
@@ -674,6 +474,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected)
674 } 474 }
675 else if (action == ACTION_STD_MENU) 475 else if (action == ACTION_STD_MENU)
676 { 476 {
477 if ((menu->flags&MENU_TYPE_MASK) == MT_OLD_MENU)
478 return MENU_SELECTED_EXIT;
677 if (menu != &root_menu_) 479 if (menu != &root_menu_)
678 ret = GO_TO_ROOT; 480 ret = GO_TO_ROOT;
679 else 481 else
@@ -709,6 +511,12 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected)
709 gui_buttonbar_unset(&buttonbar); 511 gui_buttonbar_unset(&buttonbar);
710 gui_buttonbar_draw(&buttonbar); 512 gui_buttonbar_draw(&buttonbar);
711#endif 513#endif
514 if ((menu->flags&MENU_TYPE_MASK) == MT_OLD_MENU)
515 {
516 selected = gui_synclist_get_sel_pos(&lists);
517 menus[menu->value].current_selection = selected;
518 return selected;
519 }
712 selected = get_menu_selection(gui_synclist_get_sel_pos(&lists), menu); 520 selected = get_menu_selection(gui_synclist_get_sel_pos(&lists), menu);
713 temp = menu->submenus[selected]; 521 temp = menu->submenus[selected];
714 if (in_stringlist) 522 if (in_stringlist)
@@ -797,3 +605,141 @@ int main_menu(void)
797{ 605{
798 return do_menu(NULL, 0); 606 return do_menu(NULL, 0);
799} 607}
608
609/* wrappers for the old menu system to work with the new system */
610
611
612static int menu_find_free(void)
613{
614 int i;
615 /* Tries to find an unused slot to put the new menu */
616 for ( i=0; i<MAX_MENUS; i++ ) {
617 if ( !inuse[i] ) {
618 inuse[i] = true;
619 break;
620 }
621 }
622 if ( i == MAX_MENUS ) {
623 DEBUGF("Out of menus!\n");
624 return -1;
625 }
626 return(i);
627}
628
629int menu_init(const struct menu_item* mitems, int count, int (*callback)(int, int),
630 const char *button1, const char *button2, const char *button3)
631{
632 (void)button1;
633 (void)button2;
634 (void)button3;
635 int menu=menu_find_free();
636 if(menu==-1)/* Out of menus */
637 return -1;
638 menus[menu].items = (struct menu_item*)mitems; /* de-const */
639 menus[menu].count = count;
640 menus[menu].callback = callback;
641 menus[menu].current_selection = 0;
642 return menu;
643}
644
645void menu_exit(int m)
646{
647 inuse[m] = false;
648}
649
650
651
652static int oldmenuwrapper_callback(int action,
653 const struct menu_item_ex *this_item)
654{
655 if (menus[this_item->value].callback)
656 {
657 int val = menus[this_item->value].callback(action, this_item->value);
658 switch (val)
659 {
660 case MENU_SELECTED_EXIT:
661 return ACTION_EXIT_MENUITEM;
662 }
663 return val;
664 }
665 return action;
666}
667
668static char* oldmenuwrapper_getname(int selected_item,
669 void * data, char *buffer)
670{
671 (void)buffer;
672 unsigned char* desc = menus[(intptr_t)data].items[selected_item].desc;
673 return P2STR(desc);
674}
675static void init_oldmenu(const struct menu_item_ex *menu,
676 struct gui_synclist *lists, int selected, bool callback)
677{
678 (void)callback;
679 gui_synclist_init(lists, oldmenuwrapper_getname,
680 (void*)menu->value, false, 1);
681 gui_synclist_set_nb_items(lists,
682 (menu->flags&MENU_COUNT_MASK)>>MENU_COUNT_SHIFT);
683 gui_synclist_limit_scroll(lists, true);
684 gui_synclist_select_item(lists, selected);
685}
686
687static void menu_talk_selected(int m)
688{
689 int selected = menus[m].current_selection;
690 int voice_id = P2ID(menus[m].items[selected].desc);
691 if (voice_id >= 0) /* valid ID given? */
692 talk_id(voice_id, false); /* say it */
693}
694
695int menu_show(int m)
696{
697 struct menu_item_ex menu;
698 struct menu_get_name_and_icon menu_info =
699 {
700 oldmenuwrapper_callback,
701 oldmenuwrapper_getname,
702 (void*)m, Icon_NOICON
703 };
704
705 menu.flags = (MENU_TYPE_MASK&MT_OLD_MENU) | MENU_DYNAMIC_DESC |
706 MENU_ITEM_COUNT(menus[m].count);
707 menu.value = m;
708 menu.menu_get_name_and_icon = &menu_info;
709 return do_menu(&menu, &menus[m].current_selection);
710}
711
712
713bool menu_run(int m)
714{
715 int selected;
716 while (1) {
717 switch (selected=menu_show(m))
718 {
719 case MENU_SELECTED_EXIT:
720 return false;
721
722 case MENU_ATTACHED_USB:
723 return true;
724
725 default:
726 {
727 if (menus[m].items[selected].function &&
728 menus[m].items[selected].function())
729 return true;
730 gui_syncstatusbar_draw(&statusbars, true);
731 }
732 }
733 }
734 return false;
735}
736
737/*
738 * Property function - return the "count" of menu items in "menu"
739 */
740
741int menu_count(int menu)
742{
743 return menus[menu].count;
744}
745