diff --git a/FreeMono.ttf b/FreeMono.ttf new file mode 100644 index 0000000..517ea95 Binary files /dev/null and b/FreeMono.ttf differ diff --git a/Makefile b/Makefile index ae1b7a0..46bc458 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lasnd -lSDL_mixer -lsmpeg -lvorbisidec -lSDL_image -lpng -ljpeg -lz -lSDL -lSDL_gfx -lfreetype -lfat -lwiiuse -lbte -logc -lm -lwiikeyboard +LIBS := -lasnd -lSDL_mixer -lsmpeg -lvorbisidec -lSDL_image -lpng -ljpeg -lz -lSDL_ttf -lSDL -lSDL_gfx -lfreetype -lfat -lwiiuse -lbte -logc -lm -lwiikeyboard #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing @@ -122,6 +122,7 @@ dist: $(BUILD) cp spectrum-roms/* $@/fbzx-wii/spectrum-roms cp keymap.bmp $@/fbzx-wii/fbzx cp ZXSpectrum48k.png $@/fbzx-wii/fbzx + cp FreeMono.ttf $@/fbzx-wii/fbzx cp AMSTRAD CAPABILITIES COPYING FAQ README README.TZX VERSIONS $@/apps/fbzx-wii/doc touch $@/fbzx-wii/tapes/dummy touch $@/fbzx-wii/snapshots/dummy diff --git a/fbzx.pnproj b/fbzx.pnproj index 0414710..dd3e0d5 100644 --- a/fbzx.pnproj +++ b/fbzx.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/fbzx.pnps b/fbzx.pnps index 7e6c7be..580ae2a 100644 --- a/fbzx.pnps +++ b/fbzx.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/computer.c b/src/computer.c index 3f60675..e707192 100644 --- a/src/computer.c +++ b/src/computer.c @@ -82,6 +82,8 @@ void computer_init () { ordenador.mode128k = 0; ordenador.joystick[0] = 1; //Kemposton ordenador.joystick[1] = 0; // Cursor + ordenador.rumble[0] = 0; + ordenador.rumble[1] = 0; ordenador.tape_readed = 0; ordenador.pause = 1; // tape stop @@ -697,7 +699,6 @@ inline void read_keyboard () { unsigned int temporal_io; SDL_Event evento,*pevento; - static int countdown; enum joystate_x {JOY_CENTER_X, JOY_LEFT, JOY_RIGHT}; enum joystate_y {JOY_CENTER_Y, JOY_UP, JOY_DOWN}; int joy_axis_x[2],joy_axis_y[2], loop; @@ -758,7 +759,7 @@ inline void read_keyboard () { joy_axis_y[loop] = SDL_JoystickGetAxis(ordenador.joystick_sdl[loop], 1); ordenador.joy_fire[loop] = SDL_JoystickGetButton(ordenador.joystick_sdl[loop], 0); //Wii button A - if (SDL_JoystickGetButton(ordenador.joystick_sdl[loop], 6)) help_menu (); //Wii button Home + if (SDL_JoystickGetButton(ordenador.joystick_sdl[loop], 6)) main_menu(); //Wii button Home if (joy_axis_x[loop] > 16384) ordenador.joy_axis_x_state[loop] = JOY_RIGHT; else if (joy_axis_x[loop] < -16384) ordenador.joy_axis_x_state[loop] = JOY_LEFT; @@ -946,8 +947,7 @@ inline void read_keyboard () { } if (ordenador.key[SDLK_SPACE]) ordenador.k15|=1; - if (ordenador.key[SDLK_RCTRL]) ordenador.k15|=2; - if (ordenador.key[SDLK_LCTRL]) ordenador.k15|=2; + if (ordenador.key[SDLK_RCTRL]||ordenador.key[SDLK_LCTRL]) ordenador.k15|=2; //Symbol shift if (ordenador.key[SDLK_m]) ordenador.k15|=4; if (ordenador.key[SDLK_n]) ordenador.k15|=8; if (ordenador.key[SDLK_b]) ordenador.k15|=16; @@ -991,8 +991,7 @@ inline void read_keyboard () { if (ordenador.key[SDLK_f]) ordenador.k9 |=8; if (ordenador.key[SDLK_g]) ordenador.k9 |=16; - if (ordenador.key[SDLK_RSHIFT]) ordenador.k8 |=1; - if (ordenador.key[SDLK_LSHIFT]) ordenador.k8 |=1; + if (ordenador.key[SDLK_RSHIFT]||ordenador.key[SDLK_LSHIFT]) ordenador.k8 |=1; //Caps shift if (ordenador.key[SDLK_z]) ordenador.k8 |=2; if (ordenador.key[SDLK_x]) ordenador.k8 |=4; if (ordenador.key[SDLK_c]) ordenador.k8 |=8; @@ -1001,8 +1000,10 @@ inline void read_keyboard () { if (ordenador.key[SDLK_UP]) {ordenador.k12 |=8;ordenador.k8|=1;} if (ordenador.key[SDLK_DOWN]) {ordenador.k12 |=16;ordenador.k8|=1;} if (ordenador.key[SDLK_LEFT]) {ordenador.k11 |=16;ordenador.k8|=1;} - if (ordenador.key[SDLK_RIGHT]) {ordenador.k12 |=4;ordenador.k8|=1;} + if (ordenador.key[SDLK_RIGHT]) {ordenador.k12 |=4;ordenador.k8|=1;} + if (ordenador.key[SDLK_TAB]) {ordenador.k15|=2;ordenador.k8|=1;} //Extended mode + ordenador.s8 = (ordenador.s8 & 0xE0) | (ordenador.k8 ^ 0x1F); ordenador.s9 = (ordenador.s9 & 0xE0) | (ordenador.k9 ^ 0x1F); ordenador.s10 = (ordenador.s10 & 0xE0)| (ordenador.k10 ^ 0x1F); diff --git a/src/computer.h b/src/computer.h index 750f10a..2ce3455 100644 --- a/src/computer.h +++ b/src/computer.h @@ -31,6 +31,8 @@ enum tapmodes {TAP_GUIDE, TAP_DATA, TAP_PAUSE, TAP_TRASH, TAP_STOP, TAP_PAUSE2, TZX_SEQ_PULSES, TAP_FINAL_BIT, TAP_PAUSE3}; enum taptypes {TAP_TAP, TAP_TZX}; +int countdown; + struct computer { unsigned int temporal_io; @@ -200,6 +202,7 @@ struct computer { unsigned char joy_axis_x_state[2]; unsigned char joy_axis_y_state[2]; unsigned char joy_fire[2]; + unsigned char rumble[2]; }; void computer_init(); diff --git a/src/emulator.c b/src/emulator.c index 08cd7db..e549e40 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -64,10 +64,10 @@ char path_mdrs[2049]; unsigned int colors[80]; unsigned int jump_frames,curr_frames; char *filenames[5]; +static SDL_Surface *image; int load_zxspectrum_picture() { -SDL_Surface *image; image=IMG_Load("/fbzx-wii/fbzx/ZXSpectrum48k.png"); @@ -707,8 +707,12 @@ int main(int argc,char *argv[]) { ordenador.screenbuffer=ordenador.screen->pixels; ordenador.screen_width=ordenador.screen->w; + //Init SDL Menu + + menu_init(ordenador.screen); + //Load the splash screen - if (load_zxspectrum_picture()) sleep(3); + if (load_zxspectrum_picture()) {sleep(1); SDL_FreeSurface (image);} // assign initial values for PATH variables @@ -775,7 +779,7 @@ int main(int argc,char *argv[]) { load_main_game(gamefile); printf("Modo: %d\n",ordenador.mode128k); - sprintf(ordenador.osd_text,"Press F1 for help"); + sprintf(ordenador.osd_text,"Press Home for menu"); ordenador.osd_time=200; printf("BPP: %d\n",ordenador.bpp); @@ -841,7 +845,7 @@ int main(int argc,char *argv[]) { } } - save_config(&ordenador); + //save_config(&ordenador); #ifdef GEKKO fatUnmount(0); diff --git a/src/gui_sdl.c b/src/gui_sdl.c new file mode 100644 index 0000000..ada454d --- /dev/null +++ b/src/gui_sdl.c @@ -0,0 +1,679 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Interface to the Tcl/Tk GUI + * + * Copyright 1996 Bernd Schmidt + */ + +#include +#include + +#include "menu_sdl.h" +#include "emulator.h" +//#include "VirtualKeyboard.h" per ora + +#define ID_BUTTON_OFFSET 0 +#define ID_AXIS_OFFSET 32 + +//extern int usbismount, smbismount; per ora + +#ifdef DEBUG +extern FILE *fdebug; +#define printf(...) fprintf(fdebug,__VA_ARGS__) +#else + #ifdef GEKKO + #define printf(...) + #endif +#endif + +extern int countdown; + + +static const char *main_menu_messages[] = { + /*00*/ "Tape", + /*01*/ "^|Insert|Load|Play|Stop|Rewind|Create|Delete", + /*02*/ "Snapshot", + /*03*/ "^|Load|Save|Delete", + /*04*/ "#1---------------------------------------------", + /*05*/ "Wiimote configuration", + /*06*/ "^|Wiimote1|Wiimote2", + /*07*/ "Emulation settings", + /*08*/ "Microdrive", + /*09*/ "Tools", + /*10*/ "Save confs", + /*11*/ "Reset", + /*12*/ "Help", + /*13*/ "Quit", + NULL +}; + +static const char *emulation_messages[] = { + /*00*/ "Emulated machine", + /*01*/ "^|48k_2|48K_3|128k|+2|+2A/+3|128K_Sp", + /*02*/ "Volume", + /*03*/ "^|0%|25%|50%|75%|100%", + /*04*/ "Tap fast speed", + /*05*/ "^|on|off", + /*06*/ "Turbo mode", + /*07*/ "^|on|off", + /*08*/ "Double scan", + /*09*/ "^|on|off", + /*10*/ "TV mode", + /*11*/ "^|Color|B&W", + /*12*/ "AY-3-8912 Emulation", + /*13*/ "^|on|off", + NULL +}; + +static const char *input_messages[] = { + /*00*/ "Joystick type", + /*01*/ "^|Cursor|Kempston|Sinclair1|Sinclair2", + /*02*/ " ", + /*03*/ "Bind key to Wiimote", + /*04*/ "^|1|2|-", + /*05*/ " ", + /*06*/ "Bind key to Nunchuk", + /*07*/ "^|Z|C", + /*08*/ " ", + /*09*/ "Bind key to Classic", + /*10*/ "^|a|b|x|y|L|R|Zl|Zr|-", + /*11*/ " ", + /*12*/ "Rumble", + /*13*/ "^|On|Off", + NULL, +}; + +static const char *microdrive_messages[] = { + /*00*/ "Select microdrive", + /*01*/ " ", + /*02*/ "Create microdrive file", + /*03*/ " ", + /*04*/ "Interface I", + /*05*/ "^|on|off", + /*06*/ " ", + /*07*/ "Write protection", + /*08*/ "^|on|off", + NULL +}; + +static const char *tools_messages[] = { + /*00*/ "Show keyboard", + /*01*/ " ", + /*02*/ "Save SCR", + /*03*/ " ", + /*04*/ "Load SCR", + /*05*/ " ", + /*06*/ "Insert poke", + NULL +}; + +static const char *help_messages[] = { + /*00*/ "#2HOME enters the menu system, where arrow keys", + /*01*/ "#2and nunchuck are used to navigate up and down.", + /*02*/ "#2You can bind keyboard keys to the wiimote", + /*03*/ "#2buttons in the 'Wiimote' menu and", + /*04*/ "#2change emulation options in the Settings menu.", + /*05*/ "#2 ", + /*06*/ "#2 ", + /*07*/ "#2 ", + /*08*/ "#2 ", + /*09*/ "#2 ", + /*10*/ "#2 ", + /*11*/ "#2More information is available on the wiki:", + /*12*/ "#2 http://wiibrew.org/wiki/FBZX_Wii", + /*13*/ "#2 ", + /*14*/ "OK", + NULL, +}; + +static void insert_tape() +{ + unsigned char char_id[11]; + int retorno, retval; + + // Maybe should go after the first control?? + if(ordenador.tap_file!=NULL) + rewind_tape(ordenador.tap_file,1); + + ordenador.tape_current_bit=0; + ordenador.tape_current_mode=TAP_TRASH; + + const char *filename = menu_select_file(path_taps, ordenador.current_tap, 0); + + if (filename==NULL) // Aborted + return; + + if (strcmp(filename, "None") == 0) //TO FIX IT + { + ordenador.current_tap[0] = '\0'; + free((void *)filename); + return; + } + + if (!(ext_matches(filename, ".tap")|ext_matches(filename, ".TAP")|ext_matches(filename, ".tzx")| + ext_matches(filename, ".TZX"))) {free((void *)filename); return;} + + + if(ordenador.tap_file!=NULL) { + fclose(ordenador.tap_file); + } + + ordenador.tap_file=fopen(filename,"r+"); // read and write + + ordenador.tape_write = 0; // by default, can't record + + if(ordenador.tap_file==NULL) + retorno=-1; + else + retorno=0; + + strcpy(ordenador.current_tap,filename); + + free((void *)filename); + + switch(retorno) { + case 0: // all right + break; + case -1: + msgInfo("Error: Can't load that file",3000,NULL); + ordenador.current_tap[0]=0; + return; + break; + } + + retval=fread(char_id,10,1,ordenador.tap_file); // read the (maybe) TZX header + if((!strncmp(char_id,"ZXTape!",7)) && (char_id[7]==0x1A)&&(char_id[8]==1)) { + ordenador.tape_file_type = TAP_TZX; + rewind_tape(ordenador.tap_file,1); + } else { + ordenador.tape_file_type = TAP_TAP; + rewind_tape(ordenador.tap_file,1); + } +} + +static void delete_tape() +{ + const char *filename = menu_select_file(path_taps, NULL, -1); + + if (filename==NULL) // Aborted + return; + + if (strcmp(filename, "None") == 0) + { + free((void *)filename); + return; + } + + if (ext_matches(filename, ".tap")|ext_matches(filename, ".TAP")|ext_matches(filename, ".tzx")| + ext_matches(filename, ".TZX")) unlink(filename); + + free((void *)filename); +} + + +static void manage_tape(int which) +{ + switch (which) + { + case 0: //Insert + insert_tape(); + break; + case 1: //Emulate load "" + ordenador.kbd_buffer_pointer=6; + countdown=5; + break; + case 2: //Play + if ((ordenador.tape_fast_load == 0) || (ordenador.tape_file_type==TAP_TZX)) + ordenador.pause = 0; + break; + case 3: //Stop + if ((ordenador.tape_fast_load == 0) || (ordenador.tape_file_type==TAP_TZX)) + ordenador.pause = 1; + break; + case 4: //Rewind + ordenador.pause=1; + if(ordenador.tap_file!=NULL) { + ordenador.tape_current_mode=TAP_TRASH; + rewind_tape(ordenador.tap_file,1); + } + msgInfo("Tape rewinded",3000,NULL); + break; + case 5: //Create + // Create tape + break; + case 6: //Delete + delete_tape(); + break; + default: + break; + } +} + +static unsigned int get_machine_model(void) +{ + return ordenador.mode128k + (ordenador.issue==3); +} + +static void set_machine_model(int which) +{ + switch (which) + { + case 0: //48k issue2 + ordenador.issue=2; + ordenador.mode128k=0; + ordenador.ay_emul=0; + break; + case 1: //48k issue3 + ordenador.issue=3; + ordenador.mode128k=0; + ordenador.ay_emul=0; + break; + case 2: //128k + ordenador.issue=3; + ordenador.mode128k=1; + ordenador.ay_emul=1; + break; + case 3: //Amstrad +2 + ordenador.issue=3; + ordenador.mode128k=2; + ordenador.ay_emul=1; + break; + case 4: //Amstrad +2A/+3 + ordenador.issue=3; + ordenador.mode128k=3; + ordenador.ay_emul=1; + ordenador.mdr_active=0; + break; + case 5: //128K Spanish + ordenador.issue=3; + ordenador.mode128k=4; + ordenador.ay_emul=1; + break; + + } +} + +static void emulation_settings(void) +{ + unsigned int submenus[7],submenus_old[7]; + int opt, i; + + memset(submenus, 0, sizeof(submenus)); + + submenus[0] = get_machine_model(); + submenus[1] = (unsigned int) (ordenador.volume/16); + submenus[2] = !ordenador.tape_fast_load; + submenus[3] = !ordenador.turbo; + submenus[4] = !ordenador.dblscan; + submenus[5] = ordenador.bw; + submenus[6] = !ordenador.ay_emul; + + for (i=0; i<7; i++) submenus_old[i] = submenus[i]; + + opt = menu_select_title("Emulation settings menu", + emulation_messages, submenus); + if (opt < 0) + return; + + set_machine_model(submenus[0]); + if (submenus[0] != submenus_old[0]) ResetComputer(); else + ordenador.ay_emul = !submenus[6]; + + ordenador.volume = submenus[1]*16; + ordenador.tape_fast_load = !submenus[2]; + ordenador.turbo = !submenus[3]; + + if(ordenador.turbo){ + ordenador.tst_sample=12000000/ordenador.freq; //5,0 MHz max emulation speed for wii at full frames + jump_frames=3; + } else { + ordenador.tst_sample=3500000/ordenador.freq; + jump_frames=0; + } + + ordenador.dblscan = !submenus[4]; + ordenador.bw = submenus[5]; + if (submenus[5]!=submenus_old[5]) computer_set_palete(); + +} + +static void setup_joystick(int joy, const char *key, int sdl_key) +{ + /* + if (!strcmp(key, "None")) + { + changed_prefs.joystick_settings[1][joy].eventid[ID_BUTTON_OFFSET + sdl_key][0] = 0; + } + else + insert_keyboard_map(key, "input.1.joystick.%d.button.%d", joy, sdl_key); + */ +} + +static void input_options(int joy) +{ + const int wiimote_to_sdl[] = {2, 3, 4, 5}; + const int nunchuk_to_sdl[] = {7, 8}; + const int classic_to_sdl[] = {9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + int sdl_key = 1; + const char *key; + unsigned int submenus[5]; + int opt; + + //struct virtkey *virtualkey; + + memset(submenus, 0, sizeof(submenus)); + + submenus[0] = ordenador.joystick[joy]; + submenus[4] = !ordenador.rumble[joy]; + + opt = menu_select_title("Input menu", + input_messages, submenus); + if (opt < 0) + return; + + ordenador.joystick[joy] = submenus[0]; + ordenador.rumble[joy] = !submenus[4]; + + /* + virtualkey = virtkbd_get_key(); + if (virtualkey == NULL) + return; + key = virtualkey->ev_name; + */ + + switch(opt) + { + case 3: // wiimote + sdl_key = wiimote_to_sdl[submenus[1]]; break; + case 6: // nunchuk + sdl_key = nunchuk_to_sdl[submenus[2]]; break; + case 9: // classic + sdl_key = classic_to_sdl[submenus[3]]; break; + default: + break; + } + + setup_joystick(joy, key, sdl_key); + +} + +static void microdrive() +{ + + unsigned int submenus[2], submenus_old[2]; + int opt,retval ; + + memset(submenus, 0, sizeof(submenus)); + + submenus[0] = !ordenador.mdr_active; + submenus[1] = !ordenador.mdr_cartridge[137922]; + + submenus_old[0] = submenus[0]; + submenus_old[1] = submenus[1]; + + opt = menu_select_title("Microdrive menu", + microdrive_messages, submenus); + if (opt < 0) + return; + + ordenador.mdr_active = !submenus[0]; + + + if (submenus[0]!=submenus_old[0]) ResetComputer(); + if (submenus[1]!=submenus_old[1]) + {if(ordenador.mdr_cartridge[137922]) + ordenador.mdr_cartridge[137922]=0; + else + ordenador.mdr_cartridge[137922]=1; + ordenador.mdr_file=fopen(ordenador.mdr_current_mdr,"wb"); // create for write + if(ordenador.mdr_file!=NULL) { + retval=fwrite(ordenador.mdr_cartridge,137923,1,ordenador.mdr_file); // save cartridge + fclose(ordenador.mdr_file); + ordenador.mdr_file=NULL; + ordenador.mdr_modified=0; + } + } + + switch(opt) + { + case 0: // Select microdrive + //Select microdrive ; + break; + case 2: // Create microdrive file + // Create microdrive file ; + break; + default: + break; + } +} +void show_keyboard_layout() { + + FILE *fichero; + int bucle1,bucle2,retval; + unsigned char *buffer,valor; + + buffer=screen->pixels; + + fichero=myfopen("fbzx/keymap.bmp","r"); + if (fichero==NULL) { + msgInfo("Keymap picture not found",3000,NULL); + return; + } + + for (bucle1=0;bucle1<344;bucle1++) + for(bucle2=0;bucle2<640;bucle2++) { + retval=fscanf(fichero,"%c",&valor); + paint_one_pixel((unsigned char *)(colors+valor),buffer); + buffer+=ordenador.bpp; + } + SDL_Flip(ordenador.screen); + menu_wait_key_press(); +} + +static void tools() +{ + int opt ; + + opt = menu_select_title("Tools menu", + tools_messages, NULL); + if (opt < 0) + return; + + switch(opt) + { + case 0: // Show keyboard + show_keyboard_layout(); + break; + case 2: // Save SCR + // Save SCR ; + break; + case 4: // Load SCR + //Load SCR ; + break; + case 6: // Insert poke + // Insert poke ; + break; + default: + break; + } +} + + +/* + +static void set_Port(int which) +{ + switch (which) + { + case PORT_SD: + prefs_set_attr ("floppy_path", strdup_path_expand (TARGET_FLOPPY_PATH)); + changed_prefs.Port = which; + currprefs.Port = changed_prefs.Port; + break; + case PORT_USB: + if (usbismount) { + prefs_set_attr ("floppy_path", strdup_path_expand (TARGET_USB_PATH)); + changed_prefs.Port = which; + currprefs.Port = changed_prefs.Port;} + else + msgInfo("USB is not mounted",3000,NULL); + break; + case PORT_SMB: + if (smbismount) { + prefs_set_attr ("floppy_path", strdup_path_expand (TARGET_SMB_PATH)); + changed_prefs.Port = which; + currprefs.Port = changed_prefs.Port;} + else + msgInfo("SMB is not mounted",3000,NULL); + break; + default: + break; + } +} + +static void virtual_keyboard(void) +{ + int key_code; + + virtkey_t *key =virtkbd_get_key(); + if (key) {key_code = key->sdl_code;} else return; + + SDL_Event event_key; + + event_key.type=SDL_KEYDOWN; + event_key.key.keysym.sym=key_code; + SDL_PushEvent(&event_key); + DEBUG_LOG ("Push Event: keycode %d %s\n", key_code, "SDL_KEYDOWN"); + + event_key.type=SDL_KEYUP; + SDL_PushEvent(&event_key); + DEBUG_LOG ("Push Event: keycode %d %s\n", key_code, "SDL_KEYUP"); + +} + +*/ + +static void save_load_snapshot(int which) +{ + const char *dir = path_snaps; + const char *tape = ordenador.current_tap; + char db[256]; + char fb[81]; + int retorno; + + // Name (for saves) - TO CHECK + if (tape && strrchr(tape, '/')) + strncpy(fb, strrchr(tape, '/') + 1, 80); + else + strcpy(fb, "unknown"); + + switch(which) + { + case 2: + case 0: // Load or delete file + { + const char *filename = menu_select_file(dir, NULL,-1); + + if (!filename) + return; + + if (ext_matches(filename, ".z80")|ext_matches(filename, ".Z80")| + ext_matches(filename, ".sna")|ext_matches(filename, ".SNA")) + { + if (which == 0) // Load snapshot file + { + retorno=load_z80(filename); + + switch(retorno) { + case 0: // all right + break; + case -1: + msgInfo("Error: Can't load that file",3000,NULL); + break; + case -2: + case -3: + msgInfo("Error: unsuported snap file",3000,NULL); + break; + } + } + else // Delete snashot file + unlink(filename); + } + free((void*)filename); + } break; + case 1: // Save snapshot file + snprintf(db, 255, "%s/%s.z80", dir, fb); + retorno=save_z80(db); + msgInfo("State saved",3000,NULL); + break; + default: + break; + } +} + + +static void help(void) +{ + menu_select_title("FBZX-WII help", + help_messages, NULL); +} + +void main_menu() +{ + int submenus[3]; + int opt; + + memset(submenus, 0, sizeof(submenus)); + + do + { + opt = menu_select_title("Main menu", main_menu_messages, submenus); + if (opt < 0) + break; + + switch(opt) + { + case 0: + manage_tape(submenus[0]); + break; + case 2: + save_load_snapshot(submenus[1]); + break; + case 5: + input_options(submenus[2]); + break; + case 7: + emulation_settings(); + break; + case 8: + microdrive(); + break; + case 9: + tools(); + break; + case 10: + save_config(&ordenador); + msgInfo("Configurations saved",3000,NULL); + break; + case 11: + ResetComputer (); + ordenador.pause = 1; + if (ordenador.tap_file != NULL) { + ordenador.tape_current_mode = TAP_TRASH; + rewind_tape (ordenador.tap_file,1); + } + break; + case 12: + help(); + break; + case 13: + if (msgYesNo("Are you sure to quit?", 0, FULL_DISPLAY_X /2-138, FULL_DISPLAY_Y /2-48)) + {salir = 0;} + break; + default: + break; + } + } while (opt == 5 || opt == 7 || opt == 8 || opt == 9 || opt == 12); + +} diff --git a/src/menu_sdl.c b/src/menu_sdl.c new file mode 100644 index 0000000..4b18f36 --- /dev/null +++ b/src/menu_sdl.c @@ -0,0 +1,976 @@ +/********************************************************************* +* +* Copyright (C) 2004,2008, Simon Kagstrom +* +* Filename: menu.c +* Author: Simon Kagstrom +* Description: Code for menus (originally for Mophun) +* +* $Id$ +* +********************************************************************/ +#include +#include +#include +#include +#include +#include +#include + + +#include "menu_sdl.h" +#include "emulator.h" //Necessary to use ordenador.joystick_number and ordenador.joystick_sdl +//#include "VirtualKeyboard.h" + + + +typedef struct +{ + int n_entries; + int index; + int sel; +} submenu_t; + +typedef struct +{ + char title[256]; + const char **pp_msgs; + TTF_Font *p_font; + int x1,y1; + int x2,y2; + int text_w; + int text_h; + + int n_submenus; + submenu_t *p_submenus; + + int cur_sel; /* Main selection */ + int start_entry_visible; + int n_entries; +} menu_t; + +static SDL_Surface *real_screen; + +#define IS_SUBMENU(p_msg) ( (p_msg)[0] == '^' ) +#define IS_TEXT(p_msg) ( (p_msg)[0] == '#' || (p_msg)[0] == ' ' ) +#define IS_MARKER(p_msg) ( (p_msg)[0] == '@' ) + +static int is_inited = 0; +static TTF_Font *menu_font16, *menu_font20; +#if defined(GEKKO) +#define FONT_PATH "/fbzx-wii/fbzx/FreeMono.ttf" +#else +#define FONT_PATH "FreeMono.ttf" +#endif + +int fh, fw; + +int msgInfo(char *text, int duration, SDL_Rect *irc) +{ + int len = strlen(text); + int X, Y; + SDL_Rect src; + SDL_Rect rc; + SDL_Rect brc; + + X = (FULL_DISPLAY_X /2) - (len / 2 + 1)*12; + Y = (FULL_DISPLAY_Y /2) - 24; + + brc.x = FULL_DISPLAY_X/2-2*12; + brc.y=Y+42; + brc.w=48; + brc.h=20; + + rc.x = X; + rc.y=Y; + rc.w=12*(len + 2); + rc.h=duration > 0 ? 48 : 80; + + src.x=rc.x+4; + src.y=rc.y+4; + src.w=rc.w; + src.h=rc.h; + + + if (irc) + { + irc->x=rc.x; + irc->y=rc.y; + irc->w=src.w; + irc->h=src.h; + } + SDL_FillRect(real_screen, &src, SDL_MapRGB(real_screen->format, 0, 96, 0)); + SDL_FillRect(real_screen, &rc, SDL_MapRGB(real_screen->format, 128, 128, 128)); + menu_print_font(real_screen, 255,255,255, X+12, Y+12, text,20); + SDL_UpdateRect(real_screen, src.x, src.y, src.w, src.h); + SDL_UpdateRect(real_screen, rc.x, rc.y, rc.w,rc.h); + if (duration > 0) + SDL_Delay(duration); + else if (duration < 0) + { + SDL_FillRect(real_screen, &brc, SDL_MapRGB(real_screen->format, 0x00, 0x80, 0x00)); + menu_print_font(real_screen, 0,0,0, FULL_DISPLAY_X/2-12, Y+42, "OK",20); + SDL_UpdateRect(real_screen, brc.x, brc.y, brc.w, brc.h); + while (!(KEY_SELECT & menu_wait_key_press())) {} + + } + + return 1; +} + +/* +void msgKill(SDL_Rect *rc) +{ + SDL_UpdateRect(real_screen, rc->x, rc->y, rc->w,rc->h); +} +*/ + +int msgYesNo(char *text, int default_opt, int x, int y) +{ + int len = strlen(text); + int X, Y; + SDL_Rect src; + SDL_Rect rc; + SDL_Rect brc; + uint32_t key; + + if (x < 0) + X = (FULL_DISPLAY_X /2) - (len / 2 + 1)*12; + else + X = x; + + if (y < 0) + Y = (FULL_DISPLAY_Y /2) - 48; + else + Y = y; + + rc.x=X; + rc.y=Y; + rc.w=12*(len + 2); + rc.h=80; + + src.x=rc.x+4; + src.y=rc.y+4; + src.w=rc.w; + src.h=rc.h; + + while (1) + { + SDL_FillRect(real_screen, &src, SDL_MapRGB(real_screen->format, 0, 96, 0)); + SDL_FillRect(real_screen, &rc, SDL_MapRGB(real_screen->format, 128, 128, 128)); + menu_print_font(real_screen, 255,255,255, X+12, Y+12, text,20); + + if (default_opt) + { + brc.x=rc.x + rc.w/2-5*12; + brc.y=rc.y+42; + brc.w=12*3; + brc.h=20; + SDL_FillRect(real_screen, &brc, SDL_MapRGB(real_screen->format, 0x00, 0x80, 0x00)); + } + else + { + brc.x=rc.x + rc.w/2+5*12-2*12-6; + brc.y=rc.y+42; + brc.w=12*3; + brc.h=20; + SDL_FillRect(real_screen, &brc, SDL_MapRGB(real_screen->format, 0x80, 0x00, 0x00)); + } + + menu_print_font(real_screen, 255,255,255, rc.x + rc.w/2-5*12, Y+42, "YES",20); + menu_print_font(real_screen, 255,255,255, rc.x + rc.w/2-5*12+8*12, Y+42, "NO",20); + + SDL_UpdateRect(real_screen, src.x, src.y, src.w, src.h); + SDL_UpdateRect(real_screen, rc.x, rc.y, rc.w,rc.h); + SDL_UpdateRect(real_screen, brc.x, brc.y, brc.w,brc.h); + + //SDL_Flip(real_screen); + key = menu_wait_key_press(); + if (key & KEY_SELECT) + { + return default_opt; + } + else if (key & KEY_ESCAPE) + { + return 0; + } + else if (key & KEY_LEFT) + { + default_opt = !default_opt; + } + else if (key & KEY_RIGHT) + { + default_opt = !default_opt; + } + } +} + + + +static int cmpstringp(const void *p1, const void *p2) +{ + const char *p1_s = *(const char**)p1; + const char *p2_s = *(const char**)p2; + + /* Put directories first */ + if (*p1_s == '[' && *p2_s != '[') + return -1; + if (*p1_s != '[' && *p2_s == '[') + return 1; + return strcmp(* (char * const *) p1, * (char * const *) p2); +} + +/* Return true if name ends with ext (for filenames) */ +int ext_matches(const char *name, const char *ext) +{ + int len = strlen(name); + int ext_len = strlen(ext); + + if (len <= ext_len) + return 0; + return (strcmp(name + len - ext_len, ext) == 0); +} + +static int ext_matches_list(const char *name, const char **exts) +{ + const char **p; + + for (p = exts; *p; p++) + { + if (ext_matches(name, *p)) + return 1; + } + + return 0; +} + +static const char **get_file_list(const char *base_dir) +{ + DIR *d = opendir(base_dir); + const char **file_list; + int cur = 0; + struct dirent *de; + int cnt = 16; + + if (!d) + return NULL; + + file_list = (const char**)malloc(cnt * sizeof(char*)); + file_list[cur++] = strdup("None"); + file_list[cur] = NULL; + + for (de = readdir(d); + de; + de = readdir(d)) + { + char buf[255]; + const char *exts[] = {".tap", ".TAP", ".tzx", ".TZX", ".z80",".Z80",".sna", ".SNA", + ".mdr", ".MDR", NULL}; + struct stat st; + + snprintf(buf, 255, "%s/%s", base_dir, de->d_name); + if (stat(buf, &st) < 0) + continue; + if (S_ISDIR(st.st_mode)&&strcmp(".", de->d_name)) + { + char *p; + size_t len = strlen(de->d_name) + 4; + + p = (char*)malloc( len ); + snprintf(p, len, "[%s]", de->d_name); + file_list[cur++] = p; + file_list[cur] = NULL; + } + else if (ext_matches_list(de->d_name, exts)) + { + char *p; + + p = strdup(de->d_name); + file_list[cur++] = p; + file_list[cur] = NULL; + } + + if (cur > cnt - 2) + { + cnt = cnt + 32; + file_list = (const char**)realloc(file_list, cnt * sizeof(char*)); + if (!file_list) + return NULL; + } + } + closedir(d); + qsort(&file_list[1], cur-1, sizeof(const char *), cmpstringp); + + return file_list; +} + + +static submenu_t *find_submenu(menu_t *p_menu, int index) +{ + int i; + + for (i=0; in_submenus; i++) + { + if (p_menu->p_submenus[i].index == index) + return &p_menu->p_submenus[i]; + } + + return NULL; +} + +void menu_print_font(SDL_Surface *screen, int r, int g, int b, + int x, int y, const char *msg, int font_size) +{ +#define _MAX_STRING 64 + SDL_Surface *font_surf; + SDL_Rect dst = {x, y, 0, 0}; + SDL_Color color = {r, g, b}; + char buf[255]; + unsigned int i; + + memset(buf, 0, sizeof(buf)); + strncpy(buf, msg, 254); + if (buf[0] != '|' && buf[0] != '^' && buf[0] != '.' + && buf[0] != '-' && buf[0] != ' ' && !strstr(buf, " \"")) + { + if (strlen(buf)>_MAX_STRING) + { + //buf[_MAX_STRING-3] = '.'; + //buf[_MAX_STRING-2] = '.'; + //buf[_MAX_STRING-1] = '.'; + buf[_MAX_STRING] = '\0'; + } + } + /* Fixup multi-menu option look */ + for (i = 0; i < strlen(buf) ; i++) + { + if (buf[i] == '^' || buf[i] == '|') + buf[i] = ' '; + } + + if (font_size == 16) font_surf = TTF_RenderUTF8_Blended(menu_font16, buf, color); + else font_surf = TTF_RenderUTF8_Blended(menu_font20, buf, color); + if (!font_surf) + { + fprintf(stderr, "%s\n", TTF_GetError()); + exit(1); + } + + SDL_BlitSurface(font_surf, NULL, screen, &dst); + SDL_FreeSurface(font_surf); +} + + +static void menu_draw(SDL_Surface *screen, menu_t *p_menu, int sel, int font_size) +{ + int font_height = TTF_FontHeight(p_menu->p_font); + int line_height = (font_height + font_height / 4); + int x_start = p_menu->x1; + int y_start = p_menu->y1 + line_height; + SDL_Rect r; + int entries_visible = (p_menu->y2 - p_menu->y1) / line_height - 1; + + int i, y; + + if ( p_menu->n_entries * line_height > p_menu->y2 ) + y_start = p_menu->y1 + line_height; + + if (p_menu->cur_sel - p_menu->start_entry_visible > entries_visible) + { + while (p_menu->cur_sel - p_menu->start_entry_visible > entries_visible) + { + p_menu->start_entry_visible ++; + if (p_menu->start_entry_visible > p_menu->n_entries) + { + p_menu->start_entry_visible = 0; + break; + } + } + } + else if ( p_menu->cur_sel < p_menu->start_entry_visible ) + p_menu->start_entry_visible = p_menu->cur_sel; + + if (strlen(p_menu->title)) + { + r.x = p_menu->x1; + r.y = p_menu->y1; + r.w = p_menu->x2 - p_menu->x1; + r.h = line_height-1; + if (sel < 0) + SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 0x40, 0x00, 0x00)); + else + SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 0x00, 0xe7, 0xe7)); + menu_print_font(screen, 0,0,0, p_menu->x1, p_menu->y1, p_menu->title, font_size); + } + + for (i = p_menu->start_entry_visible; i <= p_menu->start_entry_visible + entries_visible; i++) + { + const char *msg = p_menu->pp_msgs[i]; + + if (i >= p_menu->n_entries) + break; + if (IS_MARKER(msg)) + p_menu->cur_sel = atoi(&msg[1]); + else + { + y = (i - p_menu->start_entry_visible) * line_height; + + if (sel < 0) + menu_print_font(screen, 0x40,0x40,0x40, + x_start, y_start + y, msg, font_size); + else if (p_menu->cur_sel == i) /* Selected - color */ + menu_print_font(screen, 0,200,0, + x_start, y_start + y, msg, font_size); + else if (IS_SUBMENU(msg)) + { + if (p_menu->cur_sel == i-1) + menu_print_font(screen, 0,200,0, + x_start, y_start + y, msg, font_size); + else + menu_print_font(screen, 0x40,0x40,0x40, + x_start, y_start + y, msg, font_size); + } + else if (msg[0] == '#') + { + switch (msg[1]) + { + case '1': + menu_print_font(screen, 0,0,255, + x_start, y_start + y, msg+2, font_size); + break; + case '2': + menu_print_font(screen, 0x40,0x40,0x40, + x_start, y_start + y, msg+2, font_size); + break; + default: + menu_print_font(screen, 0x40,0x40,0x40, + x_start, y_start + y, msg, font_size); + break; + } + } + else /* Otherwise white */ + menu_print_font(screen, 0x40,0x40,0x40, + x_start, y_start + y, msg, font_size); + if (IS_SUBMENU(msg)) + { + submenu_t *p_submenu = find_submenu(p_menu, i); + int n_pipe = 0; + int n; + + for (n=0; msg[n] != '\0'; n++) + { + /* Underline the selected entry */ + if (msg[n] == '|') + { + int16_t n_chars; + + for (n_chars = 1; msg[n+n_chars] && msg[n+n_chars] != '|'; n_chars++); + + n_pipe++; + if (p_submenu->sel == n_pipe-1) + { + int w; + int h; + + if (TTF_SizeText(p_menu->p_font, "X", &w, &h) < 0) + { + fw = w; + fh = h; + fprintf(stderr, "%s\n", TTF_GetError()); + exit(1); + } + + r = (SDL_Rect){ x_start + (n+1) * w-1, y_start + (i+ 1 - p_menu->start_entry_visible) * ((h + h/4)) -3, (n_chars - 1) * w, 2}; + if (p_menu->cur_sel == i-1) + SDL_FillRect(screen, &r, + SDL_MapRGB(screen->format, 255,0,0)); + else + SDL_FillRect(screen, &r, + SDL_MapRGB(screen->format, 0x40,0x40,0x40)); + break; + } + } + } + } + } + } +} + +static int get_next_seq_y(menu_t *p_menu, int v, int dy, int cicle) +{ + if (v + dy < 0) + {if (cicle) return (p_menu->n_entries - 1); else return 0;} + + if (v + dy > p_menu->n_entries - 1) + {if (cicle) return 0; else return (p_menu->n_entries - 1);} + return v + dy; +} + +static void select_next(menu_t *p_menu, int dx, int dy, int cicle) +{ + int next; + + + p_menu->cur_sel = get_next_seq_y(p_menu, p_menu->cur_sel, dy, cicle); + next = get_next_seq_y(p_menu, p_menu->cur_sel, dy + 1, cicle); + if (p_menu->pp_msgs[p_menu->cur_sel][0] == ' ' || + p_menu->pp_msgs[p_menu->cur_sel][0] == '#' || + IS_SUBMENU(p_menu->pp_msgs[p_menu->cur_sel]) ) + select_next(p_menu, dx, dy, cicle); + + /* If the next is a submenu */ + if (dx != 0 && IS_SUBMENU(p_menu->pp_msgs[next])) + { + submenu_t *p_submenu = find_submenu(p_menu, next); + + p_submenu->sel = (p_submenu->sel + dx) < 0 ? p_submenu->n_entries - 1 : + (p_submenu->sel + dx) % p_submenu->n_entries; + } + else if (dx == -1 && !strcmp(p_menu->pp_msgs[0], "[..]")) + p_menu->cur_sel = 0; +} + +static void select_one(menu_t *p_menu, int sel) +{ + if (sel >= p_menu->n_entries) + sel = 0; + p_menu->cur_sel = sel; + if (p_menu->pp_msgs[p_menu->cur_sel][0] == ' ' || + p_menu->pp_msgs[p_menu->cur_sel][0] == '#' || + IS_SUBMENU(p_menu->pp_msgs[p_menu->cur_sel])) + select_next(p_menu, 0, 1 , 1); +} + +/* +static int is_submenu_title(menu_t *p_menu, int n) +{ + if (n+1 >= p_menu->n_entries) + return 0; + else + return IS_SUBMENU(p_menu->pp_msgs[n+1]); +} +*/ + +static void menu_init_internal(menu_t *p_menu, const char *title, + TTF_Font *p_font, const char **pp_msgs, + int16_t x1, int16_t y1, int16_t x2, int16_t y2) +{ + int submenu; + int j; + + memset(p_menu, 0, sizeof(menu_t)); + + p_menu->pp_msgs = pp_msgs; + p_menu->p_font = p_font; + p_menu->x1 = x1; + p_menu->y1 = y1; + p_menu->x2 = x2; + p_menu->y2 = y2; + + p_menu->text_w = 0; + p_menu->n_submenus = 0; + strcpy(p_menu->title, title); + + for (p_menu->n_entries = 0; p_menu->pp_msgs[p_menu->n_entries]; p_menu->n_entries++) + { + int text_w_font; + + /* Is this a submenu? */ + if (IS_SUBMENU(p_menu->pp_msgs[p_menu->n_entries])) + { + p_menu->n_submenus++; + continue; /* Length of submenus is unimportant */ + } + + if (TTF_SizeText(p_font, p_menu->pp_msgs[p_menu->n_entries], &text_w_font, NULL) != 0) + { + fprintf(stderr, "%s\n", TTF_GetError()); + exit(1); + } + if (text_w_font > p_menu->text_w) + p_menu->text_w = text_w_font; + } + if (p_menu->text_w > p_menu->x2 - p_menu->x1) + p_menu->text_w = p_menu->x2 - p_menu->x1; + + if ( !(p_menu->p_submenus = (submenu_t *)malloc(sizeof(submenu_t) * p_menu->n_submenus)) ) + { + perror("malloc failed!\n"); + exit(1); + } + + j=0; + submenu = 0; + for (; j < p_menu->n_entries; j++) + { + if (IS_SUBMENU(p_menu->pp_msgs[j])) + { + int n; + + p_menu->p_submenus[submenu].index = j; + p_menu->p_submenus[submenu].sel = 0; + p_menu->p_submenus[submenu].n_entries = 0; + for (n=0; p_menu->pp_msgs[j][n] != '\0'; n++) + { + if (p_menu->pp_msgs[j][n] == '|') + p_menu->p_submenus[submenu].n_entries++; + } + submenu++; + } + } + p_menu->text_h = p_menu->n_entries * (TTF_FontHeight(p_font) + TTF_FontHeight(p_font) / 4); +} + +static void menu_fini(menu_t *p_menu) +{ + free(p_menu->p_submenus); +} + +uint32_t menu_wait_key_press(void) +{ + SDL_Event ev; + uint32_t keys = 0; + + while (1) + { + int i, hats, nr; + SDL_Joystick *joy; + static int joy_keys_changed; + static int joy_keys_last; + SDL_JoystickUpdate(); + /* Wii-specific, sorry */ + for (nr = 0; nr < ordenador.joystick_number; nr++) { + joy = ordenador.joystick_sdl[nr]; + if (!joy) + continue; + + hats = SDL_JoystickNumHats (joy); + for (i = 0; i < hats; i++) { + Uint8 v = SDL_JoystickGetHat (joy, i); + + if (v & SDL_HAT_UP) + keys |= KEY_UP; + if (v & SDL_HAT_DOWN) + keys |= KEY_DOWN; + if (v & SDL_HAT_LEFT) + keys |= KEY_LEFT; + if (v & SDL_HAT_RIGHT) + keys |= KEY_RIGHT; + } + + Sint16 axis0 = SDL_JoystickGetAxis(joy, 0); + Sint16 axis1 = SDL_JoystickGetAxis(joy, 1); + + if ( axis0 < -15000 ) keys |= KEY_LEFT; + else if (axis0 > 15000 ) keys |= KEY_RIGHT; + + if (axis1 < -15000 ) keys |= KEY_UP; + else if( axis1 > 15000 ) keys |= KEY_DOWN; + + + if (SDL_JoystickGetButton(joy, 0) != 0 || /* A */ + SDL_JoystickGetButton(joy, 3) != 0 || /* 2 */ + SDL_JoystickGetButton(joy, 9) != 0 || /* CA */ + SDL_JoystickGetButton(joy, 10) != 0) /* CB */ + keys |= KEY_SELECT; + if (SDL_JoystickGetButton(joy, 2) != 0 || /* 1 */ + SDL_JoystickGetButton(joy, 11) != 0 || /* CX */ + SDL_JoystickGetButton(joy, 12) != 0) /* CY */ + keys |= KEY_ESCAPE; + if (SDL_JoystickGetButton(joy, 5) != 0 || /* + */ + SDL_JoystickGetButton(joy, 18) != 0) /* C+ */ + keys |= KEY_PAGEUP; + if (SDL_JoystickGetButton(joy, 4) != 0 || /* + */ + SDL_JoystickGetButton(joy, 17) != 0) /* C+ */ + keys |= KEY_PAGEDOWN; + } + joy_keys_changed = keys != joy_keys_last; + joy_keys_last = keys; + if (!joy_keys_changed) + keys = 0; + + if (SDL_PollEvent(&ev)) + { + switch(ev.type) + { + case SDL_KEYDOWN: + switch (ev.key.keysym.sym) + { + case SDLK_UP: + keys |= KEY_UP; + break; + case SDLK_DOWN: + keys |= KEY_DOWN; + break; + case SDLK_LEFT: + keys |= KEY_LEFT; + break; + case SDLK_RIGHT: + keys |= KEY_RIGHT; + break; + case SDLK_PAGEDOWN: + keys |= KEY_PAGEDOWN; + break; + case SDLK_PAGEUP: + keys |= KEY_PAGEUP; + break; + case SDLK_RETURN: + case SDLK_SPACE: + keys |= KEY_SELECT; + break; + case SDLK_HOME: + case SDLK_ESCAPE: + keys |= KEY_ESCAPE; + break; + default: + break; + } + break; + case SDL_QUIT: + exit(0); + break; + default: + break; + + } + break; + } + + if (keys != 0) + break; + SDL_Delay(100); + } + return keys; +} + + +extern void PicDisplay(char *name, int off_x, int off_y, int wait); +extern const char **get_t64_list(char *t64); +extern const char **get_prg_list(char *t64); + +extern char curdir[256]; + +static int menu_select_internal(SDL_Surface *screen, + menu_t *p_menu, int *p_submenus, int sel, + void (*select_next_cb)(menu_t *p, void *data), + void *select_next_cb_data, int font_size) +{ + int ret = -1; + int i; + + for (i = 0; i < p_menu->n_submenus; i++) + p_menu->p_submenus[i].sel = p_submenus[i]; + + while(1) + { + SDL_Rect r = {p_menu->x1, p_menu->y1, + p_menu->x2 - p_menu->x1, p_menu->y2 - p_menu->y1}; + uint32_t keys; + int sel_last = p_menu->cur_sel; + + SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 0xff, 0xff, 0xff)); + + menu_draw(screen, p_menu, 0, font_size); + SDL_Flip(screen); + + keys = menu_wait_key_press(); + + if (keys & KEY_UP) + select_next(p_menu, 0, -1, 1); + else if (keys & KEY_DOWN) + select_next(p_menu, 0, 1, 1); + else if (keys & KEY_PAGEUP) + select_next(p_menu, 0, -18, 0); + else if (keys & KEY_PAGEDOWN) + select_next(p_menu, 0, 18, 0); + else if (keys & KEY_LEFT) + select_next(p_menu, -1, 0 ,1); + else if (keys & KEY_RIGHT) + select_next(p_menu, 1, 0 ,1); + else if (keys & KEY_ESCAPE) + break; + else if (keys & KEY_SELECT) + { + ret = p_menu->cur_sel; + int i; + + for (i=0; in_submenus; i++) + p_submenus[i] = p_menu->p_submenus[i].sel; + break; + } + /* Invoke the callback when an entry is selected */ + if (sel_last != p_menu->cur_sel && + select_next_cb != NULL) + select_next_cb(p_menu, select_next_cb_data); + } + + SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0)); + return ret; +} + +int menu_select_sized(const char *title, const char **msgs, int *submenus, int sel, + int x, int y, int x2, int y2, + void (*select_next_cb)(menu_t *p, void *data), + void *select_next_cb_data, int font_size) + +{ + menu_t menu; + int out; + + if (font_size == 16) menu_init_internal(&menu, title, menu_font16, msgs, x, y, x2, y2); + else menu_init_internal(&menu, title, menu_font20, msgs, x, y, x2, y2); + + if (sel >= 0) + select_one(&menu, sel); + out = menu_select_internal(real_screen, &menu, submenus, sel, + select_next_cb, select_next_cb_data, font_size); + + menu_fini(&menu); + + return out; +} + +int menu_select_title(const char *title, const char **msgs, int *submenus) +{ + SDL_FillRect(real_screen, 0, SDL_MapRGB(real_screen->format, 0, 0, 0)); + return menu_select_sized(title, msgs, submenus, 0, + 32, 32, FULL_DISPLAY_X-32, FULL_DISPLAY_Y-32, + NULL, NULL, 20); +} + +int menu_select(const char **msgs, int *submenus) +{ + return menu_select_title("", msgs, submenus); +} + +static const char *menu_select_file_internal(const char *dir_path, + int x, int y, int x2, int y2, const char *selected_file, int which) +{ + const char **file_list = get_file_list(dir_path); + char *sel; + char *out; + const char *ptr_selected_file; + int opt; + int i; + char buf[64]; + + if (file_list == NULL) + return NULL; + + if (selected_file) + { + ptr_selected_file= strrchr(selected_file,'/'); + if (ptr_selected_file) ptr_selected_file++; + else ptr_selected_file = selected_file; + snprintf(buf,64,"tp%d:%s",which, ptr_selected_file); + opt = menu_select_sized(buf, file_list, NULL, 0, x, y, x2, y2, NULL, NULL, 16); + } + else opt = menu_select_sized("Select file", file_list, NULL, 0, x, y, x2, y2, NULL, NULL ,16); + + if (opt < 0) + return NULL; + sel = strdup(file_list[opt]); + + /* Cleanup everything - file_list is NULL-terminated */ + for ( i = 0; file_list[i]; i++ ) + free((void*)file_list[i]); + free(file_list); + + if (!sel) + return NULL; + /* If this is a folder, enter it recursively */ + if (sel[0] == '[') + { + char buf[255]; + int len = strlen(sel); + int s; + + /* Remove trailing ] */ + sel[len-1] = '\0'; + s = snprintf(buf, 128, "%s/%s", dir_path, sel + 1); + + /* We don't need this anymore */ + free((void*)sel); + /* Too deep recursion! */ + if (s >= sizeof(buf)) + return NULL; + return menu_select_file(buf, selected_file, which); + } + + out = (char*)malloc(strlen(dir_path) + strlen(sel) + 4); + snprintf(out, strlen(dir_path) + strlen(sel) + 4, + "%s/%s", dir_path, sel); + + free(sel); + return out; +} + +/* +const char *menu_select_file_start(const char *dir_path, const char **d64_name) +{ + const char *file = menu_select_file_internal(dir_path, + 32, 32, FULL_DISPLAY_X, FULL_DISPLAY_Y - 32); + + if (!file) + return NULL; + + return file; +} +*/ +const char *menu_select_file(const char *dir_path,const char *selected_file, int which) +{ + if (dir_path == NULL) + dir_path = ""; + return menu_select_file_internal(dir_path, + 0, 32, FULL_DISPLAY_X, FULL_DISPLAY_Y - 32, selected_file, which); +} + +static TTF_Font *read_font(const char *path, int font_size) +{ + TTF_Font *out; + SDL_RWops *rw; + Uint8 *data = (Uint8*)malloc(1 * 1024*1024); + FILE *fp = fopen(path, "r"); + + if (!data) { + fprintf(stderr, "Malloc failed\n"); + exit(1); + } + if (!fp) { + fprintf(stderr, "Could not open font\n"); + exit(1); + } + fread(data, 1, 1 * 1024 * 1024, fp); + rw = SDL_RWFromMem(data, 1 * 1024 * 1024); + if (!rw) + { + fprintf(stderr, "Could not create RW: %s\n", SDL_GetError()); + exit(1); + } + out = TTF_OpenFontRW(rw, 1, font_size); + if (!out) + { + fprintf(stderr, "Unable to open font %s\n", path); + exit(1); + } + fclose(fp); + + return out; +} + +void menu_init(SDL_Surface *screen) +{ + TTF_Init(); + + menu_font16 = read_font(FONT_PATH, 16); + menu_font20 = read_font(FONT_PATH, 20); + + real_screen = screen; + //virtkbd_init(screen, menu_font_alt16); per ora + is_inited = 1; +} + +int menu_is_inited(void) +{ + return is_inited; +} diff --git a/src/menu_sdl.h b/src/menu_sdl.h new file mode 100644 index 0000000..d455975 --- /dev/null +++ b/src/menu_sdl.h @@ -0,0 +1,62 @@ +/********************************************************************* + * + * Copyright (C) 2004, 2008, Simon Kagstrom + * + * Filename: menu.h + * Author: Simon Kagstrom + * Description: + * + * $Id$ + * + ********************************************************************/ +#ifndef __MENU_H__ +#define __MENU_H__ + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define KEY_UP 1 +#define KEY_DOWN 2 +#define KEY_LEFT 4 +#define KEY_RIGHT 8 +#define KEY_SELECT 16 +#define KEY_ESCAPE 32 +#define KEY_PAGEDOWN 64 +#define KEY_PAGEUP 128 +#define KEY_HELP 256 +#define FULL_DISPLAY_X 640 +#define FULL_DISPLAY_Y 480 + + +void menu_print_font(SDL_Surface *screen, int r, int g, int b, int x, int y, const char *msg, int font_size); + + +/* Various option selects */ +int menu_select_title(const char *title, const char **pp_msgs, int *p_submenus); +int menu_select(const char **pp_msgs, int *p_submenus); +const char *menu_select_file(const char *dir_path,const char *selected_file, int which); +const char *menu_select_file_start(const char *dir_path, const char **d64_name); + +uint32_t menu_wait_key_press(void); + +extern void msgKill(SDL_Rect *rc); +extern int msgInfo(char *text, int duration, SDL_Rect *rc); + +extern int msgYesNo(char *text, int def,int x, int y); + +void menu_init(SDL_Surface *screen); + +int menu_is_inited(void); + +int ext_matches(const char *name, const char *ext); + +#if defined(__cplusplus) +} +#endif + +#endif /* !__MENU_H__ */