UI: Added load/save state menus with dates & previews

This commit is contained in:
Sour 2020-01-28 20:20:54 -05:00
parent 66b618153a
commit d6728ee306
31 changed files with 599 additions and 232 deletions

View file

@ -69,7 +69,7 @@ uint32_t* BaseVideoFilter::GetOutputBuffer()
return _outputBuffer;
}
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream)
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream, bool rawScreenshot)
{
uint32_t* pngBuffer;
FrameInfo frameInfo;
@ -87,22 +87,24 @@ void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename
pngBuffer = frameBuffer;
uint32_t rotationAngle = _console->GetSettings()->GetScreenRotation();
shared_ptr<RotateFilter> rotateFilter;
if(rotationAngle > 0) {
rotateFilter.reset(new RotateFilter(rotationAngle));
pngBuffer = rotateFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height);
frameInfo = rotateFilter->GetFrameInfo(frameInfo);
}
if(!rawScreenshot) {
uint32_t rotationAngle = _console->GetSettings()->GetScreenRotation();
shared_ptr<RotateFilter> rotateFilter;
if(rotationAngle > 0) {
rotateFilter.reset(new RotateFilter(rotationAngle));
pngBuffer = rotateFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height);
frameInfo = rotateFilter->GetFrameInfo(frameInfo);
}
shared_ptr<ScaleFilter> scaleFilter = ScaleFilter::GetScaleFilter(filterType);
if(scaleFilter) {
pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetPictureSettings().ScanlineIntensity);
frameInfo = scaleFilter->GetFrameInfo(frameInfo);
}
shared_ptr<ScaleFilter> scaleFilter = ScaleFilter::GetScaleFilter(filterType);
if(scaleFilter) {
pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetPictureSettings().ScanlineIntensity);
frameInfo = scaleFilter->GetFrameInfo(frameInfo);
}
VideoHud hud;
hud.DrawHud(_console, pngBuffer, frameInfo, _console->GetSettings()->GetOverscanDimensions());
VideoHud hud;
hud.DrawHud(_console, pngBuffer, frameInfo, _console->GetSettings()->GetOverscanDimensions());
}
if(!filename.empty()) {
PNGHelper::WritePNG(filename, pngBuffer, frameInfo.Width, frameInfo.Height);

View file

@ -32,7 +32,7 @@ public:
uint32_t* GetOutputBuffer();
void SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
void TakeScreenshot(string romName, VideoFilterType filterType);
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr);
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr, bool rawScreenshot = false);
virtual OverscanDimensions GetOverscan();
virtual FrameInfo GetFrameInfo() = 0;

View file

@ -472,6 +472,7 @@ enum class EmulatorShortcut
SaveStateSlot9,
SaveStateSlot10,
SaveStateToFile,
SaveStateDialog,
LoadStateSlot1,
LoadStateSlot2,
@ -485,6 +486,7 @@ enum class EmulatorShortcut
LoadStateSlot10,
LoadStateSlotAuto,
LoadStateFromFile,
LoadStateDialog,
LoadLastSession,

View file

@ -79,6 +79,12 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream)
string sha1Hash = romInfo.Hash.Sha1;
stream.write(sha1Hash.c_str(), sha1Hash.size());
std::stringstream screenshotStream;
_console->GetVideoDecoder()->TakeScreenshot(screenshotStream, true);
uint32_t screenshotLength = (uint32_t)screenshotStream.tellp();
stream.write((char*)&screenshotLength, sizeof(uint32_t));
stream.write(screenshotStream.str().c_str(), screenshotLength);
string romName = romInfo.RomName;
uint32_t nameLength = (uint32_t)romName.size();
stream.write((char*)&nameLength, sizeof(uint32_t));
@ -151,6 +157,13 @@ bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired)
char hash[41] = {};
stream.read(hash, 40);
if(fileFormatVersion >= 13) {
//Skip screenshot data
uint32_t screenshotLength = 0;
stream.read((char*)&screenshotLength, sizeof(uint32_t));
stream.seekg(screenshotLength, std::ios::cur);
}
uint32_t nameLength = 0;
stream.read((char*)&nameLength, sizeof(uint32_t));
@ -229,7 +242,7 @@ void SaveStateManager::SaveRecentGame(string romName, string romPath, string pat
writer.Initialize(FolderUtilities::CombinePath(FolderUtilities::GetRecentGamesFolder(), filename));
std::stringstream pngStream;
_console->GetVideoDecoder()->TakeScreenshot(pngStream);
_console->GetVideoDecoder()->TakeScreenshot(pngStream, true);
writer.AddFile(pngStream, "Screenshot.png");
std::stringstream stateStream;
@ -270,4 +283,45 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame)
_console->Stop();
}
_console->Resume();
}
int32_t SaveStateManager::GetSaveStatePreview(string saveStatePath, uint8_t* pngData)
{
ifstream stream(saveStatePath, ios::binary);
if(!stream) {
return -1;
}
char header[3];
stream.read(header, 3);
if(memcmp(header, "MST", 3) == 0) {
uint32_t emuVersion = 0;
stream.read((char*)&emuVersion, sizeof(emuVersion));
if(emuVersion > EmulationSettings::GetMesenVersion()) {
return -1;
}
uint32_t fileFormatVersion = 0;
stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion));
if(fileFormatVersion <= 12) {
return -1;
}
//Skip some header fields
stream.seekg(43, ios::cur);
uint32_t screenshotLength = 0;
stream.read((char*)&screenshotLength, sizeof(screenshotLength));
if(screenshotLength > 0) {
stream.read((char*)pngData, screenshotLength);
return screenshotLength;
}
return -1;
}
return -1;
}

View file

@ -14,7 +14,7 @@ private:
string GetStateFilepath(int stateIndex);
public:
static constexpr uint32_t FileFormatVersion = 12;
static constexpr uint32_t FileFormatVersion = 13;
SaveStateManager(shared_ptr<Console> console);
@ -35,6 +35,8 @@ public:
void SaveRecentGame(string romName, string romPath, string patchPath);
void LoadRecentGame(string filename, bool resetGame);
int32_t GetSaveStatePreview(string saveStatePath, uint8_t* pngData);
void SelectSaveSlot(int slotIndex);
void MoveToNextSlot();
void MoveToPreviousSlot();

View file

@ -245,9 +245,14 @@ void VideoDecoder::TakeScreenshot()
}
}
void VideoDecoder::TakeScreenshot(std::stringstream &stream)
void VideoDecoder::TakeScreenshot(std::stringstream &stream, bool rawScreenshot)
{
if(_videoFilter) {
_videoFilter->TakeScreenshot(_videoFilterType, "", &stream);
if(rawScreenshot) {
//Take screenshot without NTSC filter on
DefaultVideoFilter filter(_console);
filter.SendFrame(_ppuOutputBuffer, 0);
filter.TakeScreenshot(_videoFilterType, "", &stream, rawScreenshot);
} else if(_videoFilter) {
_videoFilter->TakeScreenshot(_videoFilterType, "", &stream, rawScreenshot);
}
}

View file

@ -61,7 +61,7 @@ public:
void DecodeFrame(bool synchronous = false);
void TakeScreenshot();
void TakeScreenshot(std::stringstream &stream);
void TakeScreenshot(std::stringstream &stream, bool rawScreenshot = false);
uint32_t GetFrameCount();

View file

@ -28,9 +28,9 @@
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.picPreviousState = new Mesen.GUI.Controls.GamePreviewBox();
this.lblGameName = new System.Windows.Forms.Label();
this.lblSaveDate = new System.Windows.Forms.Label();
this.picPreviousState = new Mesen.GUI.Controls.GamePreviewBox();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).BeginInit();
this.SuspendLayout();
@ -53,36 +53,12 @@
this.tableLayoutPanel1.Size = new System.Drawing.Size(158, 93);
this.tableLayoutPanel1.TabIndex = 0;
//
// 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(3, 64);
this.lblGameName.Name = "lblGameName";
this.lblGameName.Size = new System.Drawing.Size(152, 16);
this.lblGameName.TabIndex = 12;
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(64, 80);
this.lblSaveDate.Name = "lblSaveDate";
this.lblSaveDate.Size = new System.Drawing.Size(30, 13);
this.lblSaveDate.TabIndex = 13;
this.lblSaveDate.Text = "Date";
//
// picPreviousState
//
this.picPreviousState.BackColor = System.Drawing.Color.Black;
this.picPreviousState.Cursor = System.Windows.Forms.Cursors.Hand;
this.picPreviousState.Dock = System.Windows.Forms.DockStyle.Fill;
this.picPreviousState.Highlight = false;
this.picPreviousState.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
this.picPreviousState.Location = new System.Drawing.Point(0, 0);
this.picPreviousState.Margin = new System.Windows.Forms.Padding(0);
@ -94,6 +70,31 @@
this.picPreviousState.Visible = false;
this.picPreviousState.Click += new System.EventHandler(this.picPreviousState_Click);
//
// 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(3, 64);
this.lblGameName.Name = "lblGameName";
this.lblGameName.Size = new System.Drawing.Size(152, 16);
this.lblGameName.TabIndex = 12;
this.lblGameName.Text = "Game Name";
this.lblGameName.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// lblSaveDate
//
this.lblSaveDate.BackColor = System.Drawing.Color.Transparent;
this.lblSaveDate.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblSaveDate.ForeColor = System.Drawing.Color.White;
this.lblSaveDate.Location = new System.Drawing.Point(3, 80);
this.lblSaveDate.Name = "lblSaveDate";
this.lblSaveDate.Size = new System.Drawing.Size(152, 13);
this.lblSaveDate.TabIndex = 13;
this.lblSaveDate.Text = "Date";
this.lblSaveDate.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// ctrlRecentGame
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -103,7 +104,6 @@
this.Name = "ctrlRecentGame";
this.Size = new System.Drawing.Size(158, 93);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picPreviousState)).EndInit();
this.ResumeLayout(false);

View file

@ -11,6 +11,8 @@ using System.IO;
using System.IO.Compression;
using Mesen.GUI.Config;
using static Mesen.GUI.Controls.ctrlRecentGames;
using System.Drawing.Drawing2D;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Controls
{
@ -24,6 +26,8 @@ namespace Mesen.GUI.Controls
InitializeComponent();
}
public GameScreenMode Mode { get; set; }
public RecentGameInfo RecentGame
{
get { return _recentGame; }
@ -43,33 +47,52 @@ namespace Mesen.GUI.Controls
_recentGame = value;
lblGameName.Text = Path.GetFileNameWithoutExtension(_recentGame.FileName);
lblSaveDate.Text = new FileInfo(_recentGame.FileName).LastWriteTime.ToString();
if(this.Mode == GameScreenMode.RecentGames) {
lblGameName.Text = !string.IsNullOrEmpty(value.Name) ? value.Name : Path.GetFileNameWithoutExtension(_recentGame.FileName);
lblGameName.Visible = true;
} else {
lblGameName.Text = value.Name;
lblGameName.Visible = !string.IsNullOrEmpty(value.Name);
}
bool fileExists = File.Exists(_recentGame.FileName);
if(fileExists) {
lblSaveDate.Text = new FileInfo(_recentGame.FileName).LastWriteTime.ToString();
} else {
lblSaveDate.Text = ResourceHelper.GetMessage("EmptyState");
picPreviousState.Image = null;
}
this.Enabled = fileExists || this.Mode == GameScreenMode.SaveState;
lblGameName.Visible = true;
lblSaveDate.Visible = true;
picPreviousState.Visible = true;
Task.Run(() => {
Image img = null;
try {
ZipArchive zip = new ZipArchive(new MemoryStream(File.ReadAllBytes(value.FileName)));
ZipArchiveEntry entry = zip.GetEntry("Screenshot.png");
if(entry != null) {
using(Stream stream = entry.Open()) {
img = Image.FromStream(stream);
if(fileExists) {
Task.Run(() => {
Image img = null;
try {
if(this.Mode != GameScreenMode.RecentGames && Path.GetExtension(value.FileName) == ".mst") {
img = InteropEmu.GetSaveStatePreview(value.FileName);
} else {
ZipArchive zip = new ZipArchive(new MemoryStream(File.ReadAllBytes(value.FileName)));
ZipArchiveEntry entry = zip.GetEntry("Screenshot.png");
if(entry != null) {
using(Stream stream = entry.Open()) {
img = Image.FromStream(stream);
}
}
using(StreamReader sr = new StreamReader(zip.GetEntry("RomInfo.txt").Open())) {
sr.ReadLine(); //skip first line (rom name)
value.RomPath = sr.ReadLine();
}
}
}
using(StreamReader sr = new StreamReader(zip.GetEntry("RomInfo.txt").Open())) {
string romName = sr.ReadLine();
value.RomPath = sr.ReadLine();
}
} catch { }
} catch { }
this.BeginInvoke((Action)(() => {
picPreviousState.Image = img;
}));
});
this.BeginInvoke((Action)(() => {
picPreviousState.Image = img;
}));
});
}
}
}
@ -80,8 +103,78 @@ namespace Mesen.GUI.Controls
private void picPreviousState_Click(object sender, EventArgs e)
{
InteropEmu.LoadRecentGame(_recentGame.FileName, ConfigManager.Config.PreferenceInfo.GameSelectionScreenResetGame);
ProcessClick();
}
public void ProcessClick()
{
if(!this.Enabled) {
return;
}
if(Path.GetExtension(_recentGame.FileName) == ".rgd") {
InteropEmu.LoadRecentGame(_recentGame.FileName, ConfigManager.Config.PreferenceInfo.GameSelectionScreenResetGame);
} else {
switch(this.Mode) {
case GameScreenMode.LoadState: InteropEmu.LoadStateFile(_recentGame.FileName); break;
case GameScreenMode.SaveState: InteropEmu.SaveStateFile(_recentGame.FileName); break;
}
}
OnRecentGameLoaded?.Invoke(_recentGame);
}
}
public class GamePreviewBox : PictureBox
{
public InterpolationMode InterpolationMode { get; set; }
private bool _hovered = false;
private bool _highlight = false;
public GamePreviewBox()
{
DoubleBuffered = true;
InterpolationMode = InterpolationMode.Default;
}
public bool Highlight
{
get { return _highlight; }
set
{
_highlight = value;
this.Invalidate();
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
_hovered = false;
this.Invalidate();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_hovered = true;
this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_hovered = false;
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
base.OnPaint(pe);
using(Pen pen = new Pen(_hovered && this.Enabled ? Color.DeepSkyBlue : (_highlight ? Color.DodgerBlue : Color.DimGray), 2)) {
pe.Graphics.DrawRectangle(pen, 1, 1, this.Width - 2, this.Height - 2);
}
}
}
}

View file

@ -29,13 +29,20 @@
{
this.components = new System.ComponentModel.Container();
this.tlpPreviousState = new Mesen.GUI.Controls.DBTableLayoutPanel();
this.baseControl2 = new Mesen.GUI.Controls.BaseControl();
this.picNextGame = new System.Windows.Forms.PictureBox();
this.picPrevGame = new System.Windows.Forms.PictureBox();
this.tlpGrid = new Mesen.GUI.Controls.DBTableLayoutPanel();
this.tlpTitle = new Mesen.GUI.Controls.DBTableLayoutPanel();
this.lblScreenTitle = new System.Windows.Forms.Label();
this.picClose = new System.Windows.Forms.PictureBox();
this.baseControl1 = new Mesen.GUI.Controls.BaseControl();
this.tmrInput = new System.Windows.Forms.Timer(this.components);
this.tlpGrid = new DBTableLayoutPanel();
this.tlpPreviousState.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picNextGame)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).BeginInit();
this.tlpTitle.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picClose)).BeginInit();
this.SuspendLayout();
//
// tlpPreviousState
@ -45,29 +52,37 @@
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.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpPreviousState.Controls.Add(this.baseControl2, 2, 0);
this.tlpPreviousState.Controls.Add(this.picNextGame, 2, 1);
this.tlpPreviousState.Controls.Add(this.picPrevGame, 0, 1);
this.tlpPreviousState.Controls.Add(this.tlpGrid, 1, 1);
this.tlpPreviousState.Controls.Add(this.tlpTitle, 1, 0);
this.tlpPreviousState.Controls.Add(this.baseControl1, 0, 0);
this.tlpPreviousState.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpPreviousState.Location = new System.Drawing.Point(0, 0);
this.tlpPreviousState.Name = "tlpPreviousState";
this.tlpPreviousState.RowCount = 3;
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(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpPreviousState.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
this.tlpPreviousState.Size = new System.Drawing.Size(272, 236);
this.tlpPreviousState.TabIndex = 9;
//
// baseControl2
//
this.baseControl2.Location = new System.Drawing.Point(242, 3);
this.baseControl2.Name = "baseControl2";
this.baseControl2.Size = new System.Drawing.Size(6, 6);
this.baseControl2.TabIndex = 18;
//
// 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.Play;
this.picNextGame.Location = new System.Drawing.Point(242, 13);
this.picNextGame.Location = new System.Drawing.Point(242, 35);
this.picNextGame.Name = "picNextGame";
this.picNextGame.Size = new System.Drawing.Size(27, 200);
this.picNextGame.Size = new System.Drawing.Size(27, 188);
this.picNextGame.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.picNextGame.TabIndex = 11;
this.picNextGame.TabStop = false;
@ -78,34 +93,87 @@
this.picPrevGame.Cursor = System.Windows.Forms.Cursors.Hand;
this.picPrevGame.Dock = System.Windows.Forms.DockStyle.Left;
this.picPrevGame.Image = global::Mesen.GUI.Properties.Resources.Play;
this.picPrevGame.Location = new System.Drawing.Point(3, 13);
this.picPrevGame.Location = new System.Drawing.Point(3, 35);
this.picPrevGame.Name = "picPrevGame";
this.picPrevGame.Size = new System.Drawing.Size(27, 200);
this.picPrevGame.Size = new System.Drawing.Size(27, 188);
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);
//
// tlpGrid
//
this.tlpGrid.BackColor = System.Drawing.Color.Black;
this.tlpGrid.ColumnCount = 2;
this.tlpGrid.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpGrid.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpGrid.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpGrid.Location = new System.Drawing.Point(33, 10);
this.tlpGrid.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.tlpGrid.Location = new System.Drawing.Point(33, 32);
this.tlpGrid.Margin = new System.Windows.Forms.Padding(0);
this.tlpGrid.Name = "tlpGrid";
this.tlpGrid.RowCount = 2;
this.tlpGrid.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpGrid.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpGrid.Size = new System.Drawing.Size(206, 206);
this.tlpGrid.Size = new System.Drawing.Size(206, 194);
this.tlpGrid.TabIndex = 13;
//
// tlpTitle
//
this.tlpTitle.BackColor = System.Drawing.Color.Black;
this.tlpTitle.ColumnCount = 2;
this.tlpTitle.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpTitle.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlpTitle.Controls.Add(this.lblScreenTitle, 0, 0);
this.tlpTitle.Controls.Add(this.picClose, 1, 0);
this.tlpTitle.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpTitle.Location = new System.Drawing.Point(33, 0);
this.tlpTitle.Margin = new System.Windows.Forms.Padding(0);
this.tlpTitle.Name = "tlpTitle";
this.tlpTitle.RowCount = 1;
this.tlpTitle.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpTitle.Size = new System.Drawing.Size(206, 32);
this.tlpTitle.TabIndex = 16;
//
// lblScreenTitle
//
this.lblScreenTitle.Anchor = System.Windows.Forms.AnchorStyles.None;
this.lblScreenTitle.AutoSize = true;
this.lblScreenTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblScreenTitle.ForeColor = System.Drawing.Color.White;
this.lblScreenTitle.Location = new System.Drawing.Point(58, 7);
this.lblScreenTitle.Margin = new System.Windows.Forms.Padding(35, 0, 3, 0);
this.lblScreenTitle.Name = "lblScreenTitle";
this.lblScreenTitle.Size = new System.Drawing.Size(89, 18);
this.lblScreenTitle.TabIndex = 14;
this.lblScreenTitle.Text = "Load State";
this.lblScreenTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// picClose
//
this.picClose.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picClose.Cursor = System.Windows.Forms.Cursors.Hand;
this.picClose.Image = global::Mesen.GUI.Properties.Resources.CloseWhite;
this.picClose.Location = new System.Drawing.Point(174, 0);
this.picClose.Margin = new System.Windows.Forms.Padding(0);
this.picClose.Name = "picClose";
this.picClose.Padding = new System.Windows.Forms.Padding(8);
this.picClose.Size = new System.Drawing.Size(32, 32);
this.picClose.TabIndex = 15;
this.picClose.TabStop = false;
this.picClose.Click += new System.EventHandler(this.picClose_Click);
//
// baseControl1
//
this.baseControl1.Location = new System.Drawing.Point(3, 3);
this.baseControl1.Name = "baseControl1";
this.baseControl1.Size = new System.Drawing.Size(6, 6);
this.baseControl1.TabIndex = 17;
//
// tmrInput
//
this.tmrInput.Interval = 50;
this.tmrInput.Tick += new System.EventHandler(this.tmrInput_Tick);
//
// ctrlRecentGames
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -117,6 +185,9 @@
this.tlpPreviousState.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picNextGame)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picPrevGame)).EndInit();
this.tlpTitle.ResumeLayout(false);
this.tlpTitle.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picClose)).EndInit();
this.ResumeLayout(false);
}
@ -128,5 +199,10 @@
private System.Windows.Forms.PictureBox picPrevGame;
private System.Windows.Forms.Timer tmrInput;
private DBTableLayoutPanel tlpGrid;
}
private System.Windows.Forms.Label lblScreenTitle;
private System.Windows.Forms.PictureBox picClose;
private DBTableLayoutPanel tlpTitle;
private BaseControl baseControl2;
private BaseControl baseControl1;
}
}

View file

@ -9,9 +9,6 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Mesen.GUI.Config;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.IO.Compression;
using Mesen.GUI.Forms;
using Mesen.GUI.Controls;
@ -19,29 +16,30 @@ namespace Mesen.GUI.Controls
{
public partial class ctrlRecentGames : BaseControl
{
private int _elementsPerRow = 0;
private int _columnCount = 0;
private int _rowCount = 0;
private int _elementsPerPage = 0;
private bool _needResume = false;
private int _currentIndex = 0;
private List<RecentGameInfo> _recentGames = new List<RecentGameInfo>();
private List<ctrlRecentGame> _controls = new List<ctrlRecentGame>();
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; }
add { this.tlpPreviousState.MouseMove += value; this.tlpTitle.MouseMove += value; }
remove { this.tlpPreviousState.MouseMove -= value; this.tlpTitle.MouseMove -= value; }
}
public new event EventHandler DoubleClick
{
add { this.tlpPreviousState.DoubleClick += value; }
remove { this.tlpPreviousState.DoubleClick -= value; }
add { this.tlpPreviousState.DoubleClick += value; this.tlpTitle.DoubleClick += value; }
remove { this.tlpPreviousState.DoubleClick -= value; this.tlpTitle.DoubleClick -= value; }
}
private bool _initialized = false;
private int _currentIndex = 0;
private List<RecentGameInfo> _recentGames = new List<RecentGameInfo>();
private List<ctrlRecentGame> _controls = new List<ctrlRecentGame>();
public ctrlRecentGames()
{
InitializeComponent();
@ -56,40 +54,50 @@ namespace Mesen.GUI.Controls
private void InitGrid()
{
int elementsPerRow = 1;
int columnCount = 1;
if(ClientSize.Width > 850 && ClientSize.Height > 850) {
elementsPerRow = 3;
columnCount = 3;
} else if(ClientSize.Width > 450 && ClientSize.Height > 450) {
elementsPerRow = 2;
columnCount = 2;
}
if(_recentGames.Count <= 1) {
elementsPerRow = 1;
columnCount = 1;
} else if(_recentGames.Count <= 4) {
elementsPerRow = Math.Min(2, elementsPerRow);
columnCount = Math.Min(2, columnCount);
}
if(_elementsPerRow == elementsPerRow) {
int elementsPerPage = columnCount * columnCount;
int rowCount = columnCount;
if(Mode != GameScreenMode.RecentGames) {
elementsPerPage = 12;
columnCount = 4;
rowCount = 3;
}
if(_columnCount == columnCount && _elementsPerPage == elementsPerPage && _rowCount == rowCount) {
return;
}
_elementsPerRow = elementsPerRow;
_elementsPerPage = elementsPerRow * elementsPerRow;
_columnCount = columnCount;
_rowCount = rowCount;
_elementsPerPage = elementsPerPage;
_controls = new List<ctrlRecentGame>();
tlpGrid.SuspendLayout();
tlpGrid.ColumnCount = _elementsPerRow;
tlpGrid.RowCount = _elementsPerRow;
tlpGrid.ColumnCount = _columnCount;
tlpGrid.RowCount = _rowCount;
tlpGrid.ColumnStyles.Clear();
tlpGrid.RowStyles.Clear();
tlpGrid.Controls.Clear();
for(int j = 0; j < _elementsPerRow; j++) {
tlpGrid.RowStyles.Add(new RowStyle(SizeType.Percent, 100F / _elementsPerRow));
tlpGrid.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F / _elementsPerRow));
for(int j = 0; j < _columnCount; j++) {
tlpGrid.RowStyles.Add(new RowStyle(SizeType.Percent, 100F / _columnCount));
tlpGrid.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F / _columnCount));
}
for(int j = 0; j < _elementsPerRow; j++) {
for(int i = 0; i < _elementsPerRow; i++) {
for(int j = 0; j < _rowCount; j++) {
for(int i = 0; i < _columnCount; i++) {
ctrlRecentGame ctrl = new ctrlRecentGame();
ctrl.OnRecentGameLoaded += RecentGameLoaded;
ctrl.Dock = DockStyle.Fill;
@ -105,45 +113,59 @@ namespace Mesen.GUI.Controls
picNextGame.Visible = _recentGames.Count > _elementsPerPage;
}
public new bool Visible
{
get { return base.Visible; }
set
{
if(value && ((_initialized && _recentGames.Count == 0) || ConfigManager.Config.PreferenceInfo.DisableGameSelectionScreen)) {
value = false;
}
if(value != base.Visible) {
if(value && !_initialized) {
//We just re-enabled the screen, initialize it
Initialize();
}
InitGrid();
base.Visible = value;
tmrInput.Enabled = value;
}
}
}
public int GameCount
{
get { return _recentGames.Count; }
}
public void Initialize()
public GameScreenMode Mode { get; private set; } = GameScreenMode.RecentGames;
private bool Pause()
{
_initialized = true;
if(!InteropEmu.IsPaused()) {
InteropEmu.Pause();
return true;
}
return false;
}
public void ShowScreen(GameScreenMode mode)
{
if(mode == GameScreenMode.RecentGames && ConfigManager.Config.PreferenceInfo.DisableGameSelectionScreen) {
this.Visible = false;
return;
} else if(mode != GameScreenMode.RecentGames && Mode == mode && this.Visible) {
this.Visible = false;
if(_needResume) {
InteropEmu.Resume();
}
return;
}
Mode = mode;
_recentGames = new List<RecentGameInfo>();
_currentIndex = 0;
List<string> files = Directory.GetFiles(ConfigManager.RecentGamesFolder, "*.rgd").OrderByDescending((file) => new FileInfo(file).LastWriteTime).ToList();
for(int i = 0; i < files.Count && _recentGames.Count < 36; i++) {
try {
RecentGameInfo info = new RecentGameInfo();
info.FileName = files[i];
_recentGames.Add(info);
} catch { }
if(mode == GameScreenMode.RecentGames) {
_needResume = false;
tlpTitle.Visible = false;
List<string> files = Directory.GetFiles(ConfigManager.RecentGamesFolder, "*.rgd").OrderByDescending((file) => new FileInfo(file).LastWriteTime).ToList();
for(int i = 0; i < files.Count && _recentGames.Count < 36; i++) {
_recentGames.Add(new RecentGameInfo() { FileName = files[i] });
}
} else {
if(!this.Visible) {
_needResume = Pause();
}
lblScreenTitle.Text = mode == GameScreenMode.LoadState ? ResourceHelper.GetMessage("LoadStateDialog") : ResourceHelper.GetMessage("SaveStateDialog");
tlpTitle.Visible = true;
string romName = InteropEmu.GetRomInfo().GetRomName();
for(int i = 0; i < 11; i++) {
_recentGames.Add(new RecentGameInfo() { FileName = Path.Combine(ConfigManager.SaveStateFolder, romName + "_" + (i + 1) + ".mst"), Name = i == 10 ? ResourceHelper.GetMessage("AutoSave") : ResourceHelper.GetMessage("SlotNumber", i+1) });
}
_recentGames.Add(new RecentGameInfo() { FileName = Path.Combine(ConfigManager.RecentGamesFolder, romName + ".rgd"), Name = ResourceHelper.GetMessage("LastSession") });
}
InitGrid();
@ -158,18 +180,16 @@ namespace Mesen.GUI.Controls
picPrevGame.Visible = _recentGames.Count > _elementsPerPage;
picNextGame.Visible = _recentGames.Count > _elementsPerPage;
this.Visible = true;
}
public void UpdateGameInfo()
{
if(!_initialized) {
return;
}
int count = _recentGames.Count;
int pageStart = _currentIndex / _elementsPerPage * _elementsPerPage;
for(int i = 0; i < _elementsPerPage; i++) {
_controls[i].Mode = Mode;
_controls[i].RecentGame = count > pageStart + i ? _recentGames[pageStart + i] : null;
_controls[i].Highlight = (_currentIndex % _elementsPerPage) == i;
}
@ -185,7 +205,7 @@ namespace Mesen.GUI.Controls
picPrevGame.Dock = DockStyle.Fill;
}
if(this._elementsPerRow > 0) {
if(this._columnCount > 0) {
InitGrid();
}
base.OnResize(e);
@ -223,22 +243,24 @@ namespace Mesen.GUI.Controls
UpdateGameInfo();
}
private void LoadSelectedGame()
{
InteropEmu.LoadRecentGame(_recentGames[_currentIndex].FileName, ConfigManager.Config.PreferenceInfo.GameSelectionScreenResetGame);
OnRecentGameLoaded?.Invoke(_recentGames[_currentIndex]);
}
private void RecentGameLoaded(RecentGameInfo gameInfo)
{
OnRecentGameLoaded?.Invoke(gameInfo);
if(this._needResume) {
InteropEmu.Resume();
}
this.Visible = false;
}
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 && !InteropEmu.IsRunning()) {
if(Application.OpenForms.Count > 0 && Application.OpenForms[0].ContainsFocus && this.Visible) {
if(Mode != GameScreenMode.RecentGames && !InteropEmu.IsPaused()) {
this.Visible = false;
return;
}
List<uint> keyCodes = InteropEmu.GetPressedKeys();
uint keyCode = keyCodes.Count > 0 ? keyCodes[0] : 0;
if(keyCode > 0) {
@ -258,23 +280,23 @@ namespace Mesen.GUI.Controls
UpdateGameInfo();
} else if(mapping.Down == keyCode) {
_waitForRelease = true;
if(_currentIndex + _elementsPerRow < _recentGames.Count) {
_currentIndex += _elementsPerRow;
if(_currentIndex + _columnCount < _recentGames.Count) {
_currentIndex += _columnCount;
} else {
_currentIndex = IsOnLastPage ? 0 : (_recentGames.Count - 1);
_currentIndex = Math.Min(_currentIndex % _columnCount, _recentGames.Count - 1);
}
UpdateGameInfo();
} else if(mapping.Up == keyCode) {
_waitForRelease = true;
if(_currentIndex < _elementsPerRow) {
_currentIndex = _recentGames.Count - 1;
if(_currentIndex < _columnCount) {
_currentIndex = _recentGames.Count - (_columnCount - (_currentIndex % _columnCount));
} else {
_currentIndex -= _elementsPerRow;
_currentIndex -= _columnCount;
}
UpdateGameInfo();
} else if(mapping.A == keyCode || mapping.B == keyCode || mapping.Select == keyCode || mapping.Start == keyCode) {
_waitForRelease = true;
LoadSelectedGame();
_controls[_currentIndex % _elementsPerPage].ProcessClick();
}
}
}
@ -283,6 +305,14 @@ namespace Mesen.GUI.Controls
}
}
}
private void picClose_Click(object sender, EventArgs e)
{
if(_needResume) {
InteropEmu.Resume();
}
this.Visible = false;
}
}
public class DBTableLayoutPanel : TableLayoutPanel
@ -293,56 +323,17 @@ namespace Mesen.GUI.Controls
}
}
public class GamePreviewBox : PictureBox
{
public InterpolationMode InterpolationMode { get; set; }
private bool _hovered = false;
private bool _highlight = false;
public GamePreviewBox()
{
DoubleBuffered = true;
InterpolationMode = InterpolationMode.Default;
}
public bool Highlight
{
get { return _highlight; }
set
{
_highlight = value;
this.Invalidate();
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_hovered = true;
this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_hovered = false;
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
base.OnPaint(pe);
using(Pen pen = new Pen(_hovered ? Color.DeepSkyBlue : (_highlight ? Color.DodgerBlue : Color.DimGray), 2)) {
pe.Graphics.DrawRectangle(pen, 1, 1, this.Width - 2, this.Height - 2);
}
}
}
public class RecentGameInfo
{
public string FileName { get; set; }
public string Name { get; set; }
public ResourcePath RomPath { get; set; }
}
public enum GameScreenMode
{
RecentGames,
LoadState,
SaveState
}
}

View file

@ -762,6 +762,12 @@
<Message ID="FilterSavestate">Partides guardades de Mesen (*.mst)|*.mst|Tots els fitxers (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Fitxers de cassets Family Basic (*.fbt)|*.fbt|Tots els fitxers (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Carrega des d'un fitxer...</Message>
<Message ID="SaveToFile">Desa al fitxer...</Message>
@ -921,6 +927,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Desa la partida - Posició 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Desa la partida - Posició 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Desa la partida a un fitxer</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Carrega la partida - Posició 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Carrega la partida - Posició 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Carrega la partida - Posició 3</Message>
@ -933,6 +940,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Carrega la partida - Posició 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Load State - Auto Save Slot</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Carrega la partida des d'un fitxer</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Load Last Session</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -792,6 +792,12 @@
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All files (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basic Tape files (*.fbt)|*.fbt|All Files (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
@ -955,6 +961,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Save State - Slot 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Save State - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Save State to File</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Load State - Slot 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Load State - Slot 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Load State - Slot 3</Message>
@ -967,6 +974,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Load State - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Load State - Auto Save Slot</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Load State from File</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Load Last Session</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -779,6 +779,12 @@
<Message ID="FilterSavestate">Partidas de juegos de Mesen (*.mst)|*.mst|Todos los archivos (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Archivos Family Basic Tape (*.fbt)|*.fbt|Todos los archivos (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Cargar desde archivo...</Message>
<Message ID="SaveToFile">Guardar en archivo...</Message>
@ -938,6 +944,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Guardar partida - Hueco 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Guardar partida - Hueco 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Guardar partida en archivo</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Cargar partida - Hueco 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Cargar partida - Hueco 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Cargar partida - Hueco 3</Message>
@ -950,6 +957,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Cargar partida - Hueco 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Cargar partida - Hueco de auto guardado</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Cargar partida de archivo</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Cargar última sesión</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -792,6 +792,12 @@
<Message ID="FilterSavestate">Sauvegardes d'états Mesen (*.mst)|*.mst|Tous les fichiers (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Fichiers de cassettes Family Basic (*.fbt)|*.fbt|Tous les fichiers (*.*)|*.*</Message>
<Message ID="LastSession">Session précédente</Message>
<Message ID="AutoSave">Sauvegarde auto.</Message>
<Message ID="SlotNumber">Position #{0}</Message>
<Message ID="LoadStateDialog">Menu de chargement rapide</Message>
<Message ID="SaveStateDialog">Menu de sauvegarde rapide</Message>
<Message ID="LoadFromFile">Charger à partir d'un fichier...</Message>
<Message ID="SaveToFile">Sauvegarder dans un fichier...</Message>
@ -844,7 +850,7 @@
<Message ID="NsfUnknownField">[inconnu]</Message>
<Message ID="CouldNotInstallRuntime">Le package Redistribuable Visual C++ pour Visual Studio 2015 n'a pas été installé correctement.</Message>
<Message ID="EmptyState">&lt;aucune sauvegarde&gt;</Message>
<Message ID="EmptyState">&lt;vide&gt;</Message>
<Message ID="ErrorWhileCheckingUpdates">Une erreur s'est produite lors de la recherche de mises-à-jour. Vérifier votre connexion internet et essayez à nouveau.&#xA;&#xA;Détails de l'erreur :&#xA;{0}</Message>
<Message ID="AutoUpdateDisabledMessage">Les mises-à-jour automatiques ne sont pas disponibles avec votre build - s.v.p télécharger la dernière version du code et recompiler Mesen pour avoir accès à la version la plus récente.</Message>
<Message ID="BiosNotFound">Un bios est requis pour ce jeu.&#xA;&#xA; Nom du fichier : {0}&#xA; Taille : {1} octets&#xA;&#xA;Voulez-vous choisir le fichier bios maintenant?</Message>
@ -952,6 +958,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Sauvegarde d'état - Position 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Sauvegarde d'état - Position 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Sauvergarde l'état dans un fichier</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Ouvrir le menu de sauvegarde rapide</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Chargement d'état - Position 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Chargement d'état - Position 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Chargement d'état - Position 3</Message>
@ -964,6 +971,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Chargement d'état - Position 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Chargement d'état - Sauvegarde auto</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Charger l'état à partir d'un fichier</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Ouvrir le menu de chargement rapide</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Charger la session précédente</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Choisir position de sauvegarde 1</Message>

View file

@ -792,6 +792,12 @@
<Message ID="FilterSavestate">Mesen Savestati (*.mst)|*.mst|All files (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basic Tape file (*.fbt)|*.fbt|All Files (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Carica da file...</Message>
<Message ID="SaveToFile">Salva su file...</Message>
@ -954,6 +960,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Salva Stato - Slot 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Salva Stato - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Salva Stato su File</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Carica Stato - Slot 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Carica Stato - Slot 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Carica Stato - Slot 3</Message>
@ -966,6 +973,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Carica Stato - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Carica Stato - Slot Salvataggio Automatico</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Carica Stato da File</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Carica Ultima Sessione</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -780,6 +780,12 @@
<Message ID="FilterSavestate">Mesenのクイックセーブデータ (*.mst)|*.mst|すべてのファイル (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basicテープファイル (*.fbt)|*.fbt|すべてのファイル (*.*)|*.*</Message>
<Message ID="LastSession">前セッション</Message>
<Message ID="AutoSave">オートクイックセーブ</Message>
<Message ID="SlotNumber">スロット {0}</Message>
<Message ID="LoadStateDialog">クイックロードメニュー</Message>
<Message ID="SaveStateDialog">クイックセーブメニュー</Message>
<Message ID="LoadFromFile">ファイルからロードする…</Message>
<Message ID="SaveToFile">ファイルに保存する…</Message>
@ -940,6 +946,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">クイックセーブスロット9に保存する</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">クイックセーブスロット10に保存する</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">クイックセーブデータをファイルに保存する</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">クイックセーブメニューを開く</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">クイックセーブスロット1からロードする</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">クイックセーブスロット2からロードする</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">クイックセーブスロット3からロードする</Message>
@ -952,6 +959,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">クイックセーブスロット10からロードする</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">自動クイックセーブスロットからロードする</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">クイックセーブデータをファイルからロードする</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">クイックロードメニューを開く</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">前セッションをロードする</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">クイックセーブスロット1を選ぶ</Message>

View file

@ -792,6 +792,12 @@
<Message ID="FilterSavestate">Estados salvos do Mesen (*.mst)|*.mst|Todos os arquivos (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Arquivos Family Basic Tape (*.fbt)|*.fbt|Todos os arquivos (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Carregar de um arquivo...</Message>
<Message ID="SaveToFile">Salvar para arquivo...</Message>
@ -954,6 +960,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Salvar estado - Compartimento 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Salvar estado - Compartimento 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Salvar estado para arquivo</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Carregar estado - Compartimento 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Carregar estado - Compartimento 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Carregar estado - Compartimento 3</Message>
@ -966,6 +973,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Carregar estado - Compartimento 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Carregar estado - Compartimento de salvamento automático</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Carregar estado de arquivo</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Carregar a última sessão</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -780,6 +780,12 @@
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All Files (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basic Tape files (*.fbt)|*.fbt|All Files (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Load from file...</Message>
<Message ID="SaveToFile">Save to file...</Message>
@ -940,6 +946,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Save State - Slot 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Save State - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Save State to File</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Load State - Slot 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Load State - Slot 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Load State - Slot 3</Message>
@ -952,6 +959,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Load State - Slot 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Load State - Auto Save Slot</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Load State from File</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Load Last Session</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -780,6 +780,12 @@
<Message ID="FilterSavestate">Mesen Savestates (*.mst)|*.mst|All Files (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basic Tape files (*.fbt)|*.fbt|All Files (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">Завантажитти з файлу...</Message>
<Message ID="SaveToFile">Зберегти в файл...</Message>
@ -940,6 +946,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">Збереження стану - Слот 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">Збереження стану - Слот 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">Зберегти стан в файл</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">Завантаження стану - Слот 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">Завантаження стану - Слот 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">Завантаження стану - Слот 3</Message>
@ -952,6 +959,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">Завантаження стану - Слот 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">Завантаження стану - Автозавантаження</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">Завантажити стан з файлу</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">Завантажити останню сесію</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">Select Save Slot 1</Message>

View file

@ -805,6 +805,12 @@
<Message ID="FilterSavestate">Mesen 进度 (*.mst)|*.mst|所有文件 (*.*)|*.*</Message>
<Message ID="FilterTapeFiles">Family Basic 磁带文件 (*.fbt)|*.fbt|所有文件 (*.*)|*.*</Message>
<Message ID="LastSession">Last Session</Message>
<Message ID="AutoSave">Auto-save</Message>
<Message ID="SlotNumber">Slot #{0}</Message>
<Message ID="LoadStateDialog">Load State Menu</Message>
<Message ID="SaveStateDialog">Save State Menu</Message>
<Message ID="LoadFromFile">从文件载入...</Message>
<Message ID="SaveToFile">保存到文件...</Message>
@ -961,6 +967,7 @@
<Message ID="EmulatorShortcutMappings_SaveStateSlot9">保存进度 9</Message>
<Message ID="EmulatorShortcutMappings_SaveStateSlot10">保存进度 10</Message>
<Message ID="EmulatorShortcutMappings_SaveStateToFile">进度另存为</Message>
<Message ID="EmulatorShortcutMappings_SaveStateDialog">Open Save State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot1">载入进度 1</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot2">载入进度 2</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlot3">载入进度 3</Message>
@ -973,6 +980,7 @@
<Message ID="EmulatorShortcutMappings_LoadStateSlot10">载入进度 10</Message>
<Message ID="EmulatorShortcutMappings_LoadStateSlotAuto">载入自动进度</Message>
<Message ID="EmulatorShortcutMappings_LoadStateFromFile">载入进度文件</Message>
<Message ID="EmulatorShortcutMappings_LoadStateDialog">Open Load State Menu</Message>
<Message ID="EmulatorShortcutMappings_LoadLastSession">载入上次会话</Message>
<Message ID="EmulatorShortcutMappings_SelectSaveSlot1">选择进度槽 1</Message>

View file

@ -104,6 +104,7 @@ namespace Mesen.GUI.Forms.Config
EmulatorShortcut.SaveStateSlot9,
EmulatorShortcut.SaveStateSlot10,
EmulatorShortcut.SaveStateToFile,
EmulatorShortcut.SaveStateDialog,
EmulatorShortcut.LoadStateSlot1,
EmulatorShortcut.LoadStateSlot2,
@ -117,6 +118,7 @@ namespace Mesen.GUI.Forms.Config
EmulatorShortcut.LoadStateSlot10,
EmulatorShortcut.LoadStateSlotAuto,
EmulatorShortcut.LoadStateFromFile,
EmulatorShortcut.LoadStateDialog,
EmulatorShortcut.SelectSaveSlot1,
EmulatorShortcut.SelectSaveSlot2,

View file

@ -63,14 +63,23 @@ namespace Mesen.GUI.Forms
menu.DropDownItems.Add("-");
addSaveStateInfo(NumberOfSaveSlots+1);
menu.DropDownItems.Add("-");
ToolStripMenuItem loadDialog = new ToolStripMenuItem(ResourceHelper.GetMessage("LoadStateDialog"), Resources.SplitView);
menu.DropDownItems.Add(loadDialog);
BindShortcut(loadDialog, EmulatorShortcut.LoadStateDialog, () => _emuThread != null && !InteropEmu.IsConnected() && !InteropEmu.IsNsf());
ToolStripMenuItem loadFromFile = new ToolStripMenuItem(ResourceHelper.GetMessage("LoadFromFile"), Resources.FolderOpen);
menu.DropDownItems.Add(loadFromFile);
BindShortcut(loadFromFile, EmulatorShortcut.LoadStateFromFile);
} else {
menu.DropDownItems.Add("-");
ToolStripMenuItem saveDialog = new ToolStripMenuItem(ResourceHelper.GetMessage("SaveStateDialog"), Resources.SplitView);
menu.DropDownItems.Add(saveDialog);
BindShortcut(saveDialog, EmulatorShortcut.SaveStateDialog, () => _emuThread != null && !InteropEmu.IsConnected() && !InteropEmu.IsNsf());
ToolStripMenuItem saveToFile = new ToolStripMenuItem(ResourceHelper.GetMessage("SaveToFile"), Resources.Floppy);
menu.DropDownItems.Add(saveToFile);
BindShortcut(saveToFile, EmulatorShortcut.SaveStateToFile);
BindShortcut(saveToFile, EmulatorShortcut.SaveStateToFile);
}
}

View file

@ -145,8 +145,9 @@ namespace Mesen.GUI.Forms
ResourceHelper.ApplyResources(this);
UpdateMenus();
InitializeNsfMode();
ctrlRecentGames.Visible = _emuThread == null;
ctrlRecentGames.UpdateGameInfo();
if(_emuThread == null) {
ShowRecentGames();
}
TopMost = ConfigManager.Config.PreferenceInfo.AlwaysOnTop;
FormBorderStyle = ConfigManager.Config.PreferenceInfo.DisableMouseResize ? FormBorderStyle.Fixed3D : FormBorderStyle.Sizable;
} else {

View file

@ -14,6 +14,7 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using Mesen.GUI.Config;
using Mesen.GUI.Controls;
using Mesen.GUI.Debugger;
using Mesen.GUI.Forms.Cheats;
using Mesen.GUI.Forms.Config;
@ -53,7 +54,6 @@ namespace Mesen.GUI.Forms
private object _loadRomLock = new object();
private int _romLoadCounter = 0;
private bool _showUpgradeMessage = false;
private float _yFactor = 1;
private bool _enableResize = false;
private bool _overrideWindowSize = false;
private bool _shuttingDown = false;
@ -301,8 +301,9 @@ namespace Mesen.GUI.Forms
ProcessFullscreenSwitch(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, true));
ctrlRecentGames.Initialize();
ctrlRecentGames.Visible = _emuThread == null;
if(_emuThread == null) {
ShowRecentGames();
}
}
protected override void OnClosing(CancelEventArgs e)
@ -460,15 +461,15 @@ namespace Mesen.GUI.Forms
}
}
protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
_yFactor = factor.Height;
base.ScaleControl(factor, specified);
}
private void ResizeRecentGames(object sender, EventArgs e)
{
ctrlRecentGames.Height = this.ClientSize.Height - ctrlRecentGames.Top - (ctrlRecentGames.Mode == GameScreenMode.RecentGames ? 25 : 0);
}
private void ShowRecentGames()
{
ctrlRecentGames.Height = this.ClientSize.Height - ctrlRecentGames.Top - 25;
ctrlRecentGames.ShowScreen(GameScreenMode.RecentGames);
}
private void frmMain_Resize(object sender, EventArgs e)
@ -707,7 +708,7 @@ namespace Mesen.GUI.Forms
case InteropEmu.ConsoleNotificationType.EmulationStopped:
InitializeNsfMode();
this.BeginInvoke((Action)(() => {
ctrlRecentGames.Visible = true;
ShowRecentGames();
}));
break;
@ -718,10 +719,6 @@ namespace Mesen.GUI.Forms
_hdPackEditorWindow.Close();
}
if(e.Parameter == IntPtr.Zero) {
if(!ConfigManager.Config.PreferenceInfo.DisableGameSelectionScreen) {
ctrlRecentGames.Initialize();
}
//We are completely stopping the emulation, close fullscreen mode
StopExclusiveFullscreenMode();
}
@ -983,6 +980,24 @@ namespace Mesen.GUI.Forms
case EmulatorShortcut.LoadStateFromFile: LoadStateFromFile(); break;
case EmulatorShortcut.SaveStateToFile: SaveStateToFile(); break;
case EmulatorShortcut.LoadStateDialog:
if(_frmFullscreenRenderer != null) {
this.SetFullscreenState(false);
restoreFullscreen = false;
}
ctrlRecentGames.ShowScreen(GameScreenMode.LoadState);
ctrlRecentGames.Height = this.ClientSize.Height - ctrlRecentGames.Top;
break;
case EmulatorShortcut.SaveStateDialog:
if(_frmFullscreenRenderer != null) {
this.SetFullscreenState(false);
restoreFullscreen = false;
}
ctrlRecentGames.ShowScreen(GameScreenMode.SaveState);
ctrlRecentGames.Height = this.ClientSize.Height - ctrlRecentGames.Top;
break;
case EmulatorShortcut.SaveStateSlot1: SaveState(1); break;
case EmulatorShortcut.SaveStateSlot2: SaveState(2); break;
case EmulatorShortcut.SaveStateSlot3: SaveState(3); break;

View file

@ -1965,6 +1965,7 @@
<None Include="Resources\BreakpointEnableDisable.png" />
<None Include="Resources\ArrowKeys.png" />
<None Include="Resources\Barcode.png" />
<None Include="Resources\CloseWhite.png" />
<Content Include="Resources\coins.png" />
<None Include="Resources\DipSwitches.png" />
<None Include="Resources\MesenIcon.png" />

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
@ -147,6 +148,21 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void SaveStateFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath);
[DllImport(DLLPath)] public static extern void LoadStateFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath);
[DllImport(DLLPath)] public static extern Int64 GetStateInfo(UInt32 stateIndex);
[DllImport(DLLPath, EntryPoint = "GetSaveStatePreview")] private static extern Int32 GetSaveStatePreviewWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string saveStatePath, [Out]byte[] imgData);
public static Image GetSaveStatePreview(string saveStatePath)
{
if(File.Exists(saveStatePath)) {
byte[] buffer = new byte[new FileInfo(saveStatePath).Length];
Int32 size = InteropEmu.GetSaveStatePreviewWrapper(saveStatePath, buffer);
if(size > 0) {
Array.Resize(ref buffer, size);
using(MemoryStream stream = new MemoryStream(buffer)) {
return Image.FromStream(stream);
}
}
}
return null;
}
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsNsf();
[DllImport(DLLPath)] public static extern void NsfSelectTrack(Byte trackNumber);
@ -1976,6 +1992,7 @@ namespace Mesen.GUI
SaveStateSlot9,
SaveStateSlot10,
SaveStateToFile,
SaveStateDialog,
LoadStateSlot1,
LoadStateSlot2,
@ -1989,6 +2006,7 @@ namespace Mesen.GUI
LoadStateSlot10,
LoadStateSlotAuto,
LoadStateFromFile,
LoadStateDialog,
LoadLastSession,

View file

@ -19,7 +19,7 @@ namespace Mesen.GUI.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@ -190,6 +190,16 @@ namespace Mesen.GUI.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap CloseWhite {
get {
object obj = ResourceManager.GetObject("CloseWhite", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -460,4 +460,7 @@
<data name="MoveUp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\MoveUp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="CloseWhite" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CloseWhite.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

View file

@ -546,6 +546,9 @@ namespace InteropEmu {
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 int32_t __stdcall GetSaveStatePreview(char* saveStatePath, uint8_t* pngData) { return _console->GetSaveStateManager()->GetSaveStatePreview(saveStatePath, pngData); }
DllExport void __stdcall MoviePlay(char* filename) { MovieManager::Play(string(filename), _console); }