From a455cce2d7e4ffcfda46cb60a3f56fc829f03552 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Fri, 27 May 2022 01:28:38 +1000 Subject: [PATCH] Add UI for editing any core's settings/syncsettings without it loaded --- src/BizHawk.Client.Common/config/Config.cs | 2 + .../MainForm.Designer.cs | 2 +- src/BizHawk.Client.EmuHawk/MainForm.Events.cs | 403 ++++++++++++++++++ src/BizHawk.Client.EmuHawk/MainForm.cs | 47 +- .../config/GenericCoreConfig.cs | 10 + .../config/SerializationStabilityTests.cs | 1 + 6 files changed, 461 insertions(+), 4 deletions(-) diff --git a/src/BizHawk.Client.Common/config/Config.cs b/src/BizHawk.Client.Common/config/Config.cs index 6b333d3cea..50f5715f0f 100644 --- a/src/BizHawk.Client.Common/config/Config.cs +++ b/src/BizHawk.Client.Common/config/Config.cs @@ -353,5 +353,7 @@ namespace BizHawk.Client.Common /// in seconds public int OSDMessageDuration { get; set; } = 2; + + public Queue RecentCores { get; set; } = new(); } } diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs index a704c23c1c..1b9b766cf9 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -1317,7 +1317,7 @@ namespace BizHawk.Client.EmuHawk // // CoresSubMenu // - this.CoresSubMenu.Text = "Cores"; + this.CoresSubMenu.Text = "Preferred Cores"; // // SaveConfigMenuItem // diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs index 2b1a1857ca..d69216d24a 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -13,25 +13,56 @@ using BizHawk.Client.EmuHawk.CustomControls; using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Common; using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores; +using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Emulation.Cores.Atari.A7800Hawk; +using BizHawk.Emulation.Cores.Atari.Atari2600; +using BizHawk.Emulation.Cores.Atari.Lynx; using BizHawk.Emulation.Cores.Calculators.Emu83; using BizHawk.Emulation.Cores.Calculators.TI83; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Computers.AmstradCPC; using BizHawk.Emulation.Cores.Computers.AppleII; using BizHawk.Emulation.Cores.Computers.Commodore64; +using BizHawk.Emulation.Cores.Computers.MSX; using BizHawk.Emulation.Cores.Computers.SinclairSpectrum; +using BizHawk.Emulation.Cores.Consoles.Belogic; +using BizHawk.Emulation.Cores.Consoles.ChannelF; +using BizHawk.Emulation.Cores.Consoles.NEC.PCE; +using BizHawk.Emulation.Cores.Consoles.NEC.PCFX; +using BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64; +using BizHawk.Emulation.Cores.Consoles.Nintendo.Faust; +using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; +using BizHawk.Emulation.Cores.Consoles.Nintendo.VB; +using BizHawk.Emulation.Cores.Consoles.O2Hawk; +using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; +using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive; +using BizHawk.Emulation.Cores.Consoles.Sega.Saturn; +using BizHawk.Emulation.Cores.Consoles.SNK; +using BizHawk.Emulation.Cores.Consoles.Vectrex; using BizHawk.Emulation.Cores.Intellivision; +using BizHawk.Emulation.Cores.Libretro; using BizHawk.Emulation.Cores.Nintendo.BSNES; using BizHawk.Emulation.Cores.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.GBA; using BizHawk.Emulation.Cores.Nintendo.GBHawk; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x; using BizHawk.Emulation.Cores.Nintendo.N64; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.Sameboy; using BizHawk.Emulation.Cores.Nintendo.SNES; +using BizHawk.Emulation.Cores.Nintendo.SNES9X; +using BizHawk.Emulation.Cores.Nintendo.SubGBHawk; using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; +using BizHawk.Emulation.Cores.PCEngine; +using BizHawk.Emulation.Cores.Sega.GGHawkLink; +using BizHawk.Emulation.Cores.Sega.MasterSystem; +using BizHawk.Emulation.Cores.Sony.PS2; using BizHawk.Emulation.Cores.Sony.PSX; +using BizHawk.Emulation.Cores.WonderSwan; using BizHawk.WinForms.Controls; namespace BizHawk.Client.EmuHawk @@ -1854,6 +1885,10 @@ namespace BizHawk.Client.EmuHawk }; } + private void OpenGenericCoreConfigFor(string title) + where T : IEmulator + => GenericCoreConfig.DoDialogFor(this, GetSettingsAdapterFor(), title, isMovieActive: MovieSession.Movie.IsActive()); + private DialogResult OpenGenericCoreConfig(string title) => GenericCoreConfig.DoDialog(Emulator, this, title, isMovieActive: MovieSession.Movie.IsActive()); @@ -2674,5 +2709,373 @@ namespace BizHawk.Client.EmuHawk private void FormDragDrop(object sender, DragEventArgs e) => PathsFromDragDrop = (string[]) e.Data.GetData(DataFormats.FileDrop); + + private enum VSystemCategory : int + { + Consoles = 0, + Handhelds = 1, + PCs = 2, + Other = 3, + } + + private IReadOnlyCollection CreateCoreSettingsSubmenus(bool includeDupes = false) + { + static ToolStripMenuItemEx CreateSettingsItem(string text, EventHandler onClick) + { + ToolStripMenuItemEx menuItem = new() { Text = text }; + menuItem.Click += onClick; + return menuItem; + } + ToolStripMenuItemEx CreateGenericCoreConfigItem(string coreName) + where T : IEmulator + => CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfigFor($"{coreName} Settings")); + ToolStripMenuItemEx CreateCoreSubmenu(VSystemCategory cat, string coreName, params ToolStripItem[] items) + { + ToolStripMenuItemEx submenu = new() { Tag = cat, Text = coreName }; + submenu.DropDownItems.AddRange(items); + return submenu; + } + + List items = new(); + + // A7800Hawk + var a7800HawkGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenA7800HawkGamepadSettingsDialog(GetSettingsAdapterFor())); + var a7800HawkFilterSettingsItem = CreateSettingsItem("Filter Settings...", (_, _) => OpenA7800HawkFilterSettingsDialog(GetSettingsAdapterFor())); + var a7800HawkSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.A7800Hawk, a7800HawkGamepadSettingsItem, a7800HawkFilterSettingsItem); + a7800HawkSubmenu.DropDownOpened += (_, _) => + { + var isMovieActive = MovieSession.Movie.IsActive(); + var loadedCoreIsA7800Hawk = Emulator is A7800Hawk; + a7800HawkGamepadSettingsItem.Enabled = !isMovieActive || !loadedCoreIsA7800Hawk; + a7800HawkFilterSettingsItem.Enabled = !isMovieActive || !loadedCoreIsA7800Hawk; + }; + items.Add(a7800HawkSubmenu); + + // Ares64 + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Ares64, CreateGenericCoreConfigItem(CoreNames.Ares64))); + + // Atari2600Hawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Atari2600Hawk, CreateGenericCoreConfigItem(CoreNames.Atari2600Hawk))); + + // BSNES + var bsnesGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenOldBSNESGamepadSettingsDialog(GetSettingsAdapterFor())); + var bsnesSettingsItem = CreateSettingsItem("Options...", SnesOptionsMenuItem_Click); + var bsnesSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Bsnes, bsnesGamepadSettingsItem, bsnesSettingsItem); + bsnesSubmenu.DropDownOpened += (_, _) => + { + var loadedCoreIsBSNES = Emulator is LibsnesCore; + bsnesGamepadSettingsItem.Enabled = !loadedCoreIsBSNES || MovieSession.Movie.NotActive(); + bsnesSettingsItem.Enabled = loadedCoreIsBSNES; + }; + items.Add(bsnesSubmenu); + + // BSNESv115+ + var oldBSNESGamepadSettingsItem = CreateSettingsItem("Controller Configuration...", (_, _) => OpenBSNESGamepadSettingsDialog(GetSettingsAdapterFor())); + var oldBSNESSettingsItem = CreateSettingsItem("Options...", SnesOptionsMenuItem_Click); + var oldBSNESSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Bsnes115, oldBSNESGamepadSettingsItem, oldBSNESSettingsItem); + oldBSNESSubmenu.DropDownOpened += (_, _) => + { + var loadedCoreIsBSNES = Emulator is BsnesCore; + oldBSNESGamepadSettingsItem.Enabled = !loadedCoreIsBSNES || MovieSession.Movie.NotActive(); + oldBSNESSettingsItem.Enabled = loadedCoreIsBSNES; + }; + items.Add(oldBSNESSubmenu); + + // C64Hawk + items.Add(CreateCoreSubmenu(VSystemCategory.PCs, CoreNames.C64Hawk, CreateSettingsItem("Settings...", (_, _) => OpenC64HawkSettingsDialog()))); + + // ChannelFHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.ChannelFHawk, CreateGenericCoreConfigItem(CoreNames.ChannelFHawk))); + + // ColecoHawk + var colecoHawkGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenColecoHawkGamepadSettingsDialog(GetSettingsAdapterFor())); + var colecoHawkSkipBIOSItem = CreateSettingsItem("Skip BIOS intro (When Applicable)", (sender, _) => ColecoHawkSetSkipBIOSIntro(!((ToolStripMenuItem) sender).Checked, GetSettingsAdapterForLoadedCore())); + var colecoHawkUseSGMItem = CreateSettingsItem("Use the Super Game Module", (sender, _) => ColecoHawkSetSuperGameModule(!((ToolStripMenuItem)sender).Checked, GetSettingsAdapterForLoadedCore())); + var colecoHawkSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.ColecoHawk, colecoHawkGamepadSettingsItem, colecoHawkSkipBIOSItem, colecoHawkUseSGMItem); + colecoHawkSubmenu.DropDownOpened += (_, _) => + { + var ss = (ColecoVision.ColecoSyncSettings) GetSettingsAdapterFor().GetSyncSettings(); + colecoHawkGamepadSettingsItem.Enabled = MovieSession.Movie.NotActive() || Emulator is not ColecoVision; + colecoHawkSkipBIOSItem.Checked = ss.SkipBiosIntro; + colecoHawkUseSGMItem.Checked = ss.UseSGM; + }; + items.Add(colecoHawkSubmenu); + + // CPCHawk + items.Add(CreateCoreSubmenu( + VSystemCategory.PCs, + CoreNames.CPCHawk, + CreateSettingsItem("Core Emulation Settings...", (_, _) => OpenCPCHawkSyncSettingsDialog(GetSettingsAdapterFor())), + CreateSettingsItem("Audio Settings...", (_, _) => OpenCPCHawkAudioSettingsDialog(GetSettingsAdapterFor())), + CreateSettingsItem("Non-Sync Settings...", (_, _) => OpenCPCHawkSettingsDialog(GetSettingsAdapterFor())))); + + // Cygne + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.Cygne, CreateGenericCoreConfigItem(CoreNames.Cygne))); + + // DobieStation + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.DobieStation, CreateGenericCoreConfigItem(CoreNames.DobieStation))); + + // Emu83 + items.Add(CreateCoreSubmenu(VSystemCategory.Other, CoreNames.Emu83, CreateSettingsItem("Palette...", (_, _) => OpenTI83PaletteSettingsDialog(GetSettingsAdapterFor())))); + + // Faust + var faustSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.Faust} Settings")); + var faustSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Faust, faustSettingsItem); + faustSubmenu.DropDownOpened += (_, _) => faustSettingsItem.Enabled = Emulator is Faust; + items.Add(faustSubmenu); + + // Gambatte + var gambatteSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGambatteSettingsDialog(GetSettingsAdapterForLoadedCore(), (Gameboy) Emulator)); + var gambatteSubmenu = CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.Gambatte, gambatteSettingsItem); + gambatteSubmenu.DropDownOpened += (_, _) => gambatteSettingsItem.Enabled = Emulator is Gameboy; + items.Add(gambatteSubmenu); + if (includeDupes) + { + var gambatteSettingsItem1 = CreateSettingsItem("Settings...", (_, _) => OpenGambatteSettingsDialog(GetSettingsAdapterForLoadedCore(), (Gameboy) Emulator)); + var gambatteSubmenu1 = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Gambatte, gambatteSettingsItem1); + gambatteSubmenu1.DropDownOpened += (_, _) => gambatteSettingsItem1.Enabled = Emulator is Gameboy; + items.Add(gambatteSubmenu1); + } + + // GambatteLink + var gambatteLinkSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGambatteLinkSettingsDialog(GetSettingsAdapterForLoadedCore(), (GambatteLink) Emulator)); + var gambatteLinkSubmenu = CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GambatteLink, gambatteLinkSettingsItem); + gambatteLinkSubmenu.DropDownOpened += (_, _) => gambatteLinkSettingsItem.Enabled = Emulator is GambatteLink; + items.Add(gambatteLinkSubmenu); + + // GBHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GbHawk, CreateSettingsItem("Settings...", (_, _) => OpenGBHawkSettingsDialog()))); + + // GBHawkLink + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GBHawkLink, CreateGenericCoreConfigItem(CoreNames.GBHawkLink))); + + // GBHawkLink3x + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GBHawkLink3x, CreateGenericCoreConfigItem(CoreNames.GBHawkLink3x))); + + // GBHawkLink4x + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GBHawkLink4x, CreateGenericCoreConfigItem(CoreNames.GBHawkLink4x))); + + // GGHawkLink + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.GGHawkLink, CreateGenericCoreConfigItem(CoreNames.GGHawkLink))); + + // Genplus-gx + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Gpgx, CreateGenericCoreConfigItem(CoreNames.Gpgx))); + + // Handy + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.Handy, CreateGenericCoreConfigItem(CoreNames.Handy))); + + // HyperNyma + var hyperNymaSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.HyperNyma} Settings")); + var hyperNymaSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.HyperNyma, hyperNymaSettingsItem); + hyperNymaSubmenu.DropDownOpened += (_, _) => hyperNymaSettingsItem.Enabled = Emulator is HyperNyma; + items.Add(hyperNymaSubmenu); + + // IntelliHawk + var intelliHawkGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenIntelliHawkGamepadSettingsDialog(GetSettingsAdapterFor())); + var intelliHawkSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.IntelliHawk, intelliHawkGamepadSettingsItem); + intelliHawkSubmenu.DropDownOpened += (_, _) => intelliHawkGamepadSettingsItem.Enabled = MovieSession.Movie.NotActive() || Emulator is not Intellivision; + items.Add(intelliHawkSubmenu); + + // Libretro + items.Add(CreateCoreSubmenu( + VSystemCategory.Other, + CoreNames.Libretro, + CreateGenericCoreConfigItem(CoreNames.Libretro))); // as Libretro doesn't implement `IStatable<,>`, this opens an empty `GenericCoreConfig`, which is dumb, but matches the existing behaviour + + // MAME + // just guessing here --yoshi + var mameSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.MAME} Settings")); + var mameSubmenu = CreateCoreSubmenu(VSystemCategory.Other, CoreNames.MAME, mameSettingsItem); + mameSubmenu.DropDownOpened += (_, _) => mameSettingsItem.Enabled = Emulator is MAME; + items.Add(mameSubmenu); + + // melonDS + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.MelonDS, CreateGenericCoreConfigItem(CoreNames.MelonDS))); + + // mGBA + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.Mgba, CreateGenericCoreConfigItem(CoreNames.Mgba))); + + // MSXHawk + items.Add(CreateCoreSubmenu(VSystemCategory.PCs, CoreNames.MSXHawk, CreateGenericCoreConfigItem(CoreNames.MSXHawk))); + + // Mupen64Plus + var mupen64PlusGraphicsSettingsItem = CreateSettingsItem("Video Plugins...", N64PluginSettingsMenuItem_Click); + var mupen64PlusGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenMupen64PlusGamepadSettingsDialog(GetSettingsAdapterFor())); + var mupen64PlusAnalogConstraintItem = CreateSettingsItem("Circular Analog Range", N64CircularAnalogRangeMenuItem_Click); + var mupen64PlusNonVILagFramesItem = CreateSettingsItem("Non-VI Lag Frames", (sender, _) => Mupen64PlusSetNonVILagFrames(!((ToolStripMenuItem) sender).Checked, GetSettingsAdapterFor())); + var mupen64PlusUseExpansionSlotItem = CreateSettingsItem("Use Expansion Slot", (sender, _) => Mupen64PlusSetUseExpansionSlot(!((ToolStripMenuItem) sender).Checked, GetSettingsAdapterFor())); + var mupen64PlusSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Mupen64Plus, mupen64PlusGraphicsSettingsItem, mupen64PlusGamepadSettingsItem, mupen64PlusAnalogConstraintItem, mupen64PlusNonVILagFramesItem, mupen64PlusUseExpansionSlotItem); + mupen64PlusSubmenu.DropDownOpened += (_, _) => + { + var settable = GetSettingsAdapterFor(); + var s = (N64Settings) settable.GetSettings(); + var isMovieActive = MovieSession.Movie.IsActive(); + var mupen64Plus = Emulator as N64; + var loadedCoreIsMupen64Plus = mupen64Plus is not null; + mupen64PlusGraphicsSettingsItem.Enabled = !loadedCoreIsMupen64Plus || !isMovieActive; + mupen64PlusGamepadSettingsItem.Enabled = !loadedCoreIsMupen64Plus || !isMovieActive; + mupen64PlusAnalogConstraintItem.Checked = Config.N64UseCircularAnalogConstraint; + mupen64PlusNonVILagFramesItem.Checked = s.UseMupenStyleLag; + if (loadedCoreIsMupen64Plus) + { + mupen64PlusUseExpansionSlotItem.Checked = mupen64Plus.UsingExpansionSlot; + mupen64PlusUseExpansionSlotItem.Enabled = !mupen64Plus.IsOverridingUserExpansionSlotSetting; + } + else + { + mupen64PlusUseExpansionSlotItem.Checked = !((N64SyncSettings) settable.GetSyncSettings()).DisableExpansionSlot; + mupen64PlusUseExpansionSlotItem.Enabled = true; + } + }; + items.Add(mupen64PlusSubmenu); + + // NeoPop + var neoPopSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.NeoPop} Settings")); + var neoPopSubmenu = CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.NeoPop, neoPopSettingsItem); + neoPopSubmenu.DropDownOpened += (_, _) => neoPopSettingsItem.Enabled = Emulator is NeoGeoPort; + items.Add(neoPopSubmenu); + + // NesHawk + var nesHawkGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenNesHawkGamepadSettingsDialog(GetSettingsAdapterFor())); + var nesHawkVSSettingsItem = CreateSettingsItem("VS Settings...", (_, _) => OpenNesHawkVSSettingsDialog(GetSettingsAdapterFor())); + var nesHawkAdvancedSettingsItem = CreateSettingsItem("Advanced Settings...", MovieSettingsMenuItem_Click); + var nesHawkSubmenu = CreateCoreSubmenu( + VSystemCategory.Consoles, + CoreNames.NesHawk, + nesHawkGamepadSettingsItem, + CreateSettingsItem("Graphics Settings...", (_, _) => OpenNesHawkGraphicsSettingsDialog(GetSettingsAdapterFor())), + nesHawkVSSettingsItem, + nesHawkAdvancedSettingsItem); + nesHawkSubmenu.DropDownOpened += (_, _) => + { + var isMovieActive = MovieSession.Movie.IsActive(); + var nesHawk = Emulator as NES; + var loadedCoreIsNesHawk = nesHawk is not null; + nesHawkGamepadSettingsItem.Enabled = !isMovieActive && Tools.IsAvailable(); + nesHawkVSSettingsItem.Enabled = nesHawk?.IsVS is true; + nesHawkAdvancedSettingsItem.Enabled = loadedCoreIsNesHawk && !isMovieActive; + }; + items.Add(nesHawkSubmenu); + + // Nymashock + var nymashockSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.Nymashock} Settings")); + var nymashockSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Nymashock, nymashockSettingsItem); + nymashockSubmenu.DropDownOpened += (_, _) => nymashockSettingsItem.Enabled = Emulator is Nymashock; + items.Add(nymashockSubmenu); + + // O2Hawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.O2Hawk, CreateGenericCoreConfigItem(CoreNames.O2Hawk))); + + // Octoshock + var octoshockGamepadSettingsItem = CreateSettingsItem("Controller / Memcard Settings...", (_, _) => OpenOctoshockGamepadSettingsDialog(GetSettingsAdapterFor())); + var octoshockSettingsItem = CreateSettingsItem("Options...", PsxOptionsMenuItem_Click); + var octoshockSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Octoshock, octoshockGamepadSettingsItem, octoshockSettingsItem); + octoshockSubmenu.DropDownOpened += (_, _) => + { + var loadedCoreIsOctoshock = Emulator is Octoshock; + octoshockGamepadSettingsItem.Enabled = !loadedCoreIsOctoshock || MovieSession.Movie.NotActive(); + octoshockSettingsItem.Enabled = loadedCoreIsOctoshock; + }; + items.Add(octoshockSubmenu); + + // PCEHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.PceHawk, CreateGenericCoreConfigItem(CoreNames.PceHawk))); + + // PicoDrive + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.PicoDrive, CreateGenericCoreConfigItem(CoreNames.PicoDrive))); + + // QuickNes + var quickNesGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenQuickNesGamepadSettingsDialog()); + var quickNesSubmenu = CreateCoreSubmenu( + VSystemCategory.Consoles, + CoreNames.QuickNes, + quickNesGamepadSettingsItem, + CreateSettingsItem("Graphics Settings...", (_, _) => OpenQuickNesGraphicsSettingsDialog(GetSettingsAdapterFor()))); + quickNesSubmenu.DropDownOpened += (_, _) => quickNesGamepadSettingsItem.Enabled = !MovieSession.Movie.IsActive() && Emulator is QuickNES && Tools.IsAvailable(); + items.Add(quickNesSubmenu); + + // SameBoy + items.Add(CreateCoreSubmenu( + VSystemCategory.Handhelds, + CoreNames.Sameboy, + CreateSettingsItem("Settings...", (_, _) => OpenSameBoySettingsDialog()), + CreateSettingsItem("Choose Custom Palette...", (_, _) => OpenSameBoyPaletteSettingsDialog(GetSettingsAdapterFor())))); + + // Saturnus + var saturnusSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.Saturnus} Settings")); + var saturnusSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Saturnus, saturnusSettingsItem); + saturnusSubmenu.DropDownOpened += (_, _) => saturnusSettingsItem.Enabled = Emulator is Saturnus; + items.Add(saturnusSubmenu); + + // SMSHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.SMSHawk, CreateGenericCoreConfigItem(CoreNames.SMSHawk))); + if (includeDupes) items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.SMSHawk, CreateGenericCoreConfigItem(CoreNames.SMSHawk))); + + // Snes9x + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Snes9X, CreateGenericCoreConfigItem(CoreNames.Snes9X))); + + // SubGBHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Handhelds, CoreNames.SubGbHawk, CreateGenericCoreConfigItem(CoreNames.SubGbHawk))); + + // SubNESHawk + var subNESHawkGamepadSettingsItem = CreateSettingsItem("Controller Settings...", (_, _) => OpenNesHawkGamepadSettingsDialog(GetSettingsAdapterFor())); + var subNESHawkVSSettingsItem = CreateSettingsItem("VS Settings...", (_, _) => OpenNesHawkVSSettingsDialog(GetSettingsAdapterFor())); + var subNESHawkAdvancedSettingsItem = CreateSettingsItem("Advanced Settings...", MovieSettingsMenuItem_Click); + var subNESHawkSubmenu = CreateCoreSubmenu( + VSystemCategory.Consoles, + CoreNames.SubNesHawk, + subNESHawkGamepadSettingsItem, + CreateSettingsItem("Graphics Settings...", (_, _) => OpenNesHawkGraphicsSettingsDialog(GetSettingsAdapterFor())), + subNESHawkVSSettingsItem, + subNESHawkAdvancedSettingsItem); + subNESHawkSubmenu.DropDownOpened += (_, _) => + { + var isMovieActive = MovieSession.Movie.IsActive(); + var subNESHawk = Emulator as SubNESHawk; + var loadedCoreIsSubNESHawk = subNESHawk is not null; + subNESHawkGamepadSettingsItem.Enabled = !isMovieActive && Tools.IsAvailable(); + subNESHawkVSSettingsItem.Enabled = subNESHawk?.IsVs is true; + subNESHawkAdvancedSettingsItem.Enabled = loadedCoreIsSubNESHawk && !isMovieActive; + }; + items.Add(subNESHawkSubmenu); + + // TI83Hawk + items.Add(CreateCoreSubmenu(VSystemCategory.Other, CoreNames.TI83Hawk, CreateSettingsItem("Palette...", (_, _) => OpenTI83PaletteSettingsDialog(GetSettingsAdapterFor())))); + + // T. S. T. + var tstSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.TST} Settings")); + var tstSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.TST, tstSettingsItem); + tstSubmenu.DropDownOpened += (_, _) => tstSettingsItem.Enabled = Emulator is Tst; + items.Add(tstSubmenu); + + // TurboNyma + var turboNymaSettingsItem = CreateSettingsItem("Settings...", (_, _) => OpenGenericCoreConfig($"{CoreNames.TurboNyma} Settings")); + var turboNymaSubmenu = CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.TurboNyma, turboNymaSettingsItem); + turboNymaSubmenu.DropDownOpened += (_, _) => turboNymaSettingsItem.Enabled = Emulator is TurboNyma; + items.Add(turboNymaSubmenu); + + // uzem + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Uzem, CreateGenericCoreConfigItem(CoreNames.Uzem))); + + // VectrexHawk + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.VectrexHawk, CreateGenericCoreConfigItem(CoreNames.VectrexHawk))); + + // Virtu + items.Add(CreateCoreSubmenu(VSystemCategory.PCs, CoreNames.Virtu, CreateSettingsItem("Settings...", (_, _) => OpenVirtuSettingsDialog()))); + + // Virtual Boyee + items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.VirtualBoyee, CreateGenericCoreConfigItem(CoreNames.VirtualBoyee))); + + // ZXHawk + items.Add(CreateCoreSubmenu( + VSystemCategory.PCs, + CoreNames.ZXHawk, + CreateSettingsItem("Core Emulation Settings...", (_, _) => OpenZXHawkSyncSettingsDialog(GetSettingsAdapterFor())), + CreateSettingsItem("Joystick Configuration...", (_, _) => OpenZXHawkGamepadSettingsDialog(GetSettingsAdapterFor())), + CreateSettingsItem("Audio Settings...", (_, _) => OpenZXHawkAudioSettingsDialog(GetSettingsAdapterFor())), + CreateSettingsItem("Non-Sync Settings...", (_, _) => OpenZXHawkSettingsDialog(GetSettingsAdapterFor())))); + + return items; + } } } diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 1e12ab4271..8a57fcd85c 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -42,6 +42,7 @@ using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Client.EmuHawk.CoreExtensions; using BizHawk.Client.EmuHawk.CustomControls; using BizHawk.Common.CollectionExtensions; +using BizHawk.WinForms.Controls; namespace BizHawk.Client.EmuHawk { @@ -80,18 +81,56 @@ namespace BizHawk.Client.EmuHawk Config.GbAsSgb ^= true; if (!Emulator.IsNull()) FlagNeedsReboot(); //TODO only alert if a GB or SGB core is loaded }; - var N64VideoPluginSettingsMenuItem = new ToolStripMenuItem { Image = Properties.Resources.Monitor, Text = "N64 Video Plugin Settings..." }; - N64VideoPluginSettingsMenuItem.Click += N64PluginSettingsMenuItem_Click; var setLibretroCoreToolStripMenuItem = new ToolStripMenuItem { Text = "Set Libretro Core..." }; setLibretroCoreToolStripMenuItem.Click += (clickSender, clickArgs) => RunLibretroCoreChooser(); CoresSubMenu.DropDownItems.AddRange(new ToolStripItem[] { GBInSGBMenuItem, new ToolStripSeparator { AutoSize = true }, - N64VideoPluginSettingsMenuItem, setLibretroCoreToolStripMenuItem }); CoresSubMenu.DropDownOpened += (openedSender, openedArgs) => GBInSGBMenuItem.Checked = Config.GbAsSgb; + ToolStripMenuItemEx recentCoreSettingsSubmenu = new() { Text = "Recent" }; + recentCoreSettingsSubmenu.DropDownItems.AddRange(CreateCoreSettingsSubmenus().Where(submenu => Config.RecentCores.Contains(submenu.Text)).ToArray()); + ToolStripMenuItemEx consolesCoreSettingsSubmenu = new() { Text = "For Consoles" }; + ToolStripMenuItemEx handheldsCoreSettingsSubmenu = new() { Text = "For Handhelds" }; + ToolStripMenuItemEx pcsCoreSettingsSubmenu = new() { Text = "For PCs" }; + ToolStripMenuItemEx otherCoreSettingsSubmenu = new() { Text = "Other" }; + foreach (var submenu in CreateCoreSettingsSubmenus(includeDupes: true)) + { + var parentMenu = (VSystemCategory) submenu.Tag switch + { + VSystemCategory.Consoles => consolesCoreSettingsSubmenu, + VSystemCategory.Handhelds => handheldsCoreSettingsSubmenu, + VSystemCategory.PCs => pcsCoreSettingsSubmenu, + _ => otherCoreSettingsSubmenu + }; + parentMenu.DropDownItems.Add(submenu); + } + foreach (var submenu in new[] { recentCoreSettingsSubmenu, consolesCoreSettingsSubmenu, handheldsCoreSettingsSubmenu, pcsCoreSettingsSubmenu, otherCoreSettingsSubmenu }) + { + if (submenu.DropDownItems.Count is 0) + { + submenu.DropDownItems.Add(new ToolStripMenuItemEx()); + submenu.Enabled = false; + } + } + ConfigSubMenu.DropDownItems.Insert( + ConfigSubMenu.DropDownItems.IndexOf(CoresSubMenu) + 1, + new ToolStripMenuItemEx + { + DropDownItems = + { + recentCoreSettingsSubmenu, + new ToolStripSeparatorEx { AutoSize = true }, + consolesCoreSettingsSubmenu, + handheldsCoreSettingsSubmenu, + pcsCoreSettingsSubmenu, + otherCoreSettingsSubmenu, + }, + Text = "Core Settings", + }); + // Hide Status bar icons and general StatusBar prep MainStatusBar.Padding = new Padding(MainStatusBar.Padding.Left, MainStatusBar.Padding.Top, MainStatusBar.Padding.Left, MainStatusBar.Padding.Bottom); // Workaround to remove extra padding on right PlayRecordStatusButton.Visible = false; @@ -3798,6 +3837,8 @@ namespace BizHawk.Client.EmuHawk string openAdvancedArgs = $"*{OpenAdvancedSerializer.Serialize(ioa)}"; Emulator.Dispose(); Emulator = loader.LoadedEmulator; + Config.RecentCores.Enqueue(Emulator.Attributes().CoreName); + while (Config.RecentCores.Count > 5) Config.RecentCores.Dequeue(); InputManager.SyncControls(Emulator, MovieSession, Config); if (oaOpenrom != null && Path.GetExtension(oaOpenrom.Path.Replace("|", "")).ToLowerInvariant() == ".xml" && !(Emulator is LibsnesCore)) diff --git a/src/BizHawk.Client.EmuHawk/config/GenericCoreConfig.cs b/src/BizHawk.Client.EmuHawk/config/GenericCoreConfig.cs index 7104b57525..a98ff02f12 100644 --- a/src/BizHawk.Client.EmuHawk/config/GenericCoreConfig.cs +++ b/src/BizHawk.Client.EmuHawk/config/GenericCoreConfig.cs @@ -127,6 +127,16 @@ namespace BizHawk.Client.EmuHawk return owner.ShowDialogAsChild(dlg); } + public static void DoDialogFor( + IDialogParent owner, + ISettingsAdapter settable, + string title, + bool isMovieActive) + { + using GenericCoreConfig dlg = new(settable, isMovieActive) { Text = title }; + owner.ShowDialogAsChild(dlg); + } + private void PropertyGrid2_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { _syncSettingsChanged = true; diff --git a/src/BizHawk.Tests/Client.Common/config/SerializationStabilityTests.cs b/src/BizHawk.Tests/Client.Common/config/SerializationStabilityTests.cs index 75dc95e026..18b50e4260 100644 --- a/src/BizHawk.Tests/Client.Common/config/SerializationStabilityTests.cs +++ b/src/BizHawk.Tests/Client.Common/config/SerializationStabilityTests.cs @@ -34,6 +34,7 @@ namespace BizHawk.Tests.Client.Common.config typeof(List<>), typeof(Nullable<>), typeof(object), + typeof(Queue<>), typeof(float), typeof(string), };