UI: Added a log window with info on loaded rom, etc. (Tools menu)

This commit is contained in:
Souryo 2016-06-19 16:54:34 -04:00
parent b359a841b6
commit 17fb20e235
13 changed files with 401 additions and 0 deletions

View file

@ -56,6 +56,9 @@ void GameDatabase::InitDatabase()
_gameDatabase[gameInfo.Crc] = gameInfo;
}
}
MessageManager::Log();
MessageManager::Log("[DB] Initialized - " + std::to_string(_gameDatabase.size()) + " games in DB");
}
}
@ -145,7 +148,9 @@ void GameDatabase::UpdateRomData(uint32_t romCrc, RomData &romData)
InitDatabase();
auto result = _gameDatabase.find(romCrc);
if(result != _gameDatabase.end()) {
MessageManager::Log("[DB] Game found in database");
GameInfo info = result->second;
romData.MapperID = info.MapperID;
@ -160,6 +165,18 @@ void GameDatabase::UpdateRomData(uint32_t romCrc, RomData &romData)
romData.MirroringType = info.Mirroring.compare("h") == 0 ? MirroringType::Horizontal : MirroringType::Vertical;
}
MessageManager::Log("[DB] Mapper: " + std::to_string(romData.MapperID) + " Sub: " + std::to_string(romData.SubMapperID));
MessageManager::Log("[DB] System : " + info.System);
if(!info.Mirroring.empty()) {
MessageManager::Log("[DB] Mirroring: " + string(info.Mirroring.compare("h") == 0 ? "Horizontal" : "Vertical"));
}
MessageManager::Log("[DB] PRG ROM: " + std::to_string(info.PrgRomSize) + " KB");
MessageManager::Log("[DB] CHR ROM: " + std::to_string(info.ChrRomSize) + " KB");
if(info.ChrRamSize > 0) {
MessageManager::Log("[DB] CHR RAM: " + std::to_string(info.ChrRamSize) + " KB");
}
MessageManager::Log("[DB] Battery: " + string(info.HasBattery ? "Yes" : "No"));
#ifdef _DEBUG
MessageManager::DisplayMessage("DB", "Mapper: " + std::to_string(romData.MapperID) + " Sub: " + std::to_string(romData.SubMapperID) + " System: " + info.System);
#endif

View file

@ -178,6 +178,8 @@ std::unordered_map<string, string> MessageManager::_jaResources = {
{ "SynchronizationCompleted", u8"同期完了。" },
};
std::list<string> MessageManager::_log;
SimpleLock MessageManager::_logLock;
IMessageManager* MessageManager::_messageManager = nullptr;
vector<INotificationListener*> MessageManager::_notificationListeners;
@ -240,6 +242,29 @@ void MessageManager::DisplayToast(string title, string message, uint8_t* iconDat
MessageManager::_messageManager->DisplayToast(shared_ptr<ToastInfo>(new ToastInfo(title, message, 4000, iconData, iconSize)));
}
}
void MessageManager::Log(string message)
{
_logLock.AcquireSafe();
if(message.empty()) {
message = "------------------------------------------------------";
}
if(_log.size() >= 1000) {
_log.pop_front();
}
_log.push_back(message);
}
string MessageManager::GetLog()
{
_logLock.AcquireSafe();
stringstream ss;
for(string &msg : _log) {
ss << msg << "\n";
}
return ss.str();
}
void MessageManager::RegisterNotificationListener(INotificationListener* notificationListener)
{
MessageManager::_notificationListeners.push_back(notificationListener);

View file

@ -5,6 +5,7 @@
#include "IMessageManager.h"
#include "INotificationListener.h"
#include <unordered_map>
#include "../Utilities/SimpleLock.h"
class MessageManager
{
@ -15,6 +16,9 @@ private:
static std::unordered_map<string, string> _frResources;
static std::unordered_map<string, string> _jaResources;
static SimpleLock _logLock;
static std::list<string> _log;
public:
static string Localize(string key);
@ -22,6 +26,9 @@ public:
static void DisplayMessage(string title, string message, string param1 = "", string param2 = "");
static void DisplayToast(string title, string message, uint8_t* iconData, uint32_t iconSize);
static void Log(string message = "");
static string GetLog();
static void RegisterNotificationListener(INotificationListener* notificationListener);
static void UnregisterNotificationListener(INotificationListener* notificationListener);
static void SendNotification(ConsoleNotificationType type, void* parameter = nullptr);

View file

@ -97,6 +97,8 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName)
fileData = IpsPatcher::PatchBuffer(_ipsFilename, fileData);
}
MessageManager::Log("");
MessageManager::Log("Loading rom: " + romName);
if(memcmp(buffer, "NES\x1a", 4) == 0) {
iNesLoader loader;
_romData = loader.LoadRom(fileData);
@ -104,6 +106,7 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName)
FdsLoader loader;
_romData = loader.LoadRom(fileData, _filename);
} else {
MessageManager::Log("Invalid rom file.");
_romData.Error = true;
}

View file

@ -42,6 +42,23 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& romFile)
buffer += header.GetPrgSize();
romData.ChrRom.insert(romData.ChrRom.end(), buffer, buffer + header.GetChrSize());
if(romData.IsNes20Header) {
MessageManager::Log("[iNes] NES 2.0 file: Yes");
}
MessageManager::Log("[iNes] Mapper: " + std::to_string(romData.MapperID) + " Sub:" + std::to_string(romData.SubMapperID));
MessageManager::Log("[iNes] PRG ROM: " + std::to_string(romData.PrgRom.size()/1024) + " KB");
MessageManager::Log("[iNes] CHR ROM: " + std::to_string(romData.ChrRom.size()/1024) + " KB");
if(romData.ChrRamSize > 0) {
MessageManager::Log("[iNes] CHR RAM: " + std::to_string(romData.ChrRamSize) + " KB");
} else if(romData.ChrRom.size() == 0) {
MessageManager::Log("[iNes] CHR RAM: 8 KB");
}
MessageManager::Log("[iNes] Mirroring: " + string(romData.MirroringType == MirroringType::Horizontal ? "Horizontal" : romData.MirroringType == MirroringType::Vertical ? "Vertical" : "Four Screens"));
MessageManager::Log("[iNes] Battery: " + string(romData.HasBattery ? "Yes" : "No"));
if(romData.HasTrainer) {
MessageManager::Log("[iNes] Trainer: Yes");
}
if(!EmulationSettings::CheckFlag(EmulationFlags::DisableGameDatabase) && header.GetRomHeaderVersion() != RomHeaderVersion::Nes2_0) {
GameDatabase::UpdateRomData(romCrc, romData);
}

108
GUI.NET/Forms/frmLogWindow.Designer.cs generated Normal file
View file

@ -0,0 +1,108 @@
namespace Mesen.GUI.Forms
{
partial class frmLogWindow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnClose = new System.Windows.Forms.Button();
this.txtLog = new System.Windows.Forms.TextBox();
this.tmrRefresh = new System.Windows.Forms.Timer(this.components);
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.txtLog, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnClose, 1, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(480, 377);
this.tableLayoutPanel1.TabIndex = 0;
//
// btnClose
//
this.btnClose.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnClose.Location = new System.Drawing.Point(407, 349);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(70, 25);
this.btnClose.TabIndex = 0;
this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// txtLog
//
this.txtLog.BackColor = System.Drawing.Color.White;
this.tableLayoutPanel1.SetColumnSpan(this.txtLog, 2);
this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtLog.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtLog.Location = new System.Drawing.Point(3, 3);
this.txtLog.Multiline = true;
this.txtLog.Name = "txtLog";
this.txtLog.ReadOnly = true;
this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtLog.Size = new System.Drawing.Size(474, 340);
this.txtLog.TabIndex = 1;
//
// tmrRefresh
//
this.tmrRefresh.Enabled = true;
this.tmrRefresh.Tick += new System.EventHandler(this.tmrRefresh_Tick);
//
// frmLogWindow
//
this.AcceptButton = this.btnClose;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnClose;
this.ClientSize = new System.Drawing.Size(480, 377);
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "frmLogWindow";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Log Window";
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TextBox txtLog;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Timer tmrRefresh;
}
}

View file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public partial class frmLogWindow : BaseForm
{
private string _currentLog;
public frmLogWindow()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
UpdateLog(InteropEmu.GetLog());
}
private void UpdateLog(string log)
{
_currentLog = log;
txtLog.Text = _currentLog;
txtLog.SelectionLength = 0;
txtLog.SelectionStart = txtLog.Text.Length;
txtLog.ScrollToCaret();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void tmrRefresh_Tick(object sender, EventArgs e)
{
string newLog = InteropEmu.GetLog();
if(_currentLog != newLog) {
UpdateLog(newLog);
}
}
}
}

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="tmrRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
</root>

View file

@ -155,6 +155,7 @@ namespace Mesen.GUI.Forms
this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator();
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
this.mnuLogWindow = new System.Windows.Forms.ToolStripMenuItem();
this.panelRenderer.SuspendLayout();
this.menuStrip.SuspendLayout();
this.SuspendLayout();
@ -857,6 +858,7 @@ namespace Mesen.GUI.Forms
this.toolStripMenuItem12,
this.mnuTests,
this.mnuDebugger,
this.mnuLogWindow,
this.toolStripMenuItem1,
this.mnuTakeScreenshot});
this.mnuTools.Name = "mnuTools";
@ -1178,6 +1180,13 @@ namespace Mesen.GUI.Forms
this.mnuAbout.Text = "About";
this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
//
// mnuLogWindow
//
this.mnuLogWindow.Name = "mnuLogWindow";
this.mnuLogWindow.Size = new System.Drawing.Size(185, 22);
this.mnuLogWindow.Text = "Log Window";
this.mnuLogWindow.Click += new System.EventHandler(this.mnuLogWindow_Click);
//
// frmMain
//
this.AllowDrop = true;
@ -1328,6 +1337,7 @@ namespace Mesen.GUI.Forms
private System.Windows.Forms.ToolStripMenuItem mnuWaveStop;
private System.Windows.Forms.ToolStripMenuItem mnuScale5x;
private System.Windows.Forms.ToolStripMenuItem mnuScale6x;
private System.Windows.Forms.ToolStripMenuItem mnuLogWindow;
}
}

View file

@ -25,6 +25,7 @@ namespace Mesen.GUI.Forms
private InteropEmu.NotificationListener _notifListener;
private Thread _emuThread;
private frmDebugger _debugger;
private frmLogWindow _logWindow;
private string _romToLoad = null;
private string _currentGame = null;
private bool _customSize = false;
@ -1330,5 +1331,21 @@ namespace Mesen.GUI.Forms
ConfigManager.Config.ApplyConfig();
ConfigManager.ApplyChanges();
}
private void mnuLogWindow_Click(object sender, EventArgs e)
{
if(_logWindow == null) {
_logWindow = new frmLogWindow();
_logWindow.StartPosition = FormStartPosition.Manual;
_logWindow.Left = this.Left + (this.Width - _logWindow.Width) / 2;
_logWindow.Top = this.Top + (this.Height - _logWindow.Height) / 2;
_logWindow.Show();
_logWindow.FormClosed += (object a, FormClosedEventArgs b) => {
_logWindow = null;
};
} else {
_logWindow.Focus();
}
}
}
}

View file

@ -445,6 +445,12 @@
<Compile Include="Forms\frmDownloadProgress.Designer.cs">
<DependentUpon>frmDownloadProgress.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmLogWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmLogWindow.Designer.cs">
<DependentUpon>frmLogWindow.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmSelectRom.cs">
<SubType>Form</SubType>
</Compile>
@ -601,6 +607,9 @@
<EmbeddedResource Include="Forms\frmDownloadProgress.resx">
<DependentUpon>frmDownloadProgress.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmLogWindow.resx">
<DependentUpon>frmLogWindow.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmMain.resx">
<DependentUpon>frmMain.cs</DependentUpon>
</EmbeddedResource>

View file

@ -73,6 +73,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void UnregisterNotificationCallback(IntPtr notificationListener);
[DllImport(DLLPath)] public static extern void DisplayMessage([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string title, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string message, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string param1 = null);
[DllImport(DLLPath, EntryPoint= "GetLog")] private static extern IntPtr GetLogWrapper();
[DllImport(DLLPath)] public static extern void MoviePlay([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename);
[DllImport(DLLPath)] public static extern void MovieRecord([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename, [MarshalAs(UnmanagedType.I1)]bool reset);
@ -304,6 +305,7 @@ namespace Mesen.GUI
return paleteData;
}
public static string GetLog() { return PtrToStringUtf8(InteropEmu.GetLogWrapper()).Replace("\n", Environment.NewLine); }
public static string GetKeyName(UInt32 key) { return PtrToStringUtf8(InteropEmu.GetKeyNameWrapper(key)); }
public static List<string> GetAudioDevices()
{

View file

@ -23,6 +23,7 @@ SoundManager *_soundManager = nullptr;
HWND _windowHandle = nullptr;
HWND _viewerHandle = nullptr;
string _returnString;
string _logString;
AutoRomTest *_autoRomTest = nullptr;
typedef void (__stdcall *NotificationListenerCallback)(int);
@ -225,6 +226,11 @@ namespace InteropEmu {
DllExport void __stdcall UnregisterNotificationCallback(INotificationListener *listener) { MessageManager::UnregisterNotificationListener(listener); }
DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) { MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); }
DllExport const char* __stdcall GetLog()
{
_logString = MessageManager::GetLog();
return _logString.c_str();
}
DllExport void __stdcall SaveState(uint32_t stateIndex) { SaveStateManager::SaveState(stateIndex); }
DllExport uint32_t __stdcall LoadState(uint32_t stateIndex) { return SaveStateManager::LoadState(stateIndex); }