diff --git a/Core/Console.cpp b/Core/Console.cpp index ad3d371..adecffb 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -54,7 +54,7 @@ void Console::Initialize() void Console::Release() { - Stop(); + Stop(true); _videoDecoder->StopThread(); _videoRenderer->StopThread(); @@ -130,7 +130,7 @@ void Console::Run() PlatformUtilities::RestoreTimerResolution(); } -void Console::Stop() +void Console::Stop(bool sendNotification) { _stopFlag = true; @@ -141,6 +141,11 @@ void Console::Stop() _runLock.WaitForRelease(); + if(_cart) { + //TODO IPS/BPS patch support + _saveStateManager->SaveRecentGame(GetRomInfo().RomFile.GetFileName(), _cart->GetRomInfo().RomFile, ""); + } + //Make sure we release both pointers to destroy the debugger before everything else _debugger.reset(); debugger.reset(); @@ -158,21 +163,25 @@ void Console::Stop() _dmaController.reset(); _soundMixer->StopAudio(); + + if(sendNotification) { + _notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped); + } } -void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) +bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) { - Stop(); - shared_ptr cart = BaseCartridge::CreateCartridge(romFile, patchFile); if(cart) { + Stop(false); + vector spcRomData; VirtualFile spcBios(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "spc700.rom")); if(spcBios.IsValid()) { spcBios.ReadFile(spcRomData); } else { MessageManager::Log("[SPC] spc700.rom not found, cannot launch game."); - return; + return false; } _internalRegisters.reset(new InternalRegisters(shared_from_this())); @@ -204,7 +213,11 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) _paused = false; _notificationManager->SendNotification(ConsoleNotificationType::GameLoaded); + + return true; } + + return false; } RomInfo Console::GetRomInfo() diff --git a/Core/Console.h b/Core/Console.h index 00066cf..0109985 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -74,13 +74,13 @@ public: void Release(); void Run(); - void Stop(); + void Stop(bool sendNotification); void Pause(); void Resume(); bool IsPaused(); - void LoadRom(VirtualFile romFile, VirtualFile patchFile); + bool LoadRom(VirtualFile romFile, VirtualFile patchFile); RomInfo GetRomInfo(); uint32_t GetMasterClockRate(); ConsoleRegion GetRegion(); diff --git a/Core/SaveStateManager.cpp b/Core/SaveStateManager.cpp index 24c7667..89dbe62 100644 --- a/Core/SaveStateManager.cpp +++ b/Core/SaveStateManager.cpp @@ -195,30 +195,26 @@ bool SaveStateManager::LoadState(int stateIndex) return false; } -//TODO -/* void SaveStateManager::SaveRecentGame(string romName, string romPath, string patchPath) { - if(!_console->GetSettings()->CheckFlag(EmulationFlags::ConsoleMode) && !_console->GetSettings()->CheckFlag(EmulationFlags::DisableGameSelectionScreen) && _console->GetRomInfo().Format != RomFormat::Nsf) { - string filename = FolderUtilities::GetFilename(_console->GetRomInfo().RomName, false) + ".rgd"; - ZipWriter writer; - writer.Initialize(FolderUtilities::CombinePath(FolderUtilities::GetRecentGamesFolder(), filename)); + string filename = FolderUtilities::GetFilename(_console->GetRomInfo().RomFile.GetFileName(), false) + ".rgd"; + ZipWriter writer; + writer.Initialize(FolderUtilities::CombinePath(FolderUtilities::GetRecentGamesFolder(), filename)); - std::stringstream pngStream; - _console->GetVideoDecoder()->TakeScreenshot(pngStream); - writer.AddFile(pngStream, "Screenshot.png"); + std::stringstream pngStream; + _console->GetVideoDecoder()->TakeScreenshot(pngStream); + writer.AddFile(pngStream, "Screenshot.png"); - std::stringstream stateStream; - SaveStateManager::SaveState(stateStream); - writer.AddFile(stateStream, "Savestate.mst"); + std::stringstream stateStream; + SaveStateManager::SaveState(stateStream); + writer.AddFile(stateStream, "Savestate.mst"); - std::stringstream romInfoStream; - romInfoStream << romName << std::endl; - romInfoStream << romPath << std::endl; - romInfoStream << patchPath << std::endl; - writer.AddFile(romInfoStream, "RomInfo.txt"); - writer.Save(); - } + std::stringstream romInfoStream; + romInfoStream << romName << std::endl; + romInfoStream << romPath << std::endl; + romInfoStream << patchPath << std::endl; + writer.AddFile(romInfoStream, "RomInfo.txt"); + writer.Save(); } void SaveStateManager::LoadRecentGame(string filename, bool resetGame) @@ -237,14 +233,13 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame) _console->Pause(); try { - if(_console->Initialize(romPath, patchPath)) { + if(_console->LoadRom(romPath, patchPath)) { if(!resetGame) { SaveStateManager::LoadState(stateStream, false); } } } catch(std::exception ex) { - _console->Stop(); + _console->Stop(true); } _console->Resume(); } -*/ \ No newline at end of file diff --git a/Core/SaveStateManager.h b/Core/SaveStateManager.h index f232c08..74e36c6 100644 --- a/Core/SaveStateManager.h +++ b/Core/SaveStateManager.h @@ -32,8 +32,8 @@ public: bool LoadState(string filepath, bool hashCheckRequired = true); bool LoadState(int stateIndex); - //void SaveRecentGame(string romName, string romPath, string patchPath); - //void LoadRecentGame(string filename, bool resetGame); + void SaveRecentGame(string romName, string romPath, string patchPath); + void LoadRecentGame(string filename, bool resetGame); void MoveToNextSlot(); void MoveToPreviousSlot(); diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 48ef3e3..d9ac3d4 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -202,14 +202,12 @@ void VideoDecoder::StopThread() //TODO //_hud.reset(); - /*UpdateVideoFilter(); + /*UpdateVideoFilter();*/ if(_ppuOutputBuffer != nullptr) { //Clear whole screen - for(uint32_t i = 0; i < PPU::PixelCount; i++) { - _ppuOutputBuffer[i] = 14; //Black - } + memset(_ppuOutputBuffer, 0, 512 * 478 * 2); DecodeFrame(); - }*/ + } _ppuOutputBuffer = nullptr; } #endif diff --git a/InteropDLL/EmuApiWrapper.cpp b/InteropDLL/EmuApiWrapper.cpp index 092eb49..edda2ac 100644 --- a/InteropDLL/EmuApiWrapper.cpp +++ b/InteropDLL/EmuApiWrapper.cpp @@ -114,7 +114,7 @@ extern "C" { DllExport void __stdcall Stop() { - _console->Stop(); + _console->Stop(true); } DllExport void __stdcall Pause() @@ -134,7 +134,7 @@ extern "C" { DllExport void __stdcall Release() { - _console->Stop(); + _console->Stop(true); _renderer.reset(); _soundManager.reset(); @@ -175,6 +175,7 @@ extern "C" { DllExport void __stdcall SaveStateFile(char* filepath) { _console->GetSaveStateManager()->SaveState(filepath); } DllExport void __stdcall LoadStateFile(char* filepath) { _console->GetSaveStateManager()->LoadState(filepath); } DllExport int64_t __stdcall GetStateInfo(uint32_t stateIndex) { return _console->GetSaveStateManager()->GetStateInfo(stateIndex); } + DllExport void __stdcall LoadRecentGame(char* filepath, bool resetGame) { _console->GetSaveStateManager()->LoadRecentGame(filepath, resetGame); } DllExport void __stdcall PgoRunTest(vector testRoms, bool enableDebugger) { @@ -191,7 +192,7 @@ extern "C" { _console->Run(); }); std::this_thread::sleep_for(std::chrono::duration(5000)); - _console->Stop(); + _console->Stop(false); testThread.join(); _console->Release(); } diff --git a/UI/Config/RecentItems.cs b/UI/Config/RecentItems.cs index b5f2b1a..d6b3679 100644 --- a/UI/Config/RecentItems.cs +++ b/UI/Config/RecentItems.cs @@ -57,14 +57,10 @@ namespace Mesen.GUI.Config public override string ToString() { string path = RomFile.ReadablePath.Replace("&", "&&"); - string file = Path.GetFileName(path); - string folder = Path.GetDirectoryName(path); - - string text = file; + string text = Path.GetFileName(path); if(PatchFile.HasValue) { text += " [" + Path.GetFileName(PatchFile.Value) + "]"; } - text += " (" + folder + ")"; return text; } } diff --git a/UI/Controls/ctrlRecentGames.cs b/UI/Controls/ctrlRecentGames.cs new file mode 100644 index 0000000..8ecc503 --- /dev/null +++ b/UI/Controls/ctrlRecentGames.cs @@ -0,0 +1,306 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.IO; +using Mesen.GUI.Config; +using System.Drawing.Text; +using System.IO.Compression; +using Mesen.GUI.Forms; +using Mesen.GUI.Controls; +using Mesen.GUI.Emulation; + +namespace Mesen.GUI.Controls +{ + public partial class ctrlRecentGames : BaseControl + { + public delegate void RecentGameLoadedHandler(RecentGameInfo gameInfo); + public event RecentGameLoadedHandler OnRecentGameLoaded; + + public new event MouseEventHandler MouseMove + { + add { this.tlpPreviousState.MouseMove += value; } + remove { this.tlpPreviousState.MouseMove -= value; } + } + + public new event EventHandler DoubleClick + { + add { this.tlpPreviousState.DoubleClick += value; } + remove { this.tlpPreviousState.DoubleClick -= value; } + } + + private bool _initialized = false; + private int _currentIndex = 0; + private List _recentGames = new List(); + private PrivateFontCollection _fonts = new PrivateFontCollection(); + + public ctrlRecentGames() + { + InitializeComponent(); + if(IsDesignMode) { + return; + } + + DoubleBuffered = true; + + _fonts.AddFontFile(Path.Combine(ConfigManager.HomeFolder, "Resources", "PixelFont.ttf")); + lblGameName.Font = new Font(_fonts.Families[0], 10); + lblSaveDate.Font = new Font(_fonts.Families[0], 10); + + picPrevGame.Image.RotateFlip(RotateFlipType.RotateNoneFlipX); + } + + public new bool Visible + { + get { return base.Visible; } + set + { + if(value && ((_initialized && _recentGames.Count == 0) /* TODO || ConfigManager.Config.Preferences.DisableGameSelectionScreen*/)) { + value = false; + } + + if(value != base.Visible) { + if(value && !_initialized) { + //We just re-enabled the screen, initialize it + Initialize(); + } + + base.Visible = value; + tmrInput.Enabled = value; + } + } + } + + public int GameCount + { + get { return _recentGames.Count; } + } + + public void Initialize() + { + _initialized = true; + _recentGames = new List(); + _currentIndex = 0; + + foreach(string file in Directory.GetFiles(ConfigManager.RecentGamesFolder, "*.rgd")) { + try { + RecentGameInfo info = new RecentGameInfo(); + ZipArchive zip = new ZipArchive(new MemoryStream(File.ReadAllBytes(file))); + + using(StreamReader sr = new StreamReader(zip.GetEntry("RomInfo.txt").Open())) { + info.RomName = sr.ReadLine(); + info.RomPath = sr.ReadLine(); + } + + info.Timestamp = new FileInfo(file).LastWriteTime; + info.FileName = file; + + if(info.RomPath.Exists) { + _recentGames.Add(info); + } + } catch { } + } + + _recentGames = _recentGames.OrderBy((info) => info.Timestamp).Reverse().ToList(); + + if(_recentGames.Count > 5) { + _recentGames.RemoveRange(5, _recentGames.Count - 5); + } + + picPrevGame.Visible = _recentGames.Count > 1; + picNextGame.Visible = _recentGames.Count > 1; + + if(_recentGames.Count == 0) { + this.Visible = false; + tmrInput.Enabled = false; + } else { + UpdateGameInfo(); + tmrInput.Enabled = true; + } + } + + public void UpdateGameInfo() + { + if(_currentIndex < _recentGames.Count) { + lblGameName.Text = Path.GetFileNameWithoutExtension(_recentGames[_currentIndex].RomName); + lblSaveDate.Text = _recentGames[_currentIndex].Timestamp.ToString(); + + try { + ZipArchive zip = new ZipArchive(new MemoryStream(File.ReadAllBytes(_recentGames[_currentIndex].FileName))); + ZipArchiveEntry entry = zip.GetEntry("Screenshot.png"); + if(entry != null) { + using(Stream stream = entry.Open()) { + picPreviousState.Image = Image.FromStream(stream); + } + } else { + picPreviousState.Image = null; + } + } catch { + picPreviousState.Image = null; + } + UpdateSize(); + } + } + + float _xFactor = 1; + float _yFactor = 1; + protected override void ScaleControl(SizeF factor, BoundsSpecified specified) + { + _xFactor = factor.Width; + _yFactor = factor.Height; + base.ScaleControl(factor, specified); + } + + private void UpdateSize() + { + tlpPreviousState.Visible = false; + Size maxSize = new Size(this.Size.Width - (int)(120 * _xFactor), this.Size.Height - (int)(50 * _yFactor)); + + if(picPreviousState.Image != null) { + double xRatio = (double)picPreviousState.Image.Width / maxSize.Width; + double yRatio = (double)picPreviousState.Image.Height / maxSize.Height; + double ratio = Math.Max(xRatio, yRatio); + + Size newSize = new Size((int)(picPreviousState.Image.Width / ratio), (int)(picPreviousState.Image.Height / ratio)); + picPreviousState.Size = newSize; + pnlPreviousState.Size = new Size(newSize.Width+4, newSize.Height+4); + } + tlpPreviousState.Visible = true; + } + + protected override void OnResize(EventArgs e) + { + if(Program.IsMono) { + //Fix resize issues + picNextGame.Dock = DockStyle.None; + picPrevGame.Dock = DockStyle.None; + picNextGame.Dock = DockStyle.Fill; + picPrevGame.Dock = DockStyle.Fill; + } + + if(picPreviousState.Image != null) { + UpdateSize(); + } + base.OnResize(e); + } + + private void picPreviousState_MouseEnter(object sender, EventArgs e) + { + pnlPreviousState.BackColor = Color.LightBlue; + } + + private void picPreviousState_MouseLeave(object sender, EventArgs e) + { + pnlPreviousState.BackColor = Color.Gray; + } + + private void picPreviousState_Click(object sender, EventArgs e) + { + LoadSelectedGame(); + } + + private void picNextGame_MouseDown(object sender, MouseEventArgs e) + { + GoToNextGame(); + } + + private void picPrevGame_MouseDown(object sender, MouseEventArgs e) + { + GoToPreviousGame(); + } + + private void GoToPreviousGame() + { + if(_currentIndex == 0) { + _currentIndex = _recentGames.Count - 1; + } else { + _currentIndex--; + } + UpdateGameInfo(); + } + + private void GoToNextGame() + { + _currentIndex = (_currentIndex + 1) % _recentGames.Count; + UpdateGameInfo(); + } + + private void LoadSelectedGame() + { + EmuRunner.LoadRecentGame(_recentGames[_currentIndex].FileName); + } + + private bool _waitForRelease = false; + private void tmrInput_Tick(object sender, EventArgs e) + { + //Use player 1's controls to navigate the recent game selection screen + if(Application.OpenForms.Count > 0 && Application.OpenForms[0].ContainsFocus && !EmuRunner.IsRunning()) { + List keyCodes = InputApi.GetPressedKeys(); + uint keyCode = keyCodes.Count > 0 ? keyCodes[0] : 0; + if(keyCode > 0) { + if(!_waitForRelease) { + List mappings = new List() { + ConfigManager.Config.Input.Controllers[0].Keys.Mapping1, + ConfigManager.Config.Input.Controllers[0].Keys.Mapping2, + ConfigManager.Config.Input.Controllers[0].Keys.Mapping3, + ConfigManager.Config.Input.Controllers[0].Keys.Mapping4 + }; + + foreach(KeyMapping mapping in mappings) { + if(mapping.Left == keyCode) { + _waitForRelease = true; + GoToPreviousGame(); + } else if(mapping.Right == keyCode) { + _waitForRelease = true; + GoToNextGame(); + } else if(mapping.A == keyCode || mapping.B == keyCode) { + _waitForRelease = true; + LoadSelectedGame(); + } + } + } + } else { + _waitForRelease = false; + } + } + } + } + + public class DBTableLayoutPanel : TableLayoutPanel + { + public DBTableLayoutPanel() + { + DoubleBuffered = true; + } + } + + public class GamePreviewBox : PictureBox + { + public System.Drawing.Drawing2D.InterpolationMode InterpolationMode { get; set; } + + public GamePreviewBox() + { + DoubleBuffered = true; + InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; + } + + protected override void OnPaint(PaintEventArgs pe) + { + pe.Graphics.InterpolationMode = InterpolationMode; + base.OnPaint(pe); + } + } + + public class RecentGameInfo + { + public string FileName { get; set; } + public string RomName { get; set; } + public ResourcePath RomPath { get; set; } + public DateTime Timestamp { get; set; } + } +} diff --git a/UI/Controls/ctrlRecentGames.designer.cs b/UI/Controls/ctrlRecentGames.designer.cs new file mode 100644 index 0000000..163778d --- /dev/null +++ b/UI/Controls/ctrlRecentGames.designer.cs @@ -0,0 +1,183 @@ +namespace Mesen.GUI.Controls +{ + partial class ctrlRecentGames + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.tlpPreviousState = new Mesen.GUI.Controls.DBTableLayoutPanel(); + this.pnlPreviousState = new System.Windows.Forms.Panel(); + this.picPreviousState = new Mesen.GUI.Controls.GamePreviewBox(); + this.lblGameName = new System.Windows.Forms.Label(); + this.lblSaveDate = new System.Windows.Forms.Label(); + this.picNextGame = new System.Windows.Forms.PictureBox(); + this.picPrevGame = new System.Windows.Forms.PictureBox(); + this.tmrInput = new System.Windows.Forms.Timer(this.components); + this.tlpPreviousState.SuspendLayout(); + this.pnlPreviousState.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.picNextGame)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).BeginInit(); + this.SuspendLayout(); + // + // tlpPreviousState + // + this.tlpPreviousState.BackColor = System.Drawing.Color.Black; + this.tlpPreviousState.ColumnCount = 3; + this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpPreviousState.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tlpPreviousState.Controls.Add(this.pnlPreviousState, 1, 1); + this.tlpPreviousState.Controls.Add(this.lblGameName, 1, 2); + this.tlpPreviousState.Controls.Add(this.lblSaveDate, 1, 3); + this.tlpPreviousState.Controls.Add(this.picNextGame, 2, 1); + this.tlpPreviousState.Controls.Add(this.picPrevGame, 0, 1); + this.tlpPreviousState.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpPreviousState.Location = new System.Drawing.Point(0, 0); + this.tlpPreviousState.Name = "tlpPreviousState"; + this.tlpPreviousState.RowCount = 6; + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F)); + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5F)); + this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpPreviousState.Size = new System.Drawing.Size(272, 107); + this.tlpPreviousState.TabIndex = 9; + // + // pnlPreviousState + // + this.pnlPreviousState.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.pnlPreviousState.BackColor = System.Drawing.Color.Gray; + this.pnlPreviousState.Controls.Add(this.picPreviousState); + this.pnlPreviousState.Location = new System.Drawing.Point(113, 13); + this.pnlPreviousState.Name = "pnlPreviousState"; + this.pnlPreviousState.Padding = new System.Windows.Forms.Padding(2); + this.pnlPreviousState.Size = new System.Drawing.Size(46, 46); + this.pnlPreviousState.TabIndex = 8; + // + // picPreviousState + // + this.picPreviousState.BackColor = System.Drawing.Color.Black; + this.picPreviousState.Cursor = System.Windows.Forms.Cursors.Hand; + this.picPreviousState.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + this.picPreviousState.Location = new System.Drawing.Point(2, 2); + this.picPreviousState.Margin = new System.Windows.Forms.Padding(0); + this.picPreviousState.Name = "picPreviousState"; + this.picPreviousState.Size = new System.Drawing.Size(42, 42); + this.picPreviousState.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.picPreviousState.TabIndex = 7; + this.picPreviousState.TabStop = false; + this.picPreviousState.Click += new System.EventHandler(this.picPreviousState_Click); + this.picPreviousState.MouseEnter += new System.EventHandler(this.picPreviousState_MouseEnter); + this.picPreviousState.MouseLeave += new System.EventHandler(this.picPreviousState_MouseLeave); + // + // lblGameName + // + this.lblGameName.AutoEllipsis = true; + this.lblGameName.BackColor = System.Drawing.Color.Transparent; + this.lblGameName.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblGameName.ForeColor = System.Drawing.Color.White; + this.lblGameName.Location = new System.Drawing.Point(36, 62); + this.lblGameName.Name = "lblGameName"; + this.lblGameName.Size = new System.Drawing.Size(200, 16); + this.lblGameName.TabIndex = 9; + this.lblGameName.Text = "Game Name"; + this.lblGameName.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // lblSaveDate + // + this.lblSaveDate.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.lblSaveDate.AutoSize = true; + this.lblSaveDate.BackColor = System.Drawing.Color.Transparent; + this.lblSaveDate.ForeColor = System.Drawing.Color.White; + this.lblSaveDate.Location = new System.Drawing.Point(121, 78); + this.lblSaveDate.Name = "lblSaveDate"; + this.lblSaveDate.Size = new System.Drawing.Size(30, 13); + this.lblSaveDate.TabIndex = 10; + this.lblSaveDate.Text = "Date"; + // + // picNextGame + // + this.picNextGame.Cursor = System.Windows.Forms.Cursors.Hand; + this.picNextGame.Dock = System.Windows.Forms.DockStyle.Right; + this.picNextGame.Image = global::Mesen.GUI.Properties.Resources.MediaPlay; + this.picNextGame.Location = new System.Drawing.Point(242, 13); + this.picNextGame.Name = "picNextGame"; + this.picNextGame.Size = new System.Drawing.Size(27, 46); + this.picNextGame.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.picNextGame.TabIndex = 11; + this.picNextGame.TabStop = false; + this.picNextGame.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picNextGame_MouseDown); + // + // picPrevGame + // + this.picPrevGame.Cursor = System.Windows.Forms.Cursors.Hand; + this.picPrevGame.Dock = System.Windows.Forms.DockStyle.Left; + this.picPrevGame.Image = global::Mesen.GUI.Properties.Resources.MediaPlay; + this.picPrevGame.Location = new System.Drawing.Point(3, 13); + this.picPrevGame.Name = "picPrevGame"; + this.picPrevGame.Size = new System.Drawing.Size(27, 46); + this.picPrevGame.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.picPrevGame.TabIndex = 12; + this.picPrevGame.TabStop = false; + this.picPrevGame.MouseDown += new System.Windows.Forms.MouseEventHandler(this.picPrevGame_MouseDown); + // + // tmrInput + // + this.tmrInput.Interval = 50; + this.tmrInput.Tick += new System.EventHandler(this.tmrInput_Tick); + // + // ctrlRecentGames + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Transparent; + this.Controls.Add(this.tlpPreviousState); + this.Name = "ctrlRecentGames"; + this.Size = new System.Drawing.Size(272, 107); + this.tlpPreviousState.ResumeLayout(false); + this.tlpPreviousState.PerformLayout(); + this.pnlPreviousState.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.picNextGame)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private DBTableLayoutPanel tlpPreviousState; + private System.Windows.Forms.Panel pnlPreviousState; + private GamePreviewBox picPreviousState; + private System.Windows.Forms.Label lblGameName; + private System.Windows.Forms.Label lblSaveDate; + private System.Windows.Forms.PictureBox picNextGame; + private System.Windows.Forms.PictureBox picPrevGame; + private System.Windows.Forms.Timer tmrInput; + } +} diff --git a/UI/Controls/ctrlRecentGames.resx b/UI/Controls/ctrlRecentGames.resx new file mode 100644 index 0000000..0a8878c --- /dev/null +++ b/UI/Controls/ctrlRecentGames.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/UI/Emulation/EmuRunner.cs b/UI/Emulation/EmuRunner.cs index c6511ae..810c08e 100644 --- a/UI/Emulation/EmuRunner.cs +++ b/UI/Emulation/EmuRunner.cs @@ -21,11 +21,21 @@ namespace Mesen.GUI.Emulation } EmuApi.LoadRom(romPath, patchPath); - ConfigManager.Config.RecentFiles.AddRecentFile(romPath, patchPath); + StartEmulation(); + } + public static void LoadRecentGame(string recentGameArchivePath) + { + EmuApi.LoadRecentGame(recentGameArchivePath, false /* TODO , ConfigManager.Config.Preferences.GameSelectionScreenResetGame */); + StartEmulation(); + } + + private static void StartEmulation() + { _emuThread = new Thread(() => { EmuApi.Run(); + _emuThread = null; }); _emuThread.Start(); } diff --git a/UI/Forms/frmMain.Designer.cs b/UI/Forms/frmMain.Designer.cs index 9e7276f..dc64a14 100644 --- a/UI/Forms/frmMain.Designer.cs +++ b/UI/Forms/frmMain.Designer.cs @@ -98,6 +98,11 @@ this.mnuPrescale10xFilter = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem19 = new System.Windows.Forms.ToolStripSeparator(); this.mnuBilinearInterpolation = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegion = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegionAuto = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuRegionNtsc = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegionPal = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAudioConfig = new System.Windows.Forms.ToolStripMenuItem(); this.mnuInputConfig = new System.Windows.Forms.ToolStripMenuItem(); @@ -122,11 +127,7 @@ this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem(); this.pnlRenderer = new System.Windows.Forms.Panel(); - this.mnuRegion = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuRegionAuto = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuRegionNtsc = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuRegionPal = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.ctrlRecentGames = new Mesen.GUI.Controls.ctrlRecentGames(); this.mnuMain.SuspendLayout(); this.pnlRenderer.SuspendLayout(); this.SuspendLayout(); @@ -305,7 +306,7 @@ this.mnuShowFPS}); this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed; this.mnuEmulationSpeed.Name = "mnuEmulationSpeed"; - this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22); + this.mnuEmulationSpeed.Size = new System.Drawing.Size(135, 22); this.mnuEmulationSpeed.Text = "Speed"; this.mnuEmulationSpeed.DropDownOpening += new System.EventHandler(this.mnuEmulationSpeed_DropDownOpening); // @@ -393,7 +394,7 @@ this.mnuFullscreen}); this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen; this.mnuVideoScale.Name = "mnuVideoScale"; - this.mnuVideoScale.Size = new System.Drawing.Size(152, 22); + this.mnuVideoScale.Size = new System.Drawing.Size(135, 22); this.mnuVideoScale.Text = "Video Size"; this.mnuVideoScale.DropDownOpening += new System.EventHandler(this.mnuVideoScale_DropDownOpening); // @@ -479,7 +480,7 @@ this.mnuBilinearInterpolation}); this.mnuVideoFilter.Image = global::Mesen.GUI.Properties.Resources.VideoFilter; this.mnuVideoFilter.Name = "mnuVideoFilter"; - this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22); + this.mnuVideoFilter.Size = new System.Drawing.Size(135, 22); this.mnuVideoFilter.Text = "Video Filter"; this.mnuVideoFilter.DropDownOpening += new System.EventHandler(this.mnuVideoFilter_DropDownOpening); // @@ -657,16 +658,52 @@ this.mnuBilinearInterpolation.Size = new System.Drawing.Size(206, 22); this.mnuBilinearInterpolation.Text = "Use Bilinear Interpolation"; // + // mnuRegion + // + this.mnuRegion.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuRegionAuto, + this.toolStripMenuItem1, + this.mnuRegionNtsc, + this.mnuRegionPal}); + this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.WebBrowser; + this.mnuRegion.Name = "mnuRegion"; + this.mnuRegion.Size = new System.Drawing.Size(135, 22); + this.mnuRegion.Text = "Region"; + this.mnuRegion.DropDownOpening += new System.EventHandler(this.mnuRegion_DropDownOpening); + // + // mnuRegionAuto + // + this.mnuRegionAuto.Name = "mnuRegionAuto"; + this.mnuRegionAuto.Size = new System.Drawing.Size(104, 22); + this.mnuRegionAuto.Text = "Auto"; + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(101, 6); + // + // mnuRegionNtsc + // + this.mnuRegionNtsc.Name = "mnuRegionNtsc"; + this.mnuRegionNtsc.Size = new System.Drawing.Size(104, 22); + this.mnuRegionNtsc.Text = "NTSC"; + // + // mnuRegionPal + // + this.mnuRegionPal.Name = "mnuRegionPal"; + this.mnuRegionPal.Size = new System.Drawing.Size(104, 22); + this.mnuRegionPal.Text = "PAL"; + // // toolStripMenuItem4 // this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - this.toolStripMenuItem4.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem4.Size = new System.Drawing.Size(132, 6); // // mnuAudioConfig // this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio; this.mnuAudioConfig.Name = "mnuAudioConfig"; - this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22); + this.mnuAudioConfig.Size = new System.Drawing.Size(135, 22); this.mnuAudioConfig.Text = "Audio"; this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click); // @@ -674,7 +711,7 @@ // this.mnuInputConfig.Image = global::Mesen.GUI.Properties.Resources.Controller; this.mnuInputConfig.Name = "mnuInputConfig"; - this.mnuInputConfig.Size = new System.Drawing.Size(152, 22); + this.mnuInputConfig.Size = new System.Drawing.Size(135, 22); this.mnuInputConfig.Text = "Input"; this.mnuInputConfig.Click += new System.EventHandler(this.mnuInputConfig_Click); // @@ -682,7 +719,7 @@ // this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.VideoOptions; this.mnuVideoConfig.Name = "mnuVideoConfig"; - this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22); + this.mnuVideoConfig.Size = new System.Drawing.Size(135, 22); this.mnuVideoConfig.Text = "Video"; this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click); // @@ -690,20 +727,20 @@ // this.mnuEmulationConfig.Image = global::Mesen.GUI.Properties.Resources.DipSwitches; this.mnuEmulationConfig.Name = "mnuEmulationConfig"; - this.mnuEmulationConfig.Size = new System.Drawing.Size(152, 22); + this.mnuEmulationConfig.Size = new System.Drawing.Size(135, 22); this.mnuEmulationConfig.Text = "Emulation"; this.mnuEmulationConfig.Click += new System.EventHandler(this.mnuEmulationConfig_Click); // // toolStripMenuItem3 // this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - this.toolStripMenuItem3.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem3.Size = new System.Drawing.Size(132, 6); // // mnuPreferences // this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Settings; this.mnuPreferences.Name = "mnuPreferences"; - this.mnuPreferences.Size = new System.Drawing.Size(152, 22); + this.mnuPreferences.Size = new System.Drawing.Size(135, 22); this.mnuPreferences.Text = "Preferences"; this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click); // @@ -845,41 +882,15 @@ this.pnlRenderer.Size = new System.Drawing.Size(512, 448); this.pnlRenderer.TabIndex = 2; // - // mnuRegion + // ctrlRecentGames // - this.mnuRegion.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mnuRegionAuto, - this.toolStripMenuItem1, - this.mnuRegionNtsc, - this.mnuRegionPal}); - this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.WebBrowser; - this.mnuRegion.Name = "mnuRegion"; - this.mnuRegion.Size = new System.Drawing.Size(152, 22); - this.mnuRegion.Text = "Region"; - this.mnuRegion.DropDownOpening += new System.EventHandler(this.mnuRegion_DropDownOpening); - // - // mnuRegionAuto - // - this.mnuRegionAuto.Name = "mnuRegionAuto"; - this.mnuRegionAuto.Size = new System.Drawing.Size(152, 22); - this.mnuRegionAuto.Text = "Auto"; - // - // mnuRegionNtsc - // - this.mnuRegionNtsc.Name = "mnuRegionNtsc"; - this.mnuRegionNtsc.Size = new System.Drawing.Size(152, 22); - this.mnuRegionNtsc.Text = "NTSC"; - // - // mnuRegionPal - // - this.mnuRegionPal.Name = "mnuRegionPal"; - this.mnuRegionPal.Size = new System.Drawing.Size(152, 22); - this.mnuRegionPal.Text = "PAL"; - // - // toolStripMenuItem1 - // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6); + this.ctrlRecentGames.BackColor = System.Drawing.Color.Transparent; + this.ctrlRecentGames.Dock = System.Windows.Forms.DockStyle.Top; + this.ctrlRecentGames.Location = new System.Drawing.Point(0, 24); + this.ctrlRecentGames.Name = "ctrlRecentGames"; + this.ctrlRecentGames.Size = new System.Drawing.Size(512, 265); + this.ctrlRecentGames.TabIndex = 1; + this.ctrlRecentGames.Visible = false; // // frmMain // @@ -887,6 +898,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(512, 472); + this.Controls.Add(this.ctrlRecentGames); this.Controls.Add(this.pnlRenderer); this.Controls.Add(this.mnuMain); this.MainMenuStrip = this.mnuMain; @@ -1002,5 +1014,6 @@ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem mnuRegionNtsc; private System.Windows.Forms.ToolStripMenuItem mnuRegionPal; + private Controls.ctrlRecentGames ctrlRecentGames; } } \ No newline at end of file diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index 6d785a3..0463b38 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -49,6 +49,9 @@ namespace Mesen.GUI.Forms SaveStateManager.InitializeStateMenu(mnuLoadState, false, _shortcuts); BindShortcuts(); + + ctrlRecentGames.Initialize(); + ctrlRecentGames.Visible = true; } protected override void OnFormClosing(FormClosingEventArgs e) @@ -72,11 +75,19 @@ namespace Mesen.GUI.Forms switch(e.NotificationType) { case ConsoleNotificationType.GameLoaded: this.BeginInvoke((Action)(() => { + ctrlRecentGames.Visible = false; SaveStateManager.UpdateStateMenu(mnuLoadState, false); SaveStateManager.UpdateStateMenu(mnuSaveState, true); })); break; + case ConsoleNotificationType.EmulationStopped: + this.BeginInvoke((Action)(() => { + ctrlRecentGames.Initialize(); + ctrlRecentGames.Visible = true; + })); + break; + case ConsoleNotificationType.ResolutionChanged: ScreenSize size = EmuApi.GetScreenSize(false); this.BeginInvoke((Action)(() => { @@ -181,6 +192,12 @@ namespace Mesen.GUI.Forms //this.Resize += frmMain_Resize; } + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + ctrlRecentGames.Height = this.ClientSize.Height - ctrlRecentGames.Top - 80; + } + private void mnuVideoConfig_Click(object sender, EventArgs e) { using(frmVideoConfig frm = new frmVideoConfig()) { diff --git a/UI/Interop/EmuApi.cs b/UI/Interop/EmuApi.cs index 154416f..150b41d 100644 --- a/UI/Interop/EmuApi.cs +++ b/UI/Interop/EmuApi.cs @@ -48,6 +48,8 @@ namespace Mesen.GUI [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string patchFile = "" ); + [DllImport(DllPath)] public static extern void LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string filepath, [MarshalAs(UnmanagedType.I1)]bool resetGame); + [DllImport(DllPath)] public static extern void AddKnownGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string folder); [DllImport(DllPath)] public static extern void SetFolderOverrides( diff --git a/UI/UI.csproj b/UI/UI.csproj index c02b47b..1b8cfe2 100644 --- a/UI/UI.csproj +++ b/UI/UI.csproj @@ -222,6 +222,12 @@ + + UserControl + + + ctrlRecentGames.cs + @@ -605,6 +611,9 @@ ctrlPathSelection.cs + + ctrlRecentGames.cs + MesenNumericUpDown.cs