1 /* menu.c: general menu callbacks
2    Copyright (c) 2004-2018 Philip Kendall and others
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18    Author contact information:
19 
20    Philip Kendall <philip-fuse@shadowmagic.org.uk>
21 
22 */
23 
24 #include <config.h>
25 
26 #include <libspectrum.h>
27 
28 #include "event.h"
29 #include "fuse.h"
30 #include "menu.h"
31 #include "movie.h"
32 #include "machines/specplus3.h"
33 #include "peripherals/dck.h"
34 #include "peripherals/disk/beta.h"
35 #include "peripherals/disk/didaktik.h"
36 #include "peripherals/disk/disciple.h"
37 #include "peripherals/disk/opus.h"
38 #include "peripherals/disk/plusd.h"
39 #include "peripherals/ide/divide.h"
40 #include "peripherals/ide/divmmc.h"
41 #include "peripherals/ide/simpleide.h"
42 #include "peripherals/ide/zxatasp.h"
43 #include "peripherals/ide/zxcf.h"
44 #include "peripherals/ide/zxmmc.h"
45 #include "peripherals/if1.h"
46 #include "peripherals/if2.h"
47 #include "peripherals/joystick.h"
48 #include "peripherals/multiface.h"
49 #include "peripherals/scld.h"
50 #include "profile.h"
51 #include "psg.h"
52 #include "rzx.h"
53 #include "screenshot.h"
54 #include "settings.h"
55 #include "snapshot.h"
56 #include "svg.h"
57 #include "tape.h"
58 #include "ui/scaler/scaler.h"
59 #include "ui/ui.h"
60 #include "ui/uimedia.h"
61 #include "utils.h"
62 #include "z80/z80.h"
63 
64 static int menu_select_machine_roms( libspectrum_machine machine, size_t start,
65 				     size_t n );
66 
67 static int menu_select_peripheral_roms( const char *peripheral_name,
68 					size_t start, size_t n );
69 
MENU_CALLBACK(menu_file_open)70 MENU_CALLBACK( menu_file_open )
71 {
72   char *filename;
73 
74   fuse_emulation_pause();
75 
76   filename = ui_get_open_filename( "Fuse - Open Spectrum File" );
77   if( !filename ) { fuse_emulation_unpause(); return; }
78 
79   utils_open_file( filename, tape_can_autoload(), NULL );
80 
81   libspectrum_free( filename );
82 
83   display_refresh_all();
84 
85   fuse_emulation_unpause();
86 }
87 
MENU_CALLBACK(menu_file_recording_insertsnapshot)88 MENU_CALLBACK( menu_file_recording_insertsnapshot )
89 {
90   libspectrum_snap *snap;
91   libspectrum_error error;
92 
93   if( !rzx_recording ) return;
94 
95   ui_widget_finish();
96 
97   libspectrum_rzx_stop_input( rzx );
98 
99   snap = libspectrum_snap_alloc();
100 
101   error = snapshot_copy_to( snap );
102   if( error ) { libspectrum_snap_free( snap ); return; }
103 
104   libspectrum_rzx_add_snap( rzx, snap, 0 );
105 
106   libspectrum_rzx_start_input( rzx, tstates );
107 }
108 
MENU_CALLBACK(menu_file_recording_rollback)109 MENU_CALLBACK( menu_file_recording_rollback )
110 {
111   libspectrum_error error;
112 
113   if( !rzx_recording ) return;
114 
115   ui_widget_finish();
116 
117   fuse_emulation_pause();
118 
119   error = rzx_rollback();
120   if( error ) { fuse_emulation_unpause(); return; }
121 
122   fuse_emulation_unpause();
123 }
124 
MENU_CALLBACK(menu_file_recording_rollbackto)125 MENU_CALLBACK( menu_file_recording_rollbackto )
126 {
127   libspectrum_error error;
128 
129   if( !rzx_recording ) return;
130 
131   ui_widget_finish();
132 
133   fuse_emulation_pause();
134 
135   error = rzx_rollback_to();
136   if( error ) { fuse_emulation_unpause(); return; }
137 
138   fuse_emulation_unpause();
139 }
140 
MENU_CALLBACK(menu_file_recording_play)141 MENU_CALLBACK( menu_file_recording_play )
142 {
143   char *recording;
144 
145   if( rzx_playback || rzx_recording ) return;
146 
147   fuse_emulation_pause();
148 
149   recording = ui_get_open_filename( "Fuse - Start Replay" );
150   if( !recording ) { fuse_emulation_unpause(); return; }
151 
152   rzx_start_playback( recording, 1 );
153 
154   libspectrum_free( recording );
155 
156   display_refresh_all();
157 
158   if( rzx_playback ) ui_menu_activate( UI_MENU_ITEM_RECORDING, 1 );
159 
160   fuse_emulation_unpause();
161 }
162 
MENU_CALLBACK(menu_file_recording_stop)163 MENU_CALLBACK( menu_file_recording_stop )
164 {
165   if( !( rzx_recording || rzx_playback ) ) return;
166 
167   ui_widget_finish();
168 
169   if( rzx_recording ) rzx_stop_recording();
170   if( rzx_playback  ) rzx_stop_playback( 1 );
171 }
172 
MENU_CALLBACK(menu_file_recording_finalise)173 MENU_CALLBACK( menu_file_recording_finalise )
174 {
175   char *rzx_filename;
176   int error;
177 
178   if( rzx_playback || rzx_recording ) return;
179 
180   fuse_emulation_pause();
181 
182   rzx_filename = ui_get_open_filename( "Fuse - Finalise Recording" );
183   if( !rzx_filename ) { fuse_emulation_unpause(); return; }
184 
185   error = rzx_finalise_recording( rzx_filename );
186 
187   if( error == LIBSPECTRUM_ERROR_NONE ) {
188     ui_error( UI_ERROR_INFO, "RZX file finalised" );
189   } else {
190     ui_error( UI_ERROR_WARNING, "RZX file cannot be finalised" );
191   }
192 
193   libspectrum_free( rzx_filename );
194 
195   fuse_emulation_unpause();
196 }
197 
MENU_CALLBACK(menu_file_aylogging_stop)198 MENU_CALLBACK( menu_file_aylogging_stop )
199 {
200   if ( !psg_recording ) return;
201 
202   ui_widget_finish();
203 
204   psg_stop_recording();
205   ui_menu_activate( UI_MENU_ITEM_AY_LOGGING, 0 );
206 }
207 
MENU_CALLBACK(menu_file_screenshot_openscrscreenshot)208 MENU_CALLBACK( menu_file_screenshot_openscrscreenshot )
209 {
210   char *filename;
211 
212   fuse_emulation_pause();
213 
214   filename = ui_get_open_filename( "Fuse - Open SCR Screenshot" );
215   if( !filename ) { fuse_emulation_unpause(); return; }
216 
217   screenshot_scr_read( filename );
218 
219   libspectrum_free( filename );
220 
221   fuse_emulation_unpause();
222 }
223 
MENU_CALLBACK(menu_file_screenshot_openmltscreenshot)224 MENU_CALLBACK( menu_file_screenshot_openmltscreenshot )
225 {
226   char *filename;
227 
228   fuse_emulation_pause();
229 
230   filename = ui_get_open_filename( "Fuse - Open MLT Screenshot" );
231   if( !filename ) { fuse_emulation_unpause(); return; }
232 
233   screenshot_mlt_read( filename );
234 
235   libspectrum_free( filename );
236 
237   fuse_emulation_unpause();
238 }
239 
MENU_CALLBACK(menu_file_movie_stop)240 MENU_CALLBACK( menu_file_movie_stop )
241 {
242   ui_widget_finish();
243 
244   movie_stop();
245 }
246 
MENU_CALLBACK(menu_file_movie_pause)247 MENU_CALLBACK( menu_file_movie_pause )
248 {
249   ui_widget_finish();
250 
251   movie_pause();
252 }
253 
MENU_CALLBACK_WITH_ACTION(menu_options_selectroms_machine_select)254 MENU_CALLBACK_WITH_ACTION( menu_options_selectroms_machine_select )
255 {
256   switch( action ) {
257 
258   case  1: menu_select_machine_roms( LIBSPECTRUM_MACHINE_16,        0, 1 ); return;
259   case  2: menu_select_machine_roms( LIBSPECTRUM_MACHINE_48,        1, 1 ); return;
260   case  3: menu_select_machine_roms( LIBSPECTRUM_MACHINE_128,       2, 2 ); return;
261   case  4: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PLUS2,     4, 2 ); return;
262   case  5: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PLUS2A,    6, 4 ); return;
263   case  6: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PLUS3,    10, 4 ); return;
264   case  7: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PLUS3E,   14, 4 ); return;
265   case  8: menu_select_machine_roms( LIBSPECTRUM_MACHINE_TC2048,   18, 1 ); return;
266   case  9: menu_select_machine_roms( LIBSPECTRUM_MACHINE_TC2068,   19, 2 ); return;
267   case 10: menu_select_machine_roms( LIBSPECTRUM_MACHINE_TS2068,   21, 2 ); return;
268   case 11: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PENT,     23, 3 ); return;
269   case 12: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PENT512,  26, 4 ); return;
270   case 13: menu_select_machine_roms( LIBSPECTRUM_MACHINE_PENT1024, 30, 4 ); return;
271   case 14: menu_select_machine_roms( LIBSPECTRUM_MACHINE_SCORP,    34, 4 ); return;
272   case 15: menu_select_machine_roms( LIBSPECTRUM_MACHINE_SE,       38, 2 ); return;
273 
274   }
275 
276   ui_error( UI_ERROR_ERROR,
277 	    "menu_options_selectroms_machine_select: unknown action %d", action );
278   fuse_abort();
279 }
280 
MENU_CALLBACK_WITH_ACTION(menu_options_selectroms_peripheral_select)281 MENU_CALLBACK_WITH_ACTION( menu_options_selectroms_peripheral_select )
282 {
283   switch( action ) {
284 
285   case  1: menu_select_peripheral_roms( "Interface 1",     0, 1 ); return;
286   case  2: menu_select_peripheral_roms( "Beta 128",        1, 1 ); return;
287   case  3: menu_select_peripheral_roms( "+D",              2, 1 ); return;
288   case  4: menu_select_peripheral_roms( "Didaktik 80",     3, 1 ); return;
289   case  5: menu_select_peripheral_roms( "DISCiPLE",        4, 1 ); return;
290   case  6: menu_select_peripheral_roms( "Multiface One",   5, 1 ); return;
291   case  7: menu_select_peripheral_roms( "Multiface 128",   6, 1 ); return;
292   case  8: menu_select_peripheral_roms( "Multiface 3",     7, 1 ); return;
293   case  9: menu_select_peripheral_roms( "Opus Discovery",  8, 1 ); return;
294   case 10: menu_select_peripheral_roms( "SpeccyBoot",      9, 1 ); return;
295   case 11: menu_select_peripheral_roms( "TTX2000S",       10, 1 ); return;
296   case 12: menu_select_peripheral_roms( "uSource",        11, 1 ); return;
297 
298   }
299 
300   ui_error( UI_ERROR_ERROR,
301 	    "menu_options_selectroms_peripheral_select: unknown action %d", action );
302   fuse_abort();
303 }
304 
MENU_CALLBACK(menu_options_filter)305 MENU_CALLBACK( menu_options_filter )
306 {
307   scaler_type scaler;
308 
309   /* Stop emulation */
310   fuse_emulation_pause();
311 
312   scaler = menu_get_scaler( scaler_is_supported );
313   if( scaler != SCALER_NUM && scaler != current_scaler )
314     scaler_select_scaler( scaler );
315 
316   /* Carry on with emulation again */
317   fuse_emulation_unpause();
318 }
319 
MENU_CALLBACK(menu_options_fullscreen)320 MENU_CALLBACK( menu_options_fullscreen )
321 {
322   ui_widget_finish();
323   settings_current.full_screen = !settings_current.full_screen;
324 }
325 
MENU_CALLBACK(menu_options_save)326 MENU_CALLBACK( menu_options_save )
327 {
328   ui_widget_finish();
329   settings_write_config( &settings_current );
330 }
331 
MENU_CALLBACK(menu_machine_profiler_start)332 MENU_CALLBACK( menu_machine_profiler_start )
333 {
334   ui_widget_finish();
335   profile_start();
336 }
337 
MENU_CALLBACK(menu_machine_profiler_stop)338 MENU_CALLBACK( menu_machine_profiler_stop )
339 {
340   char *filename;
341 
342   fuse_emulation_pause();
343 
344   filename = ui_get_save_filename( "Fuse - Save Profile Data" );
345   if( !filename ) { fuse_emulation_unpause(); return; }
346 
347   profile_finish( filename );
348 
349   libspectrum_free( filename );
350 
351   fuse_emulation_unpause();
352 }
353 
MENU_CALLBACK(menu_machine_nmi)354 MENU_CALLBACK( menu_machine_nmi )
355 {
356   ui_widget_finish();
357   event_add( 0, z80_nmi_event );
358 }
359 
MENU_CALLBACK(menu_machine_multifaceredbutton)360 MENU_CALLBACK( menu_machine_multifaceredbutton )
361 {
362   ui_widget_finish();
363   multiface_red_button();
364 }
365 
MENU_CALLBACK(menu_media_tape_open)366 MENU_CALLBACK( menu_media_tape_open )
367 {
368   char *filename;
369 
370   fuse_emulation_pause();
371 
372   filename = ui_get_open_filename( "Fuse - Open Tape" );
373   if( !filename ) { fuse_emulation_unpause(); return; }
374 
375   tape_open( filename, 0 );
376 
377   libspectrum_free( filename );
378 
379   fuse_emulation_unpause();
380 }
381 
MENU_CALLBACK(menu_media_tape_play)382 MENU_CALLBACK( menu_media_tape_play )
383 {
384   ui_widget_finish();
385   tape_toggle_play( 0 );
386 }
387 
MENU_CALLBACK(menu_media_tape_rewind)388 MENU_CALLBACK( menu_media_tape_rewind )
389 {
390   ui_widget_finish();
391   tape_rewind();
392 }
393 
MENU_CALLBACK(menu_media_tape_clear)394 MENU_CALLBACK( menu_media_tape_clear )
395 {
396   ui_widget_finish();
397   tape_close();
398 }
399 
MENU_CALLBACK(menu_media_tape_write)400 MENU_CALLBACK( menu_media_tape_write )
401 {
402   ui_tape_write();
403 }
404 
MENU_CALLBACK(menu_media_tape_recordstart)405 MENU_CALLBACK( menu_media_tape_recordstart )
406 {
407   ui_widget_finish();
408   tape_record_start();
409 }
410 
MENU_CALLBACK(menu_media_tape_recordstop)411 MENU_CALLBACK( menu_media_tape_recordstop )
412 {
413   ui_widget_finish();
414   tape_record_stop();
415 }
416 
MENU_CALLBACK_WITH_ACTION(menu_media_if1_rs232)417 MENU_CALLBACK_WITH_ACTION( menu_media_if1_rs232 )
418 {
419   char *filename;
420 
421   fuse_emulation_pause();
422 
423   if( action & 0xf0 ) {
424     ui_widget_finish();
425     if1_unplug( action & 0x0f );
426   } else {
427     filename = ui_get_open_filename( "Fuse - Select File for Communication" );
428     if( !filename ) { fuse_emulation_unpause(); return; }
429 
430     if1_plug( filename, action );
431 
432     libspectrum_free( filename );
433   }
434   fuse_emulation_unpause();
435 
436 }
437 
MENU_CALLBACK_WITH_ACTION(menu_media_insert_new)438 MENU_CALLBACK_WITH_ACTION( menu_media_insert_new )
439 {
440   int which, type;
441   ui_media_drive_info_t *drive;
442 
443   ui_widget_finish();
444 
445   action--;
446   which = action & 0x0f;
447   type = ( action & 0xf0 ) >> 4;
448 
449   switch( type ) {
450   case 3:
451     if1_mdr_insert( which, NULL );
452     break;
453   default:
454     drive = ui_media_drive_find( type, which );
455     if( !drive )
456       return;
457     ui_media_drive_insert( drive, NULL, 0 );
458     break;
459   }
460 }
461 
MENU_CALLBACK_WITH_ACTION(menu_media_insert)462 MENU_CALLBACK_WITH_ACTION( menu_media_insert )
463 {
464   char *filename;
465   char title[80];
466   int which, type;
467   ui_media_drive_info_t *drive = NULL;
468 
469   action--;
470   which = action & 0x0f;
471   type = ( action & 0xf0 ) >> 4;
472 
473   fuse_emulation_pause();
474 
475   switch( type ) {
476   case 3:
477     snprintf( title, 80, "Fuse - Insert Microdrive Cartridge %i", which + 1 );
478     break;
479   default:
480     drive = ui_media_drive_find( type, which );
481     if( !drive )
482       return;
483     snprintf( title, sizeof(title), "Fuse - Insert %s", drive->name );
484     break;
485   }
486   filename = ui_get_open_filename( title );
487   if( !filename ) { fuse_emulation_unpause(); return; }
488 
489   switch( type ) {
490   case 3:
491     if1_mdr_insert( which, filename );
492     break;
493   default:
494     ui_media_drive_insert( drive, filename, 0 );
495     break;
496   }
497 
498   libspectrum_free( filename );
499 
500   fuse_emulation_unpause();
501 }
502 
MENU_CALLBACK_WITH_ACTION(menu_media_eject)503 MENU_CALLBACK_WITH_ACTION( menu_media_eject )
504 {
505   int which, type;
506 
507   ui_widget_finish();
508 
509   action--;
510   which = action & 0x00f;
511   type = ( action & 0x0f0 ) >> 4;
512 
513   switch( type ) {
514   case 3:
515     if1_mdr_eject( which );
516     break;
517   default:
518     ui_media_drive_eject( type, which );
519     break;
520   }
521 }
522 
MENU_CALLBACK_WITH_ACTION(menu_media_save)523 MENU_CALLBACK_WITH_ACTION( menu_media_save )
524 {
525   int which, saveas, type;
526 
527   ui_widget_finish();
528 
529   action--;
530   which = action & 0x00f;
531   type = ( action & 0x0f0 ) >> 4;
532   saveas = ( action & 0xf00 ) >> 8;
533 
534   switch( type ) {
535   case 3:
536     if1_mdr_save( which, saveas );
537     break;
538   default:
539     ui_media_drive_save( type, which, saveas );
540     break;
541   }
542 }
543 
MENU_CALLBACK_WITH_ACTION(menu_media_flip)544 MENU_CALLBACK_WITH_ACTION( menu_media_flip )
545 {
546   int which, type, flip;
547 
548   ui_widget_finish();
549 
550   action--;
551   which = action & 0x0f;
552   type = ( action & 0xf0 ) >> 4;
553   flip = !!( action & 0x100 );
554 
555   switch( type ) {
556   /* No flip option for IF1 */
557   default:
558     ui_media_drive_flip( type, which, flip );
559     break;
560   }
561 }
562 
MENU_CALLBACK_WITH_ACTION(menu_media_writeprotect)563 MENU_CALLBACK_WITH_ACTION( menu_media_writeprotect )
564 {
565   int which, wrprot, type;
566 
567   ui_widget_finish();
568 
569   action--;
570   which = action & 0x00f;
571   type = ( action & 0x0f0 ) >> 4;
572   wrprot = !!( action & 0x100 );
573 
574   switch( type ) {
575   case 3:
576     if1_mdr_writeprotect( which, wrprot );
577     break;
578   default:
579     ui_media_drive_writeprotect( type, which, wrprot );
580     break;
581   }
582 
583 }
584 
MENU_CALLBACK(menu_media_cartridge_timexdock_insert)585 MENU_CALLBACK( menu_media_cartridge_timexdock_insert )
586 {
587   char *filename;
588 
589   fuse_emulation_pause();
590 
591   filename = ui_get_open_filename( "Fuse - Insert Timex Dock Cartridge" );
592   if( !filename ) { fuse_emulation_unpause(); return; }
593 
594   dck_insert( filename );
595 
596   libspectrum_free( filename );
597 
598   fuse_emulation_unpause();
599 }
600 
MENU_CALLBACK(menu_media_cartridge_timexdock_eject)601 MENU_CALLBACK( menu_media_cartridge_timexdock_eject )
602 {
603   ui_widget_finish();
604   dck_eject();
605 }
606 
MENU_CALLBACK(menu_media_cartridge_interface2_insert)607 MENU_CALLBACK( menu_media_cartridge_interface2_insert )
608 {
609   char *filename;
610 
611   fuse_emulation_pause();
612 
613   filename = ui_get_open_filename( "Fuse - Insert Interface 2 Cartridge" );
614   if( !filename ) { fuse_emulation_unpause(); return; }
615 
616   if2_insert( filename );
617 
618   libspectrum_free( filename );
619 
620   fuse_emulation_unpause();
621 }
622 
MENU_CALLBACK(menu_media_cartridge_interface2_eject)623 MENU_CALLBACK( menu_media_cartridge_interface2_eject )
624 {
625   ui_widget_finish();
626   if2_eject();
627 }
628 
MENU_CALLBACK_WITH_ACTION(menu_media_ide_insert)629 MENU_CALLBACK_WITH_ACTION( menu_media_ide_insert )
630 {
631   char *filename;
632 
633   fuse_emulation_pause();
634 
635   filename = ui_get_open_filename( "Fuse - Insert Hard Disk File" );
636   if( !filename ) { fuse_emulation_unpause(); return; }
637 
638   switch( action ) {
639   case 1: simpleide_insert( filename, LIBSPECTRUM_IDE_MASTER ); break;
640   case 2: simpleide_insert( filename, LIBSPECTRUM_IDE_SLAVE  ); break;
641   case 3: zxatasp_insert( filename, LIBSPECTRUM_IDE_MASTER ); break;
642   case 4: zxatasp_insert( filename, LIBSPECTRUM_IDE_SLAVE  ); break;
643   case 5: zxcf_insert( filename ); break;
644   case 6: divide_insert( filename, LIBSPECTRUM_IDE_MASTER ); break;
645   case 7: divide_insert( filename, LIBSPECTRUM_IDE_SLAVE  ); break;
646   case 8: divmmc_insert( filename ); break;
647   case 9: zxmmc_insert( filename ); break;
648   }
649 
650   libspectrum_free( filename );
651 
652   fuse_emulation_unpause();
653 }
654 
MENU_CALLBACK_WITH_ACTION(menu_media_ide_commit)655 MENU_CALLBACK_WITH_ACTION( menu_media_ide_commit )
656 {
657   fuse_emulation_pause();
658 
659   switch( action ) {
660   case 1: simpleide_commit( LIBSPECTRUM_IDE_MASTER ); break;
661   case 2: simpleide_commit( LIBSPECTRUM_IDE_SLAVE  ); break;
662   case 3: zxatasp_commit( LIBSPECTRUM_IDE_MASTER ); break;
663   case 4: zxatasp_commit( LIBSPECTRUM_IDE_SLAVE  ); break;
664   case 5: zxcf_commit(); break;
665   case 6: divide_commit( LIBSPECTRUM_IDE_MASTER ); break;
666   case 7: divide_commit( LIBSPECTRUM_IDE_SLAVE  ); break;
667   case 8: divmmc_commit(); break;
668   case 9: zxmmc_commit(); break;
669   }
670 
671   fuse_emulation_unpause();
672 
673   ui_widget_finish();
674 }
675 
MENU_CALLBACK_WITH_ACTION(menu_media_ide_eject)676 MENU_CALLBACK_WITH_ACTION( menu_media_ide_eject )
677 {
678   fuse_emulation_pause();
679 
680   switch( action ) {
681   case 1: simpleide_eject( LIBSPECTRUM_IDE_MASTER ); break;
682   case 2: simpleide_eject( LIBSPECTRUM_IDE_SLAVE  ); break;
683   case 3: zxatasp_eject( LIBSPECTRUM_IDE_MASTER ); break;
684   case 4: zxatasp_eject( LIBSPECTRUM_IDE_SLAVE  ); break;
685   case 5: zxcf_eject(); break;
686   case 6: divide_eject( LIBSPECTRUM_IDE_MASTER ); break;
687   case 7: divide_eject( LIBSPECTRUM_IDE_SLAVE  ); break;
688   case 8: divmmc_eject(); break;
689   }
690 
691   fuse_emulation_unpause();
692 
693   ui_widget_finish();
694 }
695 
MENU_CALLBACK(menu_file_savesnapshot)696 MENU_CALLBACK( menu_file_savesnapshot )
697 {
698   char *filename;
699 
700   ui_widget_finish();
701 
702   fuse_emulation_pause();
703 
704   filename = ui_get_save_filename( "Fuse - Save Snapshot" );
705   if( !filename ) { fuse_emulation_unpause(); return; }
706 
707   snapshot_write( filename );
708 
709   libspectrum_free( filename );
710 
711   fuse_emulation_unpause();
712 }
713 
MENU_CALLBACK(menu_file_screenshot_savescreenasscr)714 MENU_CALLBACK( menu_file_screenshot_savescreenasscr )
715 {
716   char *filename;
717 
718   ui_widget_finish();
719 
720   fuse_emulation_pause();
721 
722   filename = ui_get_save_filename( "Fuse - Save Screenshot as SCR" );
723   if( !filename ) { fuse_emulation_unpause(); return; }
724 
725   screenshot_scr_write( filename );
726 
727   libspectrum_free( filename );
728 
729   fuse_emulation_unpause();
730 }
731 
MENU_CALLBACK(menu_file_screenshot_savescreenasmlt)732 MENU_CALLBACK( menu_file_screenshot_savescreenasmlt )
733 {
734   char *filename;
735 
736   ui_widget_finish();
737 
738   fuse_emulation_pause();
739 
740   if( machine_current->timex && scld_last_dec.name.hires ) {
741     ui_error( UI_ERROR_ERROR,
742               "MLT format not supported for Timex hi-res screen mode" );
743     fuse_emulation_unpause();
744     return;
745   }
746 
747   filename = ui_get_save_filename( "Fuse - Save Screenshot as MLT" );
748   if( !filename ) { fuse_emulation_unpause(); return; }
749 
750   screenshot_mlt_write( filename );
751 
752   libspectrum_free( filename );
753 
754   fuse_emulation_unpause();
755 }
756 
757 #ifdef USE_LIBPNG
758 
MENU_CALLBACK(menu_file_screenshot_savescreenaspng)759 MENU_CALLBACK( menu_file_screenshot_savescreenaspng )
760 {
761   scaler_type scaler;
762   char *filename;
763 
764   ui_widget_finish();
765 
766   fuse_emulation_pause();
767 
768   scaler = menu_get_scaler( screenshot_available_scalers );
769   if( scaler == SCALER_NUM ) {
770     fuse_emulation_unpause();
771     return;
772   }
773 
774   filename =
775     ui_get_save_filename( "Fuse - Save Screenshot as PNG" );
776   if( !filename ) { fuse_emulation_unpause(); return; }
777 
778   screenshot_write( filename, scaler );
779 
780   libspectrum_free( filename );
781 
782   fuse_emulation_unpause();
783 }
784 
785 #endif
786 
787 #ifdef HAVE_LIB_XML2
788 
MENU_CALLBACK(menu_file_scalablevectorgraphics_startcaptureinlinemode)789 MENU_CALLBACK( menu_file_scalablevectorgraphics_startcaptureinlinemode )
790 {
791   char *filename;
792 
793   ui_widget_finish();
794   if( !svg_capture_active ) {
795 
796     fuse_emulation_pause();
797 
798     filename = ui_get_save_filename( "Fuse - Capture to SVG File" );
799     if( !filename ) { fuse_emulation_unpause(); return; }
800 
801     ui_menu_activate( UI_MENU_ITEM_FILE_SVG_CAPTURE, 1 );
802     svg_startcapture( filename, SVG_CAPTURE_LINES );
803 
804     fuse_emulation_unpause();
805   }
806 }
807 
MENU_CALLBACK(menu_file_scalablevectorgraphics_startcaptureindotmode)808 MENU_CALLBACK( menu_file_scalablevectorgraphics_startcaptureindotmode )
809 {
810   char *filename;
811 
812   ui_widget_finish();
813   if( !svg_capture_active ) {
814 
815     fuse_emulation_pause();
816 
817     filename = ui_get_save_filename( "Fuse - Capture to SVG File" );
818     if( !filename ) { fuse_emulation_unpause(); return; }
819     ui_menu_activate( UI_MENU_ITEM_FILE_SVG_CAPTURE, 1 );
820 
821     svg_startcapture( filename, SVG_CAPTURE_DOTS );
822 
823     fuse_emulation_unpause();
824   }
825 }
826 
MENU_CALLBACK(menu_file_scalablevectorgraphics_stopcapture)827 MENU_CALLBACK( menu_file_scalablevectorgraphics_stopcapture )
828 {
829   ui_widget_finish();
830   if( svg_capture_active ) {
831 
832     fuse_emulation_pause();
833 
834     svg_stopcapture();
835     ui_menu_activate( UI_MENU_ITEM_FILE_SVG_CAPTURE, 0 );
836 
837     fuse_emulation_unpause();
838   }
839 }
840 
841 #endif  /* HAVE_LIB_XML2 */
842 
843 
MENU_CALLBACK(menu_file_movie_record)844 MENU_CALLBACK( menu_file_movie_record )
845 {
846   char *filename;
847 
848   ui_widget_finish();
849 
850   fuse_emulation_pause();
851 
852   filename = ui_get_save_filename( "Fuse - Record Movie File" );
853   if( !filename ) { fuse_emulation_unpause(); return; }
854 
855   movie_start( filename );
856   libspectrum_free( filename );
857 
858   fuse_emulation_unpause();
859 }
860 
MENU_CALLBACK(menu_file_movie_record_recordfromrzx)861 MENU_CALLBACK( menu_file_movie_record_recordfromrzx )
862 {
863   char *rzx_file, *fmf_file;
864 
865   ui_widget_finish();
866 
867   if( rzx_playback || rzx_recording || movie_recording ) return;
868 
869   fuse_emulation_pause();
870 
871   rzx_file = ui_get_open_filename( "Fuse - Load RZX" );
872   if( !rzx_file ) { fuse_emulation_unpause(); return; }
873 
874   rzx_start_playback( rzx_file, 1 );
875   libspectrum_free( rzx_file );
876   display_refresh_all();
877 
878   if( rzx_playback ) {
879     fmf_file = ui_get_save_filename( "Fuse - Record Movie File" );
880     if( !fmf_file ) {
881       rzx_stop_playback( 1 );
882       fuse_emulation_unpause();
883       return;
884     }
885 
886     movie_start( fmf_file );
887     libspectrum_free( fmf_file );
888     ui_menu_activate( UI_MENU_ITEM_RECORDING, 1 );
889   }
890 
891   fuse_emulation_unpause();
892 }
893 
MENU_CALLBACK(menu_file_recording_record)894 MENU_CALLBACK( menu_file_recording_record )
895 {
896   char *recording;
897 
898   if( rzx_playback || rzx_recording ) return;
899 
900   fuse_emulation_pause();
901 
902   recording = ui_get_save_filename( "Fuse - Start Recording" );
903   if( !recording ) { fuse_emulation_unpause(); return; }
904 
905   rzx_start_recording( recording, 1 );
906 
907   libspectrum_free( recording );
908 
909   fuse_emulation_unpause();
910 }
911 
MENU_CALLBACK(menu_file_recording_recordfromsnapshot)912 MENU_CALLBACK( menu_file_recording_recordfromsnapshot )
913 {
914   char *snap, *recording;
915 
916   if( rzx_playback || rzx_recording ) return;
917 
918   fuse_emulation_pause();
919 
920   snap = ui_get_open_filename( "Fuse - Load Snapshot " );
921   if( !snap ) { fuse_emulation_unpause(); return; }
922 
923   recording = ui_get_save_filename( "Fuse - Start Recording" );
924   if( !recording ) {
925     libspectrum_free( snap );
926     fuse_emulation_unpause();
927     return;
928   }
929 
930   if( snapshot_read( snap ) ) {
931     libspectrum_free( snap );
932     libspectrum_free( recording );
933     fuse_emulation_unpause();
934     return;
935   }
936 
937   rzx_start_recording( recording, settings_current.embed_snapshot );
938 
939   libspectrum_free( recording );
940 
941   display_refresh_all();
942 
943   fuse_emulation_unpause();
944 }
945 
MENU_CALLBACK(menu_file_recording_continuerecording)946 MENU_CALLBACK( menu_file_recording_continuerecording )
947 {
948   char *rzx_filename;
949   int error;
950 
951   if( rzx_playback || rzx_recording ) return;
952 
953   fuse_emulation_pause();
954 
955   rzx_filename = ui_get_open_filename( "Fuse - Continue Recording" );
956   if( !rzx_filename ) { fuse_emulation_unpause(); return; }
957 
958   error = rzx_continue_recording( rzx_filename );
959 
960   if( error != LIBSPECTRUM_ERROR_NONE ) {
961     ui_error( UI_ERROR_WARNING, "RZX file cannot be continued" );
962   }
963 
964   libspectrum_free( rzx_filename );
965 
966   fuse_emulation_unpause();
967 }
968 
MENU_CALLBACK(menu_file_aylogging_record)969 MENU_CALLBACK( menu_file_aylogging_record )
970 {
971   char *psgfile;
972 
973   if( psg_recording ) return;
974 
975   fuse_emulation_pause();
976 
977   psgfile = ui_get_save_filename( "Fuse - Start AY Log" );
978   if( !psgfile ) { fuse_emulation_unpause(); return; }
979 
980   psg_start_recording( psgfile );
981 
982   libspectrum_free( psgfile );
983 
984   display_refresh_all();
985 
986   ui_menu_activate( UI_MENU_ITEM_AY_LOGGING, 1 );
987 
988   fuse_emulation_unpause();
989 }
990 
991 int
menu_check_media_changed(void)992 menu_check_media_changed( void )
993 {
994   int confirm, i;
995 
996   confirm = tape_close(); if( confirm ) return 1;
997 
998   confirm = ui_media_drive_eject_all();
999   if( confirm ) return 1;
1000 
1001   for( i = 0; i < 8; i++ ) {
1002     confirm = if1_mdr_eject( i );
1003     if( confirm ) return 1;
1004   }
1005 
1006   if( settings_current.simpleide_master_file ) {
1007     confirm = simpleide_eject( LIBSPECTRUM_IDE_MASTER );
1008     if( confirm ) return 1;
1009   }
1010 
1011   if( settings_current.simpleide_slave_file ) {
1012     confirm = simpleide_eject( LIBSPECTRUM_IDE_SLAVE );
1013     if( confirm ) return 1;
1014   }
1015 
1016   if( settings_current.zxatasp_master_file ) {
1017     confirm = zxatasp_eject( LIBSPECTRUM_IDE_MASTER );
1018     if( confirm ) return 1;
1019   }
1020 
1021   if( settings_current.zxatasp_slave_file ) {
1022     confirm = zxatasp_eject( LIBSPECTRUM_IDE_SLAVE );
1023     if( confirm ) return 1;
1024   }
1025 
1026   if( settings_current.zxcf_pri_file ) {
1027     confirm = zxcf_eject(); if( confirm ) return 1;
1028   }
1029 
1030   if( settings_current.divide_master_file ) {
1031     confirm = divide_eject( LIBSPECTRUM_IDE_MASTER );
1032     if( confirm ) return 1;
1033   }
1034 
1035   if( settings_current.divide_slave_file ) {
1036     confirm = divide_eject( LIBSPECTRUM_IDE_SLAVE );
1037     if( confirm ) return 1;
1038   }
1039 
1040   if( settings_current.divmmc_file ) {
1041     confirm = divmmc_eject();
1042     if( confirm ) return 1;
1043   }
1044 
1045   if( settings_current.zxmmc_file ) {
1046     confirm = zxmmc_eject();
1047     if( confirm ) return 1;
1048   }
1049 
1050   return 0;
1051 }
1052 
1053 static int
menu_select_machine_roms(libspectrum_machine machine,size_t start,size_t n)1054 menu_select_machine_roms( libspectrum_machine machine, size_t start, size_t n )
1055 {
1056   return menu_select_roms_with_title( libspectrum_machine_name( machine ),
1057 				      start, n, 0 );
1058 }
1059 
1060 static int
menu_select_peripheral_roms(const char * peripheral_name,size_t start,size_t n)1061 menu_select_peripheral_roms( const char *peripheral_name, size_t start, size_t n )
1062 {
1063   return menu_select_roms_with_title( peripheral_name,
1064 				      start, n, 1 );
1065 }
1066 
1067 const char*
menu_machine_detail(void)1068 menu_machine_detail( void )
1069 {
1070   return libspectrum_machine_name( machine_current->machine );
1071 }
1072 
1073 const char*
menu_filter_detail(void)1074 menu_filter_detail( void )
1075 {
1076   return scaler_name(current_scaler);
1077 }
1078 
1079 const char*
menu_keyboard_joystick_detail(void)1080 menu_keyboard_joystick_detail( void )
1081 {
1082   return joystick_name[ settings_current.joystick_keyboard_output ];
1083 }
1084 
1085 const char*
menu_joystick_1_detail(void)1086 menu_joystick_1_detail( void )
1087 {
1088   return joystick_name[ settings_current.joystick_1_output ];
1089 }
1090 
1091 const char*
menu_joystick_2_detail(void)1092 menu_joystick_2_detail( void )
1093 {
1094   return joystick_name[ settings_current.joystick_2_output ];
1095 }
1096 
1097 const char*
menu_tape_detail(void)1098 menu_tape_detail( void )
1099 {
1100   if( !tape_present() ) return "Not inserted";
1101 
1102   if( tape_is_playing() ) return "Playing";
1103   else return "Stopped";
1104 }
1105 
1106 static const char * const disk_detail_str[] = {
1107   "Inserted",
1108   "Inserted WP",
1109   "Inserted UD",
1110   "Inserted WP,UD",
1111 
1112   "*Inserted",
1113   "*Inserted WP",
1114   "*Inserted UD",
1115   "*Inserted WP,UD",
1116   "Not inserted",
1117 };
1118 
1119 static const char*
menu_disk_detail(fdd_t * f)1120 menu_disk_detail( fdd_t *f )
1121 {
1122   int i = 0;
1123 
1124   if( !f->loaded ) return disk_detail_str[8];
1125   if( f->wrprot ) i = 1;
1126   if( f->upsidedown ) i += 2;
1127   if( f->disk.dirty ) i += 4;
1128   return disk_detail_str[i];
1129 }
1130 
1131 const char*
menu_plus3a_detail(void)1132 menu_plus3a_detail( void )
1133 {
1134   fdd_t *f = specplus3_get_fdd( SPECPLUS3_DRIVE_A );
1135 
1136   return menu_disk_detail( f );
1137 }
1138 
1139 const char*
menu_plus3b_detail(void)1140 menu_plus3b_detail( void )
1141 {
1142   fdd_t *f = specplus3_get_fdd( SPECPLUS3_DRIVE_B );
1143 
1144   return menu_disk_detail( f );
1145 }
1146 
1147 const char*
menu_beta128a_detail(void)1148 menu_beta128a_detail( void )
1149 {
1150   fdd_t *f = beta_get_fdd( BETA_DRIVE_A );
1151 
1152   return menu_disk_detail( f );
1153 }
1154 
1155 const char*
menu_beta128b_detail(void)1156 menu_beta128b_detail( void )
1157 {
1158   fdd_t *f = beta_get_fdd( BETA_DRIVE_B );
1159 
1160   return menu_disk_detail( f );
1161 }
1162 
1163 const char*
menu_beta128c_detail(void)1164 menu_beta128c_detail( void )
1165 {
1166   fdd_t *f = beta_get_fdd( BETA_DRIVE_C );
1167 
1168   return menu_disk_detail( f );
1169 }
1170 
1171 const char*
menu_beta128d_detail(void)1172 menu_beta128d_detail( void )
1173 {
1174   fdd_t *f = beta_get_fdd( BETA_DRIVE_D );
1175 
1176   return menu_disk_detail( f );
1177 }
1178 
1179 const char*
menu_opus1_detail(void)1180 menu_opus1_detail( void )
1181 {
1182   fdd_t *f = opus_get_fdd( OPUS_DRIVE_1 );
1183 
1184   return menu_disk_detail( f );
1185 }
1186 
1187 const char*
menu_opus2_detail(void)1188 menu_opus2_detail( void )
1189 {
1190   fdd_t *f = opus_get_fdd( OPUS_DRIVE_2 );
1191 
1192   return menu_disk_detail( f );
1193 }
1194 
1195 const char*
menu_plusd1_detail(void)1196 menu_plusd1_detail( void )
1197 {
1198   fdd_t *f = plusd_get_fdd( PLUSD_DRIVE_1 );
1199 
1200   return menu_disk_detail( f );
1201 }
1202 
1203 const char*
menu_plusd2_detail(void)1204 menu_plusd2_detail( void )
1205 {
1206   fdd_t *f = plusd_get_fdd( PLUSD_DRIVE_2 );
1207 
1208   return menu_disk_detail( f );
1209 }
1210 
1211 const char*
menu_didaktik_a_detail(void)1212 menu_didaktik_a_detail( void )
1213 {
1214   fdd_t *f = didaktik80_get_fdd( DIDAKTIK80_DRIVE_A );
1215 
1216   return menu_disk_detail( f );
1217 }
1218 
1219 const char*
menu_didaktik_b_detail(void)1220 menu_didaktik_b_detail( void )
1221 {
1222   fdd_t *f = didaktik80_get_fdd( DIDAKTIK80_DRIVE_B );
1223 
1224   return menu_disk_detail( f );
1225 }
1226 
1227 const char*
menu_disciple1_detail(void)1228 menu_disciple1_detail( void )
1229 {
1230   fdd_t *f = disciple_get_fdd( DISCIPLE_DRIVE_1 );
1231 
1232   return menu_disk_detail( f );
1233 }
1234 
1235 const char*
menu_disciple2_detail(void)1236 menu_disciple2_detail( void )
1237 {
1238   fdd_t *f = disciple_get_fdd( DISCIPLE_DRIVE_2 );
1239 
1240   return menu_disk_detail( f );
1241 }
1242 
MENU_CALLBACK(menu_machine_didaktiksnap)1243 MENU_CALLBACK( menu_machine_didaktiksnap )
1244 {
1245   ui_widget_finish();
1246   didaktik80_snap = 1;
1247   event_add( 0, z80_nmi_event );
1248 }
1249