1 /* menu.c: general menu widget
2    Copyright (c) 2001-2006 Philip Kendall
3 
4    $Id: menu.c 4968 2013-05-19 16:11:17Z zubzero $
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20    Author contact information:
21 
22    E-mail: philip-fuse@shadowmagic.org.uk
23 
24 */
25 
26 #include <config.h>
27 
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "debugger/debugger.h"
33 #include "event.h"
34 #include "fuse.h"
35 #include "keyboard.h"
36 #include "machine.h"
37 #include "machines/specplus3.h"
38 #include "menu.h"
39 #include "peripherals/dck.h"
40 #include "peripherals/disk/beta.h"
41 #include "peripherals/joystick.h"
42 #include "psg.h"
43 #include "rzx.h"
44 #include "screenshot.h"
45 #include "settings.h"
46 #include "snapshot.h"
47 #include "tape.h"
48 #include "ui/uidisplay.h"
49 #include "utils.h"
50 #include "widget_internals.h"
51 #include "widget.h"
52 
53 widget_menu_entry *menu;
54 static size_t highlight_line = 0;
55 static size_t count;
56 static int *current_settings[ 16 ];
57 
58 #define GET_SET_KEY_FUNCTIONS( which ) \
59 \
60 void \
61 set_key_for_button_ ## which ( int action ) \
62 { \
63   *current_settings[ which ] = action; \
64   widget_end_all( WIDGET_FINISHED_OK ); \
65 } \
66 \
67 const char* \
68 get_key_name_for_button_ ## which ( void ) \
69 { \
70   return keyboard_key_text( *current_settings[ which ] ); \
71 }
72 
73 GET_SET_KEY_FUNCTIONS( 1 )
74 GET_SET_KEY_FUNCTIONS( 2 )
75 GET_SET_KEY_FUNCTIONS( 3 )
76 GET_SET_KEY_FUNCTIONS( 4 )
77 GET_SET_KEY_FUNCTIONS( 5 )
78 GET_SET_KEY_FUNCTIONS( 6 )
79 GET_SET_KEY_FUNCTIONS( 7 )
80 GET_SET_KEY_FUNCTIONS( 8 )
81 GET_SET_KEY_FUNCTIONS( 9 )
82 GET_SET_KEY_FUNCTIONS( 10 )
83 GET_SET_KEY_FUNCTIONS( 11 )
84 GET_SET_KEY_FUNCTIONS( 12 )
85 GET_SET_KEY_FUNCTIONS( 13 )
86 GET_SET_KEY_FUNCTIONS( 14 )
87 GET_SET_KEY_FUNCTIONS( 15 )
88 
89 #define SUBMENU_KEY_SELECTIONS( which ) \
90 \
91 static widget_menu_entry submenu_select_number_for_button_ ## which [] = { \
92   { "Select a key" }, \
93   { "\0120\011", INPUT_KEY_0, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_0 }, \
94   { "\0121\011", INPUT_KEY_1, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_1 }, \
95   { "\0122\011", INPUT_KEY_2, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_2 }, \
96   { "\0123\011", INPUT_KEY_3, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_3 }, \
97   { "\0124\011", INPUT_KEY_4, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_4 }, \
98   { "\0125\011", INPUT_KEY_5, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_5 }, \
99   { "\0126\011", INPUT_KEY_6, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_6 }, \
100   { "\0127\011", INPUT_KEY_7, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_7 }, \
101   { "\0128\011", INPUT_KEY_8, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_8 }, \
102   { "\0129\011", INPUT_KEY_9, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_9 }, \
103   { NULL } \
104 }; \
105 \
106 static widget_menu_entry submenu_select_letters1_for_button_ ## which [] = { \
107   { "Select a key" }, \
108   { "\012A\011", INPUT_KEY_a, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_a }, \
109   { "\012B\011", INPUT_KEY_b, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_b }, \
110   { "\012C\011", INPUT_KEY_c, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_c }, \
111   { "\012D\011", INPUT_KEY_d, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_d }, \
112   { "\012E\011", INPUT_KEY_e, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_e }, \
113   { "\012F\011", INPUT_KEY_f, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_f }, \
114   { "\012G\011", INPUT_KEY_g, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_g }, \
115   { "\012H\011", INPUT_KEY_h, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_h }, \
116   { "\012I\011", INPUT_KEY_i, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_i }, \
117   { "\012J\011", INPUT_KEY_j, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_j }, \
118   { "\012K\011", INPUT_KEY_k, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_k }, \
119   { "\012L\011", INPUT_KEY_l, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_l }, \
120   { "\012M\011", INPUT_KEY_m, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_m }, \
121   { NULL } \
122 }; \
123 \
124 static widget_menu_entry submenu_select_letters2_for_button_ ## which [] = { \
125   { "Select a key" }, \
126   { "\012N\011", INPUT_KEY_n, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_n }, \
127   { "\012O\011", INPUT_KEY_o, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_o }, \
128   { "\012P\011", INPUT_KEY_p, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_p }, \
129   { "\012Q\011", INPUT_KEY_q, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_q }, \
130   { "\012R\011", INPUT_KEY_r, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_r }, \
131   { "\012S\011", INPUT_KEY_s, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_s }, \
132   { "\012T\011", INPUT_KEY_t, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_t }, \
133   { "\012U\011", INPUT_KEY_u, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_u }, \
134   { "\012V\011", INPUT_KEY_v, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_v }, \
135   { "\012W\011", INPUT_KEY_w, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_w }, \
136   { "\012X\011", INPUT_KEY_x, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_x }, \
137   { "\012Y\011", INPUT_KEY_y, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_y }, \
138   { "\012Z\011", INPUT_KEY_z, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_z }, \
139   { NULL } \
140 }; \
141 \
142 static widget_menu_entry submenu_select_key_for_button_ ## which [] = { \
143   { "Select a key" }, \
144   { "\012J\011oystick fire", INPUT_KEY_j, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_JOYSTICK_FIRE }, \
145   { "\012N\011umbers...", INPUT_KEY_n, submenu_select_number_for_button_ ## which , NULL, NULL, 0 }, \
146   { "\012A\011-M...", INPUT_KEY_a, submenu_select_letters1_for_button_ ## which , NULL, NULL, 0 }, \
147   { "N-\012Z\011...", INPUT_KEY_z, submenu_select_letters2_for_button_ ## which , NULL, NULL, 0 }, \
148   { "\012S\011pace", INPUT_KEY_s, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_space }, \
149   { "\012E\011nter", INPUT_KEY_e, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_Enter }, \
150   { "\012C\011aps Shift", INPUT_KEY_c, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_Caps }, \
151   { "S\012y\011mbol Shift", INPUT_KEY_y, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_Symbol }, \
152   { "N\012o\011thing", INPUT_KEY_o, NULL, set_key_for_button_ ## which, NULL, KEYBOARD_NONE }, \
153   { NULL } \
154 };
155 
156 SUBMENU_KEY_SELECTIONS( 1 )
157 SUBMENU_KEY_SELECTIONS( 2 )
158 SUBMENU_KEY_SELECTIONS( 3 )
159 SUBMENU_KEY_SELECTIONS( 4 )
160 SUBMENU_KEY_SELECTIONS( 5 )
161 #ifdef USE_JOYSTICK
162 SUBMENU_KEY_SELECTIONS( 6 )
163 SUBMENU_KEY_SELECTIONS( 7 )
164 SUBMENU_KEY_SELECTIONS( 8 )
165 #ifndef GEKKO
166 SUBMENU_KEY_SELECTIONS( 9 )
167 SUBMENU_KEY_SELECTIONS( 10 )
168 SUBMENU_KEY_SELECTIONS( 11 )
169 SUBMENU_KEY_SELECTIONS( 12 )
170 SUBMENU_KEY_SELECTIONS( 13 )
171 SUBMENU_KEY_SELECTIONS( 14 )
172 SUBMENU_KEY_SELECTIONS( 15 )
173 #endif  /* #ifndef GEKKO */
174 #endif  /* #ifdef USE_JOYSTICK */
175 
176 #ifdef USE_JOYSTICK
177 static widget_menu_entry submenu_joystick_buttons[] = {
178   { "Select joystick button" },
179 #ifndef GEKKO
180   { "Button \0121\011", INPUT_KEY_1, submenu_select_key_for_button_1, NULL, get_key_name_for_button_1, 0 },
181   { "Button \0122\011", INPUT_KEY_2, submenu_select_key_for_button_2, NULL, get_key_name_for_button_2, 0 },
182   { "Button \0123\011", INPUT_KEY_3, submenu_select_key_for_button_3, NULL, get_key_name_for_button_3, 0 },
183   { "Button \0124\011", INPUT_KEY_4, submenu_select_key_for_button_4, NULL, get_key_name_for_button_4, 0 },
184   { "Button \0125\011", INPUT_KEY_5, submenu_select_key_for_button_5, NULL, get_key_name_for_button_5, 0 },
185   { "Button \0126\011", INPUT_KEY_6, submenu_select_key_for_button_6, NULL, get_key_name_for_button_6, 0 },
186   { "Button \0127\011", INPUT_KEY_7, submenu_select_key_for_button_7, NULL, get_key_name_for_button_7, 0 },
187   { "Button \0128\011", INPUT_KEY_8, submenu_select_key_for_button_8, NULL, get_key_name_for_button_8, 0 },
188   { "Button \0129\011", INPUT_KEY_9, submenu_select_key_for_button_9, NULL, get_key_name_for_button_9, 0 },
189   { "Button 1\0120\011", INPUT_KEY_0, submenu_select_key_for_button_10, NULL, get_key_name_for_button_10, 0 },
190   { "Button 11(\012a\011)", INPUT_KEY_a, submenu_select_key_for_button_11, NULL, get_key_name_for_button_11, 0 },
191   { "Button 12(\012b\011)", INPUT_KEY_b, submenu_select_key_for_button_12, NULL, get_key_name_for_button_12, 0 },
192   { "Button 13(\012c\011)", INPUT_KEY_c, submenu_select_key_for_button_13, NULL, get_key_name_for_button_13, 0 },
193   { "Button 14(\012d\011)", INPUT_KEY_d, submenu_select_key_for_button_14, NULL, get_key_name_for_button_14, 0 },
194   { "Button 15(\012e\011)", INPUT_KEY_e, submenu_select_key_for_button_15, NULL, get_key_name_for_button_15, 0 },
195 #else  /* #ifndef GEKKO */
196   { "Button \0121\011", INPUT_KEY_1, submenu_select_key_for_button_1, NULL, get_key_name_for_button_1, 0 },
197   { "Button \0122\011", INPUT_KEY_2, submenu_select_key_for_button_2, NULL, get_key_name_for_button_2, 0 },
198   { "Button \012A\011", INPUT_KEY_a, submenu_select_key_for_button_3, NULL, get_key_name_for_button_3, 0 },
199   { "Button \012B\011", INPUT_KEY_b, submenu_select_key_for_button_4, NULL, get_key_name_for_button_4, 0 },
200   { "Button \012P\011lus", INPUT_KEY_p, submenu_select_key_for_button_5, NULL, get_key_name_for_button_5, 0 },
201   { "Button \012M\011inus", INPUT_KEY_m, submenu_select_key_for_button_6, NULL, get_key_name_for_button_6, 0 },
202   { "Button \012Z\011 on Nunchuck", INPUT_KEY_z, submenu_select_key_for_button_7, NULL, get_key_name_for_button_7, 0 },
203   { "Button \012C\011 on Nunchuck", INPUT_KEY_c, submenu_select_key_for_button_8, NULL, get_key_name_for_button_8, 0 },
204 #endif  /* #ifndef GEKKO */
205   { NULL }
206 };
207 #endif  /* #ifdef USE_JOYSTICK */
208 
209 static widget_menu_entry submenu_keyboard_buttons[] = {
210   { "Select keyboard key" },
211   { "Button \012U\011p", INPUT_KEY_u, submenu_select_key_for_button_1, NULL, get_key_name_for_button_1, 0 },
212   { "Button \012D\011own", INPUT_KEY_d, submenu_select_key_for_button_2, NULL, get_key_name_for_button_2, 0 },
213   { "Button \012L\011eft", INPUT_KEY_l, submenu_select_key_for_button_3, NULL, get_key_name_for_button_3, 0 },
214   { "Button \012R\011ight", INPUT_KEY_r, submenu_select_key_for_button_4, NULL,	get_key_name_for_button_4, 0 },
215   { "Button \012F\011ire", INPUT_KEY_f, submenu_select_key_for_button_5, NULL, get_key_name_for_button_5, 0 },
216   { NULL }
217 };
218 
219 #define MAX_JOYSTICK_TYPES 8
220 /* joystick types + title of the window + NULL */
221 static widget_menu_entry submenu_types[ MAX_JOYSTICK_TYPES + 2 ];
222 static char joystick_names[ MAX_JOYSTICK_TYPES ][ 100 ];
223 void set_joystick_type( int action );
224 
225 #define SUBMENU_DEVICE_SELECTIONS( device ) \
226 \
227 static widget_menu_entry submenu_type_and_mapping_for_ ## device [] = { \
228   { "Select type or map buttons" }, \
229   { "\012T\011ype", INPUT_KEY_t, submenu_types, NULL, NULL, 0 }, \
230   { "\012B\011utton Mapping", INPUT_KEY_b, submenu_ ## device ## _buttons, NULL, NULL, 0 }, \
231   { NULL } \
232 };
233 
234 #ifdef USE_JOYSTICK
235 SUBMENU_DEVICE_SELECTIONS( joystick )
236 #endif  /* #ifdef USE_JOYSTICK */
SUBMENU_DEVICE_SELECTIONS(keyboard)237 SUBMENU_DEVICE_SELECTIONS( keyboard )
238 
239 void
240 print_items( void )
241 {
242   int i;
243   char buffer[128];
244   size_t height = 24;
245   int width = widget_calculate_menu_width(menu);
246   int menu_left_edge_x = (DISPLAY_WIDTH_COLS/2-width/2)*8+1;
247 
248   for( i = 0; i < count; i++ ) {
249     int colour;
250     if( !menu[i+1].text[0] ) { height += 4; continue; }
251 
252     snprintf( buffer, sizeof (buffer), "%s", menu[i+1].text );
253     colour = menu[i+1].inactive ?
254 	     WIDGET_COLOUR_DISABLED :
255 	     WIDGET_COLOUR_FOREGROUND;
256 
257     if( i == highlight_line ) {
258       widget_rectangle( menu_left_edge_x, height, width*8-2, 1*8,
259                         WIDGET_COLOUR_HIGHLIGHT );
260     } else {
261       widget_rectangle( menu_left_edge_x, height, width*8-2, 1*8,
262                         WIDGET_COLOUR_BACKGROUND );
263     }
264 
265     widget_printstring( menu_left_edge_x+8, height, colour, buffer );
266 
267     if( menu[i+1].submenu ) {
268       widget_draw_submenu_arrow(DISPLAY_BORDER_ASPECT_WIDTH+menu_left_edge_x+
269                                 width*8-9, i*8+49, colour);
270     }
271 
272     if( menu[i+1].detail ) {
273       size_t detail_width = widget_stringwidth( menu[i+1].detail() );
274       int x = menu_left_edge_x + (width-1)*8 - detail_width - 2;
275       widget_printstring( x, height, WIDGET_COLOUR_DISABLED, menu[i+1].detail() );
276     }
277 
278     height += 8;
279   }
280 
281   widget_display_lines( 2, count + 2 );
282 }
283 
widget_menu_draw(void * data)284 int widget_menu_draw( void *data )
285 {
286   widget_menu_entry *ptr;
287   size_t menu_entries, width, height = 0;
288   int menu_left_edge_x;
289   char buffer[128];
290   highlight_line = 0;
291 
292   menu = (widget_menu_entry*)data;
293 
294   /* How many menu items do we have? */
295   for( ptr = &menu[1]; ptr->text; ptr++ )
296     height += ptr->text[0] ? 2 : 1;
297   menu_entries = ptr - &menu[1];
298   count = menu_entries;
299   width = widget_calculate_menu_width(menu);
300   menu_left_edge_x = DISPLAY_WIDTH_COLS/2-width/2;
301   widget_dialog_with_border( menu_left_edge_x, 2, width, 2 + height / 2 );
302 
303   snprintf( buffer, sizeof( buffer ), "%s", menu->text );
304   widget_printstring( menu_left_edge_x*8+2, 16, WIDGET_COLOUR_TITLE, buffer );
305 
306   print_items();
307   return 0;
308 }
309 
310 void
widget_menu_keyhandler(input_key key)311 widget_menu_keyhandler( input_key key )
312 {
313   widget_menu_entry *ptr;
314   int new_highlight_line = 0;
315   int cursor_pressed = 0;
316 
317   switch( key ) {
318 
319 #if 0
320   case INPUT_KEY_Resize:	/* Fake keypress used on window resize */
321     widget_menu_draw( menu );
322     break;
323 #endif
324 
325   case INPUT_KEY_Escape:
326   case INPUT_JOYSTICK_FIRE_2:
327     widget_end_widget( WIDGET_FINISHED_CANCEL );
328     return;
329 
330   case INPUT_KEY_Return:
331   case INPUT_KEY_KP_Enter:
332   case INPUT_JOYSTICK_FIRE_1:
333     ptr=&menu[1 + highlight_line];
334     if(!ptr->inactive) {
335       if( ptr->submenu ) {
336         widget_do( WIDGET_TYPE_MENU, ptr->submenu );
337       } else {
338         ptr->callback( ptr->action );
339       }
340     }
341     return;
342 
343   case INPUT_KEY_Up:
344   case INPUT_KEY_7:
345   case INPUT_JOYSTICK_UP:
346     if ( highlight_line ) {
347       new_highlight_line = highlight_line - 1;
348       cursor_pressed = 1;
349     }
350     break;
351 
352   case INPUT_KEY_Down:
353   case INPUT_KEY_6:
354   case INPUT_JOYSTICK_DOWN:
355     if ( highlight_line + 1 < (ptrdiff_t)count ) {
356       new_highlight_line = highlight_line + 1;
357       cursor_pressed = 1;
358     }
359     break;
360 
361   default:	/* Keep gcc happy */
362     break;
363 
364   }
365 
366   if( cursor_pressed ) {
367     highlight_line = new_highlight_line;
368     print_items();
369     return;
370   }
371 
372   for( ptr=&menu[1]; ptr->text; ptr++ ) {
373     if( !ptr->inactive && key == ptr->key ) {
374 
375       if( ptr->submenu ) {
376         widget_do( WIDGET_TYPE_MENU, ptr->submenu );
377       } else {
378         ptr->callback( ptr->action );
379       }
380 
381       break;
382     }
383   }
384 }
385 
386 /* General callbacks */
387 
388 scaler_type
menu_get_scaler(scaler_available_fn selector)389 menu_get_scaler( scaler_available_fn selector )
390 {
391   size_t count, i;
392   const char *options[ SCALER_NUM ];
393   widget_select_t info;
394   int error;
395 
396   count = 0; info.current = 0;
397 
398   for( i = 0; i < SCALER_NUM; i++ )
399     if( selector( i ) ) {
400       if( current_scaler == i ) info.current = count;
401       options[ count++ ] = scaler_name( i );
402     }
403 
404   info.title = "Select scaler";
405   info.options = options;
406   info.count = count;
407   info.finish_all = 1;
408 
409   error = widget_do( WIDGET_TYPE_SELECT, &info );
410   if( error ) return SCALER_NUM;
411 
412   if( info.result == -1 ) return SCALER_NUM;
413 
414   for( i = 0; i < SCALER_NUM; i++ )
415     if( selector( i ) && !info.result-- ) return i;
416 
417   ui_error( UI_ERROR_ERROR, "widget_select_scaler: ran out of scalers" );
418   fuse_abort();
419 }
420 
421 void
menu_file_exit(int action)422 menu_file_exit( int action )
423 {
424   if( widget_do( WIDGET_TYPE_QUERY, "Exit Fuse?" ) || !widget_query.confirm )
425     return;
426 
427   if( menu_check_media_changed() ) return;
428 
429   fuse_exiting = 1;
430 
431   widget_end_all( WIDGET_FINISHED_OK );
432 }
433 
434 void
menu_options_general(int action)435 menu_options_general( int action )
436 {
437   widget_do( WIDGET_TYPE_GENERAL, NULL );
438 }
439 
440 void
menu_options_peripherals_general(int action)441 menu_options_peripherals_general( int action )
442 {
443   widget_do( WIDGET_TYPE_PERIPHERALS_GENERAL, NULL );
444 }
445 
446 void
menu_options_peripherals_disk(int action)447 menu_options_peripherals_disk( int action )
448 {
449   widget_do( WIDGET_TYPE_PERIPHERALS_DISK, NULL );
450 }
451 
452 void
menu_options_sound(int action)453 menu_options_sound( int action )
454 {
455   widget_do( WIDGET_TYPE_SOUND, NULL );
456 }
457 
458 void
menu_options_rzx(int action)459 menu_options_rzx( int action )
460 {
461   widget_do( WIDGET_TYPE_RZX, NULL );
462 }
463 
464 void
menu_options_movie(int action)465 menu_options_movie( int action )
466 {
467   widget_do( WIDGET_TYPE_MOVIE, NULL );
468 }
469 
470 void
menu_options_diskoptions(int action)471 menu_options_diskoptions( int action )
472 {
473   widget_do( WIDGET_TYPE_DISKOPTIONS, NULL );
474 }
475 
476 void
menu_options_joysticks_select(int action)477 menu_options_joysticks_select( int action )
478 {
479   int error = 0;
480   int i;
481 
482   switch( action - 1 ) {
483 
484 #ifdef USE_JOYSTICK
485   case 0:
486     current_settings[ 0 ] = &( settings_current.joystick_1_output );
487     current_settings[ 1 ] = &( settings_current.joystick_1_fire_1 );
488     current_settings[ 2 ] = &( settings_current.joystick_1_fire_2 );
489     current_settings[ 3 ] = &( settings_current.joystick_1_fire_3 );
490     current_settings[ 4 ] = &( settings_current.joystick_1_fire_4 );
491     current_settings[ 5 ] = &( settings_current.joystick_1_fire_5 );
492     current_settings[ 6 ] = &( settings_current.joystick_1_fire_6 );
493     current_settings[ 7 ] = &( settings_current.joystick_1_fire_7 );
494     current_settings[ 8 ] = &( settings_current.joystick_1_fire_8 );
495     current_settings[ 9 ] = &( settings_current.joystick_1_fire_9 );
496     current_settings[ 10 ] = &( settings_current.joystick_1_fire_10 );
497     current_settings[ 11 ] = &( settings_current.joystick_1_fire_11 );
498     current_settings[ 12 ] = &( settings_current.joystick_1_fire_12 );
499     current_settings[ 13 ] = &( settings_current.joystick_1_fire_13 );
500     current_settings[ 14 ] = &( settings_current.joystick_1_fire_14 );
501     current_settings[ 15 ] = &( settings_current.joystick_1_fire_15 );
502     submenu_type_and_mapping_for_joystick[ 1 ].detail = menu_joystick_1_detail;
503     break;
504   case 1:
505     current_settings[ 0 ] = &( settings_current.joystick_2_output );
506     current_settings[ 1 ] = &( settings_current.joystick_2_fire_1 );
507     current_settings[ 2 ] = &( settings_current.joystick_2_fire_2 );
508     current_settings[ 3 ] = &( settings_current.joystick_2_fire_3 );
509     current_settings[ 4 ] = &( settings_current.joystick_2_fire_4 );
510     current_settings[ 5 ] = &( settings_current.joystick_2_fire_5 );
511     current_settings[ 6 ] = &( settings_current.joystick_2_fire_6 );
512     current_settings[ 7 ] = &( settings_current.joystick_2_fire_7 );
513     current_settings[ 8 ] = &( settings_current.joystick_2_fire_8 );
514     current_settings[ 9 ] = &( settings_current.joystick_2_fire_9 );
515     current_settings[ 10 ] = &( settings_current.joystick_2_fire_10 );
516     current_settings[ 11 ] = &( settings_current.joystick_2_fire_11 );
517     current_settings[ 12 ] = &( settings_current.joystick_2_fire_12 );
518     current_settings[ 13 ] = &( settings_current.joystick_2_fire_13 );
519     current_settings[ 14 ] = &( settings_current.joystick_2_fire_14 );
520     current_settings[ 15 ] = &( settings_current.joystick_2_fire_15 );
521     submenu_type_and_mapping_for_joystick[ 1 ].detail = menu_joystick_2_detail;
522     break;
523 #endif  /* #ifdef USE_JOYSTICK */
524 
525   case JOYSTICK_KEYBOARD:
526     current_settings[ 0 ] = &( settings_current.joystick_keyboard_output );
527     current_settings[ 1 ] = &( settings_current.joystick_keyboard_up );
528     current_settings[ 2 ] = &( settings_current.joystick_keyboard_down );
529     current_settings[ 3 ] = &( settings_current.joystick_keyboard_left );
530     current_settings[ 4 ] = &( settings_current.joystick_keyboard_right );
531     current_settings[ 5 ] = &( settings_current.joystick_keyboard_fire );
532     submenu_type_and_mapping_for_keyboard[ 1 ].detail = menu_keyboard_joystick_detail;
533     break;
534   }
535 
536   /* Populate joystick names */
537   if( JOYSTICK_TYPE_COUNT > MAX_JOYSTICK_TYPES )
538     ui_error( UI_ERROR_ERROR, "Not all joystick types are displayed" );
539 
540   submenu_types[ 0 ].text = "Select joystick type";
541   for( i = 0; ( i < JOYSTICK_TYPE_COUNT ) && ( i < MAX_JOYSTICK_TYPES ); i++ ) {
542     char shortcut[ 2 ] = { 'A' + i, '\0' };
543     snprintf( ( char * ) joystick_names[ i ], 100, "\012%s\011 %s", shortcut,
544               joystick_name[ i ] );
545     submenu_types[ i + 1 ].text = joystick_names[ i ];
546     submenu_types[ i + 1 ].key = INPUT_KEY_a + i;
547     submenu_types[ i + 1 ].callback = set_joystick_type;
548     submenu_types[ i + 1 ].action = i;
549   }
550   submenu_types[ i + 1 ].text = NULL;
551 
552   if( action - 1 == JOYSTICK_KEYBOARD )
553     error = widget_do( WIDGET_TYPE_MENU, submenu_type_and_mapping_for_keyboard );
554 
555 #ifdef USE_JOYSTICK
556   else
557     error = widget_do( WIDGET_TYPE_MENU, submenu_type_and_mapping_for_joystick );
558 #endif  /* #ifdef USE_JOYSTICK */
559 
560   if( error ) return;
561 }
562 
563 void
set_joystick_type(int action)564 set_joystick_type( int action )
565 {
566   *current_settings[ 0 ] = action;
567   widget_end_all( WIDGET_FINISHED_OK );
568 }
569 
570 /* Options/Select ROMs/<type> */
571 int
menu_select_roms_with_title(const char * title,size_t start,size_t count)572 menu_select_roms_with_title( const char *title, size_t start, size_t count )
573 {
574   widget_roms_info info;
575 
576   info.title = title;
577   info.start = start;
578   info.count = count;
579   info.initialised = 0;
580 
581   return widget_do( WIDGET_TYPE_ROM, &info );
582 }
583 
584 void
menu_machine_reset(int action)585 menu_machine_reset( int action )
586 {
587   int hard_reset = action;
588   const char *message = "Reset?";
589 
590   if( hard_reset )
591     message = "Hard reset?";
592 
593   if( widget_do( WIDGET_TYPE_QUERY, message ) ||
594       !widget_query.confirm )
595     return;
596 
597   widget_end_all( WIDGET_FINISHED_OK );
598   machine_reset( hard_reset );
599 }
600 
601 void
menu_machine_select(int action)602 menu_machine_select( int action )
603 {
604   widget_select_t info;
605   char **options, *buffer;
606   size_t i;
607   int error;
608   libspectrum_machine new_machine;
609 
610   options = malloc( machine_count * sizeof( const char * ) );
611   if( !options ) {
612     ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__, __LINE__ );
613     return;
614   }
615 
616   buffer = malloc( 40 * machine_count );
617   if( !buffer ) {
618     ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__, __LINE__ );
619     free( options );
620     return;
621   }
622 
623   for( i = 0; i < machine_count; i++ ) {
624     options[i] = &buffer[ i * 40 ];
625     snprintf( options[i], 40, "%s",
626               libspectrum_machine_name( machine_types[i]->machine ) );
627     if( machine_current->machine == machine_types[i]->machine )
628       info.current = i;
629   }
630 
631   info.title = "Select machine";
632   info.options = (const char**)options;
633   info.count = machine_count;
634   info.finish_all = 1;
635 
636   error = widget_do( WIDGET_TYPE_SELECT, &info );
637   free( buffer ); free( options );
638   if( error ) return;
639 
640   if( info.result == -1 ) return;
641 
642   new_machine = machine_types[ info.result ]->machine;
643 
644   if( machine_current->machine != new_machine ) machine_select( new_machine );
645 }
646 
647 void
menu_machine_debugger(int action)648 menu_machine_debugger( int action )
649 {
650   debugger_mode = DEBUGGER_MODE_HALTED;
651   widget_do( WIDGET_TYPE_DEBUGGER, NULL );
652 }
653 
654 void
menu_machine_pokememory(int action)655 menu_machine_pokememory( int action )
656 {
657   widget_do( WIDGET_TYPE_POKEMEM, NULL );
658 }
659 
660 void
menu_machine_pokefinder(int action)661 menu_machine_pokefinder( int action )
662 {
663   widget_do( WIDGET_TYPE_POKEFINDER, NULL );
664 }
665 
666 void
menu_machine_memorybrowser(int action)667 menu_machine_memorybrowser( int action )
668 {
669   widget_do( WIDGET_TYPE_MEMORYBROWSER, NULL );
670 }
671 
672 void
menu_media_tape_browse(int action)673 menu_media_tape_browse( int action )
674 {
675   widget_do( WIDGET_TYPE_BROWSE, NULL );
676 }
677 
678 void
menu_help_keyboard(int action)679 menu_help_keyboard( int action )
680 {
681   utils_file screen;
682   widget_picture_data info;
683 
684   static const char *filename = "keyboard.scr";
685 
686   if( utils_read_screen( filename, &screen ) ) {
687     return;
688   }
689 
690   info.filename = filename;
691   info.screen = screen.buffer;
692   info.border = 0;
693 
694   widget_do( WIDGET_TYPE_PICTURE, &info );
695 
696   utils_close_file( &screen );
697 }
698 
699 void
menu_help_about(int action)700 menu_help_about( int action )
701 {
702   widget_end_all( WIDGET_FINISHED_OK );
703   ui_error( UI_ERROR_INFO,
704            "Free Unix Spectrum Emulator (Fuse) %s %s. See %s for details.",
705             VERSION, FUSE_COPYRIGHT, PACKAGE_URL );
706 }
707 
708 static int
set_active(struct widget_menu_entry * menu,const char * path,int active)709 set_active( struct widget_menu_entry *menu, const char *path, int active )
710 {
711   if( *path == '/' ) path++;
712 
713   /* Skip the menu title */
714   menu++;
715 
716   for( ; menu->text; menu++ ) {
717 
718     const char *p = menu->text, *q = path;
719 
720     /* Compare the two strings, but skip hotkey-delimiter characters */
721     do {
722       if( *p == 9 || *p == 10 ) p++;
723     } while( *p && *p++ == *q++ );
724 
725     if( *p ) continue;		/* not matched */
726 
727     /* match, but with a submenu */
728     if( *q == '/' ) return set_active( menu->submenu, q, active );
729 
730     if( *q ) continue;		/* not matched */
731 
732     /* we have a match */
733     menu->inactive = !active;
734     return 0;
735   }
736 
737   return 1;
738 }
739 
740 int
ui_menu_item_set_active(const char * path,int active)741 ui_menu_item_set_active( const char *path, int active )
742 {
743   return set_active( widget_menu, path, active );
744 }
745