diff options
Diffstat (limited to 'apps/menu.c')
-rw-r--r-- | apps/menu.c | 390 |
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 */ | |
62 | struct menu { | 62 | struct 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 | |||
73 | static struct menu menus[MAX_MENUS]; | 69 | static struct menu menus[MAX_MENUS]; |
74 | static bool inuse[MAX_MENUS] = { false }; | 70 | static bool inuse[MAX_MENUS] = { false }; |
75 | 71 | static void init_oldmenu(const struct menu_item_ex *menu, | |
76 | static char * menu_get_itemname(int selected_item, void * data, char *buffer) | 72 | struct gui_synclist *lists, int selected, bool callback); |
77 | { | 73 | static 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 | |||
83 | static 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 | |||
100 | int 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 | |||
124 | void menu_exit(int m) | ||
125 | { | ||
126 | inuse[m] = false; | ||
127 | } | ||
128 | |||
129 | int 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 | |||
177 | bool 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 | |||
205 | int 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 | |||
214 | char* 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 | |||
223 | void 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 | |||
234 | void 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 | |||
255 | int 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 | |||
264 | void menu_set_cursor(int menu, int position) | ||
265 | { | ||
266 | gui_synclist_select_item(&(menus[menu].synclist), position); | ||
267 | } | ||
268 | |||
269 | void 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 | |||
280 | void 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 | |||
612 | static 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 | |||
629 | int 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 | |||
645 | void menu_exit(int m) | ||
646 | { | ||
647 | inuse[m] = false; | ||
648 | } | ||
649 | |||
650 | |||
651 | |||
652 | static 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 | |||
668 | static 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 | } | ||
675 | static 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 | |||
687 | static 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 | |||
695 | int 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 | |||
713 | bool 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 | |||
741 | int menu_count(int menu) | ||
742 | { | ||
743 | return menus[menu].count; | ||
744 | } | ||
745 | |||