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