Mesen2/NewUI/ViewModels/MainMenuViewModel.cs
2022-02-04 21:32:50 -05:00

825 lines
30 KiB
C#

using Avalonia.Controls;
using Mesen.Config;
using Mesen.Config.Shortcuts;
using Mesen.Controls;
using Mesen.Debugger.Utilities;
using Mesen.Debugger.ViewModels;
using Mesen.Debugger.Windows;
using Mesen.Interop;
using Mesen.Localization;
using Mesen.Utilities;
using Mesen.Windows;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Mesen.ViewModels
{
public class MainMenuViewModel : ViewModelBase
{
public MainWindowViewModel MainWindow { get; set; }
[Reactive] public bool IsGameRunning { get; private set; }
[Reactive] public bool IsFdsGame { get; private set; }
[Reactive] public bool IsVsSystemGame { get; private set; }
[Reactive] public bool IsVsDualSystemGame { get; private set; }
[Reactive] public bool IsNesGame { get; private set; }
[Reactive] public bool IsGbGame { get; private set; }
[Reactive] public ObservableCollection<RecentItem> RecentItems { get; private set; }
[Reactive] public bool HasRecentItems { get; private set; }
public ReactiveCommand<RecentItem, Unit> OpenRecentCommand { get; }
[Reactive] public List<object> GameMenuItems { get; set; } = new();
[Reactive] public List<object> OptionsMenuItems { get; set; } = new();
[Reactive] public List<object> ToolsMenuItems { get; set; } = new();
[Reactive] public List<object> DebugMenuItems { get; set; } = new();
[Reactive] public List<object> HelpMenuItems { get; set; } = new();
private ConfigWindow? _cfgWindow = null;
[Obsolete("For designer only")]
public MainMenuViewModel() : this(new MainWindowViewModel()) { }
public MainMenuViewModel(MainWindowViewModel windowModel)
{
MainWindow = windowModel;
OpenRecentCommand = ReactiveCommand.Create<RecentItem>(OpenRecent);
RecentItems = ConfigManager.Config.RecentFiles.Items;
this.WhenAnyValue(x => x.RecentItems.Count).Subscribe(count => {
HasRecentItems = count > 0;
});
this.WhenAnyValue(x => x.MainWindow.RomInfo).Subscribe(x => {
IsGameRunning = x.Format != RomFormat.Unknown;
IsFdsGame = x.Format == RomFormat.Fds;
IsVsSystemGame = x.Format == RomFormat.VsSystem || x.Format == RomFormat.VsDualSystem;
IsVsDualSystemGame = x.Format == RomFormat.VsDualSystem;
IsNesGame = x.ConsoleType == ConsoleType.Nes;
IsGbGame = x.ConsoleType == ConsoleType.GameboyColor || x.ConsoleType == ConsoleType.Gameboy;
});
}
private void OpenRecent(RecentItem recent)
{
//Avalonia bug - Run in another thread to allow menu to close properly
//See: https://github.com/AvaloniaUI/Avalonia/issues/5376
Task.Run(() => {
LoadRomHelper.LoadRom(recent.RomFile, recent.PatchFile);
});
}
private void OpenConfig(MainWindow wnd, ConfigWindowTab tab)
{
if(_cfgWindow == null) {
_cfgWindow = new ConfigWindow(tab);
_cfgWindow.Closed += cfgWindow_Closed;
_cfgWindow.ShowCentered((Control)wnd);
} else {
(_cfgWindow.DataContext as ConfigViewModel)!.SelectTab(tab);
_cfgWindow.Activate();
}
}
private void cfgWindow_Closed(object? sender, EventArgs e)
{
_cfgWindow = null;
if(ConfigManager.Config.Preferences.DisableGameSelectionScreen && MainWindow.RecentGames.Visible) {
MainWindow.RecentGames.Visible = false;
} else if(!ConfigManager.Config.Preferences.DisableGameSelectionScreen && !IsGameRunning) {
MainWindow.RecentGames.Init(GameScreenMode.RecentGames);
}
}
public void Initialize(MainWindow wnd)
{
InitGameMenu(wnd);
InitOptionsMenu(wnd);
InitToolMenu(wnd);
InitDebugMenu(wnd);
InitHelpMenu(wnd);
}
private void InitGameMenu(MainWindow wnd)
{
GameMenuItems = new List<object>() {
new MainMenuAction(EmulatorShortcut.Pause) { ActionType = ActionType.Pause, IsVisible = () => !EmuApi.IsPaused() },
new MainMenuAction(EmulatorShortcut.Pause) { ActionType = ActionType.Resume, IsVisible = () => EmuApi.IsPaused() },
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.Reset) { ActionType = ActionType.Reset },
new MainMenuAction(EmulatorShortcut.PowerCycle) { ActionType = ActionType.PowerCycle },
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.PowerOff) { ActionType = ActionType.PowerOff },
new ContextMenuSeparator() { IsVisible = () => IsFdsGame },
new MainMenuAction() {
ActionType = ActionType.SelectDisk,
IsVisible = () => IsFdsGame,
SubActions = new List<object>() {
GetFdsInsertDiskItem(0),
GetFdsInsertDiskItem(1),
GetFdsInsertDiskItem(2),
GetFdsInsertDiskItem(3),
GetFdsInsertDiskItem(4),
GetFdsInsertDiskItem(5),
GetFdsInsertDiskItem(6),
GetFdsInsertDiskItem(7),
}
},
new MainMenuAction(EmulatorShortcut.FdsEjectDisk) {
ActionType = ActionType.EjectDisk,
IsVisible = () => IsFdsGame,
},
new ContextMenuSeparator() { IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin1) { ActionType = ActionType.InsertCoin1, IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin2) { ActionType = ActionType.InsertCoin2, IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin3) { ActionType = ActionType.InsertCoin3, IsVisible = () => IsVsDualSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin4) { ActionType = ActionType.InsertCoin4, IsVisible = () => IsVsDualSystemGame }
};
}
private MainMenuAction GetFdsInsertDiskItem(int diskSide)
{
return new MainMenuAction(EmulatorShortcut.FdsInsertDiskNumber) {
ActionType = ActionType.Custom,
CustomText = "Disk " + ((diskSide / 2) + 1) + " Side " + ((diskSide % 2 == 0) ? "A" : "B"),
ShortcutParam = (uint)diskSide,
IsVisible = () => EmuApi.IsShortcutAllowed(EmulatorShortcut.FdsInsertDiskNumber, (uint)diskSide)
};
}
private void InitOptionsMenu(MainWindow wnd)
{
OptionsMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.Speed,
SubActions = new List<object> {
GetSpeedMenuItem(ActionType.NormalSpeed, 100),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.IncreaseSpeed) {
ActionType = ActionType.IncreaseSpeed
},
new MainMenuAction(EmulatorShortcut.DecreaseSpeed) {
ActionType = ActionType.DecreaseSpeed
},
GetSpeedMenuItem(ActionType.MaximumSpeed, 0, EmulatorShortcut.MaxSpeed),
new ContextMenuSeparator(),
GetSpeedMenuItem(ActionType.TripleSpeed, 300),
GetSpeedMenuItem(ActionType.DoubleSpeed, 200),
GetSpeedMenuItem(ActionType.HalfSpeed, 50),
GetSpeedMenuItem(ActionType.QuarterSpeed, 25),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.ToggleFps) {
ActionType = ActionType.ShowFps,
IsSelected = () => ConfigManager.Config.Preferences.ShowFps
}
}
},
new MainMenuAction() {
ActionType = ActionType.VideoScale,
SubActions = new List<object>() {
GetScaleMenuItem(1, EmulatorShortcut.SetScale1x),
GetScaleMenuItem(2, EmulatorShortcut.SetScale2x),
GetScaleMenuItem(3, EmulatorShortcut.SetScale3x),
GetScaleMenuItem(4, EmulatorShortcut.SetScale4x),
GetScaleMenuItem(5, EmulatorShortcut.SetScale5x),
GetScaleMenuItem(6, EmulatorShortcut.SetScale6x),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.ToggleFullscreen) {
ActionType = ActionType.Fullscreen
},
}
},
new MainMenuAction() {
ActionType = ActionType.VideoFilter,
SubActions = new List<object>() {
GetVideoFilterMenuItem(VideoFilterType.None),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.NTSC),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.xBRZ2x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ3x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ4x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ5x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ6x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.HQ2x),
GetVideoFilterMenuItem(VideoFilterType.HQ3x),
GetVideoFilterMenuItem(VideoFilterType.HQ4x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.Scale2x),
GetVideoFilterMenuItem(VideoFilterType.Scale3x),
GetVideoFilterMenuItem(VideoFilterType.Scale4x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType._2xSai),
GetVideoFilterMenuItem(VideoFilterType.Super2xSai),
GetVideoFilterMenuItem(VideoFilterType.SuperEagle),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.Prescale2x),
GetVideoFilterMenuItem(VideoFilterType.Prescale3x),
GetVideoFilterMenuItem(VideoFilterType.Prescale4x),
GetVideoFilterMenuItem(VideoFilterType.Prescale6x),
GetVideoFilterMenuItem(VideoFilterType.Prescale8x),
GetVideoFilterMenuItem(VideoFilterType.Prescale10x)
}
},
new MainMenuAction() {
ActionType = ActionType.Region,
IsEnabled = () => IsGameRunning && MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
SubActions = new List<object>() {
GetRegionMenuItem(ConsoleRegion.Auto),
new ContextMenuSeparator(),
GetRegionMenuItem(ConsoleRegion.Ntsc),
GetRegionMenuItem(ConsoleRegion.Pal),
GetRegionMenuItem(ConsoleRegion.Dendy),
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Audio,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Audio)
},
new MainMenuAction() {
ActionType = ActionType.Emulation,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Emulation)
},
new MainMenuAction() {
ActionType = ActionType.Video,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Video)
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Nes,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Nes)
},
new MainMenuAction() {
ActionType = ActionType.Snes,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Snes)
},
new MainMenuAction() {
ActionType = ActionType.Gameboy,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Gameboy)
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Preferences,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Preferences)
}
};
}
private MainMenuAction GetRegionMenuItem(ConsoleRegion region)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetEnumText(region),
IsVisible = () => region switch {
ConsoleRegion.Ntsc => MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
ConsoleRegion.Pal => MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
ConsoleRegion.Dendy => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes,
ConsoleRegion.Auto or _ => true,
},
IsSelected = () => MainWindow.RomInfo.ConsoleType switch {
ConsoleType.Snes => ConfigManager.Config.Snes.Region == region,
ConsoleType.Nes => ConfigManager.Config.Nes.Region == region,
_ => region == ConsoleRegion.Auto
},
OnClick = () => {
switch(MainWindow.RomInfo.ConsoleType) {
case ConsoleType.Snes:
ConfigManager.Config.Snes.Region = region;
ConfigManager.Config.Snes.ApplyConfig();
break;
case ConsoleType.Nes:
ConfigManager.Config.Nes.Region = region;
ConfigManager.Config.Nes.ApplyConfig();
break;
default:
break;
}
}
};
}
private MainMenuAction GetVideoFilterMenuItem(VideoFilterType filter)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetEnumText(filter),
IsSelected = () => ConfigManager.Config.Video.VideoFilter == filter,
OnClick = () => {
ConfigManager.Config.Video.VideoFilter = filter;
ConfigManager.Config.Video.ApplyConfig();
}
};
}
private MainMenuAction GetScaleMenuItem(int scale, EmulatorShortcut shortcut)
{
return new MainMenuAction(shortcut) {
ActionType = ActionType.Custom,
CustomText = scale + "x",
IsSelected = () => (int)((double)MainWindow.RendererSize.Width / EmuApi.GetBaseScreenSize().Width) == scale
};
}
private MainMenuAction GetSpeedMenuItem(ActionType action, int speed, EmulatorShortcut? shortcut = null)
{
MainMenuAction item = new MainMenuAction(shortcut) {
ActionType = action,
IsSelected = () => ConfigManager.Config.Emulation.EmulationSpeed == speed,
};
if(shortcut == null) {
item.OnClick = () => {
ConfigManager.Config.Emulation.EmulationSpeed = (uint)speed;
ConfigManager.Config.Emulation.ApplyConfig();
};
}
return item;
}
private MainMenuAction GetMoviesMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.Movies,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Play,
IsEnabled = () => IsGameRunning && !RecordApi.MovieRecording() && !RecordApi.MoviePlaying(),
OnClick = async () => {
string? filename = await FileDialogHelper.OpenFile(ConfigManager.MovieFolder, wnd, FileDialogHelper.MesenMovieExt);
if(filename != null) {
RecordApi.MoviePlay(filename);
}
}
},
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.MovieRecording() && !RecordApi.MoviePlaying(),
OnClick = () => {
new MovieRecordWindow() {
DataContext = new MovieRecordConfigViewModel()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && (RecordApi.MovieRecording() || RecordApi.MoviePlaying()),
OnClick = async () => {
string? filename = await FileDialogHelper.OpenFile(ConfigManager.MovieFolder, wnd, FileDialogHelper.MesenMovieExt);
if(filename != null) {
RecordApi.MovieStop();
}
}
}
}
};
}
private void InitToolMenu(MainWindow wnd)
{
ToolsMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.Cheats,
IsEnabled = () => IsGameRunning,
OnClick = () => { }
},
new MainMenuAction() {
ActionType = ActionType.HistoryViewer,
IsEnabled = () => IsGameRunning,
OnClick = () => { }
},
GetMoviesMenu(wnd),
GetNetPlayMenu(wnd),
new ContextMenuSeparator(),
GetSoundRecorderMenu(wnd),
GetVideoRecorderMenu(wnd),
new ContextMenuSeparator() {
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes
},
new MainMenuAction() {
ActionType = ActionType.HdPacks,
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.InstallHdPack,
OnClick = () => InstallHdPack(wnd)
},
new MainMenuAction() {
ActionType = ActionType.HdPackBuilder,
IsEnabled = () => false,
OnClick = () => { }
}
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.LogWindow,
OnClick = () => {
LogWindow? logWindow = ApplicationHelper.GetExistingWindow<LogWindow>();
if(logWindow != null) {
logWindow.Activate();
} else {
new LogWindow().ShowCentered((Control)wnd);
}
}
},
new MainMenuAction(EmulatorShortcut.TakeScreenshot) {
ActionType = ActionType.TakeScreenshot,
},
};
}
private MainMenuAction GetVideoRecorderMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.VideoRecorder,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.AviIsRecording(),
OnClick = () => {
new VideoRecordWindow() {
DataContext = new VideoRecordConfigViewModel()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && RecordApi.AviIsRecording(),
OnClick = () => {
RecordApi.AviStop();
}
}
}
};
}
private MainMenuAction GetSoundRecorderMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.SoundRecorder,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.WaveIsRecording(),
OnClick = async () => {
string? filename = await FileDialogHelper.SaveFile(ConfigManager.WaveFolder, EmuApi.GetRomInfo().GetRomName() + ".wav", wnd, FileDialogHelper.WaveExt);
if(filename != null) {
RecordApi.WaveRecord(filename);
}
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && RecordApi.WaveIsRecording(),
OnClick = () => {
RecordApi.WaveStop();
}
}
}
};
}
private MainMenuAction GetNetPlayMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.NetPlay,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Connect,
IsEnabled = () => !NetplayApi.IsConnected() && !NetplayApi.IsServerRunning(),
OnClick = () => {
new NetplayConnectWindow() {
DataContext = ConfigManager.Config.Netplay.Clone()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Disconnect,
IsEnabled = () => NetplayApi.IsConnected(),
OnClick = () => {
NetplayApi.Disconnect();
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.StartServer,
IsEnabled = () => !NetplayApi.IsConnected() && !NetplayApi.IsServerRunning(),
OnClick = () => {
new NetplayStartServerWindow() {
DataContext = ConfigManager.Config.Netplay.Clone()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.StopServer,
IsEnabled = () => NetplayApi.IsServerRunning(),
OnClick = () => {
NetplayApi.StopServer();
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.SelectController,
IsEnabled = () => NetplayApi.IsConnected() || NetplayApi.IsServerRunning(),
SubActions = new List<object> {
GetSelectControllerAction(0),
GetSelectControllerAction(1),
GetSelectControllerAction(2),
GetSelectControllerAction(3),
GetSelectControllerAction(4),
}
}
}
};
}
private MainMenuAction GetSelectControllerAction(int i)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetMessage("Player") + " " + (i + 1) + " (" + ResourceHelper.GetEnumText(ConfigApi.GetControllerType(i)) + ")",
IsSelected = () => i == NetplayApi.NetPlayGetControllerPort(),
IsEnabled = () => (NetplayApi.NetPlayGetAvailableControllers() & (1 << i)) != 0,
OnClick = () => NetplayApi.NetPlaySelectController(i)
};
}
private void InitDebugMenu(Window wnd)
{
DebugMenuItems = new List<object>() {
new ContextMenuAction() {
ActionType = ActionType.OpenDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenDebugger),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(null))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSpcDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSpcDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Spc),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Spc))
},
new ContextMenuAction() {
ActionType = ActionType.OpenCx4Debugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenCx4Debugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Cx4),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Cx4))
},
new ContextMenuAction() {
ActionType = ActionType.OpenNecDspDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenNecDspDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.NecDsp),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.NecDsp))
},
new ContextMenuAction() {
ActionType = ActionType.OpenGsuDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGsuDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gsu),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gsu))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSa1Debugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSa1Debugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Sa1),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Sa1))
},
new ContextMenuAction() {
ActionType = ActionType.OpenGameboyDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGameboyDebugger),
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Snes && MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gameboy),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gameboy))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenEventViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenEventViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new EventViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenMemoryTools,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenMemoryTools),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new MemoryToolsWindow(new MemoryToolsViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenRegisterViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenRegisterViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new RegisterViewerWindow(new RegisterViewerWindowViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenTraceLogger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTraceLogger),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TraceLoggerWindow(new TraceLoggerViewModel()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenTilemapViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTilemapViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TilemapViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenTileViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTileViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TileViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSpriteViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSpriteViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new SpriteViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenPaletteViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenPaletteViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new PaletteViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenAssembler,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenAssembler),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new AssemblerWindow(new AssemblerWindowViewModel(MainWindow.RomInfo.ConsoleType.GetMainCpuType())))
},
new ContextMenuAction() {
ActionType = ActionType.OpenProfiler,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenProfiler),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new ProfilerWindow(new ProfilerWindowViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenScriptWindow,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenScriptWindow),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new ScriptWindow(new ScriptWindowViewModel()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenDebugSettings,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenDebugSettings),
OnClick = () => DebuggerConfigWindow.Open(DebugConfigWindowTab.Debugger, wnd)
}
};
DebugShortcutManager.RegisterActions(wnd, DebugMenuItems);
}
private void InitHelpMenu(Window wnd)
{
HelpMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.OnlineHelp,
OnClick = () => ApplicationHelper.OpenBrowser("https://www.mesen.ca/docs/")
},
new MainMenuAction() {
ActionType = ActionType.CheckForUpdates,
OnClick = () => { }
},
new MainMenuAction() {
ActionType = ActionType.ReportBug,
OnClick = () => { }
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.About,
OnClick = () => {
new AboutWindow().ShowCenteredDialog((Control)wnd);
}
},
};
}
private async void InstallHdPack(Window wnd)
{
string? filename = await FileDialogHelper.OpenFile(null, wnd, FileDialogHelper.ZipExt);
if(filename == null) {
return;
}
try {
using(FileStream stream = File.Open(filename, FileMode.Open)) {
ZipArchive zip = new ZipArchive(stream);
//Find the hires.txt file
ZipArchiveEntry? hiresEntry = null;
foreach(ZipArchiveEntry entry in zip.Entries) {
if(entry.Name == "hires.txt") {
hiresEntry = entry;
break;
}
}
if(hiresEntry == null) {
await MesenMsgBox.Show(wnd, "InstallHdPackInvalidPack", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
using Stream entryStream = hiresEntry.Open();
using StreamReader reader = new StreamReader(entryStream);
string hiresData = reader.ReadToEnd();
RomInfo romInfo = EmuApi.GetRomInfo();
//If there's a "supportedRom" tag, check if it matches the current ROM
Regex supportedRomRegex = new Regex("<supportedRom>([^\\n]*)");
Match match = supportedRomRegex.Match(hiresData);
if(match.Success) {
if(!match.Groups[1].Value.ToUpper().Contains(romInfo.Sha1.ToUpper())) {
await MesenMsgBox.Show(wnd, "InstallHdPackWrongRom", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//Extract HD pack
try {
string targetFolder = Path.Combine(ConfigManager.HdPackFolder, romInfo.GetRomName());
if(Directory.Exists(targetFolder)) {
//Warn if the folder already exists
if(await MesenMsgBox.Show(wnd, "InstallHdPackConfirmOverwrite", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, targetFolder) != DialogResult.OK) {
return;
}
} else {
Directory.CreateDirectory(targetFolder);
}
string hiresFileFolder = hiresEntry.FullName.Substring(0, hiresEntry.FullName.Length - "hires.txt".Length);
foreach(ZipArchiveEntry entry in zip.Entries) {
//Extract only the files in the same subfolder as the hires.txt file (and only if they have a name & size > 0)
if(!string.IsNullOrWhiteSpace(entry.Name) && entry.Length > 0 && entry.FullName.StartsWith(hiresFileFolder)) {
entry.ExtractToFile(Path.Combine(targetFolder, entry.Name), true);
}
}
} catch(Exception ex) {
await MesenMsgBox.Show(wnd, "InstallHdPackError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
return;
}
//Turn on HD Pack support automatically after installation succeeds
if(!ConfigManager.Config.Nes.EnableHdPacks) {
ConfigManager.Config.Nes.EnableHdPacks = true;
ConfigManager.Config.Nes.ApplyConfig();
}
if(await MesenMsgBox.Show(wnd, "InstallHdPackConfirmReset", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) {
//Power cycle game if the user agrees
EmuApi.PowerCycle();
}
}
} catch {
//Invalid file (file missing, not a zip file, etc.)
await MesenMsgBox.Show(wnd, "InstallHdPackInvalidZipFile", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}