#include "wxvbam.h" #include #include #include #include #include #include #include #include #include #include #include "../common/version_cpp.h" #include "../gb/gbPrinter.h" #include "../gba/agbprint.h" #include "config/option-proxy.h" #include "config/option.h" #if (wxMAJOR_VERSION < 3) #define GetXRCDialog(n) \ wxStaticCast(wxGetApp().frame->FindWindow(XRCID(n)), wxDialog) #else #define GetXRCDialog(n) \ wxStaticCast(wxGetApp().frame->FindWindowByName(n), wxDialog) #endif void GDBBreak(MainFrame* mf); bool cmditem_lt(const struct cmditem& cmd1, const struct cmditem& cmd2) { return wxStrcmp(cmd1.cmd, cmd2.cmd) < 0; } void MainFrame::GetMenuOptionBool(const wxString& menuName, bool* field) { assert(field); *field = !*field; int id = wxXmlResource::GetXRCID(menuName); for (size_t i = 0; i < checkable_mi.size(); i++) { if (checkable_mi[i].cmd != id) continue; *field = checkable_mi[i].mi->IsChecked(); break; } } void MainFrame::GetMenuOptionConfig(const wxString& menu_name, const config::OptionID& option_id) { config::Option* option = config::Option::ByID(option_id); assert(option); int id = wxXmlResource::GetXRCID(menu_name); for (size_t i = 0; i < checkable_mi.size(); i++) { if (checkable_mi[i].cmd != id) continue; const bool is_checked = checkable_mi[i].mi->IsChecked(); switch (option->type()) { case config::Option::Type::kBool: option->SetBool(is_checked); break; case config::Option::Type::kInt: option->SetInt(is_checked); break; default: assert(false); return; } break; } } void MainFrame::GetMenuOptionInt(const wxString& menuName, int* field, int mask) { assert(field); int value = mask; bool is_checked = ((*field) & (mask)) != (value); int id = wxXmlResource::GetXRCID(menuName); for (size_t i = 0; i < checkable_mi.size(); i++) { if (checkable_mi[i].cmd != id) continue; is_checked = checkable_mi[i].mi->IsChecked(); break; } *field = ((*field) & ~(mask)) | (is_checked ? (value) : 0); } void MainFrame::SetMenuOption(const wxString& menuName, int value) { int id = wxXmlResource::GetXRCID(menuName); for (size_t i = 0; i < checkable_mi.size(); i++) { if (checkable_mi[i].cmd != id) continue; checkable_mi[i].mi->Check(value); break; } } static void toggleBooleanVar(bool *menuValue, bool *globalVar) { if (*menuValue == *globalVar) // used accelerator *globalVar = !(*globalVar); else // used menu item *globalVar = *menuValue; } static void toggleBitVar(bool *menuValue, int *globalVar, int mask) { bool isEnabled = ((*globalVar) & (mask)) != (mask); if (*menuValue == isEnabled) *globalVar = ((*globalVar) & ~(mask)) | (!isEnabled ? (mask) : 0); else *globalVar = ((*globalVar) & ~(mask)) | (*menuValue ? (mask) : 0); *menuValue = ((*globalVar) & (mask)) != (mask); } //// File menu static int open_ft = 0; static wxString open_dir; EVT_HANDLER(wxID_OPEN, "Open ROM...") { open_dir = wxGetApp().GetAbsolutePath(gopts.gba_rom_dir); // FIXME: ignore if non-existent or not a dir wxString pats = _( "Game Boy Advance Files (*.agb;*.gba;*.bin;*.elf;*.mb;*.zip;*.7z;*.rar)|" "*.agb;*.gba;*.bin;*.elf;*.mb;" "*.agb.gz;*.gba.gz;*.bin.gz;*.elf.gz;*.mb.gz;" "*.agb.z;*.gba.z;*.bin.z;*.elf.z;*.mb.z;" "*.zip;*.7z;*.rar|" "Game Boy Files (*.dmg;*.gb;*.gbc;*.cgb;*.sgb;*.zip;*.7z;*.rar)|" "*.dmg;*.gb;*.gbc;*.cgb;*.sgb;" "*.dmg.gz;*.gb.gz;*.gbc.gz;*.cgb.gz;*.sgb.gz;" "*.dmg.z;*.gb.z;*.gbc.z;*.cgb.z;*.sgb.z;" "*.zip;*.7z;*.rar|"); pats.append(wxALL_FILES); wxFileDialog dlg(this, _("Open ROM file"), open_dir, wxT(""), pats, wxFD_OPEN | wxFD_FILE_MUST_EXIST); dlg.SetFilterIndex(open_ft); if (ShowModal(&dlg) == wxID_OK) wxGetApp().pending_load = dlg.GetPath(); open_ft = dlg.GetFilterIndex(); open_dir = dlg.GetDirectory(); } EVT_HANDLER(OpenGB, "Open GB...") { open_dir = wxGetApp().GetAbsolutePath(gopts.gb_rom_dir); // FIXME: ignore if non-existent or not a dir wxString pats = _( "Game Boy Files (*.dmg;*.gb;*.gbc;*.cgb;*.sgb;*.zip;*.7z;*.rar)|" "*.dmg;*.gb;*.gbc;*.cgb;*.sgb;" "*.dmg.gz;*.gb.gz;*.gbc.gz;*.cgb.gz;*.sgb.gz;" "*.dmg.z;*.gb.z;*.gbc.z;*.cgb.z;*.sgb.z;" "*.zip;*.7z;*.rar|"); pats.append(wxALL_FILES); wxFileDialog dlg(this, _("Open GB ROM file"), open_dir, wxT(""), pats, wxFD_OPEN | wxFD_FILE_MUST_EXIST); dlg.SetFilterIndex(open_ft); if (ShowModal(&dlg) == wxID_OK) wxGetApp().pending_load = dlg.GetPath(); open_ft = dlg.GetFilterIndex(); open_dir = dlg.GetDirectory(); } EVT_HANDLER(OpenGBC, "Open GBC...") { open_dir = wxGetApp().GetAbsolutePath(gopts.gbc_rom_dir); // FIXME: ignore if non-existent or not a dir wxString pats = _( "Game Boy Color Files (*.dmg;*.gb;*.gbc;*.cgb;*.sgb;*.zip;*.7z;*.rar)|" "*.dmg;*.gb;*.gbc;*.cgb;*.sgb;" "*.dmg.gz;*.gb.gz;*.gbc.gz;*.cgb.gz;*.sgb.gz;" "*.dmg.z;*.gb.z;*.gbc.z;*.cgb.z;*.sgb.z;" "*.zip;*.7z;*.rar|"); pats.append(wxALL_FILES); wxFileDialog dlg(this, _("Open GBC ROM file"), open_dir, wxT(""), pats, wxFD_OPEN | wxFD_FILE_MUST_EXIST); dlg.SetFilterIndex(open_ft); if (ShowModal(&dlg) == wxID_OK) wxGetApp().pending_load = dlg.GetPath(); open_ft = dlg.GetFilterIndex(); open_dir = dlg.GetDirectory(); } EVT_HANDLER(RecentReset, "Reset recent ROM list") { // only save config if there were items to remove if (gopts.recent->GetCount()) { while (gopts.recent->GetCount()) gopts.recent->RemoveFileFromHistory(0); wxFileConfig* cfg = wxGetApp().cfg; cfg->SetPath(wxT("/Recent")); gopts.recent->Save(*cfg); cfg->SetPath(wxT("/")); cfg->Flush(); } } EVT_HANDLER(RecentFreeze, "Freeze recent ROM list (toggle)") { bool menuPress = false; GetMenuOptionBool("RecentFreeze", &menuPress); toggleBooleanVar(&menuPress, &gopts.recent_freeze); SetMenuOption("RecentFreeze", gopts.recent_freeze ? 1 : 0); update_opts(); } // following 10 should really be a single ranged handler // former names: Recent01 .. Recent10 EVT_HANDLER(wxID_FILE1, "Load recent ROM 1") { panel->LoadGame(gopts.recent->GetHistoryFile(0)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE2, "Load recent ROM 2") { panel->LoadGame(gopts.recent->GetHistoryFile(1)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE3, "Load recent ROM 3") { panel->LoadGame(gopts.recent->GetHistoryFile(2)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE4, "Load recent ROM 4") { panel->LoadGame(gopts.recent->GetHistoryFile(3)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE5, "Load recent ROM 5") { panel->LoadGame(gopts.recent->GetHistoryFile(4)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE6, "Load recent ROM 6") { panel->LoadGame(gopts.recent->GetHistoryFile(5)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE7, "Load recent ROM 7") { panel->LoadGame(gopts.recent->GetHistoryFile(6)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE8, "Load recent ROM 8") { panel->LoadGame(gopts.recent->GetHistoryFile(7)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE9, "Load recent ROM 9") { panel->LoadGame(gopts.recent->GetHistoryFile(8)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } EVT_HANDLER(wxID_FILE10, "Load recent ROM 10") { panel->LoadGame(gopts.recent->GetHistoryFile(9)); #ifndef NO_DEBUGGER if (gopts.gdb_break_on_load) GDBBreak(); #endif } static const struct rom_maker { const wxString code, name; } makers[] = { { wxT("01"), wxT("Nintendo") }, { wxT("02"), wxT("Rocket Games") }, { wxT("08"), wxT("Capcom") }, { wxT("09"), wxT("Hot B Co.") }, { wxT("0A"), wxT("Jaleco") }, { wxT("0B"), wxT("Coconuts Japan") }, { wxT("0C"), wxT("Coconuts Japan/G.X.Media") }, { wxT("0H"), wxT("Starfish") }, { wxT("0L"), wxT("Warashi Inc.") }, { wxT("0N"), wxT("Nowpro") }, { wxT("0P"), wxT("Game Village") }, { wxT("13"), wxT("Electronic Arts Japan") }, { wxT("18"), wxT("Hudson Soft Japan") }, { wxT("19"), wxT("S.C.P.") }, { wxT("1A"), wxT("Yonoman") }, { wxT("1G"), wxT("SMDE") }, { wxT("1P"), wxT("Creatures Inc.") }, { wxT("1Q"), wxT("TDK Deep Impresion") }, { wxT("20"), wxT("Destination Software") }, { wxT("22"), wxT("VR 1 Japan") }, { wxT("25"), wxT("San-X") }, { wxT("28"), wxT("Kemco Japan") }, { wxT("29"), wxT("Seta") }, { wxT("2H"), wxT("Ubisoft Japan") }, { wxT("2K"), wxT("NEC InterChannel") }, { wxT("2L"), wxT("Tam") }, { wxT("2M"), wxT("Jordan") }, { wxT("2N"), wxT("Smilesoft") }, { wxT("2Q"), wxT("Mediakite") }, { wxT("36"), wxT("Codemasters") }, { wxT("37"), wxT("GAGA Communications") }, { wxT("38"), wxT("Laguna") }, { wxT("39"), wxT("Telstar Fun and Games") }, { wxT("41"), wxT("Ubi Soft Entertainment") }, { wxT("42"), wxT("Sunsoft") }, { wxT("47"), wxT("Spectrum Holobyte") }, { wxT("49"), wxT("IREM") }, { wxT("4D"), wxT("Malibu Games") }, { wxT("4F"), wxT("Eidos/U.S. Gold") }, { wxT("4J"), wxT("Fox Interactive") }, { wxT("4K"), wxT("Time Warner Interactive") }, { wxT("4Q"), wxT("Disney") }, { wxT("4S"), wxT("Black Pearl") }, { wxT("4X"), wxT("GT Interactive") }, { wxT("4Y"), wxT("RARE") }, { wxT("4Z"), wxT("Crave Entertainment") }, { wxT("50"), wxT("Absolute Entertainment") }, { wxT("51"), wxT("Acclaim") }, { wxT("52"), wxT("Activision") }, { wxT("53"), wxT("American Sammy Corp.") }, { wxT("54"), wxT("Take 2 Interactive") }, { wxT("55"), wxT("Hi Tech") }, { wxT("56"), wxT("LJN LTD.") }, { wxT("58"), wxT("Mattel") }, { wxT("5A"), wxT("Mindscape/Red Orb Ent.") }, { wxT("5C"), wxT("Taxan") }, { wxT("5D"), wxT("Midway") }, { wxT("5F"), wxT("American Softworks") }, { wxT("5G"), wxT("Majesco Sales Inc") }, { wxT("5H"), wxT("3DO") }, { wxT("5K"), wxT("Hasbro") }, { wxT("5L"), wxT("NewKidCo") }, { wxT("5M"), wxT("Telegames") }, { wxT("5N"), wxT("Metro3D") }, { wxT("5P"), wxT("Vatical Entertainment") }, { wxT("5Q"), wxT("LEGO Media") }, { wxT("5S"), wxT("Xicat Interactive") }, { wxT("5T"), wxT("Cryo Interactive") }, { wxT("5W"), wxT("Red Storm Ent./BKN Ent.") }, { wxT("5X"), wxT("Microids") }, { wxT("5Z"), wxT("Conspiracy Entertainment Corp.") }, { wxT("60"), wxT("Titus Interactive Studios") }, { wxT("61"), wxT("Virgin Interactive") }, { wxT("62"), wxT("Maxis") }, { wxT("64"), wxT("LucasArts Entertainment") }, { wxT("67"), wxT("Ocean") }, { wxT("69"), wxT("Electronic Arts") }, { wxT("6E"), wxT("Elite Systems Ltd.") }, { wxT("6F"), wxT("Electro Brain") }, { wxT("6G"), wxT("The Learning Company") }, { wxT("6H"), wxT("BBC") }, { wxT("6J"), wxT("Software 2000") }, { wxT("6L"), wxT("BAM! Entertainment") }, { wxT("6M"), wxT("Studio 3") }, { wxT("6Q"), wxT("Classified Games") }, { wxT("6S"), wxT("TDK Mediactive") }, { wxT("6U"), wxT("DreamCatcher") }, { wxT("6V"), wxT("JoWood Productions") }, { wxT("6W"), wxT("SEGA") }, { wxT("6X"), wxT("Wannado Edition") }, { wxT("6Y"), wxT("LSP") }, { wxT("6Z"), wxT("ITE Media") }, { wxT("70"), wxT("Infogrames") }, { wxT("71"), wxT("Interplay") }, { wxT("72"), wxT("JVC Musical Industries Inc") }, { wxT("73"), wxT("Parker Brothers") }, { wxT("75"), wxT("SCI") }, { wxT("78"), wxT("THQ") }, { wxT("79"), wxT("Accolade") }, { wxT("7A"), wxT("Triffix Ent. Inc.") }, { wxT("7C"), wxT("Microprose Software") }, { wxT("7D"), wxT("Universal Interactive Studios") }, { wxT("7F"), wxT("Kemco") }, { wxT("7G"), wxT("Rage Software") }, { wxT("7H"), wxT("Encore") }, { wxT("7J"), wxT("Zoo") }, { wxT("7K"), wxT("BVM") }, { wxT("7L"), wxT("Simon & Schuster Interactive") }, { wxT("7M"), wxT("Asmik Ace Entertainment Inc./AIA") }, { wxT("7N"), wxT("Empire Interactive") }, { wxT("7Q"), wxT("Jester Interactive") }, { wxT("7T"), wxT("Scholastic") }, { wxT("7U"), wxT("Ignition Entertainment") }, { wxT("7W"), wxT("Stadlbauer") }, { wxT("80"), wxT("Misawa") }, { wxT("83"), wxT("LOZC") }, { wxT("8B"), wxT("Bulletproof Software") }, { wxT("8C"), wxT("Vic Tokai Inc.") }, { wxT("8J"), wxT("General Entertainment") }, { wxT("8N"), wxT("Success") }, { wxT("8P"), wxT("SEGA Japan") }, { wxT("91"), wxT("Chun Soft") }, { wxT("92"), wxT("Video System") }, { wxT("93"), wxT("BEC") }, { wxT("96"), wxT("Yonezawa/S'pal") }, { wxT("97"), wxT("Kaneko") }, { wxT("99"), wxT("Victor Interactive Software") }, { wxT("9A"), wxT("Nichibutsu/Nihon Bussan") }, { wxT("9B"), wxT("Tecmo") }, { wxT("9C"), wxT("Imagineer") }, { wxT("9F"), wxT("Nova") }, { wxT("9H"), wxT("Bottom Up") }, { wxT("9L"), wxT("Hasbro Japan") }, { wxT("9N"), wxT("Marvelous Entertainment") }, { wxT("9P"), wxT("Keynet Inc.") }, { wxT("9Q"), wxT("Hands-On Entertainment") }, { wxT("A0"), wxT("Telenet") }, { wxT("A1"), wxT("Hori") }, { wxT("A4"), wxT("Konami") }, { wxT("A6"), wxT("Kawada") }, { wxT("A7"), wxT("Takara") }, { wxT("A9"), wxT("Technos Japan Corp.") }, { wxT("AA"), wxT("JVC") }, { wxT("AC"), wxT("Toei Animation") }, { wxT("AD"), wxT("Toho") }, { wxT("AF"), wxT("Namco") }, { wxT("AG"), wxT("Media Rings Corporation") }, { wxT("AH"), wxT("J-Wing") }, { wxT("AK"), wxT("KID") }, { wxT("AL"), wxT("MediaFactory") }, { wxT("AP"), wxT("Infogrames Hudson") }, { wxT("AQ"), wxT("Kiratto. Ludic Inc") }, { wxT("B0"), wxT("Acclaim Japan") }, { wxT("B1"), wxT("ASCII") }, { wxT("B2"), wxT("Bandai") }, { wxT("B4"), wxT("Enix") }, { wxT("B6"), wxT("HAL Laboratory") }, { wxT("B7"), wxT("SNK") }, { wxT("B9"), wxT("Pony Canyon Hanbai") }, { wxT("BA"), wxT("Culture Brain") }, { wxT("BB"), wxT("Sunsoft") }, { wxT("BD"), wxT("Sony Imagesoft") }, { wxT("BF"), wxT("Sammy") }, { wxT("BG"), wxT("Magical") }, { wxT("BJ"), wxT("Compile") }, { wxT("BL"), wxT("MTO Inc.") }, { wxT("BN"), wxT("Sunrise Interactive") }, { wxT("BP"), wxT("Global A Entertainment") }, { wxT("BQ"), wxT("Fuuki") }, { wxT("C0"), wxT("Taito") }, { wxT("C2"), wxT("Kemco") }, { wxT("C3"), wxT("Square Soft") }, { wxT("C5"), wxT("Data East") }, { wxT("C6"), wxT("Tonkin House") }, { wxT("C8"), wxT("Koei") }, { wxT("CA"), wxT("Konami/Palcom/Ultra") }, { wxT("CB"), wxT("Vapinc/NTVIC") }, { wxT("CC"), wxT("Use Co.,Ltd.") }, { wxT("CD"), wxT("Meldac") }, { wxT("CE"), wxT("FCI/Pony Canyon") }, { wxT("CF"), wxT("Angel") }, { wxT("CM"), wxT("Konami Computer Entertainment Osaka") }, { wxT("CP"), wxT("Enterbrain") }, { wxT("D1"), wxT("Sofel") }, { wxT("D2"), wxT("Quest") }, { wxT("D3"), wxT("Sigma Enterprises") }, { wxT("D4"), wxT("Ask Kodansa") }, { wxT("D6"), wxT("Naxat") }, { wxT("D7"), wxT("Copya System") }, { wxT("D9"), wxT("Banpresto") }, { wxT("DA"), wxT("TOMY") }, { wxT("DB"), wxT("LJN Japan") }, { wxT("DD"), wxT("NCS") }, { wxT("DF"), wxT("Altron Corporation") }, { wxT("DH"), wxT("Gaps Inc.") }, { wxT("DN"), wxT("ELF") }, { wxT("E2"), wxT("Yutaka") }, { wxT("E3"), wxT("Varie") }, { wxT("E5"), wxT("Epoch") }, { wxT("E7"), wxT("Athena") }, { wxT("E8"), wxT("Asmik Ace Entertainment Inc.") }, { wxT("E9"), wxT("Natsume") }, { wxT("EA"), wxT("King Records") }, { wxT("EB"), wxT("Atlus") }, { wxT("EC"), wxT("Epic/Sony Records") }, { wxT("EE"), wxT("IGS") }, { wxT("EL"), wxT("Spike") }, { wxT("EM"), wxT("Konami Computer Entertainment Tokyo") }, { wxT("EN"), wxT("Alphadream Corporation") }, { wxT("F0"), wxT("A Wave") }, { wxT("G1"), wxT("PCCW") }, { wxT("G4"), wxT("KiKi Co Ltd") }, { wxT("G5"), wxT("Open Sesame Inc.") }, { wxT("G6"), wxT("Sims") }, { wxT("G7"), wxT("Broccoli") }, { wxT("G8"), wxT("Avex") }, { wxT("G9"), wxT("D3 Publisher") }, { wxT("GB"), wxT("Konami Computer Entertainment Japan") }, { wxT("GD"), wxT("Square-Enix") }, { wxT("HY"), wxT("Sachen") } }; #define num_makers (sizeof(makers) / sizeof(makers[0])) static bool maker_lt(const rom_maker& r1, const rom_maker& r2) { return wxStrcmp(r1.code, r2.code) < 0; } void SetDialogLabel(wxDialog* dlg, const wxString& id, wxString ts, size_t l) { (void)l; // unused params ts.Replace(wxT("&"), wxT("&&"), true); (dynamic_cast((*dlg).FindWindow(wxXmlResource::GetXRCID(id))))->SetLabel(ts); } EVT_HANDLER_MASK(RomInformation, "ROM information...", CMDEN_GB | CMDEN_GBA) { wxString s; #define setlab(id) \ do { \ /* SetLabelText is not in 2.8 */ \ s.Replace(wxT("&"), wxT("&&"), true); \ XRCCTRL(*dlg, id, wxControl) \ ->SetLabel(s); \ } while (0) #define setblab(id, b) \ do { \ s.Printf(wxT("%02x"), (unsigned int)b); \ setlab(id); \ } while (0) #define setblabs(id, b, ts) \ do { \ s.Printf(wxT("%02x (%s)"), (unsigned int)b, ts.c_str()); \ setlab(id); \ } while (0) #define setlabs(id, ts, l) \ do { \ s = wxString((const char*)&(ts), wxConvLibc, l); \ setlab(id); \ } while (0) switch (panel->game_type()) { case IMAGE_GB: { wxDialog* dlg = GetXRCDialog("GBROMInfo"); setlabs("Title", gbRom[0x134], 15); setblab("Color", gbRom[0x143]); if (gbRom[0x14b] == 0x33) s = wxString((const char*)&gbRom[0x144], wxConvUTF8, 2); else s.Printf(wxT("%02x"), gbRom[0x14b]); setlab("MakerCode"); const rom_maker m = { s, wxString() }, *rm; rm = std::lower_bound(&makers[0], &makers[num_makers], m, maker_lt); if (rm < &makers[num_makers] && !wxStrcmp(m.code, rm->code)) s = rm->name; else s = _("Unknown"); setlab("MakerName"); setblab("UnitCode", gbRom[0x146]); wxString type; switch (gbRom[0x147]) { case 0x00: type = _("ROM"); break; case 0x01: type = _("ROM + MBC1"); break; case 0x02: type = _("ROM + MBC1 + RAM"); break; case 0x03: type = _("ROM + MBC1 + RAM + BATT"); break; case 0x05: type = _("ROM + MBC2"); break; case 0x06: type = _("ROM + MBC2 + BATT"); break; case 0x0b: type = _("ROM + MMM01"); break; case 0x0c: type = _("ROM + MMM01 + RAM"); break; case 0x0d: type = _("ROM + MMM01 + RAM + BATT"); break; case 0x0f: type = _("ROM + MBC3 + TIMER + BATT"); break; case 0x10: type = _("ROM + MBC3 + TIMER + RAM + BATT"); break; case 0x11: type = _("ROM + MBC3"); break; case 0x12: type = _("ROM + MBC3 + RAM"); break; case 0x13: type = _("ROM + MBC3 + RAM + BATT"); break; case 0x19: type = _("ROM + MBC5"); break; case 0x1a: type = _("ROM + MBC5 + RAM"); break; case 0x1b: type = _("ROM + MBC5 + RAM + BATT"); break; case 0x1c: type = _("ROM + MBC5 + RUMBLE"); break; case 0x1d: type = _("ROM + MBC5 + RUMBLE + RAM"); break; case 0x1e: type = _("ROM + MBC5 + RUMBLE + RAM + BATT"); break; case 0x22: type = _("ROM + MBC7 + BATT"); break; case 0x55: type = _("GameGenie"); break; case 0x56: type = _("GameShark V3.0"); break; case 0xfc: type = _("ROM + POCKET CAMERA"); break; case 0xfd: type = _("ROM + BANDAI TAMA5"); break; case 0xfe: type = _("ROM + HuC-3"); break; case 0xff: type = _("ROM + HuC-1"); break; default: type = _("Unknown"); } setblabs("DeviceType", gbRom[0x147], type); switch (gbRom[0x148]) { case 0: type = wxT("32K"); break; case 1: type = wxT("64K"); break; case 2: type = wxT("128K"); break; case 3: type = wxT("256K"); break; case 4: type = wxT("512K"); break; case 5: type = wxT("1M"); break; case 6: type = wxT("2M"); break; case 7: type = wxT("4M"); break; default: type = _("Unknown"); } setblabs("ROMSize", gbRom[0x148], type); switch (gbRom[0x149]) { case 0: type = _("None"); break; case 1: type = wxT("2K"); break; case 2: type = wxT("8K"); break; case 3: type = wxT("32K"); break; case 4: type = wxT("128K"); break; case 5: type = wxT("64K"); break; } setblabs("RAMSize", gbRom[0x149], type); setblab("DestCode", gbRom[0x14a]); setblab("LicCode", gbRom[0x14b]); setblab("Version", gbRom[0x14c]); uint8_t crc = 25; for (int i = 0x134; i < 0x14d; i++) crc += gbRom[i]; crc = 256 - crc; s.Printf(wxT("%02x (%02x)"), crc, gbRom[0x14d]); setlab("CRC"); uint16_t crc16 = 0; for (int i = 0; i < gbRomSize; i++) crc16 += gbRom[i]; crc16 -= gbRom[0x14e] + gbRom[0x14f]; s.Printf(wxT("%04x (%04x)"), crc16, gbRom[0x14e] * 256 + gbRom[0x14f]); setlab("Checksum"); dlg->Fit(); ShowModal(dlg); } break; case IMAGE_GBA: { IdentifyRom(); wxDialog* dlg = GetXRCDialog("GBAROMInfo"); wxString rom_crc32; rom_crc32.Printf(wxT("%08X"), panel->rom_crc32); SetDialogLabel(dlg, wxT("Title"), panel->rom_name, 30); setlabs("IntTitle", rom[0xa0], 12); SetDialogLabel(dlg, wxT("Scene"), panel->rom_scene_rls_name, 30); SetDialogLabel(dlg, wxT("Release"), panel->rom_scene_rls, 4); SetDialogLabel(dlg, wxT("CRC32"), rom_crc32, 8); setlabs("GameCode", rom[0xac], 4); setlabs("MakerCode", rom[0xb0], 2); const rom_maker m = { s, wxString() }, *rm; rm = std::lower_bound(&makers[0], &makers[num_makers], m, maker_lt); if (rm < &makers[num_makers] && !wxStrcmp(m.code, rm->code)) s = rm->name; else s = _("Unknown"); setlab("MakerName"); setblab("UnitCode", rom[0xb3]); s.Printf(wxT("%02x"), (unsigned int)rom[0xb4]); if (rom[0xb4] & 0x80) s.append(wxT(" (DACS)")); setlab("DeviceType"); setblab("Version", rom[0xbc]); uint8_t crc = 0x19; for (int i = 0xa0; i < 0xbd; i++) crc += rom[i]; crc = -crc; s.Printf(wxT("%02x (%02x)"), crc, rom[0xbd]); setlab("CRC"); dlg->Fit(); ShowModal(dlg); } break; default: break; } } EVT_HANDLER_MASK(ResetLoadingDotCodeFile, "Reset Loading e-Reader Dot Code", CMDEN_GBA) { ResetLoadDotCodeFile(); } EVT_HANDLER_MASK(SetLoadingDotCodeFile, "Load e-Reader Dot Code...", CMDEN_GBA) { static wxString loaddotcodefile_path; wxFileDialog dlg(this, _("Select Dot Code file"), loaddotcodefile_path, wxEmptyString, _( "e-Reader Dot Code (*.bin;*.raw)|" "*.bin;*.raw"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); int ret = ShowModal(&dlg); if (ret != wxID_OK) return; loaddotcodefile_path = dlg.GetPath(); SetLoadDotCodeFile(UTF8(loaddotcodefile_path)); } EVT_HANDLER_MASK(ResetSavingDotCodeFile, "Reset Saving e-Reader Dot Code", CMDEN_GBA) { ResetLoadDotCodeFile(); } EVT_HANDLER_MASK(SetSavingDotCodeFile, "Save e-Reader Dot Code...", CMDEN_GBA) { static wxString savedotcodefile_path; wxFileDialog dlg(this, _("Select Dot Code file"), savedotcodefile_path, wxEmptyString, _( "e-Reader Dot Code (*.bin;*.raw)|" "*.bin;*.raw"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); int ret = ShowModal(&dlg); if (ret != wxID_OK) return; savedotcodefile_path = dlg.GetPath(); SetSaveDotCodeFile(UTF8(savedotcodefile_path)); } static wxString batimp_path; EVT_HANDLER_MASK(ImportBatteryFile, "Import battery file...", CMDEN_GB | CMDEN_GBA) { if (!batimp_path.size()) batimp_path = panel->bat_dir(); wxFileDialog dlg(this, _("Select battery file"), batimp_path, wxEmptyString, _("Battery file (*.sav)|*.sav|Flash save (*.dat)|*.dat"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); int ret = ShowModal(&dlg); batimp_path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); ret = wxMessageBox(_("Importing a battery file will erase any saved games (permanently after the next write). Do you want to continue?"), _("Confirm import"), wxYES_NO | wxICON_EXCLAMATION); if (ret == wxYES) { wxString msg; if (panel->emusys->emuReadBattery(UTF8(fn))) msg.Printf(_("Loaded battery %s"), fn.wc_str()); else msg.Printf(_("Error loading battery %s"), fn.wc_str()); systemScreenMessage(msg); } } EVT_HANDLER_MASK(ImportGamesharkCodeFile, "Import Game Shark code file...", CMDEN_GB | CMDEN_GBA) { static wxString path; wxFileDialog dlg(this, _("Select code file"), path, wxEmptyString, panel->game_type() == IMAGE_GBA ? _("Game Shark Code File (*.spc;*.xpc)|*.spc;*.xpc") : _("Game Shark Code File (*.gcf)|*.gcf"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); int ret = ShowModal(&dlg); path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); ret = wxMessageBox(_("Importing a code file will replace any loaded cheats. Do you want to continue?"), _("Confirm import"), wxYES_NO | wxICON_EXCLAMATION); if (ret == wxYES) { wxString msg; bool res; if (panel->game_type() == IMAGE_GB) // FIXME: this routine will not work on big-endian systems // if the underlying file format is little-endian // (fix in gb/gbCheats.cpp) res = gbCheatReadGSCodeFile(UTF8(fn)); else { // need to select game first wxFFile f(fn, wxT("rb")); if (!f.IsOpened()) { wxLogError(_("Cannot open file %s"), fn.c_str()); return; } // FIXME: in my code, I assume file format is little-endian // however, in core code, it is assumed to be native-endian uint32_t len; char buf[14]; if (f.Read(&len, sizeof(len)) != sizeof(len) || wxUINT32_SWAP_ON_BE(len) != 14 || f.Read(buf, 14) != 14 || memcmp(buf, "SharkPortCODES", 14)) { wxLogError(_("Unsupported code file %s"), fn.c_str()); return; } f.Seek(0x1e); if (f.Read(&len, sizeof(len)) != sizeof(len)) len = 0; uint32_t game = 0; if (len > 1) { wxDialog* seldlg = GetXRCDialog("CodeSelect"); wxControlWithItems* lst = XRCCTRL(*seldlg, "CodeList", wxControlWithItems); lst->Clear(); while (len-- > 0) { uint32_t slen; if (f.Read(&slen, sizeof(slen)) != sizeof(slen) || slen > 1024) // arbitrary upper bound break; char buf[1024]; if (f.Read(buf, slen) != slen) break; lst->Append(wxString(buf, wxConvLibc, slen)); uint32_t ncodes; if (f.Read(&ncodes, sizeof(ncodes)) != sizeof(ncodes)) break; for (; ncodes > 0; ncodes--) { if (f.Read(&slen, sizeof(slen)) != sizeof(slen)) break; f.Seek(slen, wxFromCurrent); if (f.Read(&slen, sizeof(slen)) != sizeof(slen)) break; f.Seek(slen + 4, wxFromCurrent); if (f.Read(&slen, sizeof(slen)) != sizeof(slen)) break; f.Seek(slen * 12, wxFromCurrent); } } int sel = ShowModal(seldlg); if (sel != wxID_OK) return; game = lst->GetSelection(); if ((int)game == wxNOT_FOUND) game = 0; } bool v3 = fn.size() >= 4 && wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".xpc"), false); // FIXME: this routine will not work on big-endian systems // if the underlying file format is little-endian // (fix in gba/Cheats.cpp) res = cheatsImportGSACodeFile(UTF8(fn), game, v3); } if (res) msg.Printf(_("Loaded code file %s"), fn.wc_str()); else msg.Printf(_("Error loading code file %s"), fn.wc_str()); systemScreenMessage(msg); } } static wxString gss_path; EVT_HANDLER_MASK(ImportGamesharkActionReplaySnapshot, "Import Game Shark Action Replay snapshot...", CMDEN_GB | CMDEN_GBA) { wxFileDialog dlg(this, _("Select snapshot file"), gss_path, wxEmptyString, panel->game_type() == IMAGE_GBA ? _("GS & PAC Snapshots (*.sps;*.xps)|*.sps;*.xps|Game Shark SP Snapshots (*.gsv)|*.gsv") : _("Game Boy Snapshot (*.gbs)|*.gbs"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); int ret = ShowModal(&dlg); gss_path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); ret = wxMessageBox(_("Importing a snapshot file will erase any saved games (permanently after the next write). Do you want to continue?"), _("Confirm import"), wxYES_NO | wxICON_EXCLAMATION); if (ret == wxYES) { wxString msg; bool res; if (panel->game_type() == IMAGE_GB) res = gbReadGSASnapshot(UTF8(fn)); else { bool gsv = fn.size() >= 4 && wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".gsv"), false); if (gsv) // FIXME: this will fail on big-endian machines if // file format is little-endian // fix in GBA.cpp res = CPUReadGSASPSnapshot(UTF8(fn)); else // FIXME: this will fail on big-endian machines if // file format is little-endian // fix in GBA.cpp res = CPUReadGSASnapshot(UTF8(fn)); } if (res) msg.Printf(_("Loaded snapshot file %s"), fn.wc_str()); else msg.Printf(_("Error loading snapshot file %s"), fn.wc_str()); systemScreenMessage(msg); } } EVT_HANDLER_MASK(ExportBatteryFile, "Export battery file...", CMDEN_GB | CMDEN_GBA) { if (!batimp_path.size()) batimp_path = panel->bat_dir(); wxFileDialog dlg(this, _("Select battery file"), batimp_path, wxEmptyString, _("Battery file (*.sav)|*.sav|Flash save (*.dat)|*.dat"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); int ret = ShowModal(&dlg); batimp_path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); wxString msg; if (panel->emusys->emuWriteBattery(UTF8(fn))) msg.Printf(_("Wrote battery %s"), fn.wc_str()); else msg.Printf(_("Error writing battery %s"), fn.wc_str()); systemScreenMessage(msg); } EVT_HANDLER_MASK(ExportGamesharkSnapshot, "Export GameShark snapshot...", CMDEN_GBA) { if (eepromInUse) { wxLogError(_("EEPROM saves cannot be exported")); return; } wxString def_name = panel->game_name(); def_name.append(wxT(".sps")); wxFileDialog dlg(this, _("Select snapshot file"), gss_path, def_name, _("Game Shark Snapshot (*.sps)|*.sps"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); int ret = ShowModal(&dlg); gss_path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); wxDialog* infodlg = GetXRCDialog("ExportSPS"); wxTextCtrl *tit = XRCCTRL(*infodlg, "Title", wxTextCtrl), *dsc = XRCCTRL(*infodlg, "Description", wxTextCtrl), *n = XRCCTRL(*infodlg, "Notes", wxTextCtrl); tit->SetValue(wxString((const char*)&rom[0xa0], wxConvLibc, 12)); dsc->SetValue(wxDateTime::Now().Format(wxT("%c"))); n->SetValue(_("Exported from Visual Boy Advance-M")); if (ShowModal(infodlg) != wxID_OK) return; wxString msg; // FIXME: this will fail on big-endian machines if file format is // little-endian // fix in GBA.cpp if (CPUWriteGSASnapshot(fn.utf8_str(), tit->GetValue().utf8_str(), dsc->GetValue().utf8_str(), n->GetValue().utf8_str())) msg.Printf(_("Saved snapshot file %s"), fn.wc_str()); else msg.Printf(_("Error saving snapshot file %s"), fn.wc_str()); systemScreenMessage(msg); } EVT_HANDLER_MASK(ScreenCapture, "Screen capture...", CMDEN_GB | CMDEN_GBA) { wxString scap_path = GetGamePath(gopts.scrshot_dir); wxString def_name = panel->game_name(); if (captureFormat == 0) def_name.append(wxT(".png")); else def_name.append(wxT(".bmp")); wxFileDialog dlg(this, _("Select output file"), scap_path, def_name, _("PNG images|*.png|BMP images|*.bmp"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); dlg.SetFilterIndex(captureFormat); int ret = ShowModal(&dlg); scap_path = dlg.GetDirectory(); if (ret != wxID_OK) return; wxString fn = dlg.GetPath(); int fmt = dlg.GetFilterIndex(); if (fn.size() >= 4) { if (wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".bmp"), false)) fmt = 1; else if (wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".png"), false)) fmt = 0; } if (fmt == 0) panel->emusys->emuWritePNG(UTF8(fn)); else panel->emusys->emuWriteBMP(UTF8(fn)); wxString msg; msg.Printf(_("Wrote snapshot %s"), fn.wc_str()); systemScreenMessage(msg); } EVT_HANDLER_MASK(RecordSoundStartRecording, "Start sound recording...", CMDEN_NSREC) { #ifndef NO_FFMPEG static wxString sound_exts; static int sound_extno; static wxString sound_path; if (!sound_exts.size()) { sound_extno = -1; int extno = 0; std::vector fmts = recording::getSupAudNames(); std::vector exts = recording::getSupAudExts(); for (size_t i = 0; i < fmts.size(); ++i) { sound_exts.append(wxString(fmts[i], wxConvLibc)); sound_exts.append(_(" files (")); wxString ext(exts[i], wxConvLibc); ext.Replace(wxT(","), wxT(";*.")); ext.insert(0, wxT("*.")); if (sound_extno < 0 && ext.find(wxT("*.wav")) != wxString::npos) sound_extno = extno; sound_exts.append(ext); sound_exts.append(wxT(")|")); sound_exts.append(ext); sound_exts.append(wxT('|')); extno++; } sound_exts.append(wxALL_FILES); if (sound_extno < 0) sound_extno = extno; } sound_path = GetGamePath(gopts.recording_dir); wxString def_name = panel->game_name(); wxString extoff = sound_exts; for (int i = 0; i < sound_extno; i++) { extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); } extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip * def_name += extoff.Left(wxStrcspn(extoff, wxT(";|"))); wxFileDialog dlg(this, _("Select output file"), sound_path, def_name, sound_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); dlg.SetFilterIndex(sound_extno); int ret = ShowModal(&dlg); sound_extno = dlg.GetFilterIndex(); sound_path = dlg.GetDirectory(); if (ret != wxID_OK) return; panel->StartSoundRecording(dlg.GetPath()); #endif } EVT_HANDLER_MASK(RecordSoundStopRecording, "Stop sound recording", CMDEN_SREC) { #ifndef NO_FFMPEG panel->StopSoundRecording(); #endif } EVT_HANDLER_MASK(RecordAVIStartRecording, "Start video recording...", CMDEN_NVREC) { #ifndef NO_FFMPEG static wxString vid_exts; static int vid_extno; static wxString vid_path; if (!vid_exts.size()) { vid_extno = -1; int extno = 0; std::vector fmts = recording::getSupVidNames(); std::vector exts = recording::getSupVidExts(); for (size_t i = 0; i < fmts.size(); ++i) { vid_exts.append(wxString(fmts[i], wxConvLibc)); vid_exts.append(_(" files (")); wxString ext(exts[i], wxConvLibc); ext.Replace(wxT(","), wxT(";*.")); ext.insert(0, wxT("*.")); if (vid_extno < 0 && ext.find(wxT("*.avi")) != wxString::npos) vid_extno = extno; vid_exts.append(ext); vid_exts.append(wxT(")|")); vid_exts.append(ext); vid_exts.append(wxT('|')); extno++; } vid_exts.append(wxALL_FILES); if (vid_extno < 0) vid_extno = extno; } vid_path = GetGamePath(gopts.recording_dir); wxString def_name = panel->game_name(); wxString extoff = vid_exts; for (int i = 0; i < vid_extno; i++) { extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); } extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip * def_name += extoff.Left(wxStrcspn(extoff, wxT(";|"))); wxFileDialog dlg(this, _("Select output file"), vid_path, def_name, vid_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); dlg.SetFilterIndex(vid_extno); int ret = ShowModal(&dlg); vid_extno = dlg.GetFilterIndex(); vid_path = dlg.GetDirectory(); if (ret != wxID_OK) return; panel->StartVidRecording(dlg.GetPath()); #endif } EVT_HANDLER_MASK(RecordAVIStopRecording, "Stop video recording", CMDEN_VREC) { #ifndef NO_FFMPEG panel->StopVidRecording(); #endif } static wxString mov_path; EVT_HANDLER_MASK(RecordMovieStartRecording, "Start game recording...", CMDEN_NGREC) { static wxString mov_exts; static int mov_extno; static wxString mov_path; if (!mov_exts.size()) { mov_extno = -1; int extno = 0; std::vector fmts = getSupMovNamesToRecord(); std::vector exts = getSupMovExtsToRecord(); for (auto&& fmt : fmts) { mov_exts.append(wxString(fmt, wxConvLibc)); mov_exts.append(_(" files (")); wxString ext(exts[extno], wxConvLibc); ext.Replace(wxT(","), wxT(";*.")); ext.insert(0, wxT("*.")); if (mov_extno < 0 && ext.find(wxT("*.vmv")) != wxString::npos) mov_extno = extno; mov_exts.append(ext); mov_exts.append(wxT(")|")); mov_exts.append(ext); mov_exts.append(wxT('|')); extno++; } mov_exts.append(wxALL_FILES); if (mov_extno < 0) mov_extno = extno; } mov_path = GetGamePath(gopts.recording_dir); wxString def_name = panel->game_name(); wxString extoff = mov_exts; for (int i = 0; i < mov_extno; i++) { extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); } extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip * def_name += extoff.Left(wxStrcspn(extoff, wxT(";|"))); wxFileDialog dlg(this, _("Select output file"), mov_path, def_name, mov_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); dlg.SetFilterIndex(mov_extno); int ret = ShowModal(&dlg); mov_extno = dlg.GetFilterIndex(); mov_path = dlg.GetDirectory(); if (ret != wxID_OK) return; systemStartGameRecording(dlg.GetPath(), getSupMovFormatsToRecord()[mov_extno]); } EVT_HANDLER_MASK(RecordMovieStopRecording, "Stop game recording", CMDEN_GREC) { systemStopGameRecording(); } EVT_HANDLER_MASK(PlayMovieStartPlaying, "Start playing movie...", CMDEN_NGREC | CMDEN_NGPLAY) { static wxString mov_exts; static int mov_extno; static wxString mov_path; if (!mov_exts.size()) { mov_extno = -1; int extno = 0; std::vector fmts = getSupMovNamesToPlayback(); std::vector exts = getSupMovExtsToPlayback(); for (size_t i = 0; i < fmts.size(); ++i) { mov_exts.append(wxString(fmts[i], wxConvLibc)); mov_exts.append(_(" files (")); wxString ext(exts[i], wxConvLibc); ext.Replace(wxT(","), wxT(";*.")); ext.insert(0, wxT("*.")); if (mov_extno < 0 && ext.find(wxT("*.vmv")) != wxString::npos) mov_extno = extno; mov_exts.append(ext); mov_exts.append(wxT(")|")); mov_exts.append(ext); mov_exts.append(wxT('|')); extno++; } mov_exts.append(wxALL_FILES); if (mov_extno < 0) mov_extno = extno; } mov_path = GetGamePath(gopts.recording_dir); systemStopGamePlayback(); wxString def_name = panel->game_name(); wxString extoff = mov_exts; for (int i = 0; i < mov_extno; i++) { extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); extoff = extoff.Mid(extoff.Find(wxT('|')) + 1); } extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip * def_name += extoff.Left(wxStrcspn(extoff, wxT(";|"))); wxFileDialog dlg(this, _("Select file"), mov_path, def_name, mov_exts, wxFD_OPEN | wxFD_FILE_MUST_EXIST); dlg.SetFilterIndex(mov_extno); int ret = ShowModal(&dlg); mov_extno = dlg.GetFilterIndex(); mov_path = dlg.GetDirectory(); if (ret != wxID_OK) return; systemStartGamePlayback(dlg.GetPath(), getSupMovFormatsToPlayback()[mov_extno]); } EVT_HANDLER_MASK(PlayMovieStopPlaying, "Stop playing movie", CMDEN_GPLAY) { systemStopGamePlayback(); } // formerly Close EVT_HANDLER_MASK(wxID_CLOSE, "Close", CMDEN_GB | CMDEN_GBA) { panel->UnloadGame(); } // formerly Exit EVT_HANDLER(wxID_EXIT, "Exit") { Close(false); } // Emulation menu EVT_HANDLER(Pause, "Pause (toggle)") { bool menuPress = false; GetMenuOptionBool("Pause", &menuPress); toggleBooleanVar(&menuPress, &paused); SetMenuOption("Pause", paused ? 1 : 0); if (paused) panel->Pause(); else if (!IsPaused()) panel->Resume(); // undo next-frame's zeroing of frameskip int fs = frameSkip; if (fs >= 0) systemFrameSkip = fs; } // new EVT_HANDLER_MASK(EmulatorSpeedupToggle, "Turbo mode (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; GetMenuOptionBool("EmulatorSpeedupToggle", &menuPress); toggleBooleanVar(&menuPress, &turbo); SetMenuOption("EmulatorSpeedupToggle", turbo ? 1 : 0); } EVT_HANDLER_MASK(Reset, "Reset", CMDEN_GB | CMDEN_GBA) { panel->emusys->emuReset(); // systemScreenMessage("Reset"); } EVT_HANDLER(ToggleFullscreen, "Full screen (toggle)") { panel->ShowFullScreen(!IsFullScreen()); } EVT_HANDLER(JoypadAutofireA, "Autofire A (toggle)") { bool menuPress = false; GetMenuOptionBool("JoypadAutofireA", &menuPress); toggleBitVar(&menuPress, &autofire, KEYM_A); SetMenuOption("JoypadAutofireA", menuPress ? 1 : 0); GetMenuOptionInt("JoypadAutofireA", &autofire, KEYM_A); } EVT_HANDLER(JoypadAutofireB, "Autofire B (toggle)") { bool menuPress = false; GetMenuOptionBool("JoypadAutofireB", &menuPress); toggleBitVar(&menuPress, &autofire, KEYM_B); SetMenuOption("JoypadAutofireB", menuPress ? 1 : 0); GetMenuOptionInt("JoypadAutofireB", &autofire, KEYM_B); } EVT_HANDLER(JoypadAutofireL, "Autofire L (toggle)") { bool menuPress = false; GetMenuOptionBool("JoypadAutofireL", &menuPress); toggleBitVar(&menuPress, &autofire, KEYM_L); SetMenuOption("JoypadAutofireL", menuPress ? 1 : 0); GetMenuOptionInt("JoypadAutofireL", &autofire, KEYM_L); } EVT_HANDLER(JoypadAutofireR, "Autofire R (toggle)") { bool menuPress = false; GetMenuOptionBool("JoypadAutofireR", &menuPress); toggleBitVar(&menuPress, &autofire, KEYM_R); SetMenuOption("JoypadAutofireR", menuPress ? 1 : 0); GetMenuOptionInt("JoypadAutofireR", &autofire, KEYM_R); } EVT_HANDLER(JoypadAutoholdUp, "Autohold Up (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdUp"; int keym = KEYM_UP; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdDown, "Autohold Down (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdDown"; int keym = KEYM_DOWN; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdLeft, "Autohold Left (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdLeft"; int keym = KEYM_LEFT; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdRight, "Autohold Right (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdRight"; int keym = KEYM_RIGHT; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdA, "Autohold A (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdA"; int keym = KEYM_A; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdB, "Autohold B (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdB"; int keym = KEYM_B; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdL, "Autohold L (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdL"; int keym = KEYM_L; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdR, "Autohold R (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdR"; int keym = KEYM_R; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdSelect, "Autohold Select (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdSelect"; int keym = KEYM_SELECT; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } EVT_HANDLER(JoypadAutoholdStart, "Autohold Start (toggle)") { bool menuPress = false; char keyName[] = "JoypadAutoholdStart"; int keym = KEYM_START; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &autohold, keym); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &autohold, keym); } #include "background-input.h" EVT_HANDLER(AllowKeyboardBackgroundInput, "Allow keyboard background input (toggle)") { bool menuPress = false; GetMenuOptionBool("AllowKeyboardBackgroundInput", &menuPress); toggleBooleanVar(&menuPress, &allowKeyboardBackgroundInput); SetMenuOption("AllowKeyboardBackgroundInput", allowKeyboardBackgroundInput ? 1 : 0); disableKeyboardBackgroundInput(); if (allowKeyboardBackgroundInput) { if (panel && panel->panel) { enableKeyboardBackgroundInput(panel->panel->GetWindow()); } } update_opts(); } EVT_HANDLER(AllowJoystickBackgroundInput, "Allow joystick background input (toggle)") { bool menuPress = false; GetMenuOptionBool("AllowJoystickBackgroundInput", &menuPress); toggleBooleanVar(&menuPress, &allowJoystickBackgroundInput); SetMenuOption("AllowJoystickBackgroundInput", allowJoystickBackgroundInput ? 1 : 0); update_opts(); } EVT_HANDLER_MASK(LoadGameRecent, "Load most recent save", CMDEN_SAVST) { panel->LoadState(); } EVT_HANDLER(LoadGameAutoLoad, "Auto load most recent save (toggle)") { bool menuPress = false; GetMenuOptionBool("LoadGameAutoLoad", &menuPress); toggleBooleanVar(&menuPress, &gopts.autoload_state); SetMenuOption("LoadGameAutoLoad", gopts.autoload_state ? 1 : 0); update_opts(); } EVT_HANDLER_MASK(LoadGame01, "Load saved state 1", CMDEN_SAVST) { panel->LoadState(1); } EVT_HANDLER_MASK(LoadGame02, "Load saved state 2", CMDEN_SAVST) { panel->LoadState(2); } EVT_HANDLER_MASK(LoadGame03, "Load saved state 3", CMDEN_SAVST) { panel->LoadState(3); } EVT_HANDLER_MASK(LoadGame04, "Load saved state 4", CMDEN_SAVST) { panel->LoadState(4); } EVT_HANDLER_MASK(LoadGame05, "Load saved state 5", CMDEN_SAVST) { panel->LoadState(5); } EVT_HANDLER_MASK(LoadGame06, "Load saved state 6", CMDEN_SAVST) { panel->LoadState(6); } EVT_HANDLER_MASK(LoadGame07, "Load saved state 7", CMDEN_SAVST) { panel->LoadState(7); } EVT_HANDLER_MASK(LoadGame08, "Load saved state 8", CMDEN_SAVST) { panel->LoadState(8); } EVT_HANDLER_MASK(LoadGame09, "Load saved state 9", CMDEN_SAVST) { panel->LoadState(9); } EVT_HANDLER_MASK(LoadGame10, "Load saved state 10", CMDEN_SAVST) { panel->LoadState(10); } static wxString st_dir; EVT_HANDLER_MASK(Load, "Load state...", CMDEN_GB | CMDEN_GBA) { if (st_dir.empty()) st_dir = panel->state_dir(); wxFileDialog dlg(this, _("Select state file"), st_dir, wxEmptyString, _("Visual Boy Advance saved game files|*.sgm"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); int ret = ShowModal(&dlg); st_dir = dlg.GetDirectory(); if (ret != wxID_OK) return; panel->LoadState(dlg.GetPath()); } // new EVT_HANDLER(KeepSaves, "Do not load battery saves (toggle)") { bool menuPress = false; GetMenuOptionBool("KeepSaves", &menuPress); toggleBitVar(&menuPress, &coreOptions.skipSaveGameBattery, 1); SetMenuOption("KeepSaves", menuPress ? 1 : 0); GetMenuOptionInt("KeepSaves", &coreOptions.skipSaveGameBattery, 1); update_opts(); } // new EVT_HANDLER(KeepCheats, "Do not change cheat list (toggle)") { bool menuPress = false; GetMenuOptionBool("KeepCheats", &menuPress); toggleBitVar(&menuPress, &coreOptions.skipSaveGameCheats, 1); SetMenuOption("KeepCheats", menuPress ? 1 : 0); GetMenuOptionInt("KeepCheats", &coreOptions.skipSaveGameCheats, 1); update_opts(); } EVT_HANDLER_MASK(SaveGameOldest, "Save state to oldest slot", CMDEN_GB | CMDEN_GBA) { panel->SaveState(); } EVT_HANDLER_MASK(SaveGame01, "Save state 1", CMDEN_GB | CMDEN_GBA) { panel->SaveState(1); } EVT_HANDLER_MASK(SaveGame02, "Save state 2", CMDEN_GB | CMDEN_GBA) { panel->SaveState(2); } EVT_HANDLER_MASK(SaveGame03, "Save state 3", CMDEN_GB | CMDEN_GBA) { panel->SaveState(3); } EVT_HANDLER_MASK(SaveGame04, "Save state 4", CMDEN_GB | CMDEN_GBA) { panel->SaveState(4); } EVT_HANDLER_MASK(SaveGame05, "Save state 5", CMDEN_GB | CMDEN_GBA) { panel->SaveState(5); } EVT_HANDLER_MASK(SaveGame06, "Save state 6", CMDEN_GB | CMDEN_GBA) { panel->SaveState(6); } EVT_HANDLER_MASK(SaveGame07, "Save state 7", CMDEN_GB | CMDEN_GBA) { panel->SaveState(7); } EVT_HANDLER_MASK(SaveGame08, "Save state 8", CMDEN_GB | CMDEN_GBA) { panel->SaveState(8); } EVT_HANDLER_MASK(SaveGame09, "Save state 9", CMDEN_GB | CMDEN_GBA) { panel->SaveState(9); } EVT_HANDLER_MASK(SaveGame10, "Save state 10", CMDEN_GB | CMDEN_GBA) { panel->SaveState(10); } EVT_HANDLER_MASK(Save, "Save state as...", CMDEN_GB | CMDEN_GBA) { if (st_dir.empty()) st_dir = panel->state_dir(); wxFileDialog dlg(this, _("Select state file"), st_dir, wxEmptyString, _("Visual Boy Advance saved game files|*.sgm"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); int ret = ShowModal(&dlg); st_dir = dlg.GetDirectory(); if (ret != wxID_OK) return; panel->SaveState(dlg.GetPath()); } static int state_slot = 0; // new EVT_HANDLER_MASK(LoadGameSlot, "Load current state slot", CMDEN_GB | CMDEN_GBA) { panel->LoadState(state_slot + 1); } // new EVT_HANDLER_MASK(SaveGameSlot, "Save current state slot", CMDEN_GB | CMDEN_GBA) { panel->SaveState(state_slot + 1); } // new EVT_HANDLER_MASK(IncrGameSlot, "Increase state slot number", CMDEN_GB | CMDEN_GBA) { state_slot = (state_slot + 1) % 10; wxString msg; msg.Printf(_("Current state slot #%d"), state_slot); systemScreenMessage(msg); } // new EVT_HANDLER_MASK(DecrGameSlot, "Decrease state slot number", CMDEN_GB | CMDEN_GBA) { state_slot = (state_slot + 9) % 10; wxString msg; msg.Printf(_("Current state slot #%d"), state_slot); systemScreenMessage(msg); } // new EVT_HANDLER_MASK(IncrGameSlotSave, "Increase state slot number and save", CMDEN_GB | CMDEN_GBA) { state_slot = (state_slot + 1) % 10; panel->SaveState(state_slot + 1); wxString msg; msg.Printf(_("Current state slot #%d"), state_slot); systemScreenMessage(msg); } EVT_HANDLER_MASK(Rewind, "Rewind", CMDEN_REWIND) { MainFrame* mf = wxGetApp().frame; GameArea* panel = mf->GetPanel(); int rew_st = (panel->next_rewind_state + NUM_REWINDS - 1) % NUM_REWINDS; // if within 5 seconds of last one, and > 1 state, delete last state & move back // FIXME: 5 should actually be user-configurable // maybe instead of 5, 10% of rewind_interval if (panel->num_rewind_states > 1 && (gopts.rewind_interval <= 5 || (int)panel->rewind_time / 6 > gopts.rewind_interval - 5)) { --panel->num_rewind_states; panel->next_rewind_state = rew_st; if (gopts.rewind_interval > 5) rew_st = (rew_st + NUM_REWINDS - 1) % NUM_REWINDS; } panel->emusys->emuReadMemState(&panel->rewind_mem[rew_st * REWIND_SIZE], REWIND_SIZE); InterframeCleanup(); // FIXME: if(paused) blank screen panel->do_rewind = false; panel->rewind_time = gopts.rewind_interval * 6; // systemScreenMessage(_("Rewinded")); } EVT_HANDLER_MASK(CheatsList, "List cheats...", CMDEN_GB | CMDEN_GBA) { wxDialog* dlg = GetXRCDialog("CheatList"); ShowModal(dlg); } EVT_HANDLER_MASK(CheatsSearch, "Create cheat...", CMDEN_GB | CMDEN_GBA) { wxDialog* dlg = GetXRCDialog("CheatCreate"); ShowModal(dlg); } // new EVT_HANDLER(CheatsAutoSaveLoad, "Auto save/load cheats (toggle)") { bool menuPress = false; GetMenuOptionBool("CheatsAutoSaveLoad", &menuPress); toggleBooleanVar(&menuPress, &gopts.autoload_cheats); SetMenuOption("CheatsAutoSaveLoad", gopts.autoload_cheats ? 1 : 0); update_opts(); } // was CheatsDisable // changed for convenience to match internal variable functionality EVT_HANDLER(CheatsEnable, "Enable cheats (toggle)") { bool menuPress = false; GetMenuOptionBool("CheatsEnable", &menuPress); toggleBitVar(&menuPress, &coreOptions.cheatsEnabled, 1); SetMenuOption("CheatsEnable", menuPress ? 1 : 0); GetMenuOptionInt("CheatsEnable", &coreOptions.cheatsEnabled, 1); update_opts(); } EVT_HANDLER(ColorizerHack, "Enable Colorizer Hack (toggle)") { bool val = false; GetMenuOptionBool("ColorizerHack", &val); if (val && gopts.use_bios_file_gb) { wxLogError(_("Cannot use Colorizer Hack when Game Boy BIOS File is enabled.")); val = 0; SetMenuOption("ColorizerHack", 0); } colorizerHack = val; update_opts(); } // Debug menu EVT_HANDLER_MASK(VideoLayersBG0, "Video layer BG0 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersBG0"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 8)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 8)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersBG1, "Video layer BG1 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersBG1"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 9)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 9)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersBG2, "Video layer BG2 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersBG2"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 10)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 10)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersBG3, "Video layer BG3 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersBG3"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 11)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 11)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersOBJ, "Video layer OBJ (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersOBJ"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 12)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 12)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersWIN0, "Video layer WIN0 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersWIN0"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 13)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 13)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersWIN1, "Video layer WIN1 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersWIN1"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 14)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 14)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersOBJWIN, "Video layer OBJWIN (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "VideoLayersOBJWIN"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &coreOptions.layerSettings, (1 << 15)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &coreOptions.layerSettings, (1 << 15)); coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(VideoLayersReset, "Show all video layers", CMDEN_GB | CMDEN_GBA) { #define set_vl(s) \ do { \ int id = XRCID(s); \ for (size_t i = 0; i < checkable_mi.size(); i++) \ if (checkable_mi[i].cmd == id) { \ checkable_mi[i].mi->Check(true); \ break; \ } \ } while (0) coreOptions.layerSettings = 0x7f00; coreOptions.layerEnable = DISPCNT & coreOptions.layerSettings; set_vl("VideoLayersBG0"); set_vl("VideoLayersBG1"); set_vl("VideoLayersBG2"); set_vl("VideoLayersBG3"); set_vl("VideoLayersOBJ"); set_vl("VideoLayersWIN0"); set_vl("VideoLayersWIN1"); set_vl("VideoLayersOBJWIN"); CPUUpdateRenderBuffers(false); } EVT_HANDLER_MASK(SoundChannel1, "Sound Channel 1 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "SoundChannel1"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 0)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 0)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER_MASK(SoundChannel2, "Sound Channel 2 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "SoundChannel2"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 1)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 1)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER_MASK(SoundChannel3, "Sound Channel 3 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "SoundChannel3"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 2)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 2)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER_MASK(SoundChannel4, "Sound Channel 4 (toggle)", CMDEN_GB | CMDEN_GBA) { bool menuPress = false; char keyName[] = "SoundChannel4"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 3)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 3)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER_MASK(DirectSoundA, "Direct Sound A (toggle)", CMDEN_GBA) { bool menuPress = false; char keyName[] = "DirectSoundA"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 8)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 8)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER_MASK(DirectSoundB, "Direct Sound B (toggle)", CMDEN_GBA) { bool menuPress = false; char keyName[] = "DirectSoundB"; GetMenuOptionBool(keyName, &menuPress); toggleBitVar(&menuPress, &gopts.sound_en, (1 << 9)); SetMenuOption(keyName, menuPress ? 1 : 0); GetMenuOptionInt(keyName, &gopts.sound_en, (1 << 9)); soundSetEnable(gopts.sound_en); update_opts(); } EVT_HANDLER(ToggleSound, "Enable/disable all sound channels") { bool en = gopts.sound_en == 0; gopts.sound_en = en ? 0x30f : 0; SetMenuOption("SoundChannel1", en); SetMenuOption("SoundChannel2", en); SetMenuOption("SoundChannel3", en); SetMenuOption("SoundChannel4", en); SetMenuOption("DirectSoundA", en); SetMenuOption("DirectSoundB", en); soundSetEnable(gopts.sound_en); update_opts(); systemScreenMessage(en ? _("Sound enabled") : _("Sound disabled")); } EVT_HANDLER(IncreaseVolume, "Increase volume") { gopts.sound_vol += 5; if (gopts.sound_vol > 200) gopts.sound_vol = 200; update_opts(); soundSetVolume((float)gopts.sound_vol / 100.0); wxString msg; msg.Printf(_("Volume: %d %%"), gopts.sound_vol); systemScreenMessage(msg); } EVT_HANDLER(DecreaseVolume, "Decrease volume") { gopts.sound_vol -= 5; if (gopts.sound_vol < 0) gopts.sound_vol = 0; update_opts(); soundSetVolume((float)gopts.sound_vol / 100.0); wxString msg; msg.Printf(_("Volume: %d %%"), gopts.sound_vol); systemScreenMessage(msg); } EVT_HANDLER_MASK(NextFrame, "Next Frame", CMDEN_GB | CMDEN_GBA) { SetMenuOption("Pause", true); paused = true; pause_next = true; if (!IsPaused()) panel->Resume(); systemFrameSkip = 0; } EVT_HANDLER_MASK(Disassemble, "Disassemble...", CMDEN_GB | CMDEN_GBA) { Disassemble(); } EVT_HANDLER(Logging, "Logging...") { wxDialog* dlg = wxGetApp().frame->logdlg; dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); if (gopts.keep_on_top) dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP); else dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP); dlg->Show(); dlg->Raise(); } EVT_HANDLER_MASK(IOViewer, "I/O Viewer...", CMDEN_GBA) { IOViewer(); } EVT_HANDLER_MASK(MapViewer, "Map Viewer...", CMDEN_GB | CMDEN_GBA) { MapViewer(); } EVT_HANDLER_MASK(MemoryViewer, "Memory Viewer...", CMDEN_GB | CMDEN_GBA) { MemViewer(); } EVT_HANDLER_MASK(OAMViewer, "OAM Viewer...", CMDEN_GB | CMDEN_GBA) { OAMViewer(); } EVT_HANDLER_MASK(PaletteViewer, "Palette Viewer...", CMDEN_GB | CMDEN_GBA) { PaletteViewer(); } EVT_HANDLER_MASK(TileViewer, "Tile Viewer...", CMDEN_GB | CMDEN_GBA) { TileViewer(); } #ifndef NO_DEBUGGER extern int remotePort; int GetGDBPort(MainFrame* mf) { ModalPause mp; return wxGetNumberFromUser( #ifdef __WXMSW__ wxEmptyString, #else _("Set to 0 for pseudo tty"), #endif _("Port to wait for connection:"), _("GDB Connection"), gopts.gdb_port, #ifdef __WXMSW__ 1025, #else 0, #endif 65535, mf); } #endif EVT_HANDLER(DebugGDBPort, "Configure port...") { #ifndef NO_DEBUGGER int port_selected = GetGDBPort(this); if (port_selected != -1) { gopts.gdb_port = port_selected; update_opts(); } #endif } EVT_HANDLER(DebugGDBBreakOnLoad, "Break on load") { #ifndef NO_DEBUGGER GetMenuOptionBool("DebugGDBBreakOnLoad", &gopts.gdb_break_on_load); update_opts(); #endif } #ifndef NO_DEBUGGER void MainFrame::GDBBreak() { ModalPause mp; if (gopts.gdb_port == 0) { int port_selected = GetGDBPort(this); if (port_selected != -1) { gopts.gdb_port = port_selected; update_opts(); } } if (gopts.gdb_port > 0) { if (!remotePort) { wxString msg; #ifndef __WXMSW__ if (!gopts.gdb_port) { if (!debugOpenPty()) return; msg.Printf(_("Waiting for connection at %s"), debugGetSlavePty().wc_str()); } else #endif { if (!debugStartListen(gopts.gdb_port)) return; msg.Printf(_("Waiting for connection on port %d"), gopts.gdb_port); } wxProgressDialog dlg(_("Waiting for GDB..."), msg, 100, this, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME); bool connected = false; while (dlg.Pulse()) { #ifndef __WXMSW__ if (!gopts.gdb_port) connected = debugWaitPty(); else #endif connected = debugWaitSocket(); if (connected) break; // sleep a bit more in case of infinite loop wxMilliSleep(10); } if (connected) { remotePort = gopts.gdb_port; emulating = 1; dbgMain = remoteStubMain; dbgSignal = remoteStubSignal; dbgOutput = remoteOutput; cmd_enable &= ~(CMDEN_NGDB_ANY | CMDEN_NGDB_GBA); cmd_enable |= CMDEN_GDB; enable_menus(); debugger = true; } else { remoteCleanUp(); } } else { if (armState) { armNextPC -= 4; reg[15].I -= 4; } else { armNextPC -= 2; reg[15].I -= 2; } debugger = true; } } } #endif EVT_HANDLER_MASK(DebugGDBBreak, "Break into GDB", CMDEN_NGDB_GBA | CMDEN_GDB) { #ifndef NO_DEBUGGER GDBBreak(); #endif } EVT_HANDLER_MASK(DebugGDBDisconnect, "Disconnect GDB", CMDEN_GDB) { #ifndef NO_DEBUGGER debugger = false; dbgMain = NULL; dbgSignal = NULL; dbgOutput = NULL; remotePort = 0; remoteCleanUp(); cmd_enable &= ~CMDEN_GDB; cmd_enable |= CMDEN_NGDB_GBA | CMDEN_NGDB_ANY; enable_menus(); #endif } // Options menu EVT_HANDLER(GeneralConfigure, "General options...") { int rew = gopts.rewind_interval; wxDialog* dlg = GetXRCDialog("GeneralConfig"); if (ShowModal(dlg) == wxID_OK) update_opts(); if (panel->game_type() != IMAGE_UNKNOWN) soundSetThrottle(throttle); if (rew != gopts.rewind_interval) { if (!gopts.rewind_interval) { if (panel->num_rewind_states) { cmd_enable &= ~CMDEN_REWIND; enable_menus(); } panel->num_rewind_states = 0; panel->do_rewind = false; } else { if (!panel->num_rewind_states) panel->do_rewind = true; panel->rewind_time = gopts.rewind_interval * 6; } } } EVT_HANDLER(SpeedupConfigure, "Speedup / Turbo options...") { wxDialog* dlg = GetXRCDialog("SpeedupConfig"); unsigned save_speedup_throttle = speedup_throttle; unsigned save_speedup_frame_skip = speedup_frame_skip; bool save_speedup_throttle_frame_skip = coreOptions.speedup_throttle_frame_skip; if (ShowModal(dlg) == wxID_OK) update_opts(); else { // Restore values if cancel pressed. speedup_throttle = save_speedup_throttle; speedup_frame_skip = save_speedup_frame_skip; coreOptions.speedup_throttle_frame_skip = save_speedup_throttle_frame_skip; } } EVT_HANDLER(UIConfigure, "UI Settings...") { wxDialog* dlg = GetXRCDialog("UIConfig"); if (ShowModal(dlg) == wxID_OK) update_opts(); } EVT_HANDLER(GameBoyConfigure, "Game Boy options...") { wxDialog* dlg = GetXRCDialog("GameBoyConfig"); wxChoice* c = XRCCTRL(*dlg, "Borders", wxChoice); bool borderon = gbBorderOn; if (!gbBorderOn && !gbBorderAutomatic) c->SetSelection(0); else if (gbBorderOn) c->SetSelection(1); else c->SetSelection(2); if (ShowModal(dlg) != wxID_OK) return; switch (c->GetSelection()) { case 0: gbBorderOn = gbBorderAutomatic = false; break; case 1: gbBorderOn = true; break; case 2: gbBorderOn = false; gbBorderAutomatic = true; break; } // this value might have been overwritten by FrameSkip if (panel->game_type() == IMAGE_GB) { if (borderon != gbBorderOn) { if (gbBorderOn) { panel->AddBorder(); gbSgbRenderBorder(); } else panel->DelBorder(); } // don't want to have to reset to change colors memcpy(gbPalette, &systemGbPalette[gbPaletteOption * 8], 8 * sizeof(systemGbPalette[0])); } update_opts(); } EVT_HANDLER(SetSize1x, "1x") { config::Proxy().Set(1); } EVT_HANDLER(SetSize2x, "2x") { config::Proxy().Set(2); } EVT_HANDLER(SetSize3x, "3x") { config::Proxy().Set(3); } EVT_HANDLER(SetSize4x, "4x") { config::Proxy().Set(4); } EVT_HANDLER(SetSize5x, "5x") { config::Proxy().Set(5); } EVT_HANDLER(SetSize6x, "6x") { config::Proxy().Set(6); } EVT_HANDLER(GameBoyAdvanceConfigure, "Game Boy Advance options...") { wxDialog* dlg = GetXRCDialog("GameBoyAdvanceConfig"); wxTextCtrl* ovcmt = XRCCTRL(*dlg, "Comment", wxTextCtrl); wxString cmt; wxChoice *ovrtc = XRCCTRL(*dlg, "OvRTC", wxChoice), *ovst = XRCCTRL(*dlg, "OvSaveType", wxChoice), *ovfs = XRCCTRL(*dlg, "OvFlashSize", wxChoice), *ovmir = XRCCTRL(*dlg, "OvMirroring", wxChoice); if (panel->game_type() == IMAGE_GBA) { wxString s = wxString((const char*)&rom[0xac], wxConvLibc, 4); XRCCTRL(*dlg, "GameCode", wxControl) ->SetLabel(s); cmt = wxString((const char*)&rom[0xa0], wxConvLibc, 12); wxFileConfig* cfg = wxGetApp().overrides; if (cfg->HasGroup(s)) { cfg->SetPath(s); cmt = cfg->Read(wxT("comment"), cmt); ovcmt->SetValue(cmt); ovrtc->SetSelection(cfg->Read(wxT("rtcEnabled"), -1) + 1); ovst->SetSelection(cfg->Read(wxT("saveType"), -1) + 1); ovfs->SetSelection((cfg->Read(wxT("flashSize"), -1) >> 17) + 1); ovmir->SetSelection(cfg->Read(wxT("mirroringEnabled"), -1) + 1); cfg->SetPath(wxT("/")); } else { ovcmt->SetValue(cmt); ovrtc->SetSelection(0); ovst->SetSelection(0); ovfs->SetSelection(0); ovmir->SetSelection(0); } } else { XRCCTRL(*dlg, "GameCode", wxControl) ->SetLabel(wxEmptyString); ovcmt->SetValue(wxEmptyString); ovrtc->SetSelection(0); ovst->SetSelection(0); ovfs->SetSelection(0); ovmir->SetSelection(0); } if (ShowModal(dlg) != wxID_OK) return; if (panel->game_type() == IMAGE_GBA) { agbPrintEnable(agbPrint); wxString s = wxString((const char*)&rom[0xac], wxConvLibc, 4); wxFileConfig* cfg = wxGetApp().overrides; bool chg; if (cfg->HasGroup(s)) { cfg->SetPath(s); chg = ovcmt->GetValue() != cmt || ovrtc->GetSelection() != cfg->Read(wxT("rtcEnabled"), -1) + 1 || ovst->GetSelection() != cfg->Read(wxT("saveType"), -1) + 1 || ovfs->GetSelection() != (cfg->Read(wxT("flashSize"), -1) >> 17) + 1 || ovmir->GetSelection() != cfg->Read(wxT("mirroringEnabled"), -1) + 1; cfg->SetPath(wxT("/")); } else chg = ovrtc->GetSelection() != 0 || ovst->GetSelection() != 0 || ovfs->GetSelection() != 0 || ovmir->GetSelection() != 0; if (chg) { wxString vba_over; wxFileName fn(wxGetApp().GetConfigurationPath(), wxT("vba-over.ini")); if (fn.FileExists()) { wxFileInputStream fis(fn.GetFullPath()); wxStringOutputStream sos(&vba_over); fis.Read(sos); } if (cfg->HasGroup(s)) { cfg->SetPath(s); if (cfg->Read(wxT("path"), wxEmptyString) == fn.GetPath()) { // EOL can be either \n (unix), \r\n (dos), or \r (old mac) wxString res(wxT("(^|[\n\r])" // a new line L"(" // capture group as \2 L"(#[^\n\r]*(\r?\n|\r))?" // an optional comment line L"\\[")); // the group header res += s; res += wxT("\\]" L"([^[#]" // non-comment non-group-start chars L"|[^\r\n \t][ \t]*[[#]" // or comment/grp start chars in middle of line L"|#[^\n\r]*(\r?\n|\r)[^[]" // or comments not followed by grp start L")*" L")" // end of group // no need to try to describe what's next // as the regex should maximize match size ); wxRegEx re(res); // there may be more than one group if it was hand-edited // so remove them all // could use re.Replace(), but this is more reliable while (re.Matches(vba_over)) { size_t beg, end; re.GetMatch(&beg, &end, 2); vba_over.erase(beg, end - beg); } } cfg->SetPath(wxT("/")); cfg->DeleteGroup(s); } cfg->SetPath(s); cfg->Write(wxT("path"), fn.GetPath()); cfg->Write(wxT("comment"), ovcmt->GetValue()); vba_over.append(wxT("# ")); vba_over.append(ovcmt->GetValue()); vba_over.append(wxTextFile::GetEOL()); vba_over.append(wxT('[')); vba_over.append(s); vba_over.append(wxT(']')); vba_over.append(wxTextFile::GetEOL()); int sel; #define appendval(n) \ do { \ vba_over.append(wxT(n)); \ vba_over.append(wxT('=')); \ vba_over.append((wxChar)(wxT('0') + sel - 1)); \ vba_over.append(wxTextFile::GetEOL()); \ cfg->Write(wxT(n), sel - 1); \ } while (0) if ((sel = ovrtc->GetSelection()) > 0) appendval("rtcEnabled"); if ((sel = ovst->GetSelection()) > 0) appendval("saveType"); if ((sel = ovfs->GetSelection()) > 0) { vba_over.append(wxT("flashSize=")); vba_over.append(sel == 1 ? wxT("65536") : wxT("131072")); vba_over.append(wxTextFile::GetEOL()); cfg->Write(wxT("flashSize"), 0x10000 << (sel - 1)); } if ((sel = ovmir->GetSelection()) > 0) appendval("mirroringEnabled"); cfg->SetPath(wxT("/")); vba_over.append(wxTextFile::GetEOL()); fn.Mkdir(0777, wxPATH_MKDIR_FULL); wxTempFileOutputStream fos(fn.GetFullPath()); fos.Write(vba_over.c_str(), vba_over.size()); fos.Commit(); } } update_opts(); } EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY) { if (gopts.max_threads != 1) { gopts.max_threads = wxThread::GetCPUCount(); } // Just in case GetCPUCount() returns 0 or -1 if (gopts.max_threads < 0) { gopts.max_threads = 1; } wxDialog* dlg = GetXRCDialog("DisplayConfig"); if (ShowModal(dlg) != wxID_OK) { return; } if (frameSkip >= 0) { systemFrameSkip = frameSkip; } update_opts(); } EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY) { config::Proxy().Next(); } EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY) { config::Proxy().Next(); } EVT_HANDLER_MASK(SoundConfigure, "Sound options...", CMDEN_NREC_ANY) { int oqual = gopts.sound_qual, oapi = gopts.audio_api; bool oupmix = gopts.upmix, ohw = gopts.dsound_hw_accel; wxString odev = gopts.audio_dev; wxDialog* dlg = GetXRCDialog("SoundConfig"); if (ShowModal(dlg) != wxID_OK) return; switch (panel->game_type()) { case IMAGE_UNKNOWN: break; case IMAGE_GB: gb_effects_config.echo = (float)gopts.gb_echo / 100.0; gb_effects_config.stereo = (float)gopts.gb_stereo / 100.0; gbSoundSetSampleRate(!gopts.sound_qual ? 48000 : 44100 / (1 << (gopts.sound_qual - 1))); break; case IMAGE_GBA: soundSetSampleRate(!gopts.sound_qual ? 48000 : 44100 / (1 << (gopts.sound_qual - 1))); soundFiltering = (float)gopts.gba_sound_filter / 100.0f; break; } // changing sample rate causes driver reload, so no explicit reload needed if (oqual == gopts.sound_qual && // otherwise reload if API changes (oapi != gopts.audio_api || odev != gopts.audio_dev || // or init-only options (oapi == AUD_XAUDIO2 && oupmix != gopts.upmix) || (oapi == AUD_FAUDIO && oupmix != gopts.upmix) || (oapi == AUD_DIRECTSOUND && ohw != gopts.dsound_hw_accel))) { soundShutdown(); if (!soundInit()) { wxLogError(_("Could not initialize the sound driver!")); } } soundSetVolume((float)gopts.sound_vol / 100.0); update_opts(); } EVT_HANDLER(EmulatorDirectories, "Directories...") { wxDialog* dlg = GetXRCDialog("DirectoriesConfig"); if (ShowModal(dlg) == wxID_OK) update_opts(); } EVT_HANDLER(JoypadConfigure, "Joypad options...") { wxDialog* dlg = GetXRCDialog("JoypadConfig"); joy.PollAllJoysticks(); auto frame = wxGetApp().frame; bool joy_timer = frame->IsJoyPollTimerRunning(); if (!joy_timer) frame->StartJoyPollTimer(); if (ShowModal(dlg) == wxID_OK) update_opts(); if (!joy_timer) frame->StopJoyPollTimer(); SetJoystick(); } EVT_HANDLER(Customize, "Customize UI...") { wxDialog* dlg = GetXRCDialog("AccelConfig"); joy.PollAllJoysticks(); auto frame = wxGetApp().frame; bool joy_timer = frame->IsJoyPollTimerRunning(); if (!joy_timer) frame->StartJoyPollTimer(); if (ShowModal(dlg) == wxID_OK) update_opts(); if (!joy_timer) frame->StopJoyPollTimer(); SetJoystick(); } #ifndef NO_ONLINEUPDATES #include "autoupdater/autoupdater.h" #endif // NO_ONLINEUPDATES EVT_HANDLER(UpdateEmu, "Check for updates...") { #ifndef NO_ONLINEUPDATES checkUpdatesUi(); #endif // NO_ONLINEUPDATES } EVT_HANDLER(FactoryReset, "Factory Reset...") { wxMessageDialog dlg(NULL, wxString(wxT( "YOUR CONFIGURATION WILL BE DELETED!\n\n")) + wxString(wxT( "Are you sure?")), wxT("FACTORY RESET"), wxYES_NO | wxNO_DEFAULT | wxCENTRE); if (dlg.ShowModal() == wxID_YES) { wxGetApp().cfg->DeleteAll(); wxExecute(wxStandardPaths::Get().GetExecutablePath(), wxEXEC_ASYNC); Close(true); } } EVT_HANDLER(BugReport, "Report bugs...") { wxLaunchDefaultBrowser(wxT("https://github.com/visualboyadvance-m/visualboyadvance-m/issues")); } EVT_HANDLER(FAQ, "VBA-M support forum") { wxLaunchDefaultBrowser(wxT("https://github.com/visualboyadvance-m/visualboyadvance-m/")); } EVT_HANDLER(Translate, "Translations") { wxLaunchDefaultBrowser(wxT("http://www.transifex.com/projects/p/vba-m")); } // was About EVT_HANDLER(wxID_ABOUT, "About...") { wxAboutDialogInfo ai; ai.SetName(wxT("VisualBoyAdvance-M")); wxString version(vbam_version); ai.SetVersion(version); // setting website, icon, license uses custom aboutbox on win32 & macosx // but at least win32 standard about is nothing special ai.SetWebSite(wxT("http://www.vba-m.com/")); ai.SetIcon(GetIcons().GetIcon(wxSize(32, 32), wxIconBundle::FALLBACK_NEAREST_LARGER)); ai.SetDescription(_("Nintendo Game Boy / Color / Advance) emulator.")); ai.SetCopyright(_("Copyright (C) 1999-2003 Forgotten\nCopyright (C) 2004-2006 VBA development team\nCopyright (C) 2007-2020 VBA-M development team")); ai.SetLicense(_( "This program is free software: you can redistribute it and / or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation, either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see http://www.gnu.org/licenses ." )); // from gtk ai.AddDeveloper(wxT("Forgotten")); ai.AddDeveloper(wxT("kxu")); ai.AddDeveloper(wxT("Pokemonhacker")); ai.AddDeveloper(wxT("Spacy51")); ai.AddDeveloper(wxT("mudlord")); ai.AddDeveloper(wxT("Nach")); ai.AddDeveloper(wxT("jbo_85")); ai.AddDeveloper(wxT("bgK")); ai.AddArtist(wxT("Matteo Drera")); ai.AddArtist(wxT("Jakub Steiner")); ai.AddArtist(wxT("Jones Lee")); // from win32 ai.AddDeveloper(wxT("Jonas Quinn")); ai.AddDeveloper(wxT("DJRobX")); ai.AddDeveloper(wxT("Spacy")); ai.AddDeveloper(wxT("Squall Leonhart")); // wx ai.AddDeveloper(wxT("Thomas J. Moore")); // from win32 "thanks" ai.AddDeveloper(wxT("blargg")); ai.AddDeveloper(wxT("Costis")); ai.AddDeveloper(wxT("chrono")); ai.AddDeveloper(wxT("xKiv")); ai.AddDeveloper(wxT("skidau")); ai.AddDeveloper(wxT("TheCanadianBacon")); ai.AddDeveloper(wxT("rkitover")); ai.AddDeveloper(wxT("Mystro256")); ai.AddDeveloper(wxT("retro-wertz")); ai.AddDeveloper(wxT("denisfa")); ai.AddDeveloper(wxT("orbea")); ai.AddDeveloper(wxT("Orig. VBA team")); ai.AddDeveloper(wxT("... many contributors who send us patches/PRs")); wxAboutBox(ai); } EVT_HANDLER(Bilinear, "Use bilinear filter with 3d renderer") { GetMenuOptionBool("Bilinear", &gopts.bilinear); // Force new panel with new bilinear option. panel->ResetPanel(); update_opts(); } EVT_HANDLER(RetainAspect, "Retain aspect ratio when resizing") { GetMenuOptionBool("RetainAspect", &gopts.retain_aspect); // Force new panel with new aspect ratio options. panel->ResetPanel(); update_opts(); } EVT_HANDLER(Printer, "Enable printer emulation") { GetMenuOptionInt("Printer", &coreOptions.winGbPrinterEnabled, 1); #if (defined __WIN32__ || defined _WIN32) #ifndef NO_LINK gbSerialFunction = gbStartLink; #else gbSerialFunction = NULL; #endif #endif if (coreOptions.winGbPrinterEnabled) gbSerialFunction = gbPrinterSend; update_opts(); } EVT_HANDLER(PrintGather, "Automatically gather a full page before printing") { GetMenuOptionBool("PrintGather", &gopts.print_auto_page); update_opts(); } EVT_HANDLER(PrintSnap, "Automatically save printouts as screen captures with -print suffix") { GetMenuOptionBool("PrintSnap", &gopts.print_screen_cap); update_opts(); } EVT_HANDLER(GBASoundInterpolation, "GBA sound interpolation") { GetMenuOptionBool("GBASoundInterpolation", &soundInterpolation); update_opts(); } EVT_HANDLER(GBDeclicking, "GB sound declicking") { GetMenuOptionBool("GBDeclicking", &gopts.gb_declick); // note that setting declick may reset gb sound engine gbSoundSetDeclicking(gopts.gb_declick); update_opts(); } EVT_HANDLER(GBEnhanceSound, "Enable GB sound effects") { GetMenuOptionBool("GBEnhanceSound", &gopts.gb_effects_config_enabled); gb_effects_config.enabled = gopts.gb_effects_config_enabled; update_opts(); } EVT_HANDLER(GBSurround, "GB surround sound effect (%)") { GetMenuOptionBool("GBSurround",&gopts.gb_effects_config_surround); gb_effects_config.surround = gopts.gb_effects_config_surround; update_opts(); } EVT_HANDLER(AGBPrinter, "Enable AGB printer") { GetMenuOptionInt("AGBPrinter", &agbPrint, 1); update_opts(); } EVT_HANDLER_MASK(GBALcdFilter, "Enable LCD filter", CMDEN_GBA) { bool menuPress = false; GetMenuOptionBool("GBALcdFilter", &menuPress); toggleBooleanVar(&menuPress, &gopts.gba_lcd_filter); SetMenuOption("GBALcdFilter", gopts.gba_lcd_filter ? 1 : 0); utilUpdateSystemColorMaps(gopts.gba_lcd_filter); update_opts(); } EVT_HANDLER_MASK(GBLcdFilter, "Enable LCD filter", CMDEN_GB) { bool menuPress = false; GetMenuOptionBool("GBLcdFilter", &menuPress); toggleBooleanVar(&menuPress, &gopts.gb_lcd_filter); SetMenuOption("GBLcdFilter", gopts.gb_lcd_filter ? 1 : 0); utilUpdateSystemColorMaps(gopts.gb_lcd_filter); update_opts(); } EVT_HANDLER(GBColorOption, "Enable GB color option") { bool menuPress = false; bool intVar = gbColorOption ? true : false; GetMenuOptionBool("GBColorOption", &menuPress); toggleBooleanVar(&menuPress, &intVar); SetMenuOption("GBColorOption", intVar ? 1 : 0); gbColorOption = intVar ? 1 : 0; update_opts(); } EVT_HANDLER(ApplyPatches, "Apply IPS/UPS/IPF patches if found") { GetMenuOptionInt("ApplyPatches", &autoPatch, 1); update_opts(); } EVT_HANDLER(KeepOnTop, "Keep window on top") { GetMenuOptionBool("KeepOnTop", &gopts.keep_on_top); MainFrame* mf = wxGetApp().frame; if (gopts.keep_on_top) mf->SetWindowStyle(mf->GetWindowStyle() | wxSTAY_ON_TOP); else mf->SetWindowStyle(mf->GetWindowStyle() & ~wxSTAY_ON_TOP); update_opts(); } EVT_HANDLER(StatusBar, "Enable status bar") { GetMenuOptionBool("StatusBar", &gopts.statusbar); update_opts(); MainFrame* mf = wxGetApp().frame; if (gopts.statusbar) mf->GetStatusBar()->Show(); else mf->GetStatusBar()->Hide(); mf->SendSizeEvent(); panel->AdjustSize(false); mf->SendSizeEvent(); } EVT_HANDLER(NoStatusMsg, "Disable on-screen status messages") { GetMenuOptionInt("NoStatusMsg", &disableStatusMessages, 1); update_opts(); } EVT_HANDLER(FrameSkipAuto, "Auto Skip frames.") { GetMenuOptionInt("FrameSkipAuto", &autoFrameSkip, 1); update_opts(); } EVT_HANDLER(PauseWhenInactive, "Pause game when main window loses focus") { GetMenuOptionInt("PauseWhenInactive", &pauseWhenInactive, 1); update_opts(); } EVT_HANDLER(RTC, "Enable RTC (vba-over.ini override is rtcEnabled") { GetMenuOptionInt("RTC", &coreOptions.rtcEnabled, 1); update_opts(); } EVT_HANDLER(Transparent, "Draw on-screen messages transparently") { GetMenuOptionInt("Transparent", &showSpeedTransparent, 1); update_opts(); } EVT_HANDLER(SkipIntro, "Skip BIOS initialization") { GetMenuOptionInt("SkipIntro", &coreOptions.skipBios, 1); update_opts(); } EVT_HANDLER(BootRomEn, "Use the specified BIOS file for GBA") { GetMenuOptionBool("BootRomEn", &gopts.use_bios_file_gba); update_opts(); } EVT_HANDLER(BootRomGB, "Use the specified BIOS file for GB") { int val = 0; GetMenuOptionInt("BootRomGB", &val, 1); if (val == 1 && colorizerHack == 1) { wxLogError(_("Cannot use Game Boy BIOS when Colorizer Hack is enabled.")); val = 0; SetMenuOption("BootRomGB", 0); } gopts.use_bios_file_gb = val; update_opts(); } EVT_HANDLER(BootRomGBC, "Use the specified BIOS file for GBC") { GetMenuOptionBool("BootRomGBC", &gopts.use_bios_file_gbc); update_opts(); } EVT_HANDLER(VSync, "Wait for vertical sync") { GetMenuOptionBool("VSync", &gopts.vsync); update_opts(); panel->ResetPanel(); } void MainFrame::EnableNetworkMenu() { cmd_enable &= ~CMDEN_LINK_ANY; if (gopts.gba_link_type != 0) cmd_enable |= CMDEN_LINK_ANY; if (gopts.link_proto) cmd_enable &= ~CMDEN_LINK_ANY; enable_menus(); } void SetLinkTypeMenu(const char* type, int value) { MainFrame* mf = wxGetApp().frame; mf->SetMenuOption("LinkType0Nothing", 0); mf->SetMenuOption("LinkType1Cable", 0); mf->SetMenuOption("LinkType2Wireless", 0); mf->SetMenuOption("LinkType3GameCube", 0); mf->SetMenuOption("LinkType4Gameboy", 0); mf->SetMenuOption(type, 1); gopts.gba_link_type = value; update_opts(); #ifndef NO_LINK CloseLink(); #endif mf->EnableNetworkMenu(); } EVT_HANDLER_MASK(LanLink, "Start Network link", CMDEN_LINK_ANY) { #ifndef NO_LINK LinkMode mode = GetLinkMode(); if (mode != LINK_DISCONNECTED) { // while we could deactivate the command when connected, it is more // user-friendly to display a message indidcating why wxLogError(_("LAN link is already active. Disable link mode to disconnect.")); return; } if (gopts.link_proto) { // see above comment wxLogError(_("Network is not supported in local mode.")); return; } wxDialog* dlg = GetXRCDialog("NetLink"); ShowModal(dlg); panel->SetFrameTitle(); #endif } EVT_HANDLER(LinkType0Nothing, "Link nothing") { SetLinkTypeMenu("LinkType0Nothing", 0); } EVT_HANDLER(LinkType1Cable, "Link cable") { SetLinkTypeMenu("LinkType1Cable", 1); } EVT_HANDLER(LinkType2Wireless, "Link wireless") { SetLinkTypeMenu("LinkType2Wireless", 2); } EVT_HANDLER(LinkType3GameCube, "Link GameCube") { SetLinkTypeMenu("LinkType3GameCube", 3); } EVT_HANDLER(LinkType4Gameboy, "Link Gameboy") { SetLinkTypeMenu("LinkType4Gameboy", 4); } EVT_HANDLER(LinkAuto, "Enable link at boot") { GetMenuOptionBool("LinkAuto", &gopts.link_auto); update_opts(); } EVT_HANDLER(SpeedOn, "Enable faster network protocol by default") { GetMenuOptionBool("SpeedOn", &gopts.link_hacks); update_opts(); } EVT_HANDLER(LinkProto, "Local host IPC") { GetMenuOptionBool("LinkProto", &gopts.link_proto); update_opts(); enable_menus(); EnableNetworkMenu(); } EVT_HANDLER(LinkConfigure, "Link options...") { #ifndef NO_LINK wxDialog* dlg = GetXRCDialog("LinkConfig"); if (ShowModal(dlg) != wxID_OK) return; SetLinkTimeout(gopts.link_timeout); update_opts(); EnableNetworkMenu(); #endif } // Dummy for disabling system key bindings EVT_HANDLER_MASK(NOOP, "Do nothing", CMDEN_NEVER) { } // The following have been moved to dialogs // I will not implement as command unless there is great demand // CheatsList //EVT_HANDLER(CheatsLoad, "Load Cheats...") //EVT_HANDLER(CheatsSave, "Save Cheats...") //GeneralConfigure //EVT_HANDLER(EmulatorRewindInterval, "EmulatorRewindInterval") //EVT_HANDLER(EmulatorAutoApplyPatchFiles, "EmulatorAutoApplyPatchFiles") //EVT_HANDLER(ThrottleNone, "ThrottleNone") //EVT_HANDLER(Throttle025%, "Throttle025%") //EVT_HANDLER(Throttle050%, "Throttle050%") //EVT_HANDLER(Throttle100%, "Throttle100%") //EVT_HANDLER(Throttle150%, "Throttle150%") //EVT_HANDLER(Throttle200%, "Throttle200%") //EVT_HANDLER(ThrottleOther, "ThrottleOther") //GameBoyConfigure/GameBoyAdvanceConfigure //EVT_HANDLER(FrameSkip0, "FrameSkip0") //EVT_HANDLER(FrameSkip1, "FrameSkip1") //EVT_HANDLER(FrameSkip2, "FrameSkip2") //EVT_HANDLER(FrameSkip3, "FrameSkip3") //EVT_HANDLER(FrameSkip4, "FrameSkip4") //EVT_HANDLER(FrameSkip5, "FrameSkip5") //EVT_HANDLER(FrameSkip6, "FrameSkip6") //EVT_HANDLER(FrameSkip7, "FrameSkip7") //EVT_HANDLER(FrameSkip8, "FrameSkip8") //EVT_HANDLER(FrameSkip9, "FrameSkip9") // GameBoyConfigure //EVT_HANDLER(GameboyBorder, "GameboyBorder") //EVT_HANDLER(GameboyBorderAutomatic, "GameboyBorderAutomatic") //EVT_HANDLER(GameboyColors, "GameboyColors") //GameBoyAdvanceConfigure //EVT_HANDLER(EmulatorAGBPrint, "EmulatorAGBPrint") //EVT_HANDLER(EmulatorSaveAuto, "EmulatorSaveAuto") //EVT_HANDLER(EmulatorSaveEEPROM, "EmulatorSaveEEPROM") //EVT_HANDLER(EmulatorSaveSRAM, "EmulatorSaveSRAM") //EVT_HANDLER(EmulatorSaveFLASH, "EmulatorSaveFLASH") //EVT_HANDLER(EmulatorSaveEEPROMSensor, "EmulatorSaveEEPROMSensor") //EVT_HANDLER(EmulatorSaveFlash64K, "EmulatorSaveFlash64K") //EVT_HANDLER(EmulatorSaveFlash128K, "EmulatorSaveFlash128K") //EVT_HANDLER(EmulatorSaveDetectNow, "EmulatorSaveDetectNow") //EVT_HANDLER(EmulatorRTC, "EmulatorRTC") //DisplayConfigure //EVT_HANDLER(EmulatorShowSpeedNone, "EmulatorShowSpeedNone") //EVT_HANDLER(EmulatorShowSpeedPercentage, "EmulatorShowSpeedPercentage") //EVT_HANDLER(EmulatorShowSpeedDetailed, "EmulatorShowSpeedDetailed") //EVT_HANDLER(EmulatorShowSpeedTransparent, "EmulatorShowSpeedTransparent") //EVT_HANDLER(VideoX1, "VideoX1") //EVT_HANDLER(VideoX2, "VideoX2") //EVT_HANDLER(VideoX3, "VideoX3") //EVT_HANDLER(VideoX4, "VideoX4") //EVT_HANDLER(VideoX5, "VideoX5") //EVT_HANDLER(VideoX6, "VideoX6") //EVT_HANDLER(Video320x240, "Video320x240") //EVT_HANDLER(Video640x480, "Video640x480") //EVT_HANDLER(Video800x600, "Video800x600") //EVT_HANDLER(VideoFullscreen, "VideoFullscreen") //EVT_HANDLER(VideoFullscreenMaxScale, "VideoFullscreenMaxScale") //EVT_HANDLER(VideoRenderDDRAW, "VideoRenderDDRAW") //EVT_HANDLER(VideoRenderD3D, "VideoRenderD3D") //EVT_HANDLER(VideoRenderOGL, "VideoRenderOGL") //EVT_HANDLER(VideoVsync, "VideoVsync") //EVT_HANDLER(FilterNormal, "FilterNormal") //EVT_HANDLER(FilterTVMode, "FilterTVMode") //EVT_HANDLER(Filter2xSaI, "Filter2xSaI") //EVT_HANDLER(FilterSuper2xSaI, "FilterSuper2xSaI") //EVT_HANDLER(FilterSuperEagle, "FilterSuperEagle") //EVT_HANDLER(FilterPixelate, "FilterPixelate") //EVT_HANDLER(FilterMotionBlur, "FilterMotionBlur") //EVT_HANDLER(FilterAdMameScale2x, "FilterAdMameScale2x") //EVT_HANDLER(FilterSimple2x, "FilterSimple2x") //EVT_HANDLER(FilterBilinear, "FilterBilinear") //EVT_HANDLER(FilterBilinearPlus, "FilterBilinearPlus") //EVT_HANDLER(FilterScanlines, "FilterScanlines") //EVT_HANDLER(FilterHq2x, "FilterHq2x") //EVT_HANDLER(FilterLq2x, "FilterLq2x") //EVT_HANDLER(FilterIFBNone, "FilterIFBNone") //EVT_HANDLER(FilterIFBMotionBlur, "FilterIFBMotionBlur") //EVT_HANDLER(FilterIFBSmart, "FilterIFBSmart") //EVT_HANDLER(FilterDisableMMX, "FilterDisableMMX") //JoypadConfigure //EVT_HANDLER(JoypadConfigure1, "JoypadConfigure1") //EVT_HANDLER(JoypadConfigure2, "JoypadConfigure2") //EVT_HANDLER(JoypadConfigure3, "JoypadConfigure3") //EVT_HANDLER(JoypadConfigure4, "JoypadConfigure4") //EVT_HANDLER(JoypadMotionConfigure, "JoypadMotionConfigure") // The following functionality has been removed // It should be done in OS, rather than in vbam //EVT_HANDLER(EmulatorAssociate, "EmulatorAssociate") // The following functionality has been removed // It should be done at OS level (e.g. window manager) //EVT_HANDLER(SystemMinimize, "SystemMinimize")