Imported some code from Mesen (video, audio, UI, etc.) + basic trace logger/step functionality

This commit is contained in:
Sour 2019-02-12 22:13:09 -05:00
parent 5e7eebe078
commit 5c19584019
214 changed files with 15854 additions and 94 deletions

202
Core/BaseRenderer.cpp Normal file
View file

@ -0,0 +1,202 @@
#include "stdafx.h"
#include <cmath>
#include "BaseRenderer.h"
#include "Console.h"
#include "MessageManager.h"
BaseRenderer::BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager)
{
_console = console;
if(registerAsMessageManager) {
//Only display messages on the master CPU's screen
MessageManager::RegisterMessageManager(this);
}
}
BaseRenderer::~BaseRenderer()
{
MessageManager::UnregisterMessageManager(this);
}
void BaseRenderer::DisplayMessage(string title, string message)
{
shared_ptr<ToastInfo> toast(new ToastInfo(title, message, 4000));
_toasts.push_front(toast);
}
void BaseRenderer::RemoveOldToasts()
{
_toasts.remove_if([](shared_ptr<ToastInfo> toast) { return toast->IsToastExpired(); });
}
void BaseRenderer::DrawToasts()
{
RemoveOldToasts();
int counter = 0;
int lastHeight = 5;
for(shared_ptr<ToastInfo> toast : _toasts) {
if(counter < 6) {
DrawToast(toast, lastHeight);
} else {
break;
}
counter++;
}
}
std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount)
{
using std::wstring;
wstring text = utf8::utf8::decode(utf8Text);
wstring wrappedText;
list<wstring> words;
wstring currentWord;
for(size_t i = 0, len = text.length(); i < len; i++) {
if(text[i] == L' ' || text[i] == L'\n') {
if(currentWord.length() > 0) {
words.push_back(currentWord);
currentWord.clear();
}
} else {
currentWord += text[i];
}
}
if(currentWord.length() > 0) {
words.push_back(currentWord);
}
lineCount = 1;
float spaceWidth = MeasureString(L" ");
float lineWidth = 0.0f;
for(wstring word : words) {
for(unsigned int i = 0; i < word.size(); i++) {
if(!ContainsCharacter(word[i])) {
word[i] = L'?';
}
}
float wordWidth = MeasureString(word.c_str());
if(lineWidth + wordWidth < maxLineWidth) {
wrappedText += word + L" ";
lineWidth += wordWidth + spaceWidth;
} else {
wrappedText += L"\n" + word + L" ";
lineWidth = wordWidth + spaceWidth;
lineCount++;
}
}
return wrappedText;
}
void BaseRenderer::DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight)
{
//Get opacity for fade in/out effect
uint8_t opacity = (uint8_t)(toast->GetOpacity()*255);
int textLeftMargin = 4;
int lineHeight = 25;
string text = "[" + toast->GetToastTitle() + "] " + toast->GetToastMessage();
uint32_t lineCount = 0;
std::wstring wrappedText = WrapText(text, (float)(_screenWidth - textLeftMargin * 2 - 20), lineCount);
lastHeight += lineCount * lineHeight;
DrawString(wrappedText, textLeftMargin, _screenHeight - lastHeight, opacity, opacity, opacity, opacity);
}
void BaseRenderer::DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity)
{
std::wstring textStr = utf8::utf8::decode(message);
DrawString(textStr, x, y, r, g, b, opacity);
}
void BaseRenderer::ShowFpsCounter(int lineNumber)
{
int yPos = 13 + 24 * lineNumber;
if(_fpsTimer.GetElapsedMS() > 1000) {
//Update fps every sec
//TODO
uint32_t frameCount = 0; //_console->GetFrameCount();
if(_lastFrameCount > frameCount) {
_currentFPS = 0;
} else {
_currentFPS = (int)(std::round((double)(frameCount - _lastFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
_currentRenderedFPS = (int)(std::round((double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
}
_lastFrameCount = frameCount;
_lastRenderedFrameCount = _renderedFrameCount;
_fpsTimer.Reset();
}
if(_currentFPS > 5000) {
_currentFPS = 0;
}
if(_currentRenderedFPS > 5000) {
_currentRenderedFPS = 0;
}
string fpsString = string("FPS: ") + std::to_string(_currentFPS) + " / " + std::to_string(_currentRenderedFPS);
DrawString(fpsString, _screenWidth - 125, yPos, 250, 235, 215);
}
void BaseRenderer::ShowGameTimer(int lineNumber)
{
//TODO
/*int yPos = 13 + 24 * lineNumber;
double frameCount = _console->GetFrameCount();
double frameRate = _console->GetModel() == NesModel::NTSC ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333;
//uint32_t milliseconds = (uint32_t)(frameCount / 60.1 * 1000) % 1000;
uint32_t seconds = (uint32_t)(frameCount / frameRate) % 60;
uint32_t minutes = (uint32_t)(frameCount / frameRate / 60) % 60;
uint32_t hours = (uint32_t)(frameCount / frameRate / 3600);
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << hours << ":";
ss << std::setw(2) << std::setfill('0') << minutes << ":";
ss << std::setw(2) << std::setfill('0') << seconds;
//ss << "." << std::setw(3) << std::setfill('0') << milliseconds;
DrawString(ss.str(), _screenWidth - 95, yPos, 250, 235, 215);*/
}
void BaseRenderer::ShowLagCounter(int lineNumber)
{
//TODO
/*int yPos = 13 + 24 * lineNumber;
string lagCounter = MessageManager::Localize("Lag") + ": " + std::to_string(_console->GetLagCounter());
DrawString(lagCounter, _screenWidth - 123, yPos, 250, 235, 215);*/
}
void BaseRenderer::ShowFrameCounter(int lineNumber)
{
//TODO
/*int yPos = 13 + 24 * lineNumber;
string lagCounter = MessageManager::Localize("Frame") + ": " + std::to_string(_console->GetFrameCount());
DrawString(lagCounter, _screenWidth - 146, yPos, 250, 235, 215);*/
}
void BaseRenderer::DrawCounters()
{
//TODO
/*int lineNumber = 0;
EmulationSettings* settings = _console->GetSettings();
if(settings->CheckFlag(EmulationFlags::ShowGameTimer)) {
ShowGameTimer(lineNumber++);
}
if(settings->CheckFlag(EmulationFlags::ShowFPS)) {
ShowFpsCounter(lineNumber++);
}
if(settings->CheckFlag(EmulationFlags::ShowLagCounter)) {
ShowLagCounter(lineNumber++);
}
if(settings->CheckFlag(EmulationFlags::ShowFrameCounter)) {
ShowFrameCounter(lineNumber++);
}*/
}
bool BaseRenderer::IsMessageShown()
{
return !_toasts.empty();
}

54
Core/BaseRenderer.h Normal file
View file

@ -0,0 +1,54 @@
#pragma once
#include "../Core/IMessageManager.h"
#include "../Utilities/Timer.h"
class Console;
//TODO
enum class VideoResizeFilter
{
NearestNeighbor = 0,
Bilinear = 1
};
class BaseRenderer : public IMessageManager
{
private:
list<shared_ptr<ToastInfo>> _toasts;
Timer _fpsTimer;
uint32_t _lastFrameCount = 0;
uint32_t _lastRenderedFrameCount = 0;
uint32_t _currentFPS = 0;
uint32_t _currentRenderedFPS = 0;
void RemoveOldToasts();
std::wstring WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount);
virtual float MeasureString(std::wstring text) = 0;
virtual bool ContainsCharacter(wchar_t character) = 0;
protected:
shared_ptr<Console> _console;
uint32_t _screenWidth = 0;
uint32_t _screenHeight = 0;
uint32_t _renderedFrameCount = 0;
BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager);
virtual ~BaseRenderer();
bool IsMessageShown();
void DisplayMessage(string title, string message);
void DrawToasts();
void DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight);
void DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity = 255);
virtual void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255) = 0;
void ShowFpsCounter(int lineNumber);
void ShowLagCounter(int lineNumber);
void ShowFrameCounter(int lineNumber);
void ShowGameTimer(int lineNumber);
void DrawCounters();
};

50
Core/BaseSoundManager.cpp Normal file
View file

@ -0,0 +1,50 @@
#include "stdafx.h"
#include "BaseSoundManager.h"
void BaseSoundManager::ProcessLatency(uint32_t readPosition, uint32_t writePosition)
{
//Record latency between read & write cursors once per frame
int32_t cursorGap;
if(writePosition < readPosition) {
cursorGap = writePosition - readPosition + _bufferSize;
} else {
cursorGap = writePosition - readPosition;
}
_cursorGaps[_cursorGapIndex] = cursorGap;
_cursorGapIndex = (_cursorGapIndex + 1) % 60;
if(_cursorGapIndex == 0) {
_cursorGapFilled = true;
}
if(_cursorGapFilled) {
//Once we have 60+ frames worth of data to work with, adjust playback frequency by +/- 0.5%
//To speed up or slow down playback in order to reach our latency goal.
uint32_t bytesPerSample = _isStereo ? 4 : 2;
int32_t gapSum = 0;
for(int i = 0; i < 60; i++) {
gapSum += _cursorGaps[i];
}
int32_t gapAverage = gapSum / 60;
_averageLatency = (gapAverage / bytesPerSample) / (double)_sampleRate * 1000;
}
}
AudioStatistics BaseSoundManager::GetStatistics()
{
AudioStatistics stats;
stats.AverageLatency = _averageLatency;
stats.BufferUnderrunEventCount = _bufferUnderrunEventCount;
stats.BufferSize = _bufferSize;
return stats;
}
void BaseSoundManager::ResetStats()
{
_cursorGapIndex = 0;
_cursorGapFilled = false;
_bufferUnderrunEventCount = 0;
_averageLatency = 0;
}

23
Core/BaseSoundManager.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include "../Core/IAudioDevice.h"
class BaseSoundManager : public IAudioDevice
{
public:
void ProcessLatency(uint32_t readPosition, uint32_t writePosition);
AudioStatistics GetStatistics();
protected:
bool _isStereo;
uint32_t _sampleRate = 0;
double _averageLatency = 0;
uint32_t _bufferSize = 0x10000;
uint32_t _bufferUnderrunEventCount = 0;
int32_t _cursorGaps[60];
int32_t _cursorGapIndex = 0;
bool _cursorGapFilled = false;
void ResetStats();
};

68
Core/Console.cpp Normal file
View file

@ -0,0 +1,68 @@
#include "stdafx.h"
#include "Console.h"
#include "Cpu.h"
#include "MemoryManager.h"
#include "Debugger.h"
#include "../Utilities/Timer.h"
#include "../Utilities/VirtualFile.h"
void Console::Run()
{
if(!_cpu) {
return;
}
_stopFlag = false;
auto lock = _runLock.AcquireSafe();
while(!_stopFlag) {
_cpu->Exec();
}
//Timer timer;
/*std::cout << "Time: " << std::to_string(timer.GetElapsedMS()) << std::endl;
std::cout << "OP Count: " << std::to_string(_cpu->opCount) << std::endl;
std::cout << "OP/sec: " << std::to_string(_cpu->opCount * 1000 / timer.GetElapsedMS()) << std::endl;
while(true);*/
}
void Console::Stop()
{
_stopFlag = true;
_runLock.WaitForRelease();
_cpu.reset();
_memoryManager.reset();
_debugger.reset();
}
void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
{
Stop();
shared_ptr<BaseCartridge> cart = BaseCartridge::CreateCartridge(romFile, patchFile);
if(cart) {
_memoryManager.reset(new MemoryManager(cart, shared_from_this()));
_cpu.reset(new Cpu(_memoryManager));
_debugger.reset(new Debugger(_cpu, _memoryManager));
}
}
shared_ptr<Debugger> Console::GetDebugger(bool allowStart)
{
return _debugger;
}
void Console::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
if(_debugger) {
_debugger->ProcessCpuRead(addr, value, type);
}
}
void Console::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
if(_debugger) {
_debugger->ProcessCpuWrite(addr, value, type);
}
}

31
Core/Console.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include "stdafx.h"
#include "../Utilities/VirtualFile.h"
#include "../Utilities/SimpleLock.h"
class Cpu;
class MemoryManager;
class Debugger;
enum class MemoryOperationType;
class Console : public std::enable_shared_from_this<Console>
{
private:
shared_ptr<Cpu> _cpu;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<Debugger> _debugger;
SimpleLock _runLock;
atomic<bool> _stopFlag;
public:
void Run();
void Stop();
void LoadRom(VirtualFile romFile, VirtualFile patchFile);
shared_ptr<Debugger> GetDebugger(bool allowStart = true);
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
};

View file

@ -43,14 +43,35 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BaseRenderer.h" />
<ClInclude Include="BaseSoundManager.h" />
<ClInclude Include="Console.h" />
<ClInclude Include="Cpu.h" />
<ClInclude Include="CpuTypes.h" />
<ClInclude Include="Debugger.h" />
<ClInclude Include="DisassemblyInfo.h" />
<ClInclude Include="IAudioDevice.h" />
<ClInclude Include="IInputProvider.h" />
<ClInclude Include="IInputRecorder.h" />
<ClInclude Include="IKeyManager.h" />
<ClInclude Include="IMessageManager.h" />
<ClInclude Include="INotificationListener.h" />
<ClInclude Include="IRenderingDevice.h" />
<ClInclude Include="KeyManager.h" />
<ClInclude Include="MemoryManager.h" />
<ClInclude Include="MessageManager.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="TraceLogger.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BaseRenderer.cpp" />
<ClCompile Include="BaseSoundManager.cpp" />
<ClCompile Include="Console.cpp" />
<ClCompile Include="Cpu.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Debugger.cpp" />
<ClCompile Include="DisassemblyInfo.cpp" />
<ClCompile Include="KeyManager.cpp" />
<ClCompile Include="MessageManager.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='PGO Profile|Win32'">Create</PrecompiledHeader>
@ -63,6 +84,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='PGO Optimize|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="TraceLogger.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}</ProjectGuid>
@ -73,68 +95,68 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PGO Profile|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PGO Optimize|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PGO Profile|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PGO Optimize|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>

View file

@ -1,14 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="Cpu.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="CpuTypes.h" />
<ClInclude Include="MemoryManager.h" />
<ClInclude Include="Cpu.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="CpuTypes.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="MemoryManager.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="TraceLogger.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="DisassemblyInfo.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Console.h">
<Filter>SNES</Filter>
</ClInclude>
<ClInclude Include="IAudioDevice.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="IInputProvider.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="IInputRecorder.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="IKeyManager.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="IMessageManager.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="INotificationListener.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="IRenderingDevice.h">
<Filter>Interfaces</Filter>
</ClInclude>
<ClInclude Include="BaseRenderer.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="BaseSoundManager.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="MessageManager.h">
<Filter>Misc</Filter>
</ClInclude>
<ClInclude Include="KeyManager.h">
<Filter>Misc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="Cpu.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Cpu.cpp">
<Filter>SNES</Filter>
</ClCompile>
<ClCompile Include="TraceLogger.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="DisassemblyInfo.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Console.cpp">
<Filter>SNES</Filter>
</ClCompile>
<ClCompile Include="BaseRenderer.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="BaseSoundManager.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="MessageManager.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="KeyManager.cpp">
<Filter>Misc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
<UniqueIdentifier>{9cd95372-4592-4f8d-a3fc-db38f474c5b2}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger">
<UniqueIdentifier>{eb8294f1-983e-4e76-8b52-0be06fb798d6}</UniqueIdentifier>
</Filter>
<Filter Include="Interfaces">
<UniqueIdentifier>{3dcfdfd1-4339-4513-b08b-70dc3bb735b1}</UniqueIdentifier>
</Filter>
<Filter Include="Misc">
<UniqueIdentifier>{0da6a615-3092-40f7-936c-253eb03a8784}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -2,34 +2,9 @@
#include "CpuTypes.h"
#include "Cpu.h"
#include "MemoryManager.h"
#include "../Utilities/HexUtilities.h"
//TODO: PER doesn't load the right number of bytes?
uint8_t lastTest = -1;
bool _enableLogging = false;
string opNames[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
"BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", // 0
"BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", // 1
"JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", // 2
"BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", // 3
"RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", // 4
"BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", // 5
"RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", // 6
"BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", // 7
"BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", // 8
"BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", // 9
"LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", // A
"BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", // B
"CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", // C
"BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", // D
"CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", // E
"BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F
};
/************************
Add/substract operations
*************************/
@ -997,7 +972,6 @@ Cpu::Cpu(shared_ptr<MemoryManager> memoryManager)
memcpy(_addrMode, addrMode, sizeof(addrMode));
_memoryManager = memoryManager;
_enableLogging = false;
_state = {};
_state.PC = ReadDataWord(Cpu::ResetVector);
_state.SP = 0x1FF;
@ -1016,19 +990,6 @@ void Cpu::Reset()
void Cpu::Exec()
{
/*std::cout <<
"$" << HexUtilities::ToHex(_state.K) << ":" << HexUtilities::ToHex(_state.PC) <<
" $" << HexUtilities::ToHex(ReadCode(_state.PC)) <<
" (" << opNames[ReadCode(_state.PC)] << ")" <<
" A:$" << HexUtilities::ToHex(_state.A) <<
" X:$" << HexUtilities::ToHex(_state.X) <<
" Y:$" << HexUtilities::ToHex(_state.Y) <<
" S:$" << HexUtilities::ToHex(_state.SP) <<
" D:$" << HexUtilities::ToHex(_state.D) <<
" DB:$" << HexUtilities::ToHex(_state.DBR) <<
" P:$" << HexUtilities::ToHex(_state.PS) <<
std::endl;*/
uint8_t opCode = GetOpCode();
_instAddrMode = _addrMode[opCode];
_operand = FetchEffectiveAddress();
@ -1086,12 +1047,12 @@ uint32_t Cpu::ReadOperandLong()
uint8_t Cpu::ReadCode(uint16_t addr, MemoryOperationType type)
{
return _memoryManager->Read((_state.K << 16) | addr);
return _memoryManager->Read((_state.K << 16) | addr, type);
}
uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type)
{
return _memoryManager->Read(addr);
return _memoryManager->Read(addr, type);
}
uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type)
@ -1111,10 +1072,7 @@ uint32_t Cpu::ReadDataLong(uint32_t addr, MemoryOperationType type)
void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
{
_memoryManager->Write(addr, value);
if(_enableLogging) {
std::cout << "W: $" << HexUtilities::ToHex(addr) << " = $" << HexUtilities::ToHex(value) << std::endl;
}
_memoryManager->Write(addr, value, type);
}
void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type)

View file

@ -9,6 +9,7 @@ class Cpu
public:
uint64_t opCount = 0;
uint16_t GetPc() { return _state.PC; }
CpuState GetState() { return _state; }
private:
static constexpr uint32_t NmiVector = 0x00FFFA;

83
Core/Debugger.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "stdafx.h"
#include "Debugger.h"
#include "Cpu.h"
#include "CpuTypes.h"
#include "DisassemblyInfo.h"
#include "TraceLogger.h"
#include "../Utilities/HexUtilities.h"
Debugger::Debugger(shared_ptr<Cpu> cpu, shared_ptr<MemoryManager> memoryManager)
{
_cpu = cpu;
_memoryManager = memoryManager;
_traceLogger.reset(new TraceLogger(this, memoryManager));
_cpuStepCount = 1;
}
Debugger::~Debugger()
{
}
void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
if(type == MemoryOperationType::ExecOpCode) {
CpuState state = _cpu->GetState();
DisassemblyInfo disassemblyInfo(state, _memoryManager.get());
DebugState debugState = { state };
_traceLogger->Log(debugState, disassemblyInfo);
string out;
out += HexUtilities::ToHex(state.K) + HexUtilities::ToHex(state.PC);
out += " ";
disassemblyInfo.GetDisassembly(out, _memoryManager.get());
out += string(20 - out.size(), ' ');
std::cout << out <<
" A:$" << HexUtilities::ToHex(state.A) <<
" X:$" << HexUtilities::ToHex(state.X) <<
" Y:$" << HexUtilities::ToHex(state.Y) <<
" S:$" << HexUtilities::ToHex(state.SP) <<
" D:$" << HexUtilities::ToHex(state.D) <<
" DB:$" << HexUtilities::ToHex(state.DBR) <<
" P:$" << HexUtilities::ToHex(state.PS) <<
std::endl;
//_traceLogger->Trace
if(_cpuStepCount > 0) {
_cpuStepCount--;
while(_cpuStepCount == 0) {
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));
}
}
}
}
void Debugger::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
if(type == MemoryOperationType::ExecOpCode) {
//_traceLogger->Trace
}
}
void Debugger::Run()
{
_cpuStepCount = -1;
}
void Debugger::Step(int32_t stepCount)
{
_cpuStepCount = stepCount;
}
bool Debugger::IsExecutionStopped()
{
//TODO
return false;
}
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
{
return _traceLogger;
}

42
Core/Debugger.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
#include "stdafx.h"
#include "CpuTypes.h"
class Cpu;
class MemoryManager;
enum class MemoryOperationType;
class TraceLogger;
//class Disassembler;
struct DebugState
{
CpuState Cpu;
//PpuState ppuState;
//ApuState apuState;
};
class Debugger
{
private:
shared_ptr<Cpu> _cpu;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<TraceLogger> _traceLogger;
//unique_ptr<Disassembler> _disassembler;
atomic<int32_t> _cpuStepCount;
public:
Debugger(shared_ptr<Cpu> cpu, shared_ptr<MemoryManager> memoryManager);
~Debugger();
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void Run();
void Step(int32_t stepCount);
bool IsExecutionStopped();
shared_ptr<TraceLogger> GetTraceLogger();
};

116
Core/DisassemblyInfo.cpp Normal file
View file

@ -0,0 +1,116 @@
#include "stdafx.h"
#include "DisassemblyInfo.h"
#include "CpuTypes.h"
#include "MemoryManager.h"
#include "../Utilities/HexUtilities.h"
DisassemblyInfo::DisassemblyInfo()
{
}
DisassemblyInfo::DisassemblyInfo(CpuState &state, MemoryManager *memoryManager)
{
uint32_t addr = (state.K << 16) | state.PC;
_byteCode[0] = memoryManager->Peek(addr);
_addrMode = DisassemblyInfo::OpMode[_byteCode[0]];
_opSize = GetOperandSize() + 1;
for(int i = 1; i < _opSize; i++) {
_byteCode[i] = memoryManager->Peek(addr+i);
}
_flags = state.PS;
_emulationMode = state.EmulationMode;
}
void DisassemblyInfo::GetDisassembly(string &out, MemoryManager *memoryManager)
{
out += DisassemblyInfo::OpName[_byteCode[0]];
out += _opSize > 1 ? " $" : " ";
for(int i = _opSize - 1; i > 0; i--) {
out += HexUtilities::ToHex(_byteCode[i]);
}
}
uint8_t DisassemblyInfo::GetOperandSize()
{
switch(_addrMode) {
case AddrMode::Abs: return 2;
case AddrMode::AbsIdxXInd: return 2;
case AddrMode::AbsIdxX: return 2;
case AddrMode::AbsIdxY: return 2;
case AddrMode::AbsInd: return 2;
case AddrMode::AbsIndLng: return 3;
case AddrMode::AbsLngIdxX: return 3;
case AddrMode::AbsLng: return 3;
case AddrMode::Acc: return 0;
case AddrMode::BlkMov: return 2;
case AddrMode::DirIdxIndX: return 1;
case AddrMode::DirIdxX: return 1;
case AddrMode::DirIdxY: return 1;
case AddrMode::DirIndIdxY: return 1;
case AddrMode::DirIndLngIdxY: return 1;
case AddrMode::DirIndLng: return 1;
case AddrMode::DirInd: return 1;
case AddrMode::Dir: return 1;
case AddrMode::Imm8: return 1;
case AddrMode::ImmX: return _flags & ProcFlags::IndexMode8 ? 1 : 2;
case AddrMode::ImmM: return _flags & ProcFlags::MemoryMode8 ? 1 : 2;
case AddrMode::Imp: return 0;
case AddrMode::RelLng: return 2;
case AddrMode::Rel: return 1;
case AddrMode::Stk: return 0; //TODO
case AddrMode::StkRel: return 1;
case AddrMode::StkRelIndIdxY: return 1;
}
throw new std::runtime_error("Invalid mode");
}
void DisassemblyInfo::GetByteCode(string &out)
{
for(int i = 0; i < _opSize; i++) {
out += "$" + HexUtilities::ToHex(_byteCode[i]) + ((i < _opSize - 1) ? " " : "");
}
}
string DisassemblyInfo::OpName[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
"BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", // 0
"BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", // 1
"JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", // 2
"BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", // 3
"RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", // 4
"BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", // 5
"RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", // 6
"BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", // 7
"BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", // 8
"BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", // 9
"LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", // A
"BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", // B
"CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", // C
"BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", // D
"CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", // E
"BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" // F
};
typedef AddrMode M;
AddrMode DisassemblyInfo::OpMode[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1
M::Abs, M::DirIdxIndX, M::AbsLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3
M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 4
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5
M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7
M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9
M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Stk, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D
M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E
M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Stk, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F
};

43
Core/DisassemblyInfo.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include "stdafx.h"
#include <unordered_map>
class MemoryManager;
struct CpuState;
enum class AddrMode : uint8_t;
class DisassemblyInfo
{
public:
static string OpName[256];
static AddrMode OpMode[256];
static uint8_t OpSize[256];
private:
uint8_t _byteCode[4];
uint8_t _opSize;
AddrMode _addrMode;
uint8_t _flags;
bool _emulationMode;
public:
DisassemblyInfo();
DisassemblyInfo(CpuState &state, MemoryManager *memoryManager);
void GetDisassembly(string &out, MemoryManager* memoryManager);
uint8_t GetOperandSize();
void GetByteCode(string &out);
/*
int32_t GetEffectiveAddress(CpuState& cpuState, MemoryManager* memoryManager);
void GetEffectiveAddressString(string &out, CpuState& cpuState, MemoryManager* memoryManager);
/*int32_t GetMemoryValue(CpuState& cpuState, MemoryManager* memoryManager);
uint16_t GetJumpDestination(uint16_t pc, MemoryManager* memoryManager);
uint16_t GetIndirectJumpDestination(MemoryManager* memoryManager);
void ToString(string &out, uint32_t memoryAddr, MemoryManager* memoryManager, bool extendZeroPage);
void GetByteCode(string &out);
uint32_t GetSize();
uint16_t GetOpAddr(uint16_t memoryAddr);*/
};

25
Core/IAudioDevice.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include "stdafx.h"
struct AudioStatistics
{
double AverageLatency = 0;
uint32_t BufferUnderrunEventCount = 0;
uint32_t BufferSize = 0;
};
class IAudioDevice
{
public:
virtual ~IAudioDevice() {}
virtual void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0;
virtual void Stop() = 0;
virtual void Pause() = 0;
virtual void ProcessEndOfFrame() = 0;
virtual string GetAvailableDevices() = 0;
virtual void SetAudioDevice(string deviceName) = 0;
virtual AudioStatistics GetStatistics() = 0;
};

9
Core/IInputProvider.h Normal file
View file

@ -0,0 +1,9 @@
#pragma once
class BaseControlDevice;
class IInputProvider
{
public:
virtual bool SetInput(BaseControlDevice* device) = 0;
};

10
Core/IInputRecorder.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "stdafx.h"
class BaseControlDevice;
class IInputRecorder
{
public:
virtual void RecordInput(vector<shared_ptr<BaseControlDevice>> devices) = 0;
};

39
Core/IKeyManager.h Normal file
View file

@ -0,0 +1,39 @@
#pragma once
#include "stdafx.h"
enum class MouseButton
{
LeftButton = 0,
RightButton = 1,
MiddleButton = 2,
};
struct MousePosition
{
int16_t X;
int16_t Y;
};
struct MouseMovement
{
int16_t dx;
int16_t dy;
};
class IKeyManager
{
public:
virtual ~IKeyManager() {}
virtual void RefreshState() = 0;
virtual void UpdateDevices() = 0;
virtual bool IsMouseButtonPressed(MouseButton button) = 0;
virtual bool IsKeyPressed(uint32_t keyCode) = 0;
virtual vector<uint32_t> GetPressedKeys() = 0;
virtual string GetKeyName(uint32_t keyCode) = 0;
virtual uint32_t GetKeyCode(string keyName) = 0;
virtual void SetKeyState(uint16_t scanCode, bool state) = 0;
virtual void ResetKeyState() = 0;
virtual void SetDisabled(bool disabled) = 0;
};

64
Core/IMessageManager.h Normal file
View file

@ -0,0 +1,64 @@
#pragma once
#include "stdafx.h"
#include <chrono>
class ToastInfo;
class IMessageManager
{
public:
virtual void DisplayMessage(string title, string message) = 0;
};
class ToastInfo
{
private:
string _title;
string _message;
uint64_t _endTime;
uint64_t _startTime;
uint64_t GetCurrentTime()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}
public:
ToastInfo(string title, string message, int displayDuration)
{
_title = title;
_message = message;
_startTime = GetCurrentTime();
_endTime = _startTime + displayDuration;
}
string GetToastTitle()
{
return _title;
}
string GetToastMessage()
{
return _message;
}
float GetOpacity()
{
uint64_t currentTime = GetCurrentTime();
if(currentTime - _startTime < 200) {
return (currentTime - _startTime) * 5.0f / 1000.0f;
} else if(_endTime - currentTime < 200) {
return (_endTime - currentTime) * 5.0f / 1000.0f;
} else if(currentTime >= _endTime) {
return 0.0f;
} else {
return 1.0f;
}
}
bool IsToastExpired()
{
return _endTime < GetCurrentTime();
}
};

View file

@ -0,0 +1,25 @@
#pragma once
#include "stdafx.h"
enum class ConsoleNotificationType
{
GameLoaded = 0,
StateLoaded = 1,
GameReset = 2,
GamePaused = 3,
GameResumed = 4,
GameStopped = 5,
CodeBreak = 6,
PpuFrameDone = 9,
ResolutionChanged = 11,
ConfigChanged = 13,
ExecuteShortcut = 16,
EmulationStopped = 17,
BeforeEmulationStop = 19,
};
class INotificationListener
{
public:
virtual void ProcessNotification(ConsoleNotificationType type, void* parameter) = 0;
};

13
Core/IRenderingDevice.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "stdafx.h"
class IRenderingDevice
{
public:
virtual ~IRenderingDevice() {}
virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) = 0;
virtual void Render() = 0;
virtual void Reset() = 0;
virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0;
};

108
Core/KeyManager.cpp Normal file
View file

@ -0,0 +1,108 @@
#include "stdafx.h"
#include "KeyManager.h"
#include "IKeyManager.h"
IKeyManager* KeyManager::_keyManager = nullptr;
MousePosition KeyManager::_mousePosition = { 0, 0 };
atomic<int16_t> KeyManager::_xMouseMovement;
atomic<int16_t> KeyManager::_yMouseMovement;
void KeyManager::RegisterKeyManager(IKeyManager* keyManager)
{
_xMouseMovement = 0;
_yMouseMovement = 0;
_keyManager = keyManager;
}
void KeyManager::RefreshKeyState()
{
if(_keyManager != nullptr) {
return _keyManager->RefreshState();
}
}
bool KeyManager::IsKeyPressed(uint32_t keyCode)
{
//TODO
/*if(_keyManager != nullptr) {
return _settings->InputEnabled() && _keyManager->IsKeyPressed(keyCode);
}*/
return false;
}
bool KeyManager::IsMouseButtonPressed(MouseButton button)
{
//TODO
/*if(_keyManager != nullptr) {
return _settings->InputEnabled() && _keyManager->IsMouseButtonPressed(button);
}*/
return false;
}
vector<uint32_t> KeyManager::GetPressedKeys()
{
if(_keyManager != nullptr) {
return _keyManager->GetPressedKeys();
}
return vector<uint32_t>();
}
string KeyManager::GetKeyName(uint32_t keyCode)
{
if(_keyManager != nullptr) {
return _keyManager->GetKeyName(keyCode);
}
return "";
}
uint32_t KeyManager::GetKeyCode(string keyName)
{
if(_keyManager != nullptr) {
return _keyManager->GetKeyCode(keyName);
}
return 0;
}
void KeyManager::UpdateDevices()
{
if(_keyManager != nullptr) {
_keyManager->UpdateDevices();
}
}
void KeyManager::SetMouseMovement(int16_t x, int16_t y)
{
_xMouseMovement += x;
_yMouseMovement += y;
}
MouseMovement KeyManager::GetMouseMovement(double mouseSensitivity)
{
//TODO
//double factor = _settings->GetVideoScale() / mouseSensitivity;
MouseMovement mov = {};
/*mov.dx = (int16_t)(_xMouseMovement / factor);
mov.dy = (int16_t)(_yMouseMovement / factor);
_xMouseMovement -= (int16_t)(mov.dx * factor);
_yMouseMovement -= (int16_t)(mov.dy * factor);*/
return mov;
}
void KeyManager::SetMousePosition(double x, double y)
{
//TODO
/*if(x < 0 || y < 0) {
_mousePosition.X = -1;
_mousePosition.Y = -1;
} else {
OverscanDimensions overscan = _settings->GetOverscanDimensions();
_mousePosition.X = (int32_t)(x * (PPU::ScreenWidth - overscan.Left - overscan.Right) + overscan.Left);
_mousePosition.Y = (int32_t)(y * (PPU::ScreenHeight - overscan.Top - overscan.Bottom) + overscan.Top);
}*/
}
MousePosition KeyManager::GetMousePosition()
{
return _mousePosition;
}

30
Core/KeyManager.h Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include "stdafx.h"
#include "IKeyManager.h"
class KeyManager
{
private:
static IKeyManager* _keyManager;
static MousePosition _mousePosition;
static atomic<int16_t> _xMouseMovement;
static atomic<int16_t> _yMouseMovement;
public:
static void RegisterKeyManager(IKeyManager* keyManager);
static void RefreshKeyState();
static bool IsKeyPressed(uint32_t keyCode);
static bool IsMouseButtonPressed(MouseButton button);
static vector<uint32_t> GetPressedKeys();
static string GetKeyName(uint32_t keyCode);
static uint32_t GetKeyCode(string keyName);
static void UpdateDevices();
static void SetMouseMovement(int16_t x, int16_t y);
static MouseMovement GetMouseMovement(double mouseSensitivity);
static void SetMousePosition(double x, double y);
static MousePosition GetMousePosition();
};

View file

@ -1,5 +1,8 @@
#pragma once
#include "stdafx.h"
#include "Console.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/VirtualFile.h"
class IMemoryHandler
{
@ -16,17 +19,25 @@ public:
class BaseCartridge : public IMemoryHandler
{
private:
uint32_t _prgRomSize;
size_t _prgRomSize;
uint8_t* _prgRom;
public:
BaseCartridge()
static shared_ptr<BaseCartridge> CreateCartridge(VirtualFile romFile, VirtualFile patchFile)
{
_prgRomSize = 1024 * 1024;
_prgRom = new uint8_t[_prgRomSize];
if(romFile.IsValid()) {
vector<uint8_t> romData;
romFile.ReadFile(romData);
ifstream rom("..\\bin\\x64\\Debug\\game.sfc", ios::binary);
rom.read((char*)_prgRom, _prgRomSize);
shared_ptr<BaseCartridge> cart(new BaseCartridge());
cart->_prgRomSize = romData.size();
cart->_prgRom = new uint8_t[cart->_prgRomSize];
memcpy(cart->_prgRom, romData.data(), cart->_prgRomSize);
return cart;
} else {
return nullptr;
}
}
uint8_t Read(uint32_t addr) override
@ -65,16 +76,20 @@ public:
class MemoryManager
{
private:
shared_ptr<Console> _console;
uint8_t * _workRam;
IMemoryHandler* _handlers[0x100 * 0x10];
vector<unique_ptr<WorkRamHandler>> _workRamHandlers;
unique_ptr<BaseCartridge> _cart;
shared_ptr<BaseCartridge> _cart;
public:
MemoryManager()
MemoryManager(shared_ptr<BaseCartridge> cart, shared_ptr<Console> console)
{
_cart.reset(new BaseCartridge());
_console = console;
_cart = cart;
memset(_handlers, 0, sizeof(_handlers));
_workRam = new uint8_t[128 * 1024];
for(uint32_t i = 0; i < 128 * 1024; i += 0x1000) {
_workRamHandlers.push_back(unique_ptr<WorkRamHandler>(new WorkRamHandler(_workRam + i)));
@ -105,19 +120,37 @@ public:
}
}
uint8_t Read(uint32_t addr)
uint8_t Read(uint32_t addr, MemoryOperationType type)
{
uint8_t value = 0;
if(_handlers[addr >> 12]) {
return _handlers[addr >> 12]->Read(addr);
value = _handlers[addr >> 12]->Read(addr);
} else {
return 0;
//std::cout << "Read - missing handler: $" << HexUtilities::ToHex(addr) << std::endl;
}
_console->ProcessCpuRead(addr, value, type);
return value;
}
void Write(uint32_t addr, uint8_t value)
uint8_t Peek(uint32_t addr)
{
//Read, without triggering side-effects
uint8_t value = 0;
if(_handlers[addr >> 12]) {
value = _handlers[addr >> 12]->Read(addr);
} else {
//std::cout << "Read - missing handler: $" << HexUtilities::ToHex(addr) << std::endl;
}
return value;
}
void Write(uint32_t addr, uint8_t value, MemoryOperationType type)
{
_console->ProcessCpuWrite(addr, value, type);
if(_handlers[addr >> 12]) {
return _handlers[addr >> 12]->Write(addr, value);
} else {
//std::cout << "Write - missing handler: $" << HexUtilities::ToHex(addr) << " = " << HexUtilities::ToHex(value) << std::endl;
}
}
};

183
Core/MessageManager.cpp Normal file
View file

@ -0,0 +1,183 @@
#include "stdafx.h"
#include "MessageManager.h"
std::unordered_map<string, string> MessageManager::_enResources = {
{ "Cheats", u8"Cheats" },
{ "Debug", u8"Debug" },
{ "EmulationSpeed", u8"Emulation Speed" },
{ "ClockRate", u8"Clock Rate" },
{ "Error", u8"Error" },
{ "GameInfo", u8"Game Info" },
{ "GameLoaded", u8"Game loaded" },
{ "Input", u8"Input" },
{ "Patch", u8"Patch" },
{ "Movies", u8"Movies" },
{ "NetPlay", u8"Net Play" },
{ "Region", u8"Region" },
{ "SaveStates", u8"Save States" },
{ "ScreenshotSaved", u8"Screenshot Saved" },
{ "SoundRecorder", u8"Sound Recorder" },
{ "Test", u8"Test" },
{ "VideoRecorder", u8"Video Recorder" },
{ "ApplyingPatch", u8"Applying patch: %1" },
{ "CheatApplied", u8"1 cheat applied." },
{ "CheatsApplied", u8"%1 cheats applied." },
{ "CheatsDisabled", u8"All cheats disabled." },
{ "CoinInsertedSlot", u8"Coin inserted (slot %1)" },
{ "ConnectedToServer", u8"Connected to server." },
{ "ConnectedAsPlayer", u8"Connected as player %1" },
{ "ConnectedAsSpectator", u8"Connected as spectator." },
{ "ConnectionLost", u8"Connection to server lost." },
{ "CouldNotConnect", u8"Could not connect to the server." },
{ "CouldNotInitializeAudioSystem", u8"Could not initialize audio system" },
{ "CouldNotFindRom", u8"Could not find matching game ROM." },
{ "CouldNotLoadFile", u8"Could not load file: %1" },
{ "EmulationMaximumSpeed", u8"Maximum speed" },
{ "EmulationSpeedPercent", u8"%1%" },
{ "FdsDiskInserted", u8"Disk %1 Side %2 inserted." },
{ "Frame", u8"Frame" },
{ "GameCrash", u8"Game has crashed (%1)" },
{ "KeyboardModeDisabled", u8"Keyboard mode disabled." },
{ "KeyboardModeEnabled", u8"Keyboard mode enabled." },
{ "Lag", u8"Lag" },
{ "Mapper", u8"Mapper: %1, SubMapper: %2" },
{ "MovieEnded", u8"Movie ended." },
{ "MovieInvalid", u8"Invalid movie file." },
{ "MovieMissingRom", u8"Missing ROM required (%1) to play movie." },
{ "MovieNewerVersion", u8"Cannot load movies created by a more recent version of Mesen. Please download the latest version." },
{ "MovieIncompatibleVersion", u8"This movie is incompatible with this version of Mesen." },
{ "MoviePlaying", u8"Playing movie: %1" },
{ "MovieRecordingTo", u8"Recording to: %1" },
{ "MovieSaved", u8"Movie saved to file: %1" },
{ "NetplayVersionMismatch", u8"%1 is not running the same version of Mesen and has been disconnected." },
{ "PrgSizeWarning", u8"PRG size is smaller than 32kb" },
{ "SaveStateEmpty", u8"Slot is empty." },
{ "SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen." },
{ "SaveStateInvalidFile", u8"Invalid save state file." },
{ "SaveStateLoaded", u8"State #%1 loaded." },
{ "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." },
{ "SaveStateNewerVersion", u8"Cannot load save states created by a more recent version of Mesen. Please download the latest version." },
{ "SaveStateSaved", u8"State #%1 saved." },
{ "SaveStateSlotSelected", u8"Slot #%1 selected." },
{ "ScanlineTimingWarning", u8"PPU timing has been changed." },
{ "ServerStarted", u8"Server started (Port: %1)" },
{ "ServerStopped", u8"Server stopped" },
{ "SoundRecorderStarted", u8"Recording to: %1" },
{ "SoundRecorderStopped", u8"Recording saved to: %1" },
{ "TestFileSavedTo", u8"Test file saved to: %1" },
{ "UnsupportedMapper", u8"Unsupported mapper (%1), cannot load game." },
{ "VideoRecorderStarted", u8"Recording to: %1" },
{ "VideoRecorderStopped", u8"Recording saved to: %1" },
};
std::list<string> MessageManager::_log;
SimpleLock MessageManager::_logLock;
SimpleLock MessageManager::_messageLock;
bool MessageManager::_osdEnabled = false;
IMessageManager* MessageManager::_messageManager = nullptr;
void MessageManager::RegisterMessageManager(IMessageManager* messageManager)
{
auto lock = _messageLock.AcquireSafe();
MessageManager::_messageManager = messageManager;
}
void MessageManager::UnregisterMessageManager(IMessageManager* messageManager)
{
auto lock = _messageLock.AcquireSafe();
if(MessageManager::_messageManager == messageManager) {
MessageManager::_messageManager = nullptr;
}
}
void MessageManager::SetOsdState(bool enabled)
{
_osdEnabled = enabled;
}
string MessageManager::Localize(string key)
{
std::unordered_map<string, string> *resources = &_enResources;
/*switch(EmulationSettings::GetDisplayLanguage()) {
case Language::English: resources = &_enResources; break;
case Language::French: resources = &_frResources; break;
case Language::Japanese: resources = &_jaResources; break;
case Language::Russian: resources = &_ruResources; break;
case Language::Spanish: resources = &_esResources; break;
case Language::Ukrainian: resources = &_ukResources; break;
case Language::Portuguese: resources = &_ptResources; break;
case Language::Catalan: resources = &_caResources; break;
case Language::Chinese: resources = &_zhResources; break;
}*/
if(resources) {
if(resources->find(key) != resources->end()) {
return (*resources)[key];
}/* else if(EmulationSettings::GetDisplayLanguage() != Language::English) {
//Fallback on English if resource key is missing another language
resources = &_enResources;
if(resources->find(key) != resources->end()) {
return (*resources)[key];
}
}*/
}
return key;
}
void MessageManager::DisplayMessage(string title, string message, string param1, string param2)
{
if(MessageManager::_messageManager) {
auto lock = _messageLock.AcquireSafe();
if(!MessageManager::_messageManager) {
return;
}
title = Localize(title);
message = Localize(message);
size_t startPos = message.find(u8"%1");
if(startPos != std::string::npos) {
message.replace(startPos, 2, param1);
}
startPos = message.find(u8"%2");
if(startPos != std::string::npos) {
message.replace(startPos, 2, param2);
}
if(_osdEnabled) {
MessageManager::_messageManager->DisplayMessage(title, message);
} else {
MessageManager::Log("[" + title + "] " + message);
}
}
}
void MessageManager::Log(string message)
{
#ifndef LIBRETRO
auto lock = _logLock.AcquireSafe();
if(message.empty()) {
message = "------------------------------------------------------";
}
if(_log.size() >= 1000) {
_log.pop_front();
}
_log.push_back(message);
#else
if(MessageManager::_messageManager) {
MessageManager::_messageManager->DisplayMessage("", message + "\n");
}
#endif
}
string MessageManager::GetLog()
{
auto lock = _logLock.AcquireSafe();
stringstream ss;
for(string &msg : _log) {
ss << msg << "\n";
}
return ss.str();
}

31
Core/MessageManager.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include "stdafx.h"
#include "IMessageManager.h"
#include <unordered_map>
#include "../Utilities/SimpleLock.h"
class MessageManager
{
private:
static IMessageManager* _messageManager;
static std::unordered_map<string, string> _enResources;
static bool _osdEnabled;
static SimpleLock _logLock;
static SimpleLock _messageLock;
static std::list<string> _log;
public:
static void SetOsdState(bool enabled);
static string Localize(string key);
static void RegisterMessageManager(IMessageManager* messageManager);
static void UnregisterMessageManager(IMessageManager* messageManager);
static void DisplayMessage(string title, string message, string param1 = "", string param2 = "");
static void Log(string message = "");
static string GetLog();
};

332
Core/TraceLogger.cpp Normal file
View file

@ -0,0 +1,332 @@
#include "stdafx.h"
#include <regex>
#include "TraceLogger.h"
#include "DisassemblyInfo.h"
#include "Console.h"
#include "Debugger.h"
#include "MemoryManager.h"
#include "../Utilities/HexUtilities.h"
string TraceLogger::_executionTrace = "";
TraceLogger::TraceLogger(Debugger* debugger, shared_ptr<MemoryManager> memoryManager)
{
_memoryManager = memoryManager;
_currentPos = 0;
_logCount = 0;
_logToFile = false;
_pendingLog = false;
}
TraceLogger::~TraceLogger()
{
StopLogging();
}
template<typename T>
void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart)
{
string str = rowPart.DisplayInHex ? HexUtilities::ToHex((uint32_t)value) : std::to_string(value);
output += str;
if(rowPart.MinWidth > (int)str.size()) {
output += std::string(rowPart.MinWidth - str.size(), ' ');
}
}
template<>
void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart)
{
output += value;
if(rowPart.MinWidth > (int)value.size()) {
output += std::string(rowPart.MinWidth - value.size(), ' ');
}
}
void TraceLogger::SetOptions(TraceLoggerOptions options)
{
_options = options;
string condition = _options.Condition;
string format = _options.Format;
auto lock = _lock.AcquireSafe();
/*_conditionData = ExpressionData();
if(!condition.empty()) {
bool success = false;
ExpressionData rpnList = _expEvaluator->GetRpnList(condition, success);
if(success) {
_conditionData = rpnList;
}
}*/
_rowParts.clear();
std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", std::regex_constants::icase);
std::sregex_iterator start = std::sregex_iterator(format.cbegin(), format.cend(), formatRegex);
std::sregex_iterator end = std::sregex_iterator();
for(std::sregex_iterator it = start; it != end; it++) {
const std::smatch& match = *it;
if(match.str(1) == "") {
RowPart part = {};
part.DataType = RowDataType::Text;
part.Text = match.str(6);
_rowParts.push_back(part);
} else {
RowPart part = {};
string dataType = match.str(2);
if(dataType == "ByteCode") {
part.DataType = RowDataType::ByteCode;
} else if(dataType == "Disassembly") {
part.DataType = RowDataType::Disassembly;
} else if(dataType == "EffectiveAddress") {
part.DataType = RowDataType::EffectiveAddress;
} else if(dataType == "MemoryValue") {
part.DataType = RowDataType::MemoryValue;
} else if(dataType == "Align") {
part.DataType = RowDataType::Align;
} else if(dataType == "PC") {
part.DataType = RowDataType::PC;
} else if(dataType == "A") {
part.DataType = RowDataType::A;
} else if(dataType == "X") {
part.DataType = RowDataType::X;
} else if(dataType == "Y") {
part.DataType = RowDataType::Y;
} else if(dataType == "P") {
part.DataType = RowDataType::PS;
} else if(dataType == "SP") {
part.DataType = RowDataType::SP;
} else if(dataType == "Cycle") {
part.DataType = RowDataType::Cycle;
} else if(dataType == "Scanline") {
part.DataType = RowDataType::Scanline;
} else if(dataType == "FrameCount") {
part.DataType = RowDataType::FrameCount;
} else if(dataType == "CycleCount") {
part.DataType = RowDataType::CycleCount;
} else {
part.DataType = RowDataType::Text;
part.Text = "[Invalid tag]";
}
if(!match.str(4).empty()) {
try {
part.MinWidth = std::stoi(match.str(4));
} catch(std::exception) {
}
}
part.DisplayInHex = match.str(5) == "h";
_rowParts.push_back(part);
}
}
}
void TraceLogger::StartLogging(string filename)
{
_outputBuffer.clear();
_outputFile.open(filename, ios::out | ios::binary);
_logToFile = true;
}
void TraceLogger::StopLogging()
{
if(_logToFile) {
_logToFile = false;
if(_outputFile) {
if(!_outputBuffer.empty()) {
_outputFile << _outputBuffer;
}
_outputFile.close();
}
}
}
void TraceLogger::LogExtraInfo(const char *log, uint32_t cycleCount)
{
if(_logToFile && _options.ShowExtraInfo) {
//Flush current buffer
_outputFile << _outputBuffer;
_outputBuffer.clear();
_outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << (_options.UseWindowsEol ? "\r\n" : "\n");
}
}
void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part)
{
if(part.DisplayInHex) {
WriteValue(output, ps, part);
} else {
constexpr char activeStatusLetters[8] = { 'N', 'V', 'X', 'M', 'D', 'I', 'Z', 'C' };
constexpr char inactiveStatusLetters[8] = { 'n', 'v', 'x', 'm', 'd', 'i', 'z', 'c' };
string flags;
for(int i = 0; i < 8; i++) {
if(ps & 0x80) {
flags += activeStatusLetters[i];
} else if(part.MinWidth >= 8) {
flags += inactiveStatusLetters[i];
}
ps <<= 1;
}
WriteValue(output, flags, part);
}
}
void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, DisassemblyInfo &disassemblyInfo)
{
int originalSize = (int)output.size();
for(RowPart& rowPart : _rowParts) {
switch(rowPart.DataType) {
case RowDataType::Text: output += rowPart.Text; break;
case RowDataType::ByteCode:
{
string byteCode;
disassemblyInfo.GetByteCode(byteCode);
if(!rowPart.DisplayInHex) {
//Remove $ marks if not in "hex" mode (but still display the bytes as hex)
byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end());
}
WriteValue(output, byteCode, rowPart);
break;
}
case RowDataType::Disassembly:
{
int indentLevel = 0;
string code;
if(_options.IndentCode) {
indentLevel = 0xFF - (cpuState.SP & 0xFF);
code = std::string(indentLevel, ' ');
}
//LabelManager* labelManager = _options.UseLabels ? _labelManager.get() : nullptr;
disassemblyInfo.GetDisassembly(code, _memoryManager.get());
WriteValue(output, code, rowPart);
break;
}
case RowDataType::EffectiveAddress:
{
/*string effectiveAddress;
disassemblyInfo.GetEffectiveAddressString(effectiveAddress, cpuState, _memoryManager.get(), _options.UseLabels ? _labelManager.get() : nullptr);
WriteValue(output, effectiveAddress, rowPart);*/
break;
}
case RowDataType::MemoryValue:
{
/*int32_t value = disassemblyInfo.GetMemoryValue(cpuState, _memoryManager.get());
if(value >= 0) {
output += rowPart.DisplayInHex ? "= $" : "= ";
WriteValue(output, (uint8_t)value, rowPart);
}*/
break;
}
case RowDataType::Align:
if((int)output.size() - originalSize < rowPart.MinWidth) {
output += std::string(rowPart.MinWidth - (output.size() - originalSize), ' ');
}
break;
case RowDataType::PC: WriteValue(output, (cpuState.K << 16) | cpuState.PC, rowPart); break;
case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
//case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
//case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
//case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
case RowDataType::CycleCount: WriteValue(output, cpuState.CycleCount, rowPart); break;
}
}
output += _options.UseWindowsEol ? "\r\n" : "\n";
}
/*
bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo)
{
if(!_conditionData.RpnQueue.empty()) {
EvalResultType type;
if(!_expEvaluator->Evaluate(_conditionData, state, type, operationInfo)) {
if(operationInfo.OperationType == MemoryOperationType::ExecOpCode) {
//Condition did not match, keep state/disassembly info for instruction's subsequent cycles
_lastState = state;
_lastDisassemblyInfo = disassemblyInfo;
_pendingLog = true;
}
return false;
}
}
return true;
}
*/
void TraceLogger::AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state)
{
_disassemblyCache[_currentPos] = disassemblyInfo;
_cpuStateCache[_currentPos] = state.Cpu;
//_ppuStateCache[_currentPos] = state.PPU;
_pendingLog = false;
if(_logCount < ExecutionLogSize) {
_logCount++;
}
if(_logToFile) {
GetTraceRow(_outputBuffer, state.Cpu, disassemblyInfo);
if(_outputBuffer.size() > 32768) {
_outputFile << _outputBuffer;
_outputBuffer.clear();
}
}
_currentPos = (_currentPos + 1) % ExecutionLogSize;
}
/*
void TraceLogger::LogNonExec(OperationInfo& operationInfo)
{
if(_pendingLog) {
auto lock = _lock.AcquireSafe();
if(ConditionMatches(_lastState, _lastDisassemblyInfo, operationInfo)) {
AddRow(_lastDisassemblyInfo, _lastState);
}
}
}*/
void TraceLogger::Log(DebugState &state, DisassemblyInfo &disassemblyInfo)
{
auto lock = _lock.AcquireSafe();
//if(ConditionMatches(state, disassemblyInfo, operationInfo)) {
AddRow(disassemblyInfo, state);
//}
}
const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
{
int startPos;
_executionTrace.clear();
{
auto lock = _lock.AcquireSafe();
lineCount = std::min(lineCount, _logCount);
memcpy(_cpuStateCacheCopy, _cpuStateCache, sizeof(_cpuStateCache));
//memcpy(_ppuStateCacheCopy, _ppuStateCache, sizeof(_ppuStateCache));
memcpy(_disassemblyCacheCopy, _disassemblyCache, sizeof(_disassemblyCache));
startPos = _currentPos + ExecutionLogSize - lineCount;
}
for(int i = 0; i < (int)lineCount; i++) {
int index = (startPos + i) % ExecutionLogSize;
_executionTrace += HexUtilities::ToHex((_cpuStateCacheCopy[index].K << 16) | _cpuStateCacheCopy[index].PC) + "\x1";
string byteCode;
_disassemblyCacheCopy[index].GetByteCode(byteCode);
_executionTrace += byteCode + "\x1";
GetTraceRow(_executionTrace, _cpuStateCacheCopy[index], _disassemblyCacheCopy[index]);
}
return _executionTrace.c_str();
}

106
Core/TraceLogger.h Normal file
View file

@ -0,0 +1,106 @@
#pragma once
#include "stdafx.h"
#include "CpuTypes.h"
#include "DisassemblyInfo.h"
#include "../Utilities/SimpleLock.h"
class MemoryManager;
class Debugger;
struct DebugState;
struct TraceLoggerOptions
{
bool ShowExtraInfo;
bool IndentCode;
bool UseLabels;
bool UseWindowsEol;
bool ExtendZeroPage;
char Condition[1000];
char Format[1000];
};
enum class RowDataType
{
Text = 0,
ByteCode,
Disassembly,
EffectiveAddress,
MemoryValue,
Align,
PC,
A,
X,
Y,
SP,
PS,
Cycle,
Scanline,
FrameCount,
CycleCount
};
struct RowPart
{
RowDataType DataType;
string Text;
bool DisplayInHex;
int MinWidth;
};
class TraceLogger
{
private:
static constexpr int ExecutionLogSize = 30000;
//Must be static to be thread-safe when switching game
static string _executionTrace;
TraceLoggerOptions _options;
string _outputFilepath;
string _outputBuffer;
ofstream _outputFile;
shared_ptr<MemoryManager> _memoryManager;
//shared_ptr<LabelManager> _labelManager;
vector<RowPart> _rowParts;
bool _pendingLog;
//CpuState _lastState;
//DisassemblyInfo _lastDisassemblyInfo;
bool _logToFile;
uint16_t _currentPos;
uint32_t _logCount;
CpuState _cpuStateCache[ExecutionLogSize] = {};
//PPUDebugState _ppuStateCache[ExecutionLogSize] = {};
DisassemblyInfo _disassemblyCache[ExecutionLogSize];
CpuState _cpuStateCacheCopy[ExecutionLogSize] = {};
//PPUDebugState _ppuStateCacheCopy[ExecutionLogSize] = {};
DisassemblyInfo _disassemblyCacheCopy[ExecutionLogSize];
SimpleLock _lock;
void GetStatusFlag(string &output, uint8_t ps, RowPart& part);
void AddRow(DisassemblyInfo &disassemblyInfo, DebugState &state);
//bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo);
void GetTraceRow(string &output, CpuState &cpuState, DisassemblyInfo &disassemblyInfo);
template<typename T> void WriteValue(string &output, T value, RowPart& rowPart);
public:
TraceLogger(Debugger* debugger, shared_ptr<MemoryManager> memoryManager);
~TraceLogger();
void Log(DebugState &state, DisassemblyInfo &disassemblyInfo);
//void LogNonExec(OperationInfo& operationInfo);
void SetOptions(TraceLoggerOptions options);
void StartLogging(string filename);
void StopLogging();
void LogExtraInfo(const char *log, uint32_t cycleCount);
const char* GetExecutionTrace(uint32_t lineCount);
};

View file

@ -1,19 +0,0 @@
#include "stdafx.h"
#include "Cpu.h"
#include "MemoryManager.h"
#include "../Utilities/Timer.h"
int main()
{
shared_ptr<MemoryManager> memoryManager(new MemoryManager());
shared_ptr<Cpu> cpu(new Cpu(memoryManager));
Timer timer;
while(cpu->opCount < 10000000) {
cpu->Exec();
}
std::cout << "Time: " << std::to_string(timer.GetElapsedMS()) << std::endl;
std::cout << "OP Count: " << std::to_string(cpu->opCount) << std::endl;
std::cout << "OP/sec: " << std::to_string(cpu->opCount * 1000 / timer.GetElapsedMS()) << std::endl;
while(true);
}

View file

@ -14,7 +14,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utilities", "Utilities\Util
{52C4BA3A-E699-4305-B23F-C9083FD07AB6} = {52C4BA3A-E699-4305-B23F-C9083FD07AB6}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUI.NET", "GUI.NET\GUI.NET.csproj", "{08D83A7E-52A9-451E-A53A-1A7946F8BB77}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI", "UI\UI.csproj", "{08D83A7E-52A9-451E-A53A-1A7946F8BB77}"
ProjectSection(ProjectDependencies) = postProject
{36ABBF1C-66E1-4577-828A-619A2EF0DAE9} = {36ABBF1C-66E1-4577-828A-619A2EF0DAE9}
{AABB5225-3A49-47FF-8A48-031673CADCE9} = {AABB5225-3A49-47FF-8A48-031673CADCE9}

70
UI/CommandLineHelper.cs Normal file
View file

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI
{
class CommandLineHelper
{
public static List<string> PreprocessCommandLineArguments(string[] args, bool toLower)
{
var switches = new List<string>();
for(int i = 0; i < args.Length; i++) {
if(args[i] != null) {
string arg = args[i].Trim();
if(arg.StartsWith("--")) {
arg = "/" + arg.Substring(2);
} else if(arg.StartsWith("-")) {
arg = "/" + arg.Substring(1);
}
if(toLower) {
arg = arg.ToLowerInvariant();
}
switches.Add(arg);
}
}
return switches;
}
public static void GetRomPathFromCommandLine(List<string> switches, out string romPath, out List<string> luaScriptsToLoad)
{
Func<string, bool, string> getValidPath = (string path, bool forLua) => {
path = path.Trim();
if(path.ToLower().EndsWith(".lua") == forLua) {
try {
if(!File.Exists(path)) {
//Try loading file as a relative path to the folder Mesen was started from
path = Path.Combine(Program.OriginalFolder, path);
}
if(File.Exists(path)) {
return path;
}
} catch { }
}
return null;
};
//Check if any Lua scripts were specified
luaScriptsToLoad = new List<string>();
foreach(string arg in switches) {
string path = getValidPath(arg, true);
if(path != null) {
luaScriptsToLoad.Add(path);
}
}
romPath = null;
foreach(string arg in switches) {
string path = getValidPath(arg, false);
if(path != null) {
romPath = path;
break;
}
}
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
public class MinMaxAttribute : Attribute
{
public object Min { get; set; }
public object Max { get; set; }
public MinMaxAttribute(object min, object max)
{
this.Min = min;
this.Max = max;
}
}
public class ValidValuesAttribute : Attribute
{
public uint[] ValidValues { get; set; }
public ValidValuesAttribute(params uint[] validValues)
{
this.ValidValues = validValues;
}
}
}

301
UI/Config/ConfigManager.cs Normal file
View file

@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml.Serialization;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Windows.Forms;
namespace Mesen.GUI.Config
{
class ConfigManager
{
private static Configuration _config;
private static Configuration _dirtyConfig;
public static bool DoNotSaveSettings { get; set; }
public static string DefaultPortableFolder { get { return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); } }
public static string DefaultDocumentsFolder
{
get
{
if(Program.IsMono) {
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), ".config", "mesen-s");
} else {
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Mesen-S");
}
}
}
public static string DefaultAviFolder { get { return Path.Combine(HomeFolder, "Avi"); } }
public static string DefaultMovieFolder { get { return Path.Combine(HomeFolder, "Movies"); } }
public static string DefaultSaveDataFolder { get { return Path.Combine(HomeFolder, "Saves"); } }
public static string DefaultSaveStateFolder { get { return Path.Combine(HomeFolder, "SaveStates"); } }
public static string DefaultScreenshotFolder { get { return Path.Combine(HomeFolder, "Screenshots"); } }
public static string DefaultWaveFolder { get { return Path.Combine(HomeFolder, "Wave"); } }
public static void InitHomeFolder()
{
string portableFolder = DefaultPortableFolder;
string documentsFolder = DefaultDocumentsFolder;
//Linux only
string portableConfig = Path.Combine(portableFolder, "settings.xml");
string documentsConfig = Path.Combine(documentsFolder, "settings.xml");
HomeFolder = null;
if(File.Exists(portableConfig)) {
HomeFolder = portableFolder;
} else if(File.Exists(documentsConfig)) {
HomeFolder = documentsFolder;
}
}
public static string GetConfigFile()
{
InitHomeFolder();
if(!string.IsNullOrWhiteSpace(HomeFolder)) {
return Path.Combine(HomeFolder, "settings.xml");
} else {
return null;
}
}
public static void CreateConfig(bool portable)
{
if(portable) {
HomeFolder = DefaultPortableFolder;
} else {
HomeFolder = DefaultDocumentsFolder;
}
LoadConfig();
}
private static object _initLock = new object();
private static void LoadConfig()
{
if(_config == null) {
lock(_initLock) {
if(_config == null) {
if(File.Exists(ConfigFile)) {
_config = Configuration.Deserialize(ConfigFile);
_dirtyConfig = Configuration.Deserialize(ConfigFile);
} else {
//Create new config file and save it to disk
_config = new Configuration();
_dirtyConfig = new Configuration();
_config.Save();
}
}
}
}
}
private static void ApplySetting(Type type, object instance, string name, string value)
{
FieldInfo[] fields = type.GetFields();
foreach(FieldInfo info in fields) {
if(string.Compare(info.Name, name, true) == 0) {
try {
if(info.FieldType == typeof(int) || info.FieldType == typeof(uint) || info.FieldType == typeof(double)) {
MinMaxAttribute minMaxAttribute = info.GetCustomAttribute(typeof(MinMaxAttribute)) as MinMaxAttribute;
if(minMaxAttribute != null) {
if(info.FieldType == typeof(int)) {
int result;
if(int.TryParse(value, out result)) {
if(result >= (int)minMaxAttribute.Min && result <= (int)minMaxAttribute.Max) {
info.SetValue(instance, result);
}
}
} else if(info.FieldType == typeof(uint)) {
uint result;
if(uint.TryParse(value, out result)) {
if(result >= (uint)(int)minMaxAttribute.Min && result <= (uint)(int)minMaxAttribute.Max) {
info.SetValue(instance, result);
}
}
} else if(info.FieldType == typeof(double)) {
double result;
if(double.TryParse(value, out result)) {
if(result >= (double)minMaxAttribute.Min && result <= (double)minMaxAttribute.Max) {
info.SetValue(instance, result);
}
}
}
} else {
ValidValuesAttribute validValuesAttribute = info.GetCustomAttribute(typeof(ValidValuesAttribute)) as ValidValuesAttribute;
if(validValuesAttribute != null) {
uint result;
if(uint.TryParse(value, out result)) {
if(validValuesAttribute.ValidValues.Contains(result)) {
info.SetValue(instance, result);
}
}
}
}
} else if(info.FieldType == typeof(bool)) {
if(string.Compare(value, "false", true) == 0) {
info.SetValue(instance, false);
} else if(string.Compare(value, "true", true) == 0) {
info.SetValue(instance, true);
}
} else if(info.FieldType.IsEnum) {
int indexOf = Enum.GetNames(info.FieldType).Select((enumValue) => enumValue.ToLower()).ToList().IndexOf(value.ToLower());
if(indexOf >= 0) {
info.SetValue(instance, indexOf);
}
}
} catch {
}
break;
}
}
}
public static void ProcessSwitches(List<string> switches)
{
Regex regex = new Regex("/([a-z0-9_A-Z.]+)=([a-z0-9_A-Z.\\-]+)");
foreach(string param in switches) {
Match match = regex.Match(param);
if(match.Success) {
string switchName = match.Groups[1].Value;
string switchValue = match.Groups[2].Value;
/*ApplySetting(typeof(VideoInfo), Config.VideoInfo, switchName, switchValue);
ApplySetting(typeof(AudioInfo), Config.AudioInfo, switchName, switchValue);
ApplySetting(typeof(EmulationInfo), Config.EmulationInfo, switchName, switchValue);*/
ApplySetting(typeof(Configuration), Config, switchName, switchValue);
}
}
}
public static void SaveConfig()
{
_config.Save();
}
public static string HomeFolder { get; private set; }
public static string GetFolder(string defaultFolderName, string overrideFolder, bool useOverride)
{
string folder;
if(useOverride) {
folder = overrideFolder;
} else {
folder = defaultFolderName;
}
try {
if(!Directory.Exists(folder)) {
Directory.CreateDirectory(folder);
}
} catch {
//If the folder doesn't exist and we couldn't create it, use the default folder
//EmuApi.WriteLogEntry("[UI] Folder could not be created: " + folder);
folder = defaultFolderName;
}
return folder;
}
/* public static string AviFolder { get { return GetFolder(DefaultAviFolder, Config.PreferenceInfo.AviFolder, Config.PreferenceInfo.OverrideAviFolder); } }
public static string MovieFolder { get { return GetFolder(DefaultMovieFolder, Config.PreferenceInfo.MovieFolder, Config.PreferenceInfo.OverrideMovieFolder); } }
public static string SaveFolder { get { return GetFolder(DefaultSaveDataFolder, Config.PreferenceInfo.SaveDataFolder, Config.PreferenceInfo.OverrideSaveDataFolder); } }
public static string SaveStateFolder { get { return GetFolder(DefaultSaveStateFolder, Config.PreferenceInfo.SaveStateFolder, Config.PreferenceInfo.OverrideSaveStateFolder); } }
public static string ScreenshotFolder { get { return GetFolder(DefaultScreenshotFolder, Config.PreferenceInfo.ScreenshotFolder, Config.PreferenceInfo.OverrideScreenshotFolder); } }
public static string WaveFolder { get { return GetFolder(DefaultWaveFolder, Config.PreferenceInfo.WaveFolder, Config.PreferenceInfo.OverrideWaveFolder); } }
*/
public static string DebuggerFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "Debugger"), null, false); } }
public static string DownloadFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "Downloads"), null, false); } }
public static string BackupFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "Backups"), null, false); } }
public static string TestFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "Tests"), null, false); } }
public static string HdPackFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "HdPacks"), null, false); } }
public static string RecentGamesFolder { get { return GetFolder(Path.Combine(ConfigManager.HomeFolder, "RecentGames"), null, false); } }
public static string FontFolder { get { return GetFolder(Environment.GetFolderPath(Environment.SpecialFolder.Fonts, Environment.SpecialFolderOption.Create), null, false); } }
public static string ConfigFile
{
get
{
if(HomeFolder == null) {
//Initializes the HomeFolder property
InitHomeFolder();
}
if(!Directory.Exists(HomeFolder)) {
Directory.CreateDirectory(HomeFolder);
}
return Path.Combine(HomeFolder, "settings.xml");
}
}
public static Configuration Config
{
get
{
LoadConfig();
return _dirtyConfig;
}
}
private static DateTime _lastSaveTime = DateTime.MinValue;
public static void ApplyChanges()
{
_config.NeedToSave = false;
_config = _dirtyConfig.Clone();
_config.NeedToSave = true;
if((DateTime.Now - _lastSaveTime).Seconds > 1) {
ConfigManager.SaveConfig();
_lastSaveTime = DateTime.Now;
}
}
public static void RejectChanges()
{
_dirtyConfig = _config.Clone();
}
public static void RevertToBackup(Configuration config)
{
_config = config;
_dirtyConfig = _config.Clone();
}
public static void RevertDirtyToBackup(Configuration config)
{
_dirtyConfig = config.Clone();
}
public static void ResetSettings()
{
//DefaultKeyMappingType defaultMappings = Config.InputInfo.DefaultMapping;
_dirtyConfig = new Configuration();
//Config.InputInfo.DefaultMapping = defaultMappings;
Config.InitializeDefaults();
ApplyChanges();
Config.ApplyConfig();
}
public static void RestartMesen(bool preventSave = false)
{
if(preventSave) {
DoNotSaveSettings = true;
}
if(Program.IsMono) {
System.Diagnostics.Process.Start("mono", "\"" + Assembly.GetEntryAssembly().Location + "\" /delayrestart");
} else {
System.Diagnostics.Process.Start(Assembly.GetEntryAssembly().Location, "/delayrestart");
}
}
}
}

149
UI/Config/Configuration.cs Normal file
View file

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Config
{
public class Configuration
{
private const int MaxRecentFiles = 10;
private bool _needToSave = false;
public string Version = "0.1.0";
public List<RecentItem> RecentFiles;
public DebugInfo Debug;
public Point? WindowLocation;
public Size? WindowSize;
public Configuration()
{
RecentFiles = new List<RecentItem>();
Debug = new DebugInfo();
}
~Configuration()
{
//Try to save before destruction if we were unable to save at a previous point in time
Save();
}
public void Save()
{
if(_needToSave) {
Serialize(ConfigManager.ConfigFile);
}
}
public bool NeedToSave
{
set
{
_needToSave = value;
}
}
public void ApplyConfig()
{
}
public void InitializeDefaults()
{
}
public void AddRecentFile(ResourcePath romFile, ResourcePath? patchFile)
{
RecentItem existingItem = RecentFiles.Where((item) => item.RomFile == romFile && item.PatchFile == patchFile).FirstOrDefault();
if(existingItem != null) {
RecentFiles.Remove(existingItem);
}
RecentItem recentItem = new RecentItem { RomFile = romFile, PatchFile = patchFile };
RecentFiles.Insert(0, recentItem);
if(RecentFiles.Count > Configuration.MaxRecentFiles) {
RecentFiles.RemoveAt(Configuration.MaxRecentFiles);
}
ConfigManager.ApplyChanges();
}
public static Configuration Deserialize(string configFile)
{
Configuration config;
try {
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Configuration));
using(TextReader textReader = new StreamReader(configFile)) {
config = (Configuration)xmlSerializer.Deserialize(textReader);
}
} catch {
config = new Configuration();
}
return config;
}
public void Serialize(string configFile)
{
try {
if(!ConfigManager.DoNotSaveSettings) {
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Configuration));
using(TextWriter textWriter = new StreamWriter(configFile)) {
xmlSerializer.Serialize(textWriter, this);
}
}
_needToSave = false;
} catch {
//This can sometime fail due to the file being used by another Mesen instance, etc.
//In this case, the _needToSave flag will still be set, and the config will be saved when the emulator is closed
}
}
public Configuration Clone()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Configuration));
StringWriter stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, this);
StringReader stringReader = new StringReader(stringWriter.ToString());
Configuration config = (Configuration)xmlSerializer.Deserialize(stringReader);
config.NeedToSave = false;
return config;
}
}
public class RecentItem
{
public ResourcePath RomFile;
public ResourcePath? PatchFile;
public override string ToString()
{
string text;
/*if(ConfigManager.Config.PreferenceInfo.ShowFullPathInRecents) {
text = RomFile.ReadablePath.Replace("&", "&&");
} else {*/
text = Path.GetFileName(RomFile.FileName).Replace("&", "&&");
//}
if(PatchFile.HasValue) {
text += " [" + Path.GetFileName(PatchFile.Value) + "]";
}
return text;
}
}
[Flags]
public enum DefaultKeyMappingType
{
None = 0,
Xbox = 1,
Ps4 = 2,
WasdKeys = 3,
ArrowKeys = 4
}
}

85
UI/Config/DebugInfo.cs Normal file
View file

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using Mesen.GUI.Debugger;
using Mesen.GUI.Controls;
using Mesen.GUI.Utilities;
namespace Mesen.GUI.Config
{
public class TraceLoggerOptions
{
public bool ShowByteCode;
public bool ShowRegisters;
public bool ShowCpuCycles;
public bool ShowPpuCycles;
public bool ShowPpuScanline;
public bool ShowPpuFrames;
public bool ShowExtraInfo;
public bool IndentCode;
public bool ShowEffectiveAddresses;
public bool ShowMemoryValues;
public bool UseLabels;
public bool ExtendZeroPage;
public bool UseWindowsEol = !Program.IsMono;
public StatusFlagFormat StatusFormat;
public bool OverrideFormat;
public string Format;
}
public class DebugInfo
{
public bool ShowSelectionLength = false;
public XmlColor EventViewerBreakpointColor = ColorTranslator.FromHtml("#1898E4");
public XmlColor AssemblerOpcodeColor = Color.FromArgb(22, 37, 37);
public XmlColor AssemblerLabelDefinitionColor = Color.Blue;
public XmlColor AssemblerImmediateColor = Color.Chocolate;
public XmlColor AssemblerAddressColor = Color.DarkRed;
public XmlColor AssemblerCommentColor = Color.Green;
public XmlColor CodeEffectiveAddressColor = Color.SteelBlue;
public TraceLoggerOptions TraceLoggerOptions;
public bool TraceAutoRefresh = true;
public int TraceLineCount = 1000;
public Size TraceLoggerSize = new Size(0, 0);
public Point TraceLoggerLocation;
public string TraceFontFamily = BaseControl.MonospaceFontFamily;
public FontStyle TraceFontStyle = FontStyle.Regular;
public float TraceFontSize = BaseControl.DefaultFontSize;
public int TraceTextZoom = 100;
public DebugInfo()
{
TraceLoggerOptions = new TraceLoggerOptions() {
ShowByteCode = true,
ShowCpuCycles = true,
ShowEffectiveAddresses = true,
ShowExtraInfo = true,
ShowPpuFrames = false,
ShowPpuCycles = true,
ShowPpuScanline = true,
ShowRegisters = true,
UseLabels = false,
StatusFormat = StatusFlagFormat.Hexadecimal
};
}
}
public enum StatusFlagFormat
{
Hexadecimal = 0,
Text = 1,
CompactText = 2
}
}

View file

@ -0,0 +1,74 @@
using System.Windows.Forms;
using System.Drawing;
using Mesen.GUI;
using System;
using System.ComponentModel;
namespace Mesen.GUI.Controls
{
public class BaseControl : UserControl
{
public static float DefaultFontSize = Program.IsMono ? 10 : 12;
public static string MonospaceFontFamily
{
get
{
if(Program.IsMono) {
return "DroidSansMono";
} else {
return "Consolas";
}
}
}
private static bool? _isDesignMode = null;
public bool IsDesignMode
{
get
{
try {
if(!_isDesignMode.HasValue) {
_isDesignMode = System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv";
}
return _isDesignMode.Value || LicenseManager.UsageMode == LicenseUsageMode.Designtime;
} catch {
return false;
}
}
}
public static Bitmap DownArrow
{
get
{
if(!Program.IsMono && Environment.OSVersion.Version >= new Version(6, 2)) {
return Properties.Resources.DownArrowWin10;
} else {
return Properties.Resources.DownArrow;
}
}
}
public new AutoScaleMode AutoScaleMode
{
set {
if(Program.IsMono) {
base.AutoScaleMode = AutoScaleMode.None;
} else {
base.AutoScaleMode = value;
}
}
}
public new SizeF AutoScaleDimensions
{
set
{
if(!Program.IsMono) {
base.AutoScaleDimensions = value;
}
}
}
}
}

View file

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
class MesenNumericUpDown : BaseControl
{
private TextBox txtValue;
private Button btnUp;
private Button btnDown;
private Panel pnlButtons;
private Timer tmrRepeat;
private int _repeatCount = 0;
private bool _repeatIncrease = false;
private bool _preventClick = false;
public event EventHandler ValueChanged;
public MesenNumericUpDown()
{
InitializeComponent();
if(!IsDesignMode) {
this.BackColor = SystemColors.ControlLightLight;
this.MaximumSize = new Size(10000, 21);
this.MinimumSize = new Size(0, 21);
this.Size = new Size(62, 21);
this.btnDown.Image = Properties.Resources.NudDownArrow;
this.btnUp.Image = Properties.Resources.NudUpArrow;
if(Program.IsMono) {
this.BorderStyle = BorderStyle.None;
this.txtValue.Dock = DockStyle.Fill;
this.txtValue.Multiline = true;
this.btnUp.Location = new Point(-1, 0);
this.btnDown.Location = new Point(-1, 10);
this.MinimumSize = new Size(0, 22);
} else {
this.BorderStyle = BorderStyle.FixedSingle;
}
}
}
private void tmrRepeat_Tick(object sender, EventArgs e)
{
tmrRepeat.Interval = _repeatCount > 5 ? 75 : 200;
if(_repeatIncrease) {
this.Value += this.Increment;
} else {
this.Value -= this.Increment;
}
_repeatCount++;
_preventClick = true;
}
private void btn_MouseDown(object sender, MouseEventArgs e)
{
_repeatCount = 0;
_repeatIncrease = (sender == btnUp);
tmrRepeat.Start();
}
private void btn_MouseUp(object sender, MouseEventArgs e)
{
tmrRepeat.Stop();
}
private void btnDown_Click(object sender, EventArgs e)
{
if(!_preventClick) {
this.Value -= this.Increment;
}
_preventClick = false;
}
private void btnUp_Click(object sender, EventArgs e)
{
if(!_preventClick) {
this.Value += this.Increment;
}
_preventClick = false;
}
private void txtValue_TextChanged(object sender, EventArgs e)
{
decimal val;
if(string.IsNullOrWhiteSpace(txtValue.Text)) {
SetValue(0, false);
} else if(decimal.TryParse(txtValue.Text, out val)) {
SetValue(val, false);
}
}
private void txtValue_Validated(object sender, EventArgs e)
{
decimal val;
if(string.IsNullOrWhiteSpace(txtValue.Text)) {
SetValue(0, true);
} else if(decimal.TryParse(txtValue.Text, out val)) {
SetValue(val, true);
} else {
SetValue(this.Value, true);
}
}
private void SetValue(decimal value, bool updateText)
{
value = decimal.Round(value, this.DecimalPlaces);
if(value > Maximum) {
value = Maximum;
}
if(value < Minimum) {
value = Minimum;
}
if(value != _value) {
_value = value;
ValueChanged?.Invoke(this, EventArgs.Empty);
}
if(updateText) {
txtValue.Text = value.ToString("0" + (this.DecimalPlaces > 0 ? "." : "") + new string('0', this.DecimalPlaces));
}
}
private decimal _value = 0;
public decimal Value
{
get { return _value; }
set
{
SetValue(value, true);
}
}
public new string Text
{
get { return txtValue.Text; }
set { txtValue.Text = value; }
}
private decimal _maximum = 100;
public decimal Maximum
{
get { return _maximum; }
set { _maximum = value; SetValue(this.Value, true); }
}
private decimal _minimum = 0;
public decimal Minimum
{
get { return _minimum; }
set { _minimum = value; SetValue(this.Value, true); }
}
public decimal Increment { get; set; } = 1;
private int _decimalPlaces = 0;
public int DecimalPlaces
{
get { return _decimalPlaces; }
set { _decimalPlaces = value; }
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if(this.Height < 21) {
this.Height = 21;
}
}
private void txtValue_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Up) {
this.Value += this.Increment;
e.SuppressKeyPress = true;
} else if(e.KeyCode == Keys.Down) {
this.Value -= this.Increment;
e.SuppressKeyPress = true;
} else if(
!((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ||
(e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) ||
e.KeyCode == Keys.OemPeriod || e.KeyCode == Keys.Oemcomma ||
e.KeyCode == Keys.Delete || e.KeyCode == Keys.Left ||
e.KeyCode == Keys.Right || e.KeyCode == Keys.Home ||
e.KeyCode == Keys.End || e.KeyCode == Keys.Back)
) {
e.SuppressKeyPress = true;
}
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.txtValue = new System.Windows.Forms.TextBox();
this.btnUp = new System.Windows.Forms.Button();
this.btnDown = new System.Windows.Forms.Button();
this.pnlButtons = new System.Windows.Forms.Panel();
this.pnlButtons.SuspendLayout();
this.SuspendLayout();
//
// txtValue
//
this.txtValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.txtValue.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtValue.Location = new System.Drawing.Point(1, 3);
this.txtValue.Margin = new System.Windows.Forms.Padding(0);
this.txtValue.Name = "txtValue";
this.txtValue.Size = new System.Drawing.Size(44, 13);
this.txtValue.TabIndex = 0;
this.txtValue.TextChanged += new System.EventHandler(this.txtValue_TextChanged);
this.txtValue.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txtValue_KeyDown);
this.txtValue.Validated += new System.EventHandler(this.txtValue_Validated);
//
// btnUp
//
this.btnUp.Location = new System.Drawing.Point(1, -1);
this.btnUp.Margin = new System.Windows.Forms.Padding(0);
this.btnUp.Name = "btnUp";
this.btnUp.Size = new System.Drawing.Size(15, 11);
this.btnUp.TabIndex = 2;
this.btnUp.TabStop = false;
this.btnUp.UseVisualStyleBackColor = true;
this.btnUp.Click += new System.EventHandler(this.btnUp_Click);
this.btnUp.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btn_MouseDown);
this.btnUp.MouseUp += new System.Windows.Forms.MouseEventHandler(this.btn_MouseUp);
//
// btnDown
//
this.btnDown.Location = new System.Drawing.Point(1, 9);
this.btnDown.Margin = new System.Windows.Forms.Padding(0);
this.btnDown.Name = "btnDown";
this.btnDown.Size = new System.Drawing.Size(15, 11);
this.btnDown.TabIndex = 3;
this.btnDown.TabStop = false;
this.btnDown.UseVisualStyleBackColor = true;
this.btnDown.Click += new System.EventHandler(this.btnDown_Click);
this.btnDown.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btn_MouseDown);
this.btnDown.MouseUp += new System.Windows.Forms.MouseEventHandler(this.btn_MouseUp);
//
// pnlButtons
//
this.pnlButtons.Controls.Add(this.btnDown);
this.pnlButtons.Controls.Add(this.btnUp);
this.pnlButtons.Dock = System.Windows.Forms.DockStyle.Right;
this.pnlButtons.Location = new System.Drawing.Point(47, 0);
this.pnlButtons.Margin = new System.Windows.Forms.Padding(0);
this.pnlButtons.Name = "pnlButtons";
this.pnlButtons.Size = new System.Drawing.Size(15, 21);
this.pnlButtons.TabIndex = 1;
//
// tmrRepeat
//
this.tmrRepeat = new Timer(components);
this.tmrRepeat.Tick += tmrRepeat_Tick;
//
// MesenNumericUpDown
//
this.Controls.Add(this.txtValue);
this.Controls.Add(this.pnlButtons);
this.MaximumSize = new System.Drawing.Size(10000, 21);
this.MinimumSize = new System.Drawing.Size(0, 21);
this.Name = "MesenNumericUpDown";
this.Size = new System.Drawing.Size(62, 21);
this.pnlButtons.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
/// <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);
}
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

79
UI/Controls/MyListView.cs Normal file
View file

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
class MyListView : ListView
{
private bool _preventCheck = false;
public MyListView()
{
this.DoubleBuffered = true;
}
protected override void OnItemCheck(ItemCheckEventArgs e)
{
if(this._preventCheck || Control.ModifierKeys.HasFlag(Keys.Control) || Control.ModifierKeys.HasFlag(Keys.Shift)) {
e.NewValue = e.CurrentValue;
this._preventCheck = false;
} else {
base.OnItemCheck(e);
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
if(e.Button == MouseButtons.Left && e.Clicks > 1) {
this._preventCheck = true;
} else {
this._preventCheck = false;
}
base.OnMouseDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
this._preventCheck = false;
base.OnKeyDown(e);
}
}
public class WatchListView : DoubleBufferedListView
{
public delegate void MoveUpDownHandler(Keys keyData, ref bool processed);
public event MoveUpDownHandler OnMoveUpDown;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData.HasFlag(Keys.Up) || keyData.HasFlag(Keys.Down)) {
bool processed = false;
OnMoveUpDown?.Invoke(keyData, ref processed);
if(processed) {
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
public class DoubleBufferedListView : ListView
{
public DoubleBufferedListView()
{
this.DoubleBuffered = true;
}
protected override void OnVirtualItemsSelectionRangeChanged(ListViewVirtualItemsSelectionRangeChangedEventArgs e)
{
base.OnVirtualItemsSelectionRangeChanged(e);
base.OnSelectedIndexChanged(e);
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public class ctrlAutoGrowLabel : Label
{
private bool _growing;
public ctrlAutoGrowLabel()
{
this.AutoSize = false;
}
private void resizeLabel()
{
if(_growing) {
return;
}
try {
_growing = true;
Size textSize = new Size(this.ClientSize.Width - this.Padding.Left - this.Padding.Right, Int32.MaxValue);
textSize = TextRenderer.MeasureText(this.Text, this.Font, textSize, TextFormatFlags.WordBreak);
this.ClientSize = new Size(textSize.Width + this.Margin.Size.Width + this.Padding.Size.Width, textSize.Height);
} finally {
_growing = false;
}
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
resizeLabel();
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
resizeLabel();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
resizeLabel();
}
}
}

View file

@ -0,0 +1,67 @@
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;
namespace Mesen.GUI.Controls
{
public partial class ctrlHorizontalTrackbar : BaseControl
{
public event EventHandler ValueChanged
{
add { trackBar.ValueChanged += value; }
remove { trackBar.ValueChanged -= value; }
}
public ctrlHorizontalTrackbar()
{
InitializeComponent();
if(!Program.IsMono) {
this.trackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
}
}
public int Maximum
{
get { return trackBar.Maximum; }
set { trackBar.Maximum = value; }
}
public int Minimum
{
get { return trackBar.Minimum; }
set { trackBar.Minimum = value; }
}
[Bindable(true)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public override string Text
{
get { return lblText.Text; }
set { lblText.Text = value; }
}
public int Value
{
get { return trackBar.Value; }
set
{
trackBar.Value = Math.Max(trackBar.Minimum, Math.Min(value, trackBar.Maximum));
lblValue.Text = trackBar.Value.ToString();
}
}
private void trackBar_ValueChanged(object sender, EventArgs e)
{
lblValue.Text = trackBar.Value.ToString();
}
}
}

View file

@ -0,0 +1,118 @@
namespace Mesen.GUI.Controls
{
partial class ctrlHorizontalTrackbar
{
/// <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 Component 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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.trackBar = new System.Windows.Forms.TrackBar();
this.lblValue = new System.Windows.Forms.Label();
this.lblText = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit();
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(System.Windows.Forms.SizeType.Absolute, 35F));
this.tableLayoutPanel1.Controls.Add(this.trackBar, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.lblValue, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.lblText, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(206, 50);
this.tableLayoutPanel1.TabIndex = 0;
//
// trackBar
//
this.trackBar.AutoSize = false;
this.trackBar.Dock = System.Windows.Forms.DockStyle.Fill;
this.trackBar.Location = new System.Drawing.Point(0, 13);
this.trackBar.Margin = new System.Windows.Forms.Padding(0);
this.trackBar.Maximum = 100;
this.trackBar.Minimum = -100;
this.trackBar.Name = "trackBar";
this.trackBar.Size = new System.Drawing.Size(171, 35);
this.trackBar.TabIndex = 13;
this.trackBar.TickFrequency = 10;
this.trackBar.Value = 50;
this.trackBar.ValueChanged += new System.EventHandler(this.trackBar_ValueChanged);
//
// lblValue
//
this.lblValue.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblValue.BackColor = System.Drawing.Color.White;
this.lblValue.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lblValue.Location = new System.Drawing.Point(174, 13);
this.lblValue.MinimumSize = new System.Drawing.Size(30, 17);
this.lblValue.Name = "lblValue";
this.lblValue.Size = new System.Drawing.Size(30, 17);
this.lblValue.TabIndex = 17;
this.lblValue.Text = "100";
this.lblValue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// lblText
//
this.lblText.AutoSize = true;
this.lblText.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblText.Location = new System.Drawing.Point(3, 0);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(165, 13);
this.lblText.TabIndex = 18;
this.lblText.Text = "Text";
this.lblText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// ctrlHorizontalTrackbar
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Margin = new System.Windows.Forms.Padding(0);
this.Name = "ctrlHorizontalTrackbar";
this.Size = new System.Drawing.Size(206, 50);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TrackBar trackBar;
private System.Windows.Forms.Label lblValue;
private System.Windows.Forms.Label lblText;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,20 @@
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;
namespace Mesen.GUI.Controls
{
public partial class ctrlLoadingRom : BaseControl
{
public ctrlLoadingRom()
{
InitializeComponent();
}
}
}

96
UI/Controls/ctrlLoadingRom.designer.cs generated Normal file
View file

@ -0,0 +1,96 @@
namespace Mesen.GUI.Controls
{
partial class ctrlLoadingRom
{
/// <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 Component 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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.pbLoading = new System.Windows.Forms.ProgressBar();
this.lblExtractingFile = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 200F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.pbLoading, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.lblExtractingFile, 0, 2);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 4;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(261, 107);
this.tableLayoutPanel1.TabIndex = 0;
//
// pbLoading
//
this.pbLoading.Dock = System.Windows.Forms.DockStyle.Fill;
this.pbLoading.Location = new System.Drawing.Point(33, 35);
this.pbLoading.Name = "pbLoading";
this.pbLoading.Size = new System.Drawing.Size(194, 23);
this.pbLoading.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.pbLoading.TabIndex = 0;
//
// lblExtractingFile
//
this.lblExtractingFile.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lblExtractingFile.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.lblExtractingFile, 3);
this.lblExtractingFile.ForeColor = System.Drawing.Color.White;
this.lblExtractingFile.Location = new System.Drawing.Point(61, 61);
this.lblExtractingFile.Name = "lblExtractingFile";
this.lblExtractingFile.Size = new System.Drawing.Size(138, 13);
this.lblExtractingFile.TabIndex = 1;
this.lblExtractingFile.Text = "Extracting file, please wait...";
//
// ctrlLoadingRom
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "ctrlLoadingRom";
this.Size = new System.Drawing.Size(261, 107);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.ProgressBar pbLoading;
private System.Windows.Forms.Label lblExtractingFile;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public class ctrlMesenContextMenuStrip : ContextMenuStrip
{
public ctrlMesenContextMenuStrip() : base()
{
}
public ctrlMesenContextMenuStrip(IContainer container) : base(container)
{
}
internal bool ProcessCommandKey(ref Message msg, Keys keyData)
{
return this.ProcessCmdKey(ref msg, keyData);
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public class ctrlMesenMenuStrip : MenuStrip
{
private const int WM_MOUSEACTIVATE = 0x21;
protected override void WndProc(ref Message m)
{
if(m.Msg == WM_MOUSEACTIVATE && this.CanFocus && !this.Focused) {
this.FindForm()?.Focus();
}
base.WndProc(ref m);
}
}
}

View file

@ -0,0 +1,16 @@
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public class ctrlMesenPictureBox : PictureBox
{
public InterpolationMode InterpolationMode { get; set; }
protected override void OnPaint(PaintEventArgs paintEventArgs)
{
paintEventArgs.Graphics.InterpolationMode = InterpolationMode;
base.OnPaint(paintEventArgs);
}
}
}

View file

@ -0,0 +1,60 @@
using Mesen.GUI.Config;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public class ctrlMesenToolStrip : ToolStrip
{
private const int WM_MOUSEACTIVATE = 0x21;
protected override void WndProc(ref Message m)
{
if(m.Msg == WM_MOUSEACTIVATE && this.CanFocus && !this.Focused) {
this.FindForm()?.Focus();
}
base.WndProc(ref m);
}
public void AddItemToToolbar(ToolStripMenuItem item, string caption = null)
{
if(item == null) {
this.Items.Add("-");
} else {
ToolStripItem newItem = item.HasDropDownItems ? (ToolStripItem)new ToolStripDropDownButton(item.Text, item.Image) : (ToolStripItem)new ToolStripButton(item.Image);
if(item.Image == null) {
newItem.Text = item.Text;
}
//newItem.ToolTipText = (caption ?? item.Text) + (item.ShortcutKeys != Keys.None ? $" ({DebuggerShortcutsConfig.GetShortcutDisplay(item.ShortcutKeys)})" : "");
newItem.Click += (s, e) => item.PerformClick();
if(newItem is ToolStripButton) {
((ToolStripButton)newItem).Checked = item.Checked;
item.CheckedChanged += (s, e) => ((ToolStripButton)newItem).Checked = item.Checked;
}
newItem.Enabled = item.Enabled;
//newItem.MouseEnter += (s, e) => newItem.ToolTipText = (caption ?? item.Text) + (item.ShortcutKeys != Keys.None ? $" ({DebuggerShortcutsConfig.GetShortcutDisplay(item.ShortcutKeys)})" : "");
item.EnabledChanged += (s, e) => newItem.Enabled = item.Enabled;
item.VisibleChanged += (s, e) => newItem.Visible = item.Visible;
if(item.HasDropDownItems) {
foreach(ToolStripItem ddItem in item.DropDownItems) {
ToolStripItem newDdItem = ((ToolStripDropDownButton)newItem).DropDownItems.Add(ddItem.Text, ddItem.Image);
newDdItem.Click += (s, e) => ddItem.PerformClick();
}
}
this.Items.Add(newItem);
}
}
public void AddItemsToToolbar(params ToolStripMenuItem[] items)
{
foreach(ToolStripMenuItem item in items) {
AddItemToToolbar(item);
}
}
}
}

View file

@ -0,0 +1,59 @@
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 Mesen.GUI.Controls;
namespace Mesen.GUI.Forms.Config
{
public partial class ctrlPathSelection : BaseControl
{
public ctrlPathSelection()
{
InitializeComponent();
txtDisabledPath.ReadOnly = true;
txtDisabledPath.Visible = false;
}
public string DisabledText
{
get { return txtDisabledPath.Text; }
set { txtDisabledPath.Text = value; }
}
public override string Text
{
get { return txtPath.Text; }
set { txtPath.Text = value; }
}
public new bool Enabled
{
get { return !txtPath.ReadOnly; }
set
{
txtPath.Visible = value;
txtDisabledPath.Visible = !value;
tlpPath.ColumnStyles[0].SizeType = value ? SizeType.Percent : SizeType.Absolute;
tlpPath.ColumnStyles[1].SizeType = value ? SizeType.Absolute : SizeType.Percent;
tlpPath.ColumnStyles[0].Width = value ? 100F : 0F;
tlpPath.ColumnStyles[1].Width = value ? 0F : 100F;
btnBrowse.Visible = value;
}
}
private void btnBrowse_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if(fbd.ShowDialog() == DialogResult.OK) {
txtPath.Text = fbd.SelectedPath;
}
}
}
}

126
UI/Controls/ctrlPathSelection.designer.cs generated Normal file
View file

@ -0,0 +1,126 @@
namespace Mesen.GUI.Forms.Config
{
partial class ctrlPathSelection
{
/// <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 Component 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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.tlpPath = new System.Windows.Forms.TableLayoutPanel();
this.txtDisabledPath = new System.Windows.Forms.TextBox();
this.txtPath = new System.Windows.Forms.TextBox();
this.btnBrowse = new System.Windows.Forms.Button();
this.tableLayoutPanel1.SuspendLayout();
this.tlpPath.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.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Controls.Add(this.tlpPath, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnBrowse, 1, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(235, 21);
this.tableLayoutPanel1.TabIndex = 0;
//
// tlpPath
//
this.tlpPath.ColumnCount = 2;
this.tlpPath.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpPath.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 0F));
this.tlpPath.Controls.Add(this.txtDisabledPath, 1, 0);
this.tlpPath.Controls.Add(this.txtPath, 0, 0);
this.tlpPath.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpPath.Location = new System.Drawing.Point(0, 0);
this.tlpPath.Margin = new System.Windows.Forms.Padding(0);
this.tlpPath.Name = "tlpPath";
this.tlpPath.RowCount = 1;
this.tlpPath.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpPath.Size = new System.Drawing.Size(209, 21);
this.tlpPath.TabIndex = 1;
//
// txtDisabledPath
//
this.txtDisabledPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.txtDisabledPath.Location = new System.Drawing.Point(209, 0);
this.txtDisabledPath.Margin = new System.Windows.Forms.Padding(0);
this.txtDisabledPath.Name = "txtDisabledPath";
this.txtDisabledPath.Size = new System.Drawing.Size(1, 20);
this.txtDisabledPath.TabIndex = 1;
//
// txtPath
//
this.txtPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.txtPath.Location = new System.Drawing.Point(0, 0);
this.txtPath.Margin = new System.Windows.Forms.Padding(0);
this.txtPath.Name = "txtPath";
this.txtPath.Size = new System.Drawing.Size(209, 20);
this.txtPath.TabIndex = 0;
//
// btnBrowse
//
this.btnBrowse.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.btnBrowse.Location = new System.Drawing.Point(209, 0);
this.btnBrowse.Margin = new System.Windows.Forms.Padding(0);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(26, 20);
this.btnBrowse.TabIndex = 1;
this.btnBrowse.Text = "...";
this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// ctrlPathSelection
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Margin = new System.Windows.Forms.Padding(0);
this.MaximumSize = new System.Drawing.Size(1000, 21);
this.MinimumSize = new System.Drawing.Size(0, 21);
this.Name = "ctrlPathSelection";
this.Size = new System.Drawing.Size(235, 21);
this.tableLayoutPanel1.ResumeLayout(false);
this.tlpPath.ResumeLayout(false);
this.tlpPath.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TextBox txtPath;
private System.Windows.Forms.Button btnBrowse;
private System.Windows.Forms.TableLayoutPanel tlpPath;
private System.Windows.Forms.TextBox txtDisabledPath;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,67 @@
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 Mesen.GUI.Config;
namespace Mesen.GUI.Controls
{
public partial class ctrlRenderer : BaseControl
{
private const int LeftMouseButtonKeyCode = 0x200;
private const int RightMouseButtonKeyCode = 0x201;
private const int MiddleMouseButtonKeyCode = 0x202;
public ctrlRenderer()
{
InitializeComponent();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
SetMouseButtonState(Control.MouseButtons);
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
SetMouseButtonState(Control.MouseButtons);
}
private void SetMouseButtonState(MouseButtons pressedButtons)
{
EmuApi.SetKeyState(LeftMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Left));
EmuApi.SetKeyState(RightMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Right));
EmuApi.SetKeyState(MiddleMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Middle));
}
private void ctrlRenderer_MouseMove(object sender, MouseEventArgs e)
{
/*CursorManager.OnMouseMove(this);
if(CursorManager.NeedMouseIcon) {
this.Cursor = Cursors.Cross;
}
*/
double xPos = (double)e.X / this.Width;
double yPos = (double)e.Y / this.Height;
xPos = Math.Max(0.0, Math.Min(1.0, xPos));
yPos = Math.Max(0.0, Math.Min(1.0, yPos));
EmuApi.SetMousePosition(xPos, yPos);
}
private void ctrlRenderer_MouseLeave(object sender, EventArgs e)
{
//CursorManager.OnMouseLeave();
EmuApi.SetMousePosition(-1, -1);
}
}
}

45
UI/Controls/ctrlRenderer.designer.cs generated Normal file
View file

@ -0,0 +1,45 @@
namespace Mesen.GUI.Controls
{
partial class ctrlRenderer
{
/// <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 Component 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.SuspendLayout();
//
// ctrlRenderer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "ctrlRenderer";
this.MouseLeave += new System.EventHandler(this.ctrlRenderer_MouseLeave);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseMove);
this.ResumeLayout(false);
}
#endregion
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,48 @@
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 Mesen.GUI.Forms;
using System.IO;
using Mesen.GUI.Controls;
namespace Mesen.GUI.Controls
{
public partial class ctrlRiskyOption : BaseControl
{
public ctrlRiskyOption()
{
InitializeComponent();
this.lblNotRecommended.Text = ResourceHelper.GetMessage("RiskyOptionHint");
this.lblNotRecommended.ForeColor = SystemColors.ControlDark;
}
private void chkOption_CheckedChanged(object sender, EventArgs e)
{
this.lblNotRecommended.ForeColor = this.chkOption.Checked ? Color.Red : SystemColors.ControlDark;
}
[Bindable(true)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public override string Text
{
get { return chkOption.Text; }
set { chkOption.Text = value; }
}
public bool Checked
{
get { return chkOption.Checked; }
set { chkOption.Checked = value; }
}
protected override Padding DefaultMargin { get { return new Padding(0); } }
}
}

96
UI/Controls/ctrlRiskyOption.designer.cs generated Normal file
View file

@ -0,0 +1,96 @@
namespace Mesen.GUI.Controls
{
partial class ctrlRiskyOption
{
/// <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 Component 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.chkOption = new System.Windows.Forms.CheckBox();
this.lblNotRecommended = new System.Windows.Forms.Label();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// chkOption
//
this.chkOption.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkOption.AutoSize = true;
this.chkOption.Location = new System.Drawing.Point(3, 3);
this.chkOption.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.chkOption.Name = "chkOption";
this.chkOption.Size = new System.Drawing.Size(86, 15);
this.chkOption.TabIndex = 0;
this.chkOption.Text = "Option name";
this.chkOption.UseVisualStyleBackColor = true;
this.chkOption.CheckedChanged += new System.EventHandler(this.chkOption_CheckedChanged);
//
// lblNotRecommended
//
this.lblNotRecommended.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblNotRecommended.AutoSize = true;
this.lblNotRecommended.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblNotRecommended.Location = new System.Drawing.Point(89, 3);
this.lblNotRecommended.Margin = new System.Windows.Forms.Padding(0, 0, 0, 2);
this.lblNotRecommended.Name = "lblNotRecommended";
this.lblNotRecommended.Size = new System.Drawing.Size(98, 13);
this.lblNotRecommended.TabIndex = 1;
this.lblNotRecommended.Text = "(not recommended)";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.lblNotRecommended, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.chkOption, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 226F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(193, 21);
this.tableLayoutPanel1.TabIndex = 1;
//
// ctrlRiskyOption
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "ctrlRiskyOption";
this.Size = new System.Drawing.Size(193, 21);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.CheckBox chkOption;
private System.Windows.Forms.Label lblNotRecommended;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
class ctrlSplitContainer : SplitContainer
{
public event EventHandler PanelCollapsed;
public event EventHandler PanelExpanded;
private int _originalDistance = 0;
private int _originalMinSize = 0;
private bool _collapsed = false;
private bool _preventExpand = false;
private bool _hidePanel2 = false;
public ctrlSplitContainer()
{
this.DoubleBuffered = true;
this.SplitterMoving += ctrlSplitContainer_SplitterMoving;
}
public bool HidePanel2
{
get { return _hidePanel2; }
set { _hidePanel2 = value; this.Invalidate(); }
}
private void ctrlSplitContainer_SplitterMoving(object sender, SplitterCancelEventArgs e)
{
if(_originalMinSize > 0) {
e.Cancel = true;
this.BeginInvoke((MethodInvoker)(() => {
this.ExpandPanel();
}));
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if(_hidePanel2) {
return;
}
if(this.Orientation == Orientation.Horizontal) {
int top = this.SplitterDistance + 1;
int center = this.Width / 2;
e.Graphics.DrawLine(Pens.DarkGray, center - 100, top, center + 100, top);
top+=2;
e.Graphics.DrawLine(Pens.DarkGray, center - 100, top, center + 100, top);
} else {
int center = this.Height / 2;
int left = this.SplitterDistance + 1;
e.Graphics.DrawLine(Pens.DarkGray, left, center - 100, left, center + 100);
left+=2;
e.Graphics.DrawLine(Pens.DarkGray, left, center - 100, left, center + 100);
}
}
protected override void OnDoubleClick(EventArgs e)
{
base.OnDoubleClick(e);
if(_hidePanel2) {
return;
}
if(_originalMinSize == 0) {
this.CollapsePanel();
_preventExpand = true;
} else {
this.ExpandPanel();
}
}
public void ExpandPanel()
{
if(_hidePanel2 || !_collapsed) {
return;
}
if(this.FixedPanel == FixedPanel.Panel1) {
throw new Exception("Not implemented");
} else if(this.FixedPanel == FixedPanel.Panel2) {
if(_originalMinSize > 0) {
this.Panel2MinSize = _originalMinSize;
this.SplitterDistance = _originalDistance;
_originalMinSize = 0;
}
this.PanelExpanded?.Invoke(this, EventArgs.Empty);
_collapsed = false;
}
}
public void CollapsePanel()
{
if(_collapsed) {
return;
}
if(this.FixedPanel == FixedPanel.Panel1) {
throw new Exception("Not implemented");
} else if(this.FixedPanel == FixedPanel.Panel2) {
_collapsed = true;
_originalDistance = this.SplitterDistance;
_originalMinSize = this.Panel2MinSize;
this.Panel2MinSize = 2;
this.SplitterDistance = this.Orientation == Orientation.Horizontal ? this.Height : this.Width;
this.PanelCollapsed?.Invoke(this, EventArgs.Empty);
}
}
public int GetSplitterDistance()
{
return _originalMinSize > 0 ? _originalDistance : this.SplitterDistance;
}
DateTime _lastResize = DateTime.MinValue;
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
if(_hidePanel2) {
return;
}
//Horrible patch to fix what looks like a resize bug in SplitContainers
//Resizing the window sometimes doesn't resize the inner panels properly
//causing their content to go partially offscreen.
//This code alters SplitterDistance approx 100ms after the last resize event
//to fix the display bug
if(this.IsHandleCreated) {
bool firstResize;
lock(this) {
firstResize = _lastResize == DateTime.MinValue;
_lastResize = DateTime.Now;
}
if(firstResize) {
Task.Run(() => {
while((DateTime.Now - _lastResize).Milliseconds < 100) {
System.Threading.Thread.Sleep(100);
}
this.BeginInvoke((MethodInvoker)(() => {
if(_originalMinSize == 0) {
this.SuspendLayout();
this.Panel1.SuspendLayout();
this.Panel2.SuspendLayout();
try {
if(this.Width > 0 && this.Height > 0) {
this.SplitterDistance++;
this.SplitterDistance--;
}
} catch {
} finally {
this.ResumeLayout();
this.Panel1.ResumeLayout();
this.Panel2.ResumeLayout();
}
}
this.Invalidate();
lock(this) {
_lastResize = DateTime.MinValue;
}
}));
});
}
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
this.Panel1.Focus();
if(_hidePanel2) {
return;
}
if(!_preventExpand && _originalMinSize > 0) {
this.ExpandPanel();
}
_preventExpand = false;
}
}
}

View file

@ -0,0 +1,77 @@
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;
namespace Mesen.GUI.Controls
{
public partial class ctrlTrackbar : BaseControl
{
public event EventHandler ValueChanged
{
add { trackBar.ValueChanged += value; }
remove { trackBar.ValueChanged -= value; }
}
public ctrlTrackbar()
{
InitializeComponent();
if(!Program.IsMono) {
this.trackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
}
}
public int Minimum
{
get { return trackBar.Minimum; }
set { trackBar.Minimum = value; }
}
public int Maximum
{
get { return trackBar.Maximum; }
set { trackBar.Maximum = value; }
}
[Bindable(true)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public override string Text
{
get { return lblText.Text; }
set { lblText.Text = value; }
}
public int Value
{
get { return trackBar.Value; }
set
{
trackBar.Value = value;
UpdateText();
}
}
private void UpdateText()
{
if(this.Minimum == 0) {
lblValue.Text = trackBar.Value.ToString() + "%";
} else {
lblValue.Text = (trackBar.Value / 10.0).ToString() + "dB";
lblValue.Font = new Font("Microsoft Sans Serif", 6.75F);
}
}
private void trackBar_ValueChanged(object sender, EventArgs e)
{
UpdateText();
}
}
}

122
UI/Controls/ctrlTrackbar.designer.cs generated Normal file
View file

@ -0,0 +1,122 @@
namespace Mesen.GUI.Controls
{
partial class ctrlTrackbar
{
/// <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 Component 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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lblText = new System.Windows.Forms.Label();
this.trackBar = new System.Windows.Forms.TrackBar();
this.lblValue = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.lblText, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.trackBar, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.lblValue, 0, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
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.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(34, 160);
this.tableLayoutPanel1.TabIndex = 0;
//
// lblText
//
this.lblText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.lblText.AutoSize = true;
this.lblText.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblText.Location = new System.Drawing.Point(0, 148);
this.lblText.Margin = new System.Windows.Forms.Padding(0);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(34, 12);
this.lblText.TabIndex = 14;
this.lblText.Text = "Text";
this.lblText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// trackBar
//
this.trackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.trackBar.Location = new System.Drawing.Point(0, 0);
this.trackBar.Margin = new System.Windows.Forms.Padding(0);
this.trackBar.Maximum = 100;
this.trackBar.Name = "trackBar";
this.trackBar.Orientation = System.Windows.Forms.Orientation.Vertical;
this.trackBar.Size = new System.Drawing.Size(34, 133);
this.trackBar.TabIndex = 13;
this.trackBar.TickFrequency = 10;
this.trackBar.Value = 50;
this.trackBar.ValueChanged += new System.EventHandler(this.trackBar_ValueChanged);
//
// lblValue
//
this.lblValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.lblValue.AutoSize = true;
this.lblValue.BackColor = System.Drawing.Color.White;
this.lblValue.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lblValue.Location = new System.Drawing.Point(3, 133);
this.lblValue.MinimumSize = new System.Drawing.Size(28, 15);
this.lblValue.Name = "lblValue";
this.lblValue.Size = new System.Drawing.Size(28, 15);
this.lblValue.TabIndex = 15;
this.lblValue.Text = "100";
this.lblValue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// ctrlTrackbar
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Margin = new System.Windows.Forms.Padding(0);
this.MaximumSize = new System.Drawing.Size(63, 160);
this.MinimumSize = new System.Drawing.Size(34, 160);
this.Name = "ctrlTrackbar";
this.Size = new System.Drawing.Size(34, 160);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label lblText;
private System.Windows.Forms.TrackBar trackBar;
private System.Windows.Forms.Label lblValue;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger
{
class TextboxHistory
{
private List<int> _historyList = new List<int>() { 0 };
private int _historyPosition = 0;
private void ClearForwardHistory()
{
_historyList.RemoveRange(_historyPosition + 1, _historyList.Count - _historyPosition - 1);
}
public void AddHistory(int lineIndex)
{
if(_historyList.Count - 1 > _historyPosition) {
ClearForwardHistory();
}
if(_historyList[_historyList.Count-1] != lineIndex) {
_historyList.Add(lineIndex);
_historyPosition++;
}
}
public int GoBack()
{
if(_historyPosition > 0) {
_historyPosition--;
}
return _historyList[_historyPosition];
}
public int GoForward()
{
if(_historyPosition < _historyList.Count - 1) {
_historyPosition++;
}
return _historyList[_historyPosition];
}
}
}

View file

@ -0,0 +1,287 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Debugger.Controls
{
public class ctrlCodeScrollbar : Control
{
public event EventHandler ValueChanged;
private Timer _tmrScroll;
private bool _scrollUp = false;
private const int _buttonSize = 15;
private IScrollbarColorProvider _colorProvider = null;
public IScrollbarColorProvider ColorProvider
{
get { return _colorProvider; }
set { _colorProvider = value; this.Invalidate(); }
}
public ctrlCodeScrollbar()
{
this.DoubleBuffered = true;
this.ResizeRedraw = true;
this._tmrScroll = new Timer();
this._tmrScroll.Tick += tmrScroll_Tick;
}
private void tmrScroll_Tick(object sender, EventArgs e)
{
_tmrScroll.Interval = 50;
if(this._scrollUp) {
if(this.Value > 0) {
this.Value--;
}
} else {
if(this.Value < this.Maximum) {
this.Value++;
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle rect = this.ClientRectangle;
int left = rect.Left;
int width = rect.Width;
e.Graphics.FillRectangle(Brushes.DimGray, rect);
int barTop = rect.Top + _buttonSize;
int barHeight = this.Height - _buttonSize * 2;
float startPos = (float)this.Value / this.Maximum;
if(this.ColorProvider != null) {
Color prevBgColor = Color.White;
int drawHeight = 0;
for(int i = 0; i < barHeight; i++) {
float top = barTop + i;
float position = (float)i / barHeight;
Color bgColor = this.ColorProvider.GetBackgroundColor(position);
if(bgColor != prevBgColor && i > 0) {
using(Brush brush = new SolidBrush(prevBgColor)) {
e.Graphics.FillRectangle(brush, left + 1, top - drawHeight, width - 1, drawHeight);
drawHeight = 0;
}
}
drawHeight++;
if(bgColor != Color.Transparent) {
prevBgColor = bgColor;
}
}
using(Brush brush = new SolidBrush(prevBgColor)) {
e.Graphics.FillRectangle(brush, left + 1, barTop + barHeight- drawHeight, width - 1, drawHeight);
}
} else {
e.Graphics.FillRectangle(Brushes.White, left + 1, barTop, width - 1, barHeight);
}
float highlightTop = barTop + barHeight * startPos - HighlightOffset;
using(SolidBrush brush = new SolidBrush(Color.FromArgb(120, 220, 220, 255))) {
e.Graphics.FillRectangle(brush, left + 1, highlightTop, width, HighlightHeight - 2);
e.Graphics.DrawRectangle(Pens.DarkSlateGray, left + 1, highlightTop, width - 2, HighlightHeight - 2);
e.Graphics.DrawRectangle(Pens.Gray, left + 2, highlightTop + 1, width - 4, HighlightHeight - 4);
}
if(this.ColorProvider != null) {
int selectedIndex = this.ColorProvider.GetSelectedLine();
if(selectedIndex >= 0) {
int selectedTop = selectedIndex * barHeight / this.Maximum + barTop;
e.Graphics.FillRectangle(Brushes.LightBlue, left + 1, selectedTop - 1, width - 2, 3);
e.Graphics.DrawRectangle(Pens.DimGray, left + 1, selectedTop - 1, width - 2, 3);
}
int activeIndex = this.ColorProvider.GetActiveLine();
if(activeIndex >= 0) {
int activeTop = activeIndex * barHeight / this.Maximum + barTop;
e.Graphics.FillRectangle(Brushes.Yellow, left + 1, activeTop - 1, width - 2, 3);
e.Graphics.DrawRectangle(Pens.DimGray, left + 1, activeTop - 1, width - 2, 3);
}
int linesPerPixel = (int)Math.Ceiling((float)this.Maximum / barHeight);
for(int i = 0; i < barHeight; i++) {
float top = barTop + i;
float position = (float)i / barHeight;
Color markerColor = this.ColorProvider.GetMarkerColor(position, linesPerPixel);
if(markerColor != Color.Transparent) {
using(Brush brush = new SolidBrush(markerColor)) {
e.Graphics.FillRectangle(brush, left + 3, top - 2, 5, 5);
}
}
}
}
int arrowWidth = 10;
int arrowHeight = 5;
int bottom = barTop + barHeight + _buttonSize;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
e.Graphics.FillRectangle(Brushes.Gainsboro, rect.Left + 1, rect.Top, this.Width - 1, _buttonSize);
e.Graphics.FillRectangle(Brushes.Gainsboro, rect.Left + 1, bottom - _buttonSize, this.Width - 1, _buttonSize);
e.Graphics.DrawLine(Pens.DimGray, rect.Left + 1, rect.Top + _buttonSize, rect.Left + width, rect.Top + _buttonSize);
e.Graphics.DrawLine(Pens.DimGray, rect.Left + 1, bottom - _buttonSize, rect.Left + width, bottom - _buttonSize);
e.Graphics.DrawLine(Pens.DimGray, rect.Left + 1, bottom, rect.Left + width, bottom);
e.Graphics.TranslateTransform(5, (_buttonSize - arrowHeight) / 2);
e.Graphics.FillPolygon(Brushes.DimGray, new Point[] { new Point(left, rect.Top + arrowHeight), new Point(left + arrowWidth, rect.Top + arrowHeight), new Point(left + arrowWidth / 2, rect.Top) }, FillMode.Winding);
e.Graphics.TranslateTransform(0, -(_buttonSize - arrowHeight));
e.Graphics.FillPolygon(Brushes.DimGray, new Point[] { new Point(left, bottom - arrowHeight), new Point(left + arrowWidth, bottom - arrowHeight), new Point(left + arrowWidth / 2, bottom) }, FillMode.Winding);
}
//private bool _mouseDown = false;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if(e.Y > _buttonSize && e.Y < (this.Height - _buttonSize)) {
this.UpdatePosition(e.Y);
//this._mouseDown = true;
} else {
if(e.Y <= _buttonSize) {
if(this.Value > 0) {
this._scrollUp = true;
this.Value--;
this._tmrScroll.Interval = 350;
this._tmrScroll.Start();
}
} else {
if(this.Value < this.Maximum) {
this._scrollUp = false;
this.Value++;
this._tmrScroll.Interval = 350;
this._tmrScroll.Start();
}
}
}
//TODO
/*if(_codeTooltip != null) {
_codeTooltip.Close();
_codeTooltip = null;
}
_lastPreviewScrollPosition = -1;*/
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
//this._mouseDown = false;
this._tmrScroll.Stop();
}
//TODO
/*
frmCodePreviewTooltip _codeTooltip = null;
int _lastPreviewScrollPosition = -1;
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if(this._mouseDown) {
this.UpdatePosition(e.Y);
} else {
if(this.ColorProvider != null && e.Y > _buttonSize && e.Y < (this.Height - _buttonSize)) {
int scrollPosition = Math.Max(0, (e.Y - this.Top - _buttonSize) * this.Maximum / (this.Height - _buttonSize * 2));
if(_lastPreviewScrollPosition != scrollPosition) {
Point p = this.PointToScreen(new Point(this.ClientRectangle.Right, e.Y));
if(_codeTooltip == null) {
_codeTooltip = this.ColorProvider.GetPreview(scrollPosition);
if(_codeTooltip != null) {
_codeTooltip.FormClosed += (s, evt) => { _codeTooltip = null; };
}
} else {
_codeTooltip.ScrollToLineIndex(scrollPosition);
}
if(_codeTooltip != null) {
_codeTooltip.SetFormLocation(new Point(p.X + 5, p.Y), this.Parent);
}
_lastPreviewScrollPosition = scrollPosition;
}
}
}
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
if(_codeTooltip != null) {
bool restoreFocus = _codeTooltip.NeedRestoreFocus;
_codeTooltip.Close();
if(restoreFocus) {
this.Parent.Focus();
}
_codeTooltip = null;
}
_lastPreviewScrollPosition = -1;
_tmrScroll.Stop();
}*/
private int HighlightHeight { get { return Math.Max(8, (int)(((float)this.VisibleLineCount / this.Maximum) * this.Height)); } }
private int HighlightOffset
{
get
{
int highlightHeight = (int)(((float)this.VisibleLineCount / this.Maximum) * this.Height);
if(HighlightHeight - highlightHeight > 0) {
return (HighlightHeight - highlightHeight) / 2;
} else {
return 0;
}
}
}
private void UpdatePosition(int y)
{
this.Value = Math.Max(0 , y - HighlightHeight / 2 + HighlightOffset - this.Top - _buttonSize) * this.Maximum / (this.Height - _buttonSize * 2);
}
private int _value = 0;
public int Value
{
get
{
return this._value;
}
set
{
if(this._value != value) {
this._value = value;
this.ValueChanged?.Invoke(this, EventArgs.Empty);
this.Invalidate();
}
}
}
private int _maximum = 1;
public int Maximum
{
get { return Math.Max(1, this._maximum); }
set { this._maximum = value; this.Invalidate(); }
}
public int VisibleLineCount { get; set; } = 1;
public int LargeChange { get; set; } = 1;
}
public interface IScrollbarColorProvider
{
Color GetBackgroundColor(float position);
Color GetMarkerColor(float position, int linesPerPixel);
int GetActiveLine();
int GetSelectedLine();
//TODO
//frmCodePreviewTooltip GetPreview(int lineIndex);
}
}

View file

@ -0,0 +1,571 @@
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 Mesen.GUI.Controls;
using Mesen.GUI.Config;
using System.Globalization;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlScrollableTextbox : BaseControl
{
public event EventHandler ScrollPositionChanged;
private bool _showScrollbars = true;
public new event MouseEventHandler MouseUp
{
add { this.ctrlTextbox.MouseUp += value; }
remove { this.ctrlTextbox.MouseUp -= value; }
}
public new event MouseEventHandler MouseMove
{
add { this.ctrlTextbox.MouseMove += value; }
remove { this.ctrlTextbox.MouseMove -= value; }
}
public new event MouseEventHandler MouseDown
{
add { this.ctrlTextbox.MouseDown += value; }
remove { this.ctrlTextbox.MouseDown -= value; }
}
public new event MouseEventHandler MouseDoubleClick
{
add { this.ctrlTextbox.MouseDoubleClick += value; }
remove { this.ctrlTextbox.MouseDoubleClick -= value; }
}
public new event EventHandler MouseLeave
{
add { this.ctrlTextbox.MouseLeave += value; }
remove { this.ctrlTextbox.MouseLeave -= value; }
}
public event EventHandler TextZoomChanged;
public ctrlScrollableTextbox()
{
InitializeComponent();
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if(!designMode) {
this.panelSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
this.panelSearch.Location = new System.Drawing.Point(this.Width - this.panelSearch.Width - 20, -1);
this.ctrlTextbox.ShowLineNumbers = true;
this.ctrlTextbox.ShowLineInHex = true;
this.hScrollBar.ValueChanged += hScrollBar_ValueChanged;
this.vScrollBar.ValueChanged += vScrollBar_ValueChanged;
this.ctrlTextbox.ScrollPositionChanged += ctrlTextbox_ScrollPositionChanged;
this.ctrlTextbox.SelectedLineChanged += ctrlTextbox_SelectedLineChanged;
new ToolTip().SetToolTip(picCloseSearch, "Close");
new ToolTip().SetToolTip(picSearchNext, "Find Next (F3)");
new ToolTip().SetToolTip(picSearchPrevious, "Find Previous (Shift-F3)");
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.panelSearch.Location = new System.Drawing.Point(this.Width - this.panelSearch.Width - 20, -1);
}
public bool ShowScrollbars
{
get
{
return this._showScrollbars;
}
set
{
this._showScrollbars = value;
this.hScrollBar.Visible = value;
this.vScrollBar.Visible = value;
}
}
public IScrollbarColorProvider ScrollbarColorProvider
{
set { this.vScrollBar.ColorProvider = value; }
}
private void ctrlTextbox_SelectedLineChanged(object sender, EventArgs e)
{
this.vScrollBar.Invalidate();
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Font BaseFont
{
get { return this.ctrlTextbox.BaseFont; }
set
{
this.ctrlTextbox.BaseFont = value;
UpdateHorizontalScrollbar();
this.ctrlTextbox.Invalidate();
}
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int TextZoom
{
get { return this.ctrlTextbox.TextZoom; }
set {
if(this.ctrlTextbox.TextZoom != value) {
this.ctrlTextbox.TextZoom = value;
UpdateHorizontalScrollbar();
if(this.TextZoomChanged != null) {
this.TextZoomChanged(this, null);
}
}
}
}
public string GetWordUnderLocation(Point position)
{
return this.ctrlTextbox.GetWordUnderLocation(position);
}
private void ctrlTextbox_ScrollPositionChanged(object sender, EventArgs e)
{
this.vScrollBar.Value = this.ctrlTextbox.ScrollPosition;
this.hScrollBar.Value = this.ctrlTextbox.HorizontalScrollPosition;
UpdateHorizontalScrollbar();
UpdateVerticalScrollbar();
ScrollPositionChanged?.Invoke(null, null);
}
private void UpdateVerticalScrollbar()
{
this.vScrollBar.Maximum = this.ctrlTextbox.LineCount;
this.vScrollBar.VisibleLineCount = this.ctrlTextbox.GetNumberVisibleLines();
}
private void UpdateHorizontalScrollbar()
{
this.hScrollBar.Visible = this.ctrlTextbox.HorizontalScrollWidth > 0 && _showScrollbars;
int newMax = this.ctrlTextbox.HorizontalScrollWidth + this.hScrollBar.LargeChange - 1;
if(this.hScrollBar.Value > this.ctrlTextbox.HorizontalScrollWidth) {
this.hScrollBar.Value = this.ctrlTextbox.HorizontalScrollWidth;
}
this.hScrollBar.Maximum = newMax;
}
public ctrlTextbox.ILineStyleProvider StyleProvider { set { this.ctrlTextbox.StyleProvider = value; } }
public int GetLineIndex(int lineNumber)
{
return this.ctrlTextbox.GetLineIndex(lineNumber);
}
public int GetLineIndexAtPosition(int yPos)
{
return this.ctrlTextbox.GetLineIndexAtPosition(yPos);
}
public string GetLineNoteAtLineIndex(int lineIndex)
{
if(lineIndex >= 0 && lineIndex < this.ctrlTextbox.LineNumberNotes.Length) {
return this.ctrlTextbox.LineNumberNotes[lineIndex];
} else {
return "";
}
}
public int GetLineNumber(int lineIndex)
{
return this.ctrlTextbox.GetLineNumber(lineIndex);
}
public int GetLineNumberAtPosition(int yPos)
{
return this.GetLineNumber(this.GetLineIndexAtPosition(yPos));
}
public int GetNumberVisibleLines()
{
return this.ctrlTextbox.GetNumberVisibleLines();
}
public void ScrollToLineIndex(int lineIndex, eHistoryType historyType = eHistoryType.Always, bool scrollToTop = false, bool forceScroll = false)
{
this.ctrlTextbox.ScrollToLineIndex(lineIndex, historyType, scrollToTop, forceScroll);
}
public void ScrollToLineNumber(int lineNumber, eHistoryType historyType = eHistoryType.Always, bool scrollToTop = false, bool forceScroll = false)
{
this.ctrlTextbox.ScrollToLineNumber(lineNumber, historyType, scrollToTop, forceScroll);
}
public void CopySelection(bool copyLineNumbers, bool copyContentNotes, bool copyComments)
{
this.ctrlTextbox.CopySelection(copyLineNumbers, copyContentNotes, copyComments);
}
public void SetMessage(TextboxMessageInfo message)
{
this.ctrlTextbox.SetMessage(message);
}
public int CurrentLine
{
get { return this.ctrlTextbox.CurrentLine; }
}
public int SelectedLine
{
get { return this.ctrlTextbox.SelectedLine; }
}
public int LastSelectedLine
{
get { return this.ctrlTextbox.LastSelectedLine; }
}
public int CodeMargin
{
get { return this.ctrlTextbox.CodeMargin; }
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
this.vScrollBar.Value = Math.Min(this.vScrollBar.Maximum, Math.Max(0, this.vScrollBar.Value - e.Delta / 40));
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(!this.cboSearch.Focused) {
//TODO
/*if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.SelectAll) {
this.SelectAll();
return true;
}*/
switch(keyData) {
case Keys.Right | Keys.Shift:
case Keys.Down | Keys.Shift:
this.ctrlTextbox.MoveSelectionDown();
return true;
case Keys.Down:
case Keys.Right:
this.ctrlTextbox.SelectionStart = this.ctrlTextbox.SelectedLine + 1;
this.ctrlTextbox.SelectionLength = 0;
return true;
case Keys.Up | Keys.Shift:
case Keys.Left | Keys.Shift:
this.ctrlTextbox.MoveSelectionUp();
return true;
case Keys.Up:
case Keys.Left:
this.ctrlTextbox.SelectionStart = this.ctrlTextbox.SelectedLine - 1;
this.ctrlTextbox.SelectionLength = 0;
return true;
case Keys.Home | Keys.Shift:
this.ctrlTextbox.MoveSelectionUp(this.ctrlTextbox.LineCount);
break;
case Keys.End | Keys.Shift:
this.ctrlTextbox.MoveSelectionDown(this.ctrlTextbox.LineCount);
break;
case Keys.Home:
this.ctrlTextbox.SelectionStart = 0;
this.ctrlTextbox.SelectionLength = 0;
return true;
case Keys.End:
this.ctrlTextbox.SelectionStart = this.ctrlTextbox.LineCount - 1;
this.ctrlTextbox.SelectionLength = 0;
return true;
}
}
//TODO
/*
if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.IncreaseFontSize) {
this.TextZoom += 10;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.DecreaseFontSize) {
this.TextZoom -= 10;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.ResetFontSize) {
this.TextZoom = 100;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.Find) {
this.OpenSearchBox(true);
return true;
}*/
switch(keyData) {
case Keys.PageUp | Keys.Shift:
this.ctrlTextbox.MoveSelectionUp(20);
return true;
case Keys.PageUp:
this.ctrlTextbox.SelectionStart-=20;
this.ctrlTextbox.SelectionLength = 0;
return true;
case Keys.PageDown | Keys.Shift:
this.ctrlTextbox.MoveSelectionDown(20);
return true;
case Keys.PageDown:
this.ctrlTextbox.SelectionStart+=20;
this.ctrlTextbox.SelectionLength = 0;
return true;
case Keys.Escape:
if(this.cboSearch.Focused) {
this.CloseSearchBox();
return true;
}
break;
}
return base.ProcessCmdKey(ref msg, keyData);
}
public void SelectAll()
{
this.ctrlTextbox.SelectionStart = 0;
this.ctrlTextbox.SelectionLength = this.ctrlTextbox.LineCount;
}
private void vScrollBar_ValueChanged(object sender, EventArgs e)
{
this.ctrlTextbox.ScrollPosition = this.vScrollBar.Value;
}
private void hScrollBar_ValueChanged(object sender, EventArgs e)
{
this.ctrlTextbox.HorizontalScrollPosition = this.hScrollBar.Value;
}
public string[] Addressing { set { this.ctrlTextbox.Addressing = value; } }
public string[] Comments { set { this.ctrlTextbox.Comments = value; } }
public int[] LineIndentations{ set { this.ctrlTextbox.LineIndentations = value; } }
public string[] TextLines
{
set
{
this.ctrlTextbox.TextLines = value;
UpdateVerticalScrollbar();
UpdateHorizontalScrollbar();
}
}
public string[] TextLineNotes
{
set
{
this.ctrlTextbox.TextLineNotes = value;
}
}
public string[] CompareLines
{
set
{
this.ctrlTextbox.CompareLines = value;
}
}
public int[] LineNumbers
{
set
{
this.ctrlTextbox.LineNumbers = value;
}
}
public string[] LineNumberNotes
{
set
{
this.ctrlTextbox.LineNumberNotes = value;
}
}
public bool ShowSingleContentLineNotes
{
get { return this.ctrlTextbox.ShowSingleContentLineNotes; }
set { this.ctrlTextbox.ShowSingleContentLineNotes = value; }
}
public bool ShowContentNotes
{
get { return this.ctrlTextbox.ShowContentNotes; }
set { this.ctrlTextbox.ShowContentNotes = value; }
}
public bool ShowCompactPrgAddresses { get { return this.ctrlTextbox.ShowCompactPrgAddresses; } set { this.ctrlTextbox.ShowCompactPrgAddresses = value; } }
public bool ShowLineNumberNotes
{
get { return this.ctrlTextbox.ShowLineNumberNotes; }
set { this.ctrlTextbox.ShowLineNumberNotes = value; }
}
public bool ShowSingleLineLineNumberNotes
{
get { return this.ctrlTextbox.ShowSingleLineLineNumberNotes; }
set { this.ctrlTextbox.ShowSingleLineLineNumberNotes = value; }
}
public bool ShowMemoryValues
{
get { return this.ctrlTextbox.ShowMemoryValues; }
set { this.ctrlTextbox.ShowMemoryValues = value; }
}
public bool HideSelection
{
get { return this.ctrlTextbox.HideSelection; }
set { this.ctrlTextbox.HideSelection = value; }
}
public bool CodeHighlightingEnabled
{
get { return this.ctrlTextbox.CodeHighlightingEnabled; }
set { this.ctrlTextbox.CodeHighlightingEnabled = value; }
}
public int LineCount { get { return this.ctrlTextbox.LineCount; } }
public int SelectionStart { get { return this.ctrlTextbox.SelectionStart; } }
public int SelectionLength { get { return this.ctrlTextbox.SelectionLength; } }
public string Header
{
set
{
this.ctrlTextbox.Header = value;
}
}
public int MarginWidth { set { this.ctrlTextbox.MarginWidth = value; } }
public void OpenSearchBox(bool forceFocus = false)
{
bool focus = !this.panelSearch.Visible;
this.panelSearch.Visible = true;
if(focus || forceFocus) {
this.cboSearch.Focus();
this.cboSearch.SelectAll();
}
}
private void CloseSearchBox()
{
this.ctrlTextbox.Search(null, false, false);
this.panelSearch.Visible = false;
this.Focus();
}
public void FindNext()
{
this.OpenSearchBox();
this.ctrlTextbox.Search(this.cboSearch.Text, false, false);
}
public void FindPrevious()
{
this.OpenSearchBox();
this.ctrlTextbox.Search(this.cboSearch.Text, true, false);
}
private void picCloseSearch_Click(object sender, EventArgs e)
{
this.CloseSearchBox();
}
private void picSearchPrevious_MouseUp(object sender, MouseEventArgs e)
{
this.FindPrevious();
}
private void picSearchNext_MouseUp(object sender, MouseEventArgs e)
{
this.FindNext();
}
private void cboSearch_TextUpdate(object sender, EventArgs e)
{
if(!this.ctrlTextbox.Search(this.cboSearch.Text, false, true)) {
this.cboSearch.BackColor = Color.Coral;
} else {
this.cboSearch.BackColor = Color.Empty;
}
}
private void cboSearch_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter) {
this.FindNext();
if(this.cboSearch.Items.Contains(this.cboSearch.Text)) {
this.cboSearch.Items.Remove(this.cboSearch.Text);
}
this.cboSearch.Items.Insert(0, this.cboSearch.Text);
e.Handled = true;
e.SuppressKeyPress = true;
}
}
public string GetLineContent(int lineIndex)
{
return this.ctrlTextbox.GetFullWidthString(lineIndex);
}
public void NavigateForward()
{
this.ctrlTextbox.NavigateForward();
}
public void NavigateBackward()
{
this.ctrlTextbox.NavigateBackward();
}
public bool GetNoteRangeAtLocation(int yPos, out int rangeStart, out int rangeEnd)
{
rangeStart = -1;
rangeEnd = -1;
int lineIndex = GetLineIndexAtPosition(yPos);
while(lineIndex < LineCount - 2 && string.IsNullOrWhiteSpace(GetLineNoteAtLineIndex(lineIndex))) {
//Find the address of the next line with an address
lineIndex++;
}
if(Int32.TryParse(GetLineNoteAtLineIndex(lineIndex), NumberStyles.AllowHexSpecifier, null, out rangeStart)) {
while(lineIndex < LineCount - 2 && string.IsNullOrWhiteSpace(GetLineNoteAtLineIndex(lineIndex + 1))) {
//Find the next line with an address
lineIndex++;
}
if(Int32.TryParse(GetLineNoteAtLineIndex(lineIndex + 1), NumberStyles.AllowHexSpecifier, null, out rangeEnd)) {
rangeEnd--;
return true;
}
}
return false;
}
}
}

View file

@ -0,0 +1,202 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlScrollableTextbox
{
/// <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 Component 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.vScrollBar = new Mesen.GUI.Debugger.Controls.ctrlCodeScrollbar();
this.panelSearch = new System.Windows.Forms.Panel();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.picCloseSearch = new System.Windows.Forms.PictureBox();
this.picSearchNext = new System.Windows.Forms.PictureBox();
this.picSearchPrevious = new System.Windows.Forms.PictureBox();
this.cboSearch = new System.Windows.Forms.ComboBox();
this.hScrollBar = new System.Windows.Forms.HScrollBar();
this.ctrlTextbox = new Mesen.GUI.Debugger.Controls.ctrlTextbox();
this.panelSearch.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picCloseSearch)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picSearchNext)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picSearchPrevious)).BeginInit();
this.SuspendLayout();
//
// vScrollBar
//
this.vScrollBar.ColorProvider = null;
this.vScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
this.vScrollBar.LargeChange = 20;
this.vScrollBar.Location = new System.Drawing.Point(490, 0);
this.vScrollBar.Maximum = 1;
this.vScrollBar.MaximumSize = new System.Drawing.Size(18, 0);
this.vScrollBar.MinimumSize = new System.Drawing.Size(18, 0);
this.vScrollBar.Name = "vScrollBar";
this.vScrollBar.Size = new System.Drawing.Size(18, 141);
this.vScrollBar.TabIndex = 0;
this.vScrollBar.Value = 0;
this.vScrollBar.VisibleLineCount = 1;
//
// panelSearch
//
this.panelSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.panelSearch.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelSearch.Controls.Add(this.tableLayoutPanel1);
this.panelSearch.Location = new System.Drawing.Point(266, -1);
this.panelSearch.Name = "panelSearch";
this.panelSearch.Size = new System.Drawing.Size(222, 28);
this.panelSearch.TabIndex = 2;
this.panelSearch.Visible = false;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 4;
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.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.picCloseSearch, 3, 0);
this.tableLayoutPanel1.Controls.Add(this.picSearchNext, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.picSearchPrevious, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.cboSearch, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(220, 26);
this.tableLayoutPanel1.TabIndex = 0;
//
// picCloseSearch
//
this.picCloseSearch.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picCloseSearch.Cursor = System.Windows.Forms.Cursors.Hand;
this.picCloseSearch.Image = global::Mesen.GUI.Properties.Resources.Close;
this.picCloseSearch.Location = new System.Drawing.Point(201, 5);
this.picCloseSearch.Name = "picCloseSearch";
this.picCloseSearch.Size = new System.Drawing.Size(16, 16);
this.picCloseSearch.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picCloseSearch.TabIndex = 3;
this.picCloseSearch.TabStop = false;
this.picCloseSearch.Click += new System.EventHandler(this.picCloseSearch_Click);
//
// picSearchNext
//
this.picSearchNext.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picSearchNext.Cursor = System.Windows.Forms.Cursors.Hand;
this.picSearchNext.Image = global::Mesen.GUI.Properties.Resources.NextArrow;
this.picSearchNext.Location = new System.Drawing.Point(179, 5);
this.picSearchNext.Name = "picSearchNext";
this.picSearchNext.Size = new System.Drawing.Size(16, 16);
this.picSearchNext.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picSearchNext.TabIndex = 2;
this.picSearchNext.TabStop = false;
this.picSearchNext.MouseUp += new System.Windows.Forms.MouseEventHandler(this.picSearchNext_MouseUp);
//
// picSearchPrevious
//
this.picSearchPrevious.Anchor = System.Windows.Forms.AnchorStyles.None;
this.picSearchPrevious.Cursor = System.Windows.Forms.Cursors.Hand;
this.picSearchPrevious.Image = global::Mesen.GUI.Properties.Resources.PreviousArrow;
this.picSearchPrevious.Location = new System.Drawing.Point(157, 5);
this.picSearchPrevious.Name = "picSearchPrevious";
this.picSearchPrevious.Size = new System.Drawing.Size(16, 16);
this.picSearchPrevious.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picSearchPrevious.TabIndex = 1;
this.picSearchPrevious.TabStop = false;
this.picSearchPrevious.MouseUp += new System.Windows.Forms.MouseEventHandler(this.picSearchPrevious_MouseUp);
//
// cboSearch
//
this.cboSearch.Dock = System.Windows.Forms.DockStyle.Fill;
this.cboSearch.FormattingEnabled = true;
this.cboSearch.Location = new System.Drawing.Point(3, 3);
this.cboSearch.Name = "cboSearch";
this.cboSearch.Size = new System.Drawing.Size(148, 21);
this.cboSearch.TabIndex = 4;
this.cboSearch.TextUpdate += new System.EventHandler(this.cboSearch_TextUpdate);
this.cboSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cboSearch_KeyDown);
//
// hScrollBar
//
this.hScrollBar.Dock = System.Windows.Forms.DockStyle.Bottom;
this.hScrollBar.Location = new System.Drawing.Point(0, 141);
this.hScrollBar.Name = "hScrollBar";
this.hScrollBar.Size = new System.Drawing.Size(508, 18);
this.hScrollBar.TabIndex = 3;
//
// ctrlTextbox
//
this.ctrlTextbox.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlTextbox.HideSelection = false;
this.ctrlTextbox.HorizontalScrollWidth = 0;
this.ctrlTextbox.Location = new System.Drawing.Point(0, 0);
this.ctrlTextbox.Name = "ctrlTextbox";
this.ctrlTextbox.ShowCompactPrgAddresses = false;
this.ctrlTextbox.ShowContentNotes = false;
this.ctrlTextbox.ShowLineInHex = false;
this.ctrlTextbox.ShowLineNumberNotes = false;
this.ctrlTextbox.ShowLineNumbers = true;
this.ctrlTextbox.ShowMemoryValues = false;
this.ctrlTextbox.ShowSingleContentLineNotes = true;
this.ctrlTextbox.ShowSingleLineLineNumberNotes = false;
this.ctrlTextbox.Size = new System.Drawing.Size(490, 141);
this.ctrlTextbox.StyleProvider = null;
this.ctrlTextbox.TabIndex = 1;
//
// ctrlScrollableTextbox
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.panelSearch);
this.Controls.Add(this.ctrlTextbox);
this.Controls.Add(this.vScrollBar);
this.Controls.Add(this.hScrollBar);
this.Name = "ctrlScrollableTextbox";
this.Size = new System.Drawing.Size(508, 159);
this.panelSearch.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picCloseSearch)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picSearchNext)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picSearchPrevious)).EndInit();
this.ResumeLayout(false);
}
#endregion
private ctrlCodeScrollbar vScrollBar;
private ctrlTextbox ctrlTextbox;
private System.Windows.Forms.Panel panelSearch;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.PictureBox picSearchPrevious;
private System.Windows.Forms.PictureBox picSearchNext;
private System.Windows.Forms.PictureBox picCloseSearch;
private System.Windows.Forms.ComboBox cboSearch;
private System.Windows.Forms.HScrollBar hScrollBar;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

View file

@ -0,0 +1,35 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlTextbox
{
/// <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 Component 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()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Debugger
{
class FontDialogHelper
{
public static Font SelectFont(Font currentFont)
{
using(FontDialog fd = new FontDialog()) {
fd.Font = currentFont;
fd.ShowApply = false;
fd.ShowColor = false;
fd.ShowEffects = false;
fd.ShowHelp = false;
if(fd.ShowDialog() == DialogResult.OK) {
Font font = fd.Font;
Size sizeM = TextRenderer.MeasureText("M", font);
Size sizeDot = TextRenderer.MeasureText(".", font);
if(sizeM != sizeDot) {
if(MessageBox.Show("The font you've selected (" + fd.Font.FontFamily.Name.ToString() + ") doesn't appear to be a monospace font. Using anything other than a monospace font will cause display issues in the UI. Are you sure you want to use this font?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) {
return fd.Font;
} else {
return currentFont;
}
} else {
return fd.Font;
}
} else {
return currentFont;
}
}
}
}
}

View file

@ -0,0 +1,483 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Debugger
{
public partial class frmTraceLogger : BaseForm
{
private int _lineCount;
private bool _loggingEnabled = false;
private string _lastFilename;
private EntityBinder _entityBinder = new EntityBinder();
private string _previousTrace;
private volatile bool _refreshRunning;
private bool _initialized;
public frmTraceLogger()
{
InitializeComponent();
DebugInfo debugInfo = ConfigManager.Config.Debug;
if(!debugInfo.TraceLoggerSize.IsEmpty) {
this.StartPosition = FormStartPosition.Manual;
this.Size = debugInfo.TraceLoggerSize;
this.Location = debugInfo.TraceLoggerLocation;
}
txtTraceLog.BaseFont = new Font(debugInfo.TraceFontFamily, debugInfo.TraceFontSize, debugInfo.TraceFontStyle);
txtTraceLog.TextZoom = debugInfo.TraceTextZoom;
mnuAutoRefresh.Checked = debugInfo.TraceAutoRefresh;
_lineCount = debugInfo.TraceLineCount;
_entityBinder.Entity = debugInfo.TraceLoggerOptions;
_entityBinder.AddBinding("ShowByteCode", chkShowByteCode);
_entityBinder.AddBinding("ShowCpuCycles", chkShowCpuCycles);
_entityBinder.AddBinding("ShowEffectiveAddresses", chkShowEffectiveAddresses);
_entityBinder.AddBinding("ShowMemoryValues", chkShowMemoryValues);
_entityBinder.AddBinding("ShowExtraInfo", chkShowExtraInfo);
_entityBinder.AddBinding("ShowPpuFrames", chkShowFrameCount);
_entityBinder.AddBinding("ShowPpuCycles", chkShowPpuCycles);
_entityBinder.AddBinding("ShowPpuScanline", chkShowPpuScanline);
_entityBinder.AddBinding("ShowRegisters", chkShowRegisters);
_entityBinder.AddBinding("IndentCode", chkIndentCode);
_entityBinder.AddBinding("UseLabels", chkUseLabels);
_entityBinder.AddBinding("ExtendZeroPage", chkExtendZeroPage);
_entityBinder.AddBinding("UseWindowsEol", chkUseWindowsEol);
_entityBinder.AddBinding("StatusFormat", cboStatusFlagFormat);
_entityBinder.AddBinding("OverrideFormat", chkOverrideFormat);
_entityBinder.UpdateUI();
this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols.");
//this.toolTip.SetToolTip(this.picHelp, "When a condition is given, instructions will only be logged by the trace logger if the condition returns a value not equal to 0 or false." + Environment.NewLine + Environment.NewLine + frmBreakpoint.GetConditionTooltip(false));
this.toolTip.SetToolTip(this.picFormatHelp,
"You can customize the trace logger's output by enabling the 'Override' option and altering the format." + Environment.NewLine + Environment.NewLine +
"The following tags are available: " + Environment.NewLine +
"[ByteCode]: The byte code for the instruction (1 to 3 bytes)." + Environment.NewLine +
"[Disassembly]: The disassembly for the current instruction." + Environment.NewLine +
"[EffectiveAddress]: The effective address used for indirect addressing modes." + Environment.NewLine +
"[MemoryValue]: The value stored at the memory location referred to by the instruction." + Environment.NewLine +
"[PC]: Program Counter" + Environment.NewLine +
"[A]: A register" + Environment.NewLine +
"[X]: X register" + Environment.NewLine +
"[Y]: Y register" + Environment.NewLine +
"[SP]: Stack Pointer" + Environment.NewLine +
"[P]: Processor Flags" + Environment.NewLine +
"[Cycle]: The current PPU cycle." + Environment.NewLine +
"[Scanline]: The current PPU scanline." + Environment.NewLine +
"[FrameCount]: The current PPU frame." + Environment.NewLine +
"[CycleCount]: The current CPU cycle (32-bit signed value, resets to 0 at power on)" + Environment.NewLine + Environment.NewLine +
"You can also specify some options by using a comma. e.g:" + Environment.NewLine +
"[Cycle,3] will display the cycle and pad out the output to always be 3 characters wide." + Environment.NewLine +
"[Scanline,h] will display the scanline in hexadecimal." + Environment.NewLine +
"[Align,50]: Align is a special tag that is useful when trying to align some content. [Align,50] will make the next tag start on column 50."
);
this._initialized = true;
}
private void InitShortcuts()
{
//TODO
/*mnuIncreaseFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.IncreaseFontSize));
mnuDecreaseFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.DecreaseFontSize));
mnuResetFontSize.InitShortcut(this, nameof(DebuggerShortcutsConfig.ResetFontSize));
mnuRefresh.InitShortcut(this, nameof(DebuggerShortcutsConfig.Refresh));
mnuCopy.InitShortcut(this, nameof(DebuggerShortcutsConfig.Copy));
mnuSelectAll.InitShortcut(this, nameof(DebuggerShortcutsConfig.SelectAll));
mnuEditInMemoryViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer));
mnuViewInDisassembly.InitShortcut(this, nameof(DebuggerShortcutsConfig.MemoryViewer_ViewInDisassembly));*/
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
UpdateMenu();
tmrUpdateLog.Start();
RefreshLog(true, true);
InitShortcuts();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
tmrUpdateLog.Stop();
while(_refreshRunning) {
System.Threading.Thread.Sleep(50);
}
base.OnFormClosing(e);
DebugInfo debugInfo = ConfigManager.Config.Debug;
debugInfo.TraceAutoRefresh = mnuAutoRefresh.Checked;
debugInfo.TraceLineCount = _lineCount;
debugInfo.TraceLoggerSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size;
debugInfo.TraceLoggerLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location;
debugInfo.TraceFontFamily = txtTraceLog.BaseFont.FontFamily.Name;
debugInfo.TraceFontSize = txtTraceLog.BaseFont.Size;
debugInfo.TraceFontStyle = txtTraceLog.BaseFont.Style;
debugInfo.TraceTextZoom = txtTraceLog.TextZoom;
_entityBinder.UpdateObject();
ConfigManager.ApplyChanges();
if(_loggingEnabled) {
DebugApi.StopTraceLogger();
}
}
protected void UpdateFormatOptions()
{
if(!chkOverrideFormat.Checked) {
string format = "[PC,6h] ";
if(chkShowByteCode.Checked) {
format += "[ByteCode,15h] ";
}
format += "[Disassembly]";
int alignValue = 40;
if(chkShowEffectiveAddresses.Checked) {
format += "[EffectiveAddress]";
alignValue += 8;
}
if(chkShowMemoryValues.Checked) {
format += " [MemoryValue,h]";
alignValue += 6;
}
format += "[Align," + alignValue.ToString() + "] ";
if(chkShowRegisters.Checked) {
format += "A:[A,h] X:[X,h] Y:[Y,h] ";
switch(cboStatusFlagFormat.GetEnumValue<StatusFlagFormat>()) {
case StatusFlagFormat.Hexadecimal: format += "P:[P,h]"; break;
case StatusFlagFormat.CompactText: format += "P:[P]"; break;
case StatusFlagFormat.Text: format += "P:[P,8]"; break;
}
format += " SP:[SP,h] ";
}
if(chkShowPpuCycles.Checked) {
format += "CYC:[Cycle,3] ";
}
if(chkShowPpuScanline.Checked) {
format += "SL:[Scanline,3] ";
}
if(chkShowFrameCount.Checked) {
format += "FC:[FrameCount] ";
}
if(chkShowCpuCycles.Checked) {
format += "CPU Cycle:[CycleCount]";
}
txtFormat.Text = format.Trim();
}
txtFormat.ReadOnly = !chkOverrideFormat.Checked;
chkShowByteCode.Enabled = !chkOverrideFormat.Checked;
chkShowRegisters.Enabled = !chkOverrideFormat.Checked;
chkShowPpuCycles.Enabled = !chkOverrideFormat.Checked;
chkShowPpuScanline.Enabled = !chkOverrideFormat.Checked;
chkShowFrameCount.Enabled = !chkOverrideFormat.Checked;
chkShowCpuCycles.Enabled = !chkOverrideFormat.Checked;
chkShowEffectiveAddresses.Enabled = !chkOverrideFormat.Checked;
chkShowMemoryValues.Enabled = !chkOverrideFormat.Checked;
cboStatusFlagFormat.Enabled = !chkOverrideFormat.Checked;
if(_initialized) {
RefreshLog(false, true);
}
}
private void SetOptions()
{
_entityBinder.UpdateObject();
TraceLoggerOptions options = (TraceLoggerOptions)_entityBinder.Entity;
InteropTraceLoggerOptions interopOptions = new InteropTraceLoggerOptions();
interopOptions.IndentCode = options.IndentCode;
interopOptions.ShowExtraInfo = options.ShowExtraInfo;
interopOptions.UseLabels = options.UseLabels;
interopOptions.UseWindowsEol = options.UseWindowsEol;
interopOptions.ExtendZeroPage = options.ExtendZeroPage;
interopOptions.Condition = Encoding.UTF8.GetBytes(txtCondition.Text);
Array.Resize(ref interopOptions.Condition, 1000);
interopOptions.Format = Encoding.UTF8.GetBytes(txtFormat.Text.Replace("\t", "\\t"));
Array.Resize(ref interopOptions.Format, 1000);
DebugApi.SetTraceOptions(interopOptions);
}
private void btnStartLogging_Click(object sender, EventArgs e)
{
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.SetFilter("Trace logs (*.txt)|*.txt");
sfd.FileName = "Trace.txt";
sfd.InitialDirectory = ConfigManager.DebuggerFolder;
if(sfd.ShowDialog() == DialogResult.OK) {
_lastFilename = sfd.FileName;
SetOptions();
DebugApi.StartTraceLogger(sfd.FileName);
btnStartLogging.Enabled = false;
btnStopLogging.Enabled = true;
btnOpenTrace.Enabled = false;
_loggingEnabled = true;
}
}
}
private void btnStopLogging_Click(object sender, EventArgs e)
{
DebugApi.StopTraceLogger();
btnStartLogging.Enabled = true;
btnStopLogging.Enabled = false;
btnOpenTrace.Enabled = true;
}
private void btnOpenTrace_Click(object sender, EventArgs e)
{
try {
System.Diagnostics.Process.Start(_lastFilename);
} catch { }
}
private void RefreshLog(bool scrollToBottom, bool forceUpdate)
{
if(_refreshRunning) {
return;
}
//TODO
//Make sure labels are up to date
//DebugWorkspaceManager.GetWorkspace();
_refreshRunning = true;
SetOptions();
Task.Run(() => {
//Update trace log in another thread for performance
//DebugState state = new DebugState();
//InteropEmu.DebugGetState(ref state);
//if(_previousCycleCount != state.CPU.CycleCount || forceUpdate) {
//TODO
if(true) {
string newTrace = DebugApi.GetExecutionTrace((UInt32)_lineCount);
//_previousCycleCount = state.CPU.CycleCount;
_previousTrace = newTrace;
int index = 0;
string line = null;
Func<bool> readLine = () => {
if(index < newTrace.Length) {
int endOfLineIndex = newTrace.IndexOf('\n', index);
line = newTrace.Substring(index, endOfLineIndex - index);
index = endOfLineIndex + 1;
return true;
} else {
return false;
}
};
List<int> programCounter = new List<int>(30000);
List<string> byteCode = new List<string>(30000);
List<string> lineContent = new List<string>(30000);
List<int> indent = new List<int>(30000);
bool showByteCode = false;
while(readLine()) {
string[] parts = line.Split('\x1');
programCounter.Add(Int32.Parse(parts[0], System.Globalization.NumberStyles.HexNumber));
byteCode.Add(parts[1]);
string content = parts[2];
while(true) {
string str = content.TrimStart();
if(str.StartsWith(parts[0])) {
content = str.Substring(parts[0].Length);
} else if(str.StartsWith(parts[1])) {
content = str.Substring(parts[1].Length);
showByteCode = true;
} else if(str.StartsWith(parts[1].Replace("$", ""))) {
content = str.Substring(8);
showByteCode = true;
} else {
break;
}
}
lineContent.Add(content.TrimStart());
indent.Add(10);
}
this.BeginInvoke((Action)(() => {
txtTraceLog.ShowContentNotes = showByteCode;
txtTraceLog.ShowSingleContentLineNotes = showByteCode;
txtTraceLog.LineIndentations = indent.ToArray();
txtTraceLog.LineNumbers = programCounter.ToArray();
txtTraceLog.TextLineNotes = byteCode.ToArray();
txtTraceLog.TextLines = lineContent.ToArray();
if(scrollToBottom) {
txtTraceLog.ScrollToLineIndex(txtTraceLog.LineCount - 1);
}
}));
}
_refreshRunning = false;
});
}
private void UpdateMenu()
{
mnu30000Lines.Checked = _lineCount == 30000;
mnu15000Lines.Checked = _lineCount == 15000;
mnu10000Lines.Checked = _lineCount == 10000;
mnu5000Lines.Checked = _lineCount == 5000;
mnu1000Lines.Checked = _lineCount == 1000;
mnu100Lines.Checked = _lineCount == 100;
if(_lineCount >= 1000) {
tmrUpdateLog.Interval = 250;
} else {
tmrUpdateLog.Interval = 150;
}
}
private void tmrUpdateLog_Tick(object sender, EventArgs e)
{
if(txtCondition.Text.Length > 0) {
//TODO
/*EvalResultType resultType;
InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType, false);
picExpressionWarning.Visible = (resultType == EvalResultType.Invalid);*/
} else {
picExpressionWarning.Visible = false;
}
if(mnuAutoRefresh.Checked) {
RefreshLog(false, false);
}
}
private void SetLineCount(int count)
{
_lineCount = count;
UpdateMenu();
RefreshLog(false, true);
}
private void mnu30000Lines_Click(object sender, EventArgs e)
{
SetLineCount(30000);
}
private void mnu15000Lines_Click(object sender, EventArgs e)
{
SetLineCount(15000);
}
private void mnu10000Lines_Click(object sender, EventArgs e)
{
SetLineCount(10000);
}
private void mnu5000Lines_Click(object sender, EventArgs e)
{
SetLineCount(5000);
}
private void mnu1000Lines_Click(object sender, EventArgs e)
{
SetLineCount(1000);
}
private void mnu100Lines_Click(object sender, EventArgs e)
{
SetLineCount(100);
}
private void mnuRefresh_Click(object sender, EventArgs e)
{
RefreshLog(false, true);
}
private void mnuIncreaseFontSize_Click(object sender, EventArgs e)
{
txtTraceLog.TextZoom += 10;
}
private void mnuDecreaseFontSize_Click(object sender, EventArgs e)
{
txtTraceLog.TextZoom -= 10;
}
private void mnuResetFontSize_Click(object sender, EventArgs e)
{
txtTraceLog.TextZoom = 100;
}
private void mnuSelectFont_Click(object sender, EventArgs e)
{
txtTraceLog.BaseFont = FontDialogHelper.SelectFont(txtTraceLog.BaseFont);
}
private void chkOptions_CheckedChanged(object sender, EventArgs e)
{
UpdateFormatOptions();
}
private void cboStatusFlagFormat_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateFormatOptions();
}
private void txtFormat_TextChanged(object sender, EventArgs e)
{
if(chkOverrideFormat.Checked) {
//Only save format string when override flag is set
((TraceLoggerOptions)_entityBinder.Entity).Format = txtFormat.Text;
}
}
private void chkOverrideFormat_CheckedChanged(object sender, EventArgs e)
{
if(chkOverrideFormat.Checked) {
string format = ((TraceLoggerOptions)_entityBinder.Entity).Format;
if(string.IsNullOrWhiteSpace(format)) {
format = txtFormat.Text;
}
txtFormat.Text = format;
}
UpdateFormatOptions();
}
private void mnuCopy_Click(object sender, EventArgs e)
{
string[] lines = _previousTrace.Split('\n');
StringBuilder sb = new StringBuilder();
for(int i = txtTraceLog.SelectionStart, end = txtTraceLog.SelectionStart + txtTraceLog.SelectionLength; i <= end && i < lines.Length; i++) {
sb.Append(lines[i]);
}
Clipboard.SetText(sb.ToString());
txtTraceLog.CopySelection(true, true, false);
}
private void mnuSelectAll_Click(object sender, EventArgs e)
{
txtTraceLog.SelectAll();
}
}
}

842
UI/Debugger/frmTraceLogger.designer.cs generated Normal file
View file

@ -0,0 +1,842 @@
using Mesen.GUI.Debugger.Controls;
namespace Mesen.GUI.Debugger
{
partial class frmTraceLogger
{
/// <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.btnOpenTrace = new System.Windows.Forms.Button();
this.btnStartLogging = new System.Windows.Forms.Button();
this.btnStopLogging = new System.Windows.Forms.Button();
this.grpLogOptions = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
this.chkOverrideFormat = new System.Windows.Forms.CheckBox();
this.picFormatHelp = new System.Windows.Forms.PictureBox();
this.lblFormat = new System.Windows.Forms.Label();
this.txtFormat = new System.Windows.Forms.TextBox();
this.chkShowMemoryValues = new System.Windows.Forms.CheckBox();
this.chkShowRegisters = new System.Windows.Forms.CheckBox();
this.chkShowByteCode = new System.Windows.Forms.CheckBox();
this.chkShowCpuCycles = new System.Windows.Forms.CheckBox();
this.chkShowPpuCycles = new System.Windows.Forms.CheckBox();
this.chkShowPpuScanline = new System.Windows.Forms.CheckBox();
this.chkShowFrameCount = new System.Windows.Forms.CheckBox();
this.chkShowEffectiveAddresses = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.picHelp = new System.Windows.Forms.PictureBox();
this.picExpressionWarning = new System.Windows.Forms.PictureBox();
this.lblCondition = new System.Windows.Forms.Label();
this.txtCondition = new System.Windows.Forms.TextBox();
this.chkShowExtraInfo = new System.Windows.Forms.CheckBox();
this.chkIndentCode = new System.Windows.Forms.CheckBox();
this.chkUseLabels = new System.Windows.Forms.CheckBox();
this.label1 = new System.Windows.Forms.Label();
this.cboStatusFlagFormat = new System.Windows.Forms.ComboBox();
this.chkUseWindowsEol = new System.Windows.Forms.CheckBox();
this.chkExtendZeroPage = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.grpExecutionLog = new System.Windows.Forms.GroupBox();
this.txtTraceLog = new Mesen.GUI.Debugger.Controls.ctrlScrollableTextbox();
this.ctxMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuCopy = new System.Windows.Forms.ToolStripMenuItem();
this.mnuSelectAll = new System.Windows.Forms.ToolStripMenuItem();
this.tmrUpdateLog = new System.Windows.Forms.Timer(this.components);
this.menuStrip1 = new Mesen.GUI.Controls.ctrlMesenMenuStrip();
this.showToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fontSizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuIncreaseFontSize = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDecreaseFontSize = new System.Windows.Forms.ToolStripMenuItem();
this.mnuResetFontSize = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
this.mnuSelectFont = new System.Windows.Forms.ToolStripMenuItem();
this.logLinesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnu100Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu1000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu5000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu10000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu15000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu30000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.tableLayoutPanel1.SuspendLayout();
this.grpLogOptions.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel5.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picFormatHelp)).BeginInit();
this.tableLayoutPanel4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picHelp)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).BeginInit();
this.tableLayoutPanel3.SuspendLayout();
this.grpExecutionLog.SuspendLayout();
this.ctxMenu.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.btnOpenTrace, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.btnStartLogging, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnStopLogging, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.grpLogOptions, 0, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 200);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(778, 182);
this.tableLayoutPanel1.TabIndex = 0;
//
// btnOpenTrace
//
this.btnOpenTrace.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnOpenTrace.Enabled = false;
this.btnOpenTrace.Location = new System.Drawing.Point(680, 3);
this.btnOpenTrace.Name = "btnOpenTrace";
this.btnOpenTrace.Size = new System.Drawing.Size(95, 23);
this.btnOpenTrace.TabIndex = 2;
this.btnOpenTrace.Text = "Open Trace File";
this.btnOpenTrace.UseVisualStyleBackColor = true;
this.btnOpenTrace.Click += new System.EventHandler(this.btnOpenTrace_Click);
//
// btnStartLogging
//
this.btnStartLogging.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.btnStartLogging.Location = new System.Drawing.Point(3, 3);
this.btnStartLogging.Name = "btnStartLogging";
this.btnStartLogging.Size = new System.Drawing.Size(95, 23);
this.btnStartLogging.TabIndex = 0;
this.btnStartLogging.Text = "Start Logging";
this.btnStartLogging.UseVisualStyleBackColor = true;
this.btnStartLogging.Click += new System.EventHandler(this.btnStartLogging_Click);
//
// btnStopLogging
//
this.btnStopLogging.Enabled = false;
this.btnStopLogging.Location = new System.Drawing.Point(104, 3);
this.btnStopLogging.Name = "btnStopLogging";
this.btnStopLogging.Size = new System.Drawing.Size(95, 23);
this.btnStopLogging.TabIndex = 1;
this.btnStopLogging.Text = "Stop Logging";
this.btnStopLogging.UseVisualStyleBackColor = true;
this.btnStopLogging.Click += new System.EventHandler(this.btnStopLogging_Click);
//
// grpLogOptions
//
this.tableLayoutPanel1.SetColumnSpan(this.grpLogOptions, 3);
this.grpLogOptions.Controls.Add(this.tableLayoutPanel2);
this.grpLogOptions.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpLogOptions.Location = new System.Drawing.Point(3, 32);
this.grpLogOptions.Name = "grpLogOptions";
this.grpLogOptions.Size = new System.Drawing.Size(772, 150);
this.grpLogOptions.TabIndex = 3;
this.grpLogOptions.TabStop = false;
this.grpLogOptions.Text = "Log Options";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 7;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel5, 0, 4);
this.tableLayoutPanel2.Controls.Add(this.chkShowMemoryValues, 3, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowRegisters, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.chkShowByteCode, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowCpuCycles, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.chkShowPpuCycles, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.chkShowPpuScanline, 2, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowFrameCount, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowEffectiveAddresses, 3, 0);
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel4, 0, 5);
this.tableLayoutPanel2.Controls.Add(this.chkShowExtraInfo, 4, 0);
this.tableLayoutPanel2.Controls.Add(this.chkIndentCode, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.chkUseLabels, 2, 2);
this.tableLayoutPanel2.Controls.Add(this.label1, 4, 2);
this.tableLayoutPanel2.Controls.Add(this.cboStatusFlagFormat, 5, 2);
this.tableLayoutPanel2.Controls.Add(this.chkUseWindowsEol, 3, 2);
this.tableLayoutPanel2.Controls.Add(this.chkExtendZeroPage, 4, 1);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 8;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 5F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(766, 131);
this.tableLayoutPanel2.TabIndex = 0;
//
// tableLayoutPanel5
//
this.tableLayoutPanel5.ColumnCount = 5;
this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel5, 7);
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.Controls.Add(this.chkOverrideFormat, 0, 0);
this.tableLayoutPanel5.Controls.Add(this.picFormatHelp, 4, 0);
this.tableLayoutPanel5.Controls.Add(this.lblFormat, 0, 0);
this.tableLayoutPanel5.Controls.Add(this.txtFormat, 2, 0);
this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel5.Location = new System.Drawing.Point(0, 78);
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
this.tableLayoutPanel5.RowCount = 1;
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel5.Size = new System.Drawing.Size(766, 25);
this.tableLayoutPanel5.TabIndex = 18;
//
// chkOverrideFormat
//
this.chkOverrideFormat.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkOverrideFormat.AutoSize = true;
this.chkOverrideFormat.Location = new System.Drawing.Point(51, 5);
this.chkOverrideFormat.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.chkOverrideFormat.Name = "chkOverrideFormat";
this.chkOverrideFormat.Size = new System.Drawing.Size(66, 17);
this.chkOverrideFormat.TabIndex = 18;
this.chkOverrideFormat.Text = "Override";
this.chkOverrideFormat.UseVisualStyleBackColor = true;
this.chkOverrideFormat.CheckedChanged += new System.EventHandler(this.chkOverrideFormat_CheckedChanged);
//
// picFormatHelp
//
this.picFormatHelp.Image = global::Mesen.GUI.Properties.Resources.Help;
this.picFormatHelp.Location = new System.Drawing.Point(745, 5);
this.picFormatHelp.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.picFormatHelp.Name = "picFormatHelp";
this.picFormatHelp.Size = new System.Drawing.Size(18, 17);
this.picFormatHelp.TabIndex = 17;
this.picFormatHelp.TabStop = false;
//
// lblFormat
//
this.lblFormat.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblFormat.AutoSize = true;
this.lblFormat.Location = new System.Drawing.Point(3, 6);
this.lblFormat.Name = "lblFormat";
this.lblFormat.Size = new System.Drawing.Size(42, 13);
this.lblFormat.TabIndex = 14;
this.lblFormat.Text = "Format:";
//
// txtFormat
//
this.txtFormat.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtFormat.Location = new System.Drawing.Point(123, 3);
this.txtFormat.Name = "txtFormat";
this.txtFormat.Size = new System.Drawing.Size(616, 20);
this.txtFormat.TabIndex = 15;
this.txtFormat.TextChanged += new System.EventHandler(this.txtFormat_TextChanged);
//
// chkShowMemoryValues
//
this.chkShowMemoryValues.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowMemoryValues.AutoSize = true;
this.chkShowMemoryValues.Checked = true;
this.chkShowMemoryValues.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowMemoryValues.Location = new System.Drawing.Point(301, 26);
this.chkShowMemoryValues.Name = "chkShowMemoryValues";
this.chkShowMemoryValues.Size = new System.Drawing.Size(128, 17);
this.chkShowMemoryValues.TabIndex = 17;
this.chkShowMemoryValues.Text = "Show Memory Values";
this.chkShowMemoryValues.UseVisualStyleBackColor = true;
this.chkShowMemoryValues.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowRegisters
//
this.chkShowRegisters.AutoSize = true;
this.chkShowRegisters.Checked = true;
this.chkShowRegisters.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowRegisters.Location = new System.Drawing.Point(3, 3);
this.chkShowRegisters.Name = "chkShowRegisters";
this.chkShowRegisters.Size = new System.Drawing.Size(70, 17);
this.chkShowRegisters.TabIndex = 2;
this.chkShowRegisters.Text = "Registers";
this.chkShowRegisters.UseVisualStyleBackColor = true;
this.chkShowRegisters.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowByteCode
//
this.chkShowByteCode.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowByteCode.AutoSize = true;
this.chkShowByteCode.Checked = true;
this.chkShowByteCode.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowByteCode.Location = new System.Drawing.Point(3, 26);
this.chkShowByteCode.Name = "chkShowByteCode";
this.chkShowByteCode.Size = new System.Drawing.Size(75, 17);
this.chkShowByteCode.TabIndex = 4;
this.chkShowByteCode.Text = "Byte Code";
this.chkShowByteCode.UseVisualStyleBackColor = true;
this.chkShowByteCode.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowCpuCycles
//
this.chkShowCpuCycles.AutoSize = true;
this.chkShowCpuCycles.Checked = true;
this.chkShowCpuCycles.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowCpuCycles.Location = new System.Drawing.Point(84, 3);
this.chkShowCpuCycles.Name = "chkShowCpuCycles";
this.chkShowCpuCycles.Size = new System.Drawing.Size(82, 17);
this.chkShowCpuCycles.TabIndex = 3;
this.chkShowCpuCycles.Text = "CPU Cycles";
this.chkShowCpuCycles.UseVisualStyleBackColor = true;
this.chkShowCpuCycles.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowPpuCycles
//
this.chkShowPpuCycles.AutoSize = true;
this.chkShowPpuCycles.Checked = true;
this.chkShowPpuCycles.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowPpuCycles.Location = new System.Drawing.Point(203, 3);
this.chkShowPpuCycles.Name = "chkShowPpuCycles";
this.chkShowPpuCycles.Size = new System.Drawing.Size(77, 17);
this.chkShowPpuCycles.TabIndex = 5;
this.chkShowPpuCycles.Text = "PPU Cycle";
this.chkShowPpuCycles.UseVisualStyleBackColor = true;
this.chkShowPpuCycles.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowPpuScanline
//
this.chkShowPpuScanline.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowPpuScanline.AutoSize = true;
this.chkShowPpuScanline.Checked = true;
this.chkShowPpuScanline.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowPpuScanline.Location = new System.Drawing.Point(203, 26);
this.chkShowPpuScanline.Name = "chkShowPpuScanline";
this.chkShowPpuScanline.Size = new System.Drawing.Size(92, 17);
this.chkShowPpuScanline.TabIndex = 6;
this.chkShowPpuScanline.Text = "PPU Scanline";
this.chkShowPpuScanline.UseVisualStyleBackColor = true;
this.chkShowPpuScanline.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowFrameCount
//
this.chkShowFrameCount.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowFrameCount.AutoSize = true;
this.chkShowFrameCount.Location = new System.Drawing.Point(84, 26);
this.chkShowFrameCount.Name = "chkShowFrameCount";
this.chkShowFrameCount.Size = new System.Drawing.Size(86, 17);
this.chkShowFrameCount.TabIndex = 7;
this.chkShowFrameCount.Text = "Frame Count";
this.chkShowFrameCount.UseVisualStyleBackColor = true;
this.chkShowFrameCount.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkShowEffectiveAddresses
//
this.chkShowEffectiveAddresses.AutoSize = true;
this.chkShowEffectiveAddresses.Checked = true;
this.chkShowEffectiveAddresses.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowEffectiveAddresses.Location = new System.Drawing.Point(301, 3);
this.chkShowEffectiveAddresses.Name = "chkShowEffectiveAddresses";
this.chkShowEffectiveAddresses.Size = new System.Drawing.Size(150, 17);
this.chkShowEffectiveAddresses.TabIndex = 10;
this.chkShowEffectiveAddresses.Text = "Show Effective Addresses";
this.chkShowEffectiveAddresses.UseVisualStyleBackColor = true;
this.chkShowEffectiveAddresses.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.ColumnCount = 4;
this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel4, 7);
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.Controls.Add(this.picHelp, 3, 0);
this.tableLayoutPanel4.Controls.Add(this.picExpressionWarning, 2, 0);
this.tableLayoutPanel4.Controls.Add(this.lblCondition, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.txtCondition, 1, 0);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 103);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Size = new System.Drawing.Size(766, 25);
this.tableLayoutPanel4.TabIndex = 16;
//
// picHelp
//
this.picHelp.Image = global::Mesen.GUI.Properties.Resources.Help;
this.picHelp.Location = new System.Drawing.Point(745, 5);
this.picHelp.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.picHelp.Name = "picHelp";
this.picHelp.Size = new System.Drawing.Size(18, 17);
this.picHelp.TabIndex = 17;
this.picHelp.TabStop = false;
//
// picExpressionWarning
//
this.picExpressionWarning.Image = global::Mesen.GUI.Properties.Resources.Warning;
this.picExpressionWarning.Location = new System.Drawing.Point(721, 5);
this.picExpressionWarning.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.picExpressionWarning.Name = "picExpressionWarning";
this.picExpressionWarning.Size = new System.Drawing.Size(18, 17);
this.picExpressionWarning.TabIndex = 16;
this.picExpressionWarning.TabStop = false;
this.picExpressionWarning.Visible = false;
//
// lblCondition
//
this.lblCondition.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblCondition.AutoSize = true;
this.lblCondition.Location = new System.Drawing.Point(3, 6);
this.lblCondition.Name = "lblCondition";
this.lblCondition.Size = new System.Drawing.Size(54, 13);
this.lblCondition.TabIndex = 14;
this.lblCondition.Text = "Condition:";
//
// txtCondition
//
this.txtCondition.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtCondition.Location = new System.Drawing.Point(63, 3);
this.txtCondition.Name = "txtCondition";
this.txtCondition.Size = new System.Drawing.Size(652, 20);
this.txtCondition.TabIndex = 15;
//
// chkShowExtraInfo
//
this.chkShowExtraInfo.AutoSize = true;
this.chkShowExtraInfo.Checked = true;
this.chkShowExtraInfo.CheckState = System.Windows.Forms.CheckState.Checked;
this.tableLayoutPanel2.SetColumnSpan(this.chkShowExtraInfo, 2);
this.chkShowExtraInfo.Location = new System.Drawing.Point(462, 3);
this.chkShowExtraInfo.Name = "chkShowExtraInfo";
this.chkShowExtraInfo.Size = new System.Drawing.Size(204, 17);
this.chkShowExtraInfo.TabIndex = 9;
this.chkShowExtraInfo.Text = "Additional information (IRQ, NMI, etc.)";
this.chkShowExtraInfo.UseVisualStyleBackColor = true;
this.chkShowExtraInfo.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkIndentCode
//
this.chkIndentCode.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkIndentCode.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.chkIndentCode, 2);
this.chkIndentCode.Location = new System.Drawing.Point(3, 51);
this.chkIndentCode.Name = "chkIndentCode";
this.chkIndentCode.Size = new System.Drawing.Size(194, 17);
this.chkIndentCode.TabIndex = 8;
this.chkIndentCode.Text = "Indent code based on stack pointer";
this.chkIndentCode.UseVisualStyleBackColor = true;
this.chkIndentCode.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// chkUseLabels
//
this.chkUseLabels.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkUseLabels.AutoSize = true;
this.chkUseLabels.Location = new System.Drawing.Point(203, 51);
this.chkUseLabels.Name = "chkUseLabels";
this.chkUseLabels.Size = new System.Drawing.Size(79, 17);
this.chkUseLabels.TabIndex = 11;
this.chkUseLabels.Text = "Use Labels";
this.chkUseLabels.UseVisualStyleBackColor = true;
this.chkUseLabels.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// label1
//
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(462, 53);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(98, 13);
this.label1.TabIndex = 12;
this.label1.Text = "Status Flag Format:";
//
// cboStatusFlagFormat
//
this.tableLayoutPanel2.SetColumnSpan(this.cboStatusFlagFormat, 2);
this.cboStatusFlagFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboStatusFlagFormat.FormattingEnabled = true;
this.cboStatusFlagFormat.Location = new System.Drawing.Point(566, 49);
this.cboStatusFlagFormat.Name = "cboStatusFlagFormat";
this.cboStatusFlagFormat.Size = new System.Drawing.Size(121, 21);
this.cboStatusFlagFormat.TabIndex = 13;
this.cboStatusFlagFormat.SelectedIndexChanged += new System.EventHandler(this.cboStatusFlagFormat_SelectedIndexChanged);
//
// chkUseWindowsEol
//
this.chkUseWindowsEol.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkUseWindowsEol.AutoSize = true;
this.chkUseWindowsEol.Location = new System.Drawing.Point(301, 51);
this.chkUseWindowsEol.Name = "chkUseWindowsEol";
this.chkUseWindowsEol.Size = new System.Drawing.Size(155, 17);
this.chkUseWindowsEol.TabIndex = 19;
this.chkUseWindowsEol.Text = "Use Windows EOL (CR LF)";
this.chkUseWindowsEol.UseVisualStyleBackColor = true;
//
// chkExtendZeroPage
//
this.chkExtendZeroPage.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkExtendZeroPage.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.chkExtendZeroPage, 2);
this.chkExtendZeroPage.Location = new System.Drawing.Point(462, 26);
this.chkExtendZeroPage.Name = "chkExtendZeroPage";
this.chkExtendZeroPage.Size = new System.Drawing.Size(205, 17);
this.chkExtendZeroPage.TabIndex = 20;
this.chkExtendZeroPage.Text = "Show zero page addresses as 2 bytes";
this.chkExtendZeroPage.UseVisualStyleBackColor = true;
this.chkExtendZeroPage.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged);
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 1;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel1, 0, 1);
this.tableLayoutPanel3.Controls.Add(this.grpExecutionLog, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 24);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.Size = new System.Drawing.Size(784, 385);
this.tableLayoutPanel3.TabIndex = 1;
//
// grpExecutionLog
//
this.grpExecutionLog.Controls.Add(this.txtTraceLog);
this.grpExecutionLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpExecutionLog.Location = new System.Drawing.Point(3, 3);
this.grpExecutionLog.Name = "grpExecutionLog";
this.grpExecutionLog.Size = new System.Drawing.Size(778, 191);
this.grpExecutionLog.TabIndex = 2;
this.grpExecutionLog.TabStop = false;
this.grpExecutionLog.Text = "Execution Log";
//
// txtTraceLog
//
this.txtTraceLog.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtTraceLog.CodeHighlightingEnabled = true;
this.txtTraceLog.ContextMenuStrip = this.ctxMenu;
this.txtTraceLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtTraceLog.HideSelection = false;
this.txtTraceLog.Location = new System.Drawing.Point(3, 16);
this.txtTraceLog.Name = "txtTraceLog";
this.txtTraceLog.ShowCompactPrgAddresses = false;
this.txtTraceLog.ShowContentNotes = false;
this.txtTraceLog.ShowLineNumberNotes = false;
this.txtTraceLog.ShowMemoryValues = false;
this.txtTraceLog.ShowScrollbars = true;
this.txtTraceLog.ShowSingleContentLineNotes = true;
this.txtTraceLog.ShowSingleLineLineNumberNotes = false;
this.txtTraceLog.Size = new System.Drawing.Size(772, 172);
this.txtTraceLog.TabIndex = 0;
//
// ctxMenu
//
this.ctxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuCopy,
this.mnuSelectAll});
this.ctxMenu.Name = "ctxMenu";
this.ctxMenu.Size = new System.Drawing.Size(123, 48);
//
// mnuCopy
//
this.mnuCopy.Image = global::Mesen.GUI.Properties.Resources.Copy;
this.mnuCopy.Name = "mnuCopy";
this.mnuCopy.Size = new System.Drawing.Size(122, 22);
this.mnuCopy.Text = "Copy";
this.mnuCopy.Click += new System.EventHandler(this.mnuCopy_Click);
//
// mnuSelectAll
//
this.mnuSelectAll.Image = global::Mesen.GUI.Properties.Resources.SelectAll;
this.mnuSelectAll.Name = "mnuSelectAll";
this.mnuSelectAll.Size = new System.Drawing.Size(122, 22);
this.mnuSelectAll.Text = "Select All";
this.mnuSelectAll.Click += new System.EventHandler(this.mnuSelectAll_Click);
//
// tmrUpdateLog
//
this.tmrUpdateLog.Interval = 150;
this.tmrUpdateLog.Tick += new System.EventHandler(this.tmrUpdateLog_Tick);
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(784, 24);
this.menuStrip1.TabIndex = 2;
this.menuStrip1.Text = "menuStrip1";
//
// showToolStripMenuItem
//
this.showToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fontSizeToolStripMenuItem,
this.logLinesToolStripMenuItem,
this.mnuAutoRefresh,
this.toolStripMenuItem1,
this.mnuRefresh});
this.showToolStripMenuItem.Name = "showToolStripMenuItem";
this.showToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
this.showToolStripMenuItem.Text = "View";
//
// fontSizeToolStripMenuItem
//
this.fontSizeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuIncreaseFontSize,
this.mnuDecreaseFontSize,
this.mnuResetFontSize,
this.toolStripMenuItem12,
this.mnuSelectFont});
this.fontSizeToolStripMenuItem.Image = global::Mesen.GUI.Properties.Resources.Font;
this.fontSizeToolStripMenuItem.Name = "fontSizeToolStripMenuItem";
this.fontSizeToolStripMenuItem.Size = new System.Drawing.Size(143, 22);
this.fontSizeToolStripMenuItem.Text = "Font Options";
//
// mnuIncreaseFontSize
//
this.mnuIncreaseFontSize.Name = "mnuIncreaseFontSize";
this.mnuIncreaseFontSize.ShortcutKeyDisplayString = "";
this.mnuIncreaseFontSize.Size = new System.Drawing.Size(157, 22);
this.mnuIncreaseFontSize.Text = "Increase Size";
this.mnuIncreaseFontSize.Click += new System.EventHandler(this.mnuIncreaseFontSize_Click);
//
// mnuDecreaseFontSize
//
this.mnuDecreaseFontSize.Name = "mnuDecreaseFontSize";
this.mnuDecreaseFontSize.ShortcutKeyDisplayString = "";
this.mnuDecreaseFontSize.Size = new System.Drawing.Size(157, 22);
this.mnuDecreaseFontSize.Text = "Decrease Size";
this.mnuDecreaseFontSize.Click += new System.EventHandler(this.mnuDecreaseFontSize_Click);
//
// mnuResetFontSize
//
this.mnuResetFontSize.Name = "mnuResetFontSize";
this.mnuResetFontSize.ShortcutKeyDisplayString = "";
this.mnuResetFontSize.Size = new System.Drawing.Size(157, 22);
this.mnuResetFontSize.Text = "Reset to Default";
this.mnuResetFontSize.Click += new System.EventHandler(this.mnuResetFontSize_Click);
//
// toolStripMenuItem12
//
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
this.toolStripMenuItem12.Size = new System.Drawing.Size(154, 6);
//
// mnuSelectFont
//
this.mnuSelectFont.Name = "mnuSelectFont";
this.mnuSelectFont.Size = new System.Drawing.Size(157, 22);
this.mnuSelectFont.Text = "Select Font...";
this.mnuSelectFont.Click += new System.EventHandler(this.mnuSelectFont_Click);
//
// logLinesToolStripMenuItem
//
this.logLinesToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnu100Lines,
this.mnu1000Lines,
this.mnu5000Lines,
this.mnu10000Lines,
this.mnu15000Lines,
this.mnu30000Lines});
this.logLinesToolStripMenuItem.Name = "logLinesToolStripMenuItem";
this.logLinesToolStripMenuItem.Size = new System.Drawing.Size(143, 22);
this.logLinesToolStripMenuItem.Text = "Line Count";
//
// mnu100Lines
//
this.mnu100Lines.Name = "mnu100Lines";
this.mnu100Lines.Size = new System.Drawing.Size(104, 22);
this.mnu100Lines.Text = "100";
this.mnu100Lines.Click += new System.EventHandler(this.mnu100Lines_Click);
//
// mnu1000Lines
//
this.mnu1000Lines.Checked = true;
this.mnu1000Lines.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnu1000Lines.Name = "mnu1000Lines";
this.mnu1000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu1000Lines.Text = "1000";
this.mnu1000Lines.Click += new System.EventHandler(this.mnu1000Lines_Click);
//
// mnu5000Lines
//
this.mnu5000Lines.Name = "mnu5000Lines";
this.mnu5000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu5000Lines.Text = "5000";
this.mnu5000Lines.Click += new System.EventHandler(this.mnu5000Lines_Click);
//
// mnu10000Lines
//
this.mnu10000Lines.Name = "mnu10000Lines";
this.mnu10000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu10000Lines.Text = "10000";
this.mnu10000Lines.Click += new System.EventHandler(this.mnu10000Lines_Click);
//
// mnu15000Lines
//
this.mnu15000Lines.Name = "mnu15000Lines";
this.mnu15000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu15000Lines.Text = "15000";
this.mnu15000Lines.Click += new System.EventHandler(this.mnu15000Lines_Click);
//
// mnu30000Lines
//
this.mnu30000Lines.Name = "mnu30000Lines";
this.mnu30000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu30000Lines.Text = "30000";
this.mnu30000Lines.Click += new System.EventHandler(this.mnu30000Lines_Click);
//
// mnuAutoRefresh
//
this.mnuAutoRefresh.Checked = true;
this.mnuAutoRefresh.CheckOnClick = true;
this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnuAutoRefresh.Name = "mnuAutoRefresh";
this.mnuAutoRefresh.Size = new System.Drawing.Size(143, 22);
this.mnuAutoRefresh.Text = "Auto-refresh";
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(140, 6);
//
// mnuRefresh
//
this.mnuRefresh.Image = global::Mesen.GUI.Properties.Resources.Refresh;
this.mnuRefresh.Name = "mnuRefresh";
this.mnuRefresh.Size = new System.Drawing.Size(143, 22);
this.mnuRefresh.Text = "Refresh";
this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click);
//
// frmTraceLogger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(784, 409);
this.Controls.Add(this.tableLayoutPanel3);
this.Controls.Add(this.menuStrip1);
this.MinimumSize = new System.Drawing.Size(800, 448);
this.Name = "frmTraceLogger";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Trace Logger";
this.tableLayoutPanel1.ResumeLayout(false);
this.grpLogOptions.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel5.ResumeLayout(false);
this.tableLayoutPanel5.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picFormatHelp)).EndInit();
this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picHelp)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).EndInit();
this.tableLayoutPanel3.ResumeLayout(false);
this.grpExecutionLog.ResumeLayout(false);
this.ctxMenu.ResumeLayout(false);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Button btnStopLogging;
private System.Windows.Forms.Button btnStartLogging;
private System.Windows.Forms.GroupBox grpLogOptions;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.CheckBox chkShowCpuCycles;
private System.Windows.Forms.CheckBox chkShowRegisters;
private System.Windows.Forms.CheckBox chkShowFrameCount;
private System.Windows.Forms.CheckBox chkShowPpuScanline;
private System.Windows.Forms.CheckBox chkShowPpuCycles;
private System.Windows.Forms.CheckBox chkShowByteCode;
private System.Windows.Forms.CheckBox chkShowExtraInfo;
private System.Windows.Forms.CheckBox chkIndentCode;
private System.Windows.Forms.Button btnOpenTrace;
private System.Windows.Forms.CheckBox chkShowEffectiveAddresses;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Timer tmrUpdateLog;
private System.Windows.Forms.GroupBox grpExecutionLog;
private Mesen.GUI.Controls.ctrlMesenMenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem showToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem logLinesToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem mnuAutoRefresh;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem mnuRefresh;
private System.Windows.Forms.ToolStripMenuItem mnu100Lines;
private System.Windows.Forms.ToolStripMenuItem mnu1000Lines;
private System.Windows.Forms.ToolStripMenuItem mnu10000Lines;
private System.Windows.Forms.ToolStripMenuItem mnu30000Lines;
private System.Windows.Forms.CheckBox chkUseLabels;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox cboStatusFlagFormat;
private System.Windows.Forms.Label lblCondition;
private System.Windows.Forms.TextBox txtCondition;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.PictureBox picExpressionWarning;
private System.Windows.Forms.PictureBox picHelp;
private ctrlScrollableTextbox txtTraceLog;
private System.Windows.Forms.CheckBox chkShowMemoryValues;
private System.Windows.Forms.ToolStripMenuItem fontSizeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem mnuIncreaseFontSize;
private System.Windows.Forms.ToolStripMenuItem mnuDecreaseFontSize;
private System.Windows.Forms.ToolStripMenuItem mnuResetFontSize;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem12;
private System.Windows.Forms.ToolStripMenuItem mnuSelectFont;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5;
private System.Windows.Forms.PictureBox picFormatHelp;
private System.Windows.Forms.Label lblFormat;
private System.Windows.Forms.TextBox txtFormat;
private System.Windows.Forms.CheckBox chkOverrideFormat;
private System.Windows.Forms.CheckBox chkUseWindowsEol;
private System.Windows.Forms.CheckBox chkExtendZeroPage;
private System.Windows.Forms.ToolStripMenuItem mnu5000Lines;
private System.Windows.Forms.ToolStripMenuItem mnu15000Lines;
private System.Windows.Forms.ContextMenuStrip ctxMenu;
private System.Windows.Forms.ToolStripMenuItem mnuCopy;
private System.Windows.Forms.ToolStripMenuItem mnuSelectAll;
}
}

View file

@ -0,0 +1,132 @@
<?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="ctxMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>353, 17</value>
</metadata>
<metadata name="tmrUpdateLog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>238, 17</value>
</metadata>
</root>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,99 @@
-----------------------------------------------------------------------
IMPORTANT NOTE:
THIS LICENSE APPLIES TO Font.24.spritefont AND Font.64.spritefont ONLY.
Those files are derived works of SIL fonts and as such are distributed
under the same license.
-----------------------------------------------------------------------
This Font Software is licensed under the SIL Open Font License,
Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font
creation efforts of academic and linguistic communities, and to
provide a free and open framework in which fonts may be shared and
improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply to
any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software
components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to,
deleting, or substituting -- in part or in whole -- any of the
components of the Original Version, by changing formats or by porting
the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed,
modify, redistribute, and sell modified and unmodified copies of the
Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in
Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the
corresponding Copyright Holder. This restriction only applies to the
primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created using
the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

File diff suppressed because it is too large Load diff

202
UI/Forms/BaseConfigForm.cs Normal file
View file

@ -0,0 +1,202 @@
using System;
using System.Windows.Forms;
using Mesen.GUI.Config;
using System.ComponentModel;
namespace Mesen.GUI.Forms
{
public partial class BaseConfigForm : BaseForm
{
private EntityBinder _binder;
private object _entity;
private Timer _validateTimer;
public BaseConfigForm()
{
InitializeComponent();
_binder = new EntityBinder();
this.ShowInTaskbar = false;
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if(!designMode) {
_validateTimer = new Timer();
_validateTimer.Interval = 50;
_validateTimer.Tick += OnValidateInput;
_validateTimer.Start();
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
UpdateUI();
}
protected override bool IsConfigForm { get { return true; } }
protected void UpdateUI()
{
_binder.UpdateUI();
this.AfterUpdateUI();
}
protected void UpdateObject()
{
_binder.UpdateObject();
UpdateConfig();
}
private void OnValidateInput(object sender, EventArgs e)
{
btnOK.Enabled = ValidateInput();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if(DialogResult == System.Windows.Forms.DialogResult.OK) {
if(!ValidateInput()) {
e.Cancel = true;
}
}
if(!e.Cancel) {
_validateTimer.Tick -= OnValidateInput;
_validateTimer.Stop();
}
base.OnFormClosing(e);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
if(this.DialogResult == System.Windows.Forms.DialogResult.OK) {
UpdateObject();
if(ApplyChangesOnOK) {
ConfigManager.ApplyChanges();
}
} else {
if(ApplyChangesOnOK) {
ConfigManager.RejectChanges();
}
}
base.OnFormClosed(e);
}
protected virtual bool ApplyChangesOnOK
{
get { return true; }
}
protected virtual void UpdateConfig()
{
}
protected bool Updating
{
get { return _binder.Updating; }
}
protected object Entity
{
get { return _entity; }
set
{
_binder.Entity = value;
_entity = value;
}
}
protected virtual bool ValidateInput()
{
return true;
}
protected void AddBinding(string fieldName, RadioButton trueRadio, RadioButton falseRadio)
{
falseRadio.Checked = true;
_binder.AddBinding(fieldName, trueRadio);
}
protected void AddBinding(string fieldName, Control bindedField, eNumberFormat format = eNumberFormat.Default)
{
_binder.AddBinding(fieldName, bindedField, format);
}
public static void InitializeComboBox(ComboBox combo, Type enumType, Enum[] hiddenValues = null)
{
Enum selectedValue = combo.GetEnumValue(enumType);
combo.DropDownStyle = ComboBoxStyle.DropDownList;
combo.Items.Clear();
foreach(Enum value in Enum.GetValues(enumType)) {
if(hiddenValues == null || Array.IndexOf(hiddenValues, value) < 0) {
combo.Items.Add(ResourceHelper.GetEnumText(value));
}
}
if(selectedValue != null) {
combo.SetEnumValue(selectedValue);
}
}
virtual protected void AfterUpdateUI()
{
}
private void btnOK_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
public static class ComboBoxExtensions
{
public static Enum GetEnumValue(this ComboBox cbo, Type enumType)
{
if(cbo.SelectedItem == null) {
return null;
}
foreach(Enum value in Enum.GetValues(enumType)) {
if(ResourceHelper.GetEnumText(value) == cbo.SelectedItem.ToString()) {
return value;
}
}
return null;
}
public static T GetEnumValue<T>(this ComboBox cbo)
{
if(cbo.SelectedItem == null) {
return default(T);
}
foreach(Enum value in Enum.GetValues(typeof(T))) {
if(ResourceHelper.GetEnumText(value) == cbo.SelectedItem.ToString()) {
return (T)(object)value;
}
}
return default(T);
}
public static void SetEnumValue<T>(this ComboBox cbo, T value)
{
for(int i = 0; i < cbo.Items.Count; i++) {
if(ResourceHelper.GetEnumText((Enum)(object)value) == cbo.Items[i].ToString()) {
cbo.SelectedIndex = i;
break;
}
}
}
}
}

112
UI/Forms/BaseConfigForm.designer.cs generated Normal file
View file

@ -0,0 +1,112 @@
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
{
partial class BaseConfigForm
{
/// <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.btnCancel = new System.Windows.Forms.Button();
this.btnOK = new System.Windows.Forms.Button();
this.baseConfigPanel = new System.Windows.Forms.Panel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.baseConfigPanel.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(84, 3);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 0;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnOK
//
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(3, 3);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 1;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// baseConfigPanel
//
this.baseConfigPanel.Controls.Add(this.flowLayoutPanel1);
this.baseConfigPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
this.baseConfigPanel.Location = new System.Drawing.Point(0, 233);
this.baseConfigPanel.Name = "baseConfigPanel";
this.baseConfigPanel.Size = new System.Drawing.Size(327, 29);
this.baseConfigPanel.TabIndex = 1;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.Controls.Add(this.btnCancel);
this.flowLayoutPanel1.Controls.Add(this.btnOK);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Right;
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
this.flowLayoutPanel1.Location = new System.Drawing.Point(121, 0);
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(206, 29);
this.flowLayoutPanel1.TabIndex = 2;
//
// BaseConfigForm
//
this.AcceptButton = this.btnOK;
this.CancelButton = this.btnCancel;
this.Controls.Add(this.baseConfigPanel);
this.Name = "BaseConfigForm";
this.baseConfigPanel.ResumeLayout(false);
this.flowLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
protected Button btnCancel;
protected Button btnOK;
protected Panel baseConfigPanel;
private FlowLayoutPanel flowLayoutPanel1;
}
}

View file

@ -0,0 +1,120 @@
<?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>
</root>

221
UI/Forms/BaseForm.cs Normal file
View file

@ -0,0 +1,221 @@
using Mesen.GUI.Config;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public class BaseForm : Form
{
public delegate void ProcessCmdKeyHandler(Keys keyData, ref bool processed);
public event ProcessCmdKeyHandler OnProcessCmdKey;
protected ToolTip toolTip;
private System.ComponentModel.IContainer components;
private bool _iconSet = false;
protected int _inMenu = 0;
private static Timer _tmrUpdateBackground;
//private static bool _needResume = false;
public BaseForm()
{
InitializeComponent();
}
protected virtual bool IsConfigForm { get { return false; } }
public static void StartBackgroundTimer()
{
_tmrUpdateBackground = new Timer();
_tmrUpdateBackground.Start();
_tmrUpdateBackground.Tick += tmrUpdateBackground_Tick;
}
public static void StopBackgroundTimer()
{
_tmrUpdateBackground?.Stop();
}
private static void tmrUpdateBackground_Tick(object sender, EventArgs e)
{
/*Form focusedForm = null;
foreach(Form form in Application.OpenForms) {
if(form.ContainsFocus) {
focusedForm = form;
break;
}
}
bool needPause = focusedForm == null && ConfigManager.Config.PreferenceInfo.PauseWhenInBackground;
if(focusedForm != null) {
needPause |= ConfigManager.Config.PreferenceInfo.PauseWhenInMenusAndConfig && focusedForm is BaseForm && (((BaseForm)focusedForm)._inMenu > 0 || ((BaseForm)focusedForm).IsConfigForm);
needPause |= ConfigManager.Config.PreferenceInfo.PauseWhenInMenusAndConfig && !(focusedForm is BaseInputForm) && !focusedForm.GetType().FullName.Contains("Debugger");
needPause |= ConfigManager.Config.PreferenceInfo.PauseWhenInDebuggingTools && focusedForm.GetType().FullName.Contains("Debugger");
}
if(needPause) {
if(!EmuApi.IsPaused(EmuApi.ConsoleId.Master)) {
_needResume = true;
EmuApi.Pause(EmuApi.ConsoleId.Master);
}
} else if(_needResume) {
EmuApi.Resume(EmuApi.ConsoleId.Master);
_needResume = false;
}
EmuApi.SetFlag(EmulationFlags.InBackground, focusedForm == null);*/
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool processed = false;
OnProcessCmdKey?.Invoke(keyData, ref processed);
return processed || base.ProcessCmdKey(ref msg, keyData);
}
public void Show(object sender, IWin32Window owner = null)
{
if(sender is ToolStripMenuItem) {
ToolStripItem menuItem = (ToolStripMenuItem)sender;
if(menuItem.Image == null) {
menuItem = menuItem.OwnerItem;
}
this.Icon = menuItem.Image;
}
CenterOnParent(owner);
base.Show();
}
private void CenterOnParent(IWin32Window owner)
{
Form parent = (Form)owner;
Point point = parent.PointToScreen(new Point(parent.Width / 2, parent.Height / 2));
this.StartPosition = FormStartPosition.Manual;
this.Top = point.Y - this.Height / 2;
this.Left = point.X - this.Width / 2;
}
public DialogResult ShowDialog(object sender, IWin32Window owner = null)
{
if(sender is ToolStripMenuItem) {
ToolStripItem menuItem = (ToolStripMenuItem)sender;
if(menuItem.Image == null) {
menuItem = menuItem.OwnerItem;
}
this.Icon = menuItem.Image;
}
return base.ShowDialog(owner);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(!DesignMode) {
if(!_iconSet) {
base.Icon = Properties.Resources.MesenIcon;
}
}
int tabIndex = 0;
InitializeTabIndexes(this, ref tabIndex);
ResourceHelper.ApplyResources(this);
}
private void InitializeTabIndexes(TableLayoutPanel tlp, ref int tabIndex)
{
tlp.TabIndex = tabIndex;
tabIndex++;
for(int i = 0; i < tlp.RowCount; i++) {
for(int j = 0; j < tlp.ColumnCount; j++) {
Control ctrl = tlp.GetControlFromPosition(j, i);
if(ctrl != null) {
if(ctrl is TableLayoutPanel) {
InitializeTabIndexes(((TableLayoutPanel)ctrl), ref tabIndex);
} else {
InitializeTabIndexes(ctrl, ref tabIndex);
}
}
}
}
}
private void InitializeTabIndexes(Control container, ref int tabIndex)
{
container.TabIndex = tabIndex;
tabIndex++;
foreach(Control ctrl in container.Controls) {
if(ctrl is TableLayoutPanel) {
InitializeTabIndexes(((TableLayoutPanel)ctrl), ref tabIndex);
} else {
InitializeTabIndexes(ctrl, ref tabIndex);
}
}
}
public new Image Icon
{
set
{
if(value != null) {
Bitmap b = new Bitmap(value);
Icon i = System.Drawing.Icon.FromHandle(b.GetHicon());
base.Icon = i;
i.Dispose();
_iconSet = true;
}
}
}
public new SizeF AutoScaleDimensions
{
set
{
if(!Program.IsMono) {
base.AutoScaleDimensions = value;
}
}
}
public new AutoScaleMode AutoScaleMode
{
set {
if(Program.IsMono) {
base.AutoScaleMode = AutoScaleMode.None;
} else {
base.AutoScaleMode = value;
}
}
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// toolTip
//
this.toolTip.AutomaticDelay = 0;
this.toolTip.AutoPopDelay = 32700;
this.toolTip.InitialDelay = 10;
this.toolTip.ReshowDelay = 10;
//
// BaseForm
//
this.Name = "BaseForm";
this.ResumeLayout(false);
}
}
}

123
UI/Forms/BaseForm.resx Normal file
View file

@ -0,0 +1,123 @@
<?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>
</root>

80
UI/Forms/BaseInputForm.cs Normal file
View file

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public class BaseInputForm : BaseForm, IMessageFilter
{
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
public BaseInputForm()
{
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if(!designMode) {
Application.AddMessageFilter(this);
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == Keys.Escape) {
//CursorManager.ReleaseMouse();
}
return base.ProcessCmdKey(ref msg, keyData);
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if(this.ContainsFocus) {
if(m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
EmuApi.SetKeyState(scanCode, false);
} else if(m.Msg == WM_SYSKEYDOWN || m.Msg == WM_KEYDOWN) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
EmuApi.SetKeyState(scanCode, true);
}
}
return false;
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
Application.RemoveMessageFilter(this);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(Program.IsMono) {
//Mono does not trigger the activate/deactivate events when opening a modal popup, but it does set the form to disabled
//Use this to reset key states
this.EnabledChanged += (object s, EventArgs evt) => {
EmuApi.ResetKeyState();
};
}
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
EmuApi.ResetKeyState();
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
EmuApi.ResetKeyState();
}
}
}

126
UI/Forms/BaseInputForm.resx Normal file
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="tmrUpdateBackground.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
</root>

318
UI/Forms/EntityBinder.cs Normal file
View file

@ -0,0 +1,318 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms.Config;
namespace Mesen.GUI.Forms
{
public class EntityBinder
{
private Dictionary<string, Control> _bindings = new Dictionary<string, Control>();
private Dictionary<string, eNumberFormat> _fieldFormat = new Dictionary<string, eNumberFormat>();
private Dictionary<string, FieldInfoWrapper> _fieldInfo = null;
public object Entity { get; set; }
protected virtual Type BindedType
{
get { return Entity.GetType(); }
}
public bool Updating { get; private set; }
public void AddBinding(string fieldName, Control bindedField, eNumberFormat format = eNumberFormat.Default)
{
if(BindedType == null) {
throw new Exception("Need to override BindedType to use bindings");
}
if(_fieldInfo == null) {
_fieldInfo = new Dictionary<string, FieldInfoWrapper>();
PropertyInfo[] properties = BindedType.GetProperties();
foreach(PropertyInfo info in properties) {
_fieldInfo[info.Name] = new FieldInfoWrapper(info);
}
FieldInfo[] members = BindedType.GetFields();
foreach(FieldInfo info in members) {
_fieldInfo[info.Name] = new FieldInfoWrapper(info);
}
}
if(_fieldInfo.ContainsKey(fieldName)) {
Type fieldType = _fieldInfo[fieldName].FieldType;
if(fieldType.IsSubclassOf(typeof(Enum)) && bindedField is ComboBox) {
BaseConfigForm.InitializeComboBox(((ComboBox)bindedField), fieldType);
}
_bindings[fieldName] = bindedField;
_fieldFormat[fieldName] = format;
} else {
throw new Exception("Invalid field name");
}
}
public void UpdateUI()
{
this.Updating = true;
foreach(KeyValuePair<string, Control> kvp in _bindings) {
if(!_fieldInfo.ContainsKey(kvp.Key)) {
throw new Exception("Invalid binding key");
} else {
FieldInfoWrapper field = _fieldInfo[kvp.Key];
eNumberFormat format = _fieldFormat[kvp.Key];
object value = field.GetValue(this.Entity);
if(kvp.Value is TextBox) {
if(value is IFormattable) {
kvp.Value.Text = ((IFormattable)value).ToString(format == eNumberFormat.Decimal ? "" : "X", System.Globalization.CultureInfo.InvariantCulture);
} else {
kvp.Value.Text = value == null ? "" : ((string)value).Replace(Environment.NewLine, "\n").Replace("\n", Environment.NewLine);
}
} else if(kvp.Value is ctrlPathSelection) {
kvp.Value.Text = (string)value;
} else if(kvp.Value is CheckBox) {
((CheckBox)kvp.Value).Checked = Convert.ToBoolean(value);
} else if(kvp.Value is ctrlRiskyOption) {
((ctrlRiskyOption)kvp.Value).Checked = Convert.ToBoolean(value);
} else if(kvp.Value is RadioButton) {
((RadioButton)kvp.Value).Checked = (bool)value;
} else if(kvp.Value is Panel) {
RadioButton radio = kvp.Value.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Tag.Equals(value));
if(radio != null) {
radio.Checked = true;
} else {
throw new Exception("No radio button matching value found");
}
} else if(kvp.Value is ctrlTrackbar) {
if(field.FieldType == typeof(Int32)) {
((ctrlTrackbar)kvp.Value).Value = (int)value;
} else {
((ctrlTrackbar)kvp.Value).Value = (int)(uint)value;
}
} else if(kvp.Value is ctrlHorizontalTrackbar) {
((ctrlHorizontalTrackbar)kvp.Value).Value = (int)value;
} else if(kvp.Value is TrackBar) {
if(field.FieldType == typeof(Int32)) {
((TrackBar)kvp.Value).Value = (int)value;
} else {
((TrackBar)kvp.Value).Value = (int)(uint)value;
}
} else if(kvp.Value is MesenNumericUpDown) {
MesenNumericUpDown nud = kvp.Value as MesenNumericUpDown;
decimal val;
if(field.FieldType == typeof(UInt32)) {
val = (UInt32)value;
} else if(field.FieldType == typeof(Int32)) {
val = (Int32)value;
} else {
val = (decimal)(double)value;
}
val = Math.Min(Math.Max(val, nud.Minimum), nud.Maximum);
nud.Value = val;
} else if(kvp.Value is ComboBox) {
ComboBox combo = kvp.Value as ComboBox;
if(value is Enum) {
combo.SelectedItem = ResourceHelper.GetEnumText((Enum)value);
} else if(field.FieldType == typeof(UInt32)) {
for(int i = 0, len = combo.Items.Count; i < len; i++) {
UInt32 numericValue;
string item = Regex.Replace(combo.Items[i].ToString(), "[^0-9]", "");
if(UInt32.TryParse(item, out numericValue)) {
if(numericValue == (UInt32)value) {
combo.SelectedIndex = i;
break;
}
}
}
} else if(field.FieldType == typeof(string)) {
combo.SelectedItem = value;
if(combo.SelectedIndex < 0 && combo.Items.Count > 0) {
combo.SelectedIndex = 0;
}
}
}
}
}
this.Updating = false;
}
public void UpdateObject()
{
foreach(KeyValuePair<string, Control> kvp in _bindings) {
if(!_fieldInfo.ContainsKey(kvp.Key)) {
throw new Exception("Invalid binding key");
} else {
try {
FieldInfoWrapper field = _fieldInfo[kvp.Key];
eNumberFormat format = _fieldFormat[kvp.Key];
if(kvp.Value is TextBox) {
object value = kvp.Value.Text;
NumberStyles numberStyle = format == eNumberFormat.Decimal ? NumberStyles.Integer : NumberStyles.HexNumber;
if(field.FieldType != typeof(string)) {
value = ((string)value).Trim().Replace("$", "").Replace("0x", "");
if(string.IsNullOrWhiteSpace((string)value)) {
value = "0";
}
}
if(field.FieldType == typeof(UInt32)) {
UInt32 result;
if(!UInt32.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
} else if(field.FieldType == typeof(Int32)) {
Int32 result;
if(!Int32.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
} else if(field.FieldType == typeof(Byte)) {
Byte result;
if(!Byte.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
} else if(field.FieldType == typeof(UInt16)) {
UInt16 result;
if(!UInt16.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
} else if(field.FieldType == typeof(UInt64)) {
UInt64 result;
if(!UInt64.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
} else if(field.FieldType == typeof(Int64)) {
Int64 result;
if(!Int64.TryParse((string)value, numberStyle, null, out result)) {
continue; //Invalid value, ignore it
}
value = result;
}
field.SetValue(Entity, value);
} else if(kvp.Value is ctrlPathSelection) {
field.SetValue(Entity, ((ctrlPathSelection)kvp.Value).Text);
} else if(kvp.Value is CheckBox) {
if(field.FieldType == typeof(bool)) {
field.SetValue(Entity, ((CheckBox)kvp.Value).Checked);
} else if(field.FieldType == typeof(byte)) {
field.SetValue(Entity, ((CheckBox)kvp.Value).Checked ? (byte)1 : (byte)0);
}
} else if(kvp.Value is ctrlRiskyOption) {
if(field.FieldType == typeof(bool)) {
field.SetValue(Entity, ((ctrlRiskyOption)kvp.Value).Checked);
} else if(field.FieldType == typeof(byte)) {
field.SetValue(Entity, ((ctrlRiskyOption)kvp.Value).Checked ? (byte)1 : (byte)0);
}
} else if(kvp.Value is RadioButton) {
field.SetValue(Entity, ((RadioButton)kvp.Value).Checked);
} else if(kvp.Value is Panel) {
field.SetValue(Entity, kvp.Value.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked).Tag);
} else if(kvp.Value is ctrlTrackbar) {
if(field.FieldType == typeof(Int32)) {
field.SetValue(Entity, (Int32)((ctrlTrackbar)kvp.Value).Value);
} else {
field.SetValue(Entity, (UInt32)((ctrlTrackbar)kvp.Value).Value);
}
} else if(kvp.Value is ctrlHorizontalTrackbar) {
field.SetValue(Entity, (Int32)((ctrlHorizontalTrackbar)kvp.Value).Value);
} else if(kvp.Value is TrackBar) {
if(field.FieldType == typeof(Int32)) {
field.SetValue(Entity, ((TrackBar)kvp.Value).Value);
} else {
field.SetValue(Entity, (UInt32)((TrackBar)kvp.Value).Value);
}
} else if(kvp.Value is MesenNumericUpDown) {
if(field.FieldType == typeof(UInt32)) {
field.SetValue(Entity, (UInt32)((MesenNumericUpDown)kvp.Value).Value);
} else if(field.FieldType == typeof(Int32)) {
field.SetValue(Entity, (Int32)((MesenNumericUpDown)kvp.Value).Value);
} else {
field.SetValue(Entity, (double)((MesenNumericUpDown)kvp.Value).Value);
}
} else if(kvp.Value is ComboBox) {
if(field.FieldType.IsSubclassOf(typeof(Enum))) {
Enum enumValue = ((ComboBox)kvp.Value).GetEnumValue(field.FieldType);
if(enumValue != null) {
field.SetValue(Entity, enumValue);
}
} else if(field.FieldType == typeof(UInt32)) {
UInt32 numericValue;
string item = Regex.Replace(((ComboBox)kvp.Value).SelectedItem.ToString(), "[^0-9]", "");
if(UInt32.TryParse(item, out numericValue)) {
field.SetValue(Entity, numericValue);
}
} else if(field.FieldType == typeof(string)) {
field.SetValue(Entity, ((ComboBox)kvp.Value).SelectedItem);
}
}
} catch {
//Ignore exceptions caused by bad user input
}
}
}
}
private class FieldInfoWrapper
{
private FieldInfo _fieldInfo;
private PropertyInfo _propertyInfo;
public FieldInfoWrapper(PropertyInfo info)
{
_propertyInfo = info;
}
public FieldInfoWrapper(FieldInfo info)
{
_fieldInfo = info;
}
public Type FieldType
{
get
{
if(_fieldInfo != null) {
return _fieldInfo.FieldType;
} else {
return _propertyInfo.PropertyType;
}
}
}
public void SetValue(object obj, object value)
{
if(_fieldInfo != null) {
_fieldInfo.SetValue(obj, value);
} else {
_propertyInfo.SetValue(obj, value);
}
}
public object GetValue(object obj)
{
if(_fieldInfo != null) {
return _fieldInfo.GetValue(obj);
} else {
return _propertyInfo.GetValue(obj);
}
}
}
}
public enum eNumberFormat
{
Default,
Hex,
Decimal,
}
}

36
UI/Forms/MesenMsgBox.cs Normal file
View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
class MesenMsgBox
{
public static DialogResult Show(string text, MessageBoxButtons buttons, MessageBoxIcon icon, params string[] args)
{
string resourceText = ResourceHelper.GetMessage(text, args);
if(resourceText.StartsWith("[[")) {
if(args != null && args.Length > 0) {
return MessageBox.Show(string.Format("Critical error (" + text + ") {0}", args), "Mesen", buttons, icon);
} else {
return MessageBox.Show(string.Format("Critical error (" + text + ")"), "Mesen", buttons, icon);
}
} else {
Form mainForm = Application.OpenForms.Count > 0 ? Application.OpenForms[0] : null;
if(mainForm?.InvokeRequired == true) {
DialogResult result = DialogResult.Cancel;
mainForm.Invoke((Action)(() => {
result = MessageBox.Show(mainForm, ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
}));
return result;
} else {
return MessageBox.Show(ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
}
}
}
}
}

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public static class OpenFileDialogExtensions
{
private static string ToCaseInsensitiveFilter(string filter)
{
if(Program.IsMono) {
string[] filterData = filter.Split('|');
for(int i = 0; i < filterData.Length; i+=2) {
List<string> fileTypes = new List<string>(filterData[i+1].Split(';'));
for(int j = 0, len = fileTypes.Count; j < len; j++) {
fileTypes[j] = fileTypes[j].ToUpper();
fileTypes.Add(fileTypes[j].ToLower());
}
filterData[i+1] = string.Join(";", fileTypes.ToArray());
}
return string.Join("|", filterData);
} else {
return filter;
}
}
public static void SetFilter(this OpenFileDialog ofd, string filter)
{
ofd.Filter = ToCaseInsensitiveFilter(filter);
}
public static void SetFilter(this SaveFileDialog ofd, string filter)
{
ofd.Filter = ToCaseInsensitiveFilter(filter);
}
}
}

284
UI/Forms/ResourceHelper.cs Normal file
View file

@ -0,0 +1,284 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Layout;
using System.Xml;
using Mesen.GUI.Config;
using Mesen.GUI.Controls;
namespace Mesen.GUI.Forms
{
public enum Language
{
SystemDefault = 0,
English = 1,
French = 2,
Japanese = 3,
Russian = 4,
Spanish = 5,
Ukrainian = 6,
Portuguese = 7,
Catalan = 8,
Chinese = 9,
}
class ResourceHelper
{
private static Language _language;
private static XmlDocument _resources = new XmlDocument();
private static XmlDocument _enResources = new XmlDocument();
public static Language GetCurrentLanguage()
{
return _language;
}
public static string GetLanguageCode()
{
switch(ResourceHelper.GetCurrentLanguage()) {
case Language.English: return "en";
case Language.French: return "fr";
case Language.Japanese: return "ja";
case Language.Russian: return "ru";
case Language.Spanish: return "es";
case Language.Ukrainian: return "uk";
case Language.Portuguese: return "pt";
case Language.Catalan: return "ca";
case Language.Chinese: return "zh";
}
return "";
}
public static void UpdateEmuLanguage()
{
EmuApi.SetDisplayLanguage(_language);
}
public static void LoadResources(Language language)
{
if(language == Language.SystemDefault) {
switch(System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName) {
default:
case "en": language = Language.English; break;
case "fr": language = Language.French; break;
case "ja": language = Language.Japanese; break;
case "ru": language = Language.Russian; break;
case "es": language = Language.Spanish; break;
case "uk": language = Language.Ukrainian; break;
case "pt": language = Language.Portuguese; break;
case "zh": language = Language.Chinese; break;
}
}
string filename;
string enFilename = "resources.en.xml";
switch(language) {
default:
case Language.English: filename = enFilename; break;
case Language.French: filename = "resources.fr.xml"; break;
case Language.Japanese: filename = "resources.ja.xml"; break;
case Language.Russian: filename = "resources.ru.xml"; break;
case Language.Spanish: filename = "resources.es.xml"; break;
case Language.Ukrainian: filename = "resources.uk.xml"; break;
case Language.Portuguese: filename = "resources.pt.xml"; break;
case Language.Catalan: filename = "resources.ca.xml"; break;
case Language.Chinese: filename = "resources.zh.xml"; break;
}
_language = language;
using(Stream stream = ResourceExtractor.GetZippedResource(filename)) {
_resources.Load(stream);
}
using(Stream stream = ResourceExtractor.GetZippedResource(enFilename)) {
_enResources.Load(stream);
}
}
public static string GetMessage(string id, params object[] args)
{
var baseNode = _resources.SelectSingleNode("/Resources/Messages/Message[@ID='" + id + "']");
if(baseNode == null) {
baseNode = _enResources.SelectSingleNode("/Resources/Messages/Message[@ID='" + id + "']");
}
if(baseNode != null) {
return string.Format(baseNode.InnerText, args);
} else {
return "[[" + id + "]]";
}
}
public static string GetEnumText(Enum e)
{
var baseNode = _resources.SelectSingleNode("/Resources/Enums/Enum[@ID='" + e.GetType().Name + "']/Value[@ID='" + e.ToString() + "']");
if(baseNode == null) {
baseNode = _enResources.SelectSingleNode("/Resources/Enums/Enum[@ID='" + e.GetType().Name + "']/Value[@ID='" + e.ToString() + "']");
}
if(baseNode != null) {
return baseNode.InnerText;
} else {
return e.ToString();
}
}
public static void ApplyResources(Form form)
{
ApplyResources(form, form.Name);
}
public static void ApplyResources(Form form, string formName)
{
XmlNode baseNode = _resources.SelectSingleNode("/Resources/Forms/Form[@ID='" + formName + "']");
if(baseNode != null) {
if(baseNode.Attributes["Title"] != null) {
form.Text = baseNode.Attributes["Title"].Value;
}
ApplyResources(baseNode, form.Controls);
}
}
public static void ApplyResources(Form form, ContextMenuStrip contextMenu)
{
XmlNode baseNode = _resources.SelectSingleNode("/Resources/Forms/Form[@ID='" + form.Name + "']");
if(baseNode != null) {
ApplyResources(baseNode, contextMenu.Items);
}
}
private static void ApplyResources(XmlNode baseNode, UserControl control)
{
XmlNode controlNode = _resources.SelectSingleNode("/Resources/UserControls/UserControl[@ID='" + control.GetType().Name + "']");
if(controlNode != null) {
ApplyResources(controlNode, control.Controls);
} else {
ApplyResources(baseNode, control.Controls);
}
}
private static void ApplyResources(XmlNode baseNode, IEnumerable container)
{
foreach(object ctrl in container) {
string name = null;
if(ctrl is Control) {
name = ((Control)ctrl).Name;
} else if(ctrl is ToolStripItem) {
name = ((ToolStripItem)ctrl).Name;
} else if(ctrl is ColumnHeader) {
name = ((ColumnHeader)ctrl).Name;
} else if(ctrl is DataGridViewColumn) {
name = ((DataGridViewColumn)ctrl).Name;
}
var controlNode = baseNode.SelectSingleNode("Control[@ID='" + name + "']");
if(controlNode != null) {
if(ctrl is Control) {
((Control)ctrl).Text = controlNode.InnerText;
} else if(ctrl is ToolStripItem) {
((ToolStripItem)ctrl).Text = controlNode.InnerText;
if(((ToolStripItem)ctrl).DisplayStyle != ToolStripItemDisplayStyle.Image) {
((ToolStripItem)ctrl).ToolTipText = "";
}
} else if(ctrl is ColumnHeader) {
((ColumnHeader)ctrl).Text = controlNode.InnerText;
} else if(ctrl is DataGridViewColumn) {
((DataGridViewColumn)ctrl).HeaderText = controlNode.InnerText;
}
}
if(ctrl is DataGridView) {
ApplyResources(baseNode, ((DataGridView)ctrl).Columns);
} else if(ctrl is MenuStrip) {
ApplyResources(baseNode, ((MenuStrip)ctrl).Items);
} else if(ctrl is ContextMenuStrip) {
ApplyResources(baseNode, ((ContextMenuStrip)ctrl).Items);
} else if(ctrl is ListView) {
ApplyResources(baseNode, ((ListView)ctrl).Columns);
} else if(ctrl is ToolStrip) {
ApplyResources(baseNode, ((ToolStrip)ctrl).Items);
} else if(ctrl is ToolStripSplitButton) {
ApplyResources(baseNode, ((ToolStripSplitButton)ctrl).DropDownItems);
} else if(ctrl is UserControl) {
ApplyResources(baseNode, ctrl as UserControl);
} else if(ctrl is Control) {
ApplyResources(baseNode, ((Control)ctrl).Controls);
} else if(ctrl is ToolStripMenuItem) {
ApplyResources(baseNode, ((ToolStripMenuItem)ctrl).DropDownItems);
}
if(ctrl is Control) {
if(((Control)ctrl).ContextMenuStrip != null) {
ApplyResources(baseNode, ((Control)ctrl).ContextMenuStrip.Items);
}
}
}
}
private static XmlDocument BuildResourceFile(Form form)
{
XmlDocument document = new XmlDocument();
XmlNode resources = document.CreateElement("Resources");
document.AppendChild(resources);
resources.AppendChild(document.CreateElement("Forms"));
BuildResourceFile(document, form, form.Controls);
return document;
}
private static void BuildResourceFile(XmlDocument xmlDoc, Form form, IEnumerable container)
{
var baseNode = xmlDoc.SelectSingleNode("/Resources/Forms/Form[@ID='" + form.Name + "']");
if(baseNode == null) {
baseNode = xmlDoc.CreateElement("Form");
baseNode.Attributes.Append(xmlDoc.CreateAttribute("ID"));
baseNode.Attributes.Append(xmlDoc.CreateAttribute("Title"));
baseNode.Attributes["ID"].Value = form.Name;
baseNode.Attributes["Title"].Value = form.Text;
xmlDoc.SelectSingleNode("/Resources/Forms").AppendChild(baseNode);
}
foreach(Component ctrl in container) {
string text = null;
string name = null;
if(ctrl is Control) {
text = ((Control)ctrl).Text;
name = ((Control)ctrl).Name;
} else if(ctrl is ToolStripItem) {
text = ((ToolStripItem)ctrl).Text;
name = ((ToolStripItem)ctrl).Name;
}
if(!string.IsNullOrWhiteSpace(text)) {
var controlNode = baseNode.SelectSingleNode("Control[@ID='" + name + "']");
if(controlNode == null) {
controlNode = xmlDoc.CreateElement("Control");
controlNode.Attributes.Append(xmlDoc.CreateAttribute("ID"));
controlNode.Attributes["ID"].Value = name;
baseNode.AppendChild(controlNode);
}
controlNode.InnerText = text;
}
if(ctrl is MenuStrip) {
BuildResourceFile(xmlDoc, form, ((MenuStrip)ctrl).Items);
} else if(ctrl is Control) {
BuildResourceFile(xmlDoc, form, ((Control)ctrl).Controls);
} else if(ctrl is ToolStripMenuItem) {
BuildResourceFile(xmlDoc, form, ((ToolStripMenuItem)ctrl).DropDownItems);
}
}
}
}
}

66
UI/Forms/ResourcePath.cs Normal file
View file

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Forms
{
public struct ResourcePath : IEquatable<ResourcePath>
{
public string Path { get; set; }
public string InnerFile { get; set; }
public int InnerFileIndex { get; set; }
public bool Exists { get { return File.Exists(Path); } }
public bool Compressed { get { return !string.IsNullOrWhiteSpace(InnerFile); } }
public string FileName { get { return Compressed ? InnerFile : System.IO.Path.GetFileName(Path); } }
public string Folder { get { return System.IO.Path.GetDirectoryName(Path); } }
public string ReadablePath
{
get
{
if(Compressed) {
return $"{Path} ({InnerFile})";
} else {
return Path;
}
}
}
public override string ToString()
{
string resPath = Path;
if(Compressed) {
resPath += "\x1" + InnerFile;
if(InnerFileIndex > 0) {
resPath += "\x1" + (InnerFileIndex - 1).ToString();
}
}
return resPath;
}
static public implicit operator ResourcePath(string path)
{
string[] tokens = path.Split('\x1');
return new ResourcePath() {
Path = tokens[0],
InnerFile = tokens.Length > 1 ? tokens[1] : "",
InnerFileIndex = tokens.Length > 2 ? (int.Parse(tokens[2]) + 1) : 0
};
}
static public implicit operator string(ResourcePath resourcePath)
{
return resourcePath.ToString();
}
bool IEquatable<ResourcePath>.Equals(ResourcePath other)
{
return other.ToString() == this.ToString();
}
}
}

152
UI/Forms/frmMain.Designer.cs generated Normal file
View file

@ -0,0 +1,152 @@
namespace Mesen.GUI.Forms
{
partial class frmMain
{
/// <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.ctrlRenderer = new Mesen.GUI.Controls.ctrlRenderer();
this.mnuMain = new Mesen.GUI.Controls.ctrlMesenMenuStrip();
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuOpen = new System.Windows.Forms.ToolStripMenuItem();
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStep = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMain.SuspendLayout();
this.SuspendLayout();
//
// ctrlRenderer
//
this.ctrlRenderer.Location = new System.Drawing.Point(0, 27);
this.ctrlRenderer.Name = "ctrlRenderer";
this.ctrlRenderer.Size = new System.Drawing.Size(512, 448);
this.ctrlRenderer.TabIndex = 0;
//
// mnuMain
//
this.mnuMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuFile,
this.debugToolStripMenuItem});
this.mnuMain.Location = new System.Drawing.Point(0, 0);
this.mnuMain.Name = "mnuMain";
this.mnuMain.Size = new System.Drawing.Size(514, 24);
this.mnuMain.TabIndex = 1;
this.mnuMain.Text = "ctrlMesenMenuStrip1";
//
// mnuFile
//
this.mnuFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuOpen});
this.mnuFile.Name = "mnuFile";
this.mnuFile.Size = new System.Drawing.Size(37, 20);
this.mnuFile.Text = "File";
//
// mnuOpen
//
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.Folder;
this.mnuOpen.Name = "mnuOpen";
this.mnuOpen.Size = new System.Drawing.Size(152, 22);
this.mnuOpen.Text = "Open";
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
//
// debugToolStripMenuItem
//
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuRun,
this.mnuStep,
this.toolStripMenuItem1,
this.mnuDebugger,
this.mnuTraceLogger});
this.debugToolStripMenuItem.Name = "debugToolStripMenuItem";
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
this.debugToolStripMenuItem.Text = "Debug";
//
// mnuStep
//
this.mnuStep.Name = "mnuStep";
this.mnuStep.ShortcutKeys = System.Windows.Forms.Keys.F11;
this.mnuStep.Size = new System.Drawing.Size(152, 22);
this.mnuStep.Text = "Step";
this.mnuStep.Click += new System.EventHandler(this.mnuStep_Click);
//
// mnuDebugger
//
this.mnuDebugger.Name = "mnuDebugger";
this.mnuDebugger.Size = new System.Drawing.Size(152, 22);
this.mnuDebugger.Text = "Debugger";
//
// mnuTraceLogger
//
this.mnuTraceLogger.Name = "mnuTraceLogger";
this.mnuTraceLogger.Size = new System.Drawing.Size(152, 22);
this.mnuTraceLogger.Text = "Trace Logger";
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
//
// mnuRun
//
this.mnuRun.Name = "mnuRun";
this.mnuRun.Size = new System.Drawing.Size(152, 22);
this.mnuRun.Text = "Run";
this.mnuRun.Click += new System.EventHandler(this.mnuRun_Click);
//
// frmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(514, 476);
this.Controls.Add(this.ctrlRenderer);
this.Controls.Add(this.mnuMain);
this.MainMenuStrip = this.mnuMain;
this.Name = "frmMain";
this.Text = "frmMain";
this.mnuMain.ResumeLayout(false);
this.mnuMain.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Controls.ctrlRenderer ctrlRenderer;
private Controls.ctrlMesenMenuStrip mnuMain;
private System.Windows.Forms.ToolStripMenuItem debugToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem mnuDebugger;
private System.Windows.Forms.ToolStripMenuItem mnuTraceLogger;
private System.Windows.Forms.ToolStripMenuItem mnuStep;
private System.Windows.Forms.ToolStripMenuItem mnuFile;
private System.Windows.Forms.ToolStripMenuItem mnuOpen;
private System.Windows.Forms.ToolStripMenuItem mnuRun;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
}
}

62
UI/Forms/frmMain.cs Normal file
View file

@ -0,0 +1,62 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger;
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 frmMain : BaseForm
{
public frmMain(string[] args)
{
InitializeComponent();
ResourceHelper.LoadResources(Language.English);
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
EmuApi.InitDll();
EmuApi.InitializeEmu(ConfigManager.HomeFolder, Handle, ctrlRenderer.Handle, false, false, false);
}
private void mnuTraceLogger_Click(object sender, EventArgs e)
{
}
private void mnuStep_Click(object sender, EventArgs e)
{
DebugApi.Step(1);
}
private void mnuOpen_Click(object sender, EventArgs e)
{
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.Filter = ResourceHelper.GetMessage("FilterRom");
if(ofd.ShowDialog() == DialogResult.OK) {
EmuApi.LoadRom(ofd.FileName);
Task.Run(() => {
EmuApi.Run();
});
frmTraceLogger frm = new frmTraceLogger();
frm.Show();
}
}
}
private void mnuRun_Click(object sender, EventArgs e)
{
DebugApi.ResumeExecution();
}
}
}

126
UI/Forms/frmMain.resx Normal file
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="mnuMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
</root>

47
UI/Interop/DebugApi.cs Normal file
View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Forms;
namespace Mesen.GUI
{
public class DebugApi
{
private const string DllPath = "MesenSCore.dll";
[DllImport(DllPath)] public static extern void InitializeDebugger();
[DllImport(DllPath)] public static extern void ReleaseDebugger();
[DllImport(DllPath)] public static extern void ResumeExecution();
[DllImport(DllPath)] public static extern void Step(Int32 scanCode);
[DllImport(DllPath)] public static extern void StartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string filename);
[DllImport(DllPath)] public static extern void StopTraceLogger();
[DllImport(DllPath)] public static extern void SetTraceOptions(InteropTraceLoggerOptions options);
[DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 lineCount);
public static string GetExecutionTrace(UInt32 lineCount) { return Utf8Marshaler.PtrToStringUtf8(DebugApi.GetExecutionTraceWrapper(lineCount)); }
}
[Serializable]
public struct InteropTraceLoggerOptions
{
[MarshalAs(UnmanagedType.I1)] public bool ShowExtraInfo;
[MarshalAs(UnmanagedType.I1)] public bool IndentCode;
[MarshalAs(UnmanagedType.I1)] public bool UseLabels;
[MarshalAs(UnmanagedType.I1)] public bool UseWindowsEol;
[MarshalAs(UnmanagedType.I1)] public bool ExtendZeroPage;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
public byte[] Condition;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
public byte[] Format;
}
}

39
UI/Interop/EmuApi.cs Normal file
View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Forms;
namespace Mesen.GUI
{
public class EmuApi
{
private const string DllPath = "MesenSCore.dll";
[DllImport(DllPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool TestDll();
[DllImport(DllPath)] public static extern void InitDll();
[DllImport(DllPath, EntryPoint = "GetMesenVersion")] private static extern UInt32 GetMesenVersionWrapper();
[DllImport(DllPath)] public static extern void InitializeEmu([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string homeFolder, IntPtr windowHandle, IntPtr dxViewerHandle, [MarshalAs(UnmanagedType.I1)]bool noAudio, [MarshalAs(UnmanagedType.I1)]bool noVideo, [MarshalAs(UnmanagedType.I1)]bool noInput);
[DllImport(DllPath)] public static extern void Release();
[DllImport(DllPath)] public static extern void Run();
[DllImport(DllPath)] public static extern void LoadRom(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string filepath,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string patchFile = ""
);
[DllImport(DllPath)] public static extern void SetKeyState(Int32 scanCode, [MarshalAs(UnmanagedType.I1)]bool pressed);
[DllImport(DllPath)] public static extern void ResetKeyState();
[DllImport(DllPath)] public static extern void SetMousePosition(double x, double y);
[DllImport(DllPath)] public static extern void SetDisplayLanguage(Language lang);
}
}

View file

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI
{
public class Utf8Marshaler : ICustomMarshaler
{
static Utf8Marshaler _instance;
public IntPtr MarshalManagedToNative(object managedObj)
{
if(managedObj == null) {
return IntPtr.Zero;
}
if(!(managedObj is string)) {
throw new MarshalDirectiveException("UTF8Marshaler must be used on a string.");
}
// not null terminated
byte[] strbuf = Encoding.UTF8.GetBytes((string)managedObj);
IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length + 1);
Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
// write the terminating null
Marshal.WriteByte(buffer + strbuf.Length, 0);
return buffer;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return GetStringFromIntPtr(pNativeData);
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
public void CleanUpManagedData(object managedObj)
{
}
public int GetNativeDataSize()
{
return -1;
}
public static ICustomMarshaler GetInstance(string cookie)
{
if(_instance == null) {
return _instance = new Utf8Marshaler();
}
return _instance;
}
public static string GetStringFromIntPtr(IntPtr pNativeData)
{
int offset = 0;
byte b = 0;
do {
b = Marshal.ReadByte(pNativeData, offset);
offset++;
} while(b != 0);
int length = offset - 1;
// should not be null terminated
byte[] strbuf = new byte[length];
// skip the trailing null
Marshal.Copy((IntPtr)pNativeData, strbuf, 0, length);
string data = Encoding.UTF8.GetString(strbuf);
return data;
}
public static string PtrToStringUtf8(IntPtr ptr)
{
if(ptr == IntPtr.Zero) {
return "";
}
int len = 0;
while(Marshal.ReadByte(ptr, len) != 0) {
len++;
}
if(len == 0) {
return "";
}
byte[] array = new byte[len];
Marshal.Copy(ptr, array, 0, len);
return Encoding.UTF8.GetString(array);
}
}
}

147
UI/Program.cs Normal file
View file

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using Mesen.GUI.Config;
using Mesen.GUI.Forms;
namespace Mesen.GUI
{
static class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public static bool IsMono { get; private set; }
public static string OriginalFolder { get; private set; }
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, e.Exception.ToString());
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, e.ExceptionObject.ToString());
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
[HandleProcessCorruptedStateExceptions]
private static void Main(string[] args)
{
try {
Task.Run(() => {
//Cache deserializers in another thread
new XmlSerializer(typeof(Configuration));
//new XmlSerializer(typeof(DebugWorkspace));
});
if(Type.GetType("Mono.Runtime") != null) {
Program.IsMono = true;
}
Program.OriginalFolder = Directory.GetCurrentDirectory();
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += Application_ThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
/*if(ConfigManager.GetConfigFile() == null) {
//Show config wizard
ResourceHelper.LoadResources(Language.SystemDefault);
Application.Run(new frmConfigWizard());
if(ConfigManager.GetConfigFile() == null) {
Application.Exit();
return;
}
}*/
ConfigManager.GetConfigFile();
ConfigManager.CreateConfig(false);
Directory.CreateDirectory(ConfigManager.HomeFolder);
Directory.SetCurrentDirectory(ConfigManager.HomeFolder);
try {
if(!ResourceExtractor.ExtractResources()) {
return;
}
} catch(FileNotFoundException e) {
string message = "The Microsoft .NET Framework 4.5 could not be found. Please download and install the latest version of the .NET Framework from Microsoft's website and try again.";
switch(ResourceHelper.GetCurrentLanguage()) {
case Language.French: message = "Le .NET Framework 4.5 de Microsoft n'a pas été trouvé. Veuillez télécharger la plus récente version du .NET Framework à partir du site de Microsoft et essayer à nouveau."; break;
case Language.Japanese: message = "Microsoft .NET Framework 4.5はインストールされていないため、Mesenは起動できません。Microsoft .NET Frameworkの最新版をMicrosoftのサイトからダウンロードして、インストールしてください。"; break;
case Language.Russian: message = "Microsoft .NET Framework 4.5 не найден. Пожалуйста загрузите и установите последнюю версию .NET Framework с сайта Microsoft и попробуйте снова."; break;
case Language.Spanish: message = "Microsoft .NET Framework 4.5 no se ha encontrado. Por favor, descargue la versión más reciente de .NET Framework desde el sitio de Microsoft y vuelva a intentarlo."; break;
case Language.Ukrainian: message = "Microsoft .NET Framework 4.5 не знайдений. Будь ласка завантажте і встановіть останню версію .NET Framework з сайту Microsoft і спробуйте знову."; break;
case Language.Portuguese: message = "Microsoft .NET Framework 4.5 não foi encontrado. Por favor, baixe a versão mais recente de .NET Framework do site da Microsoft e tente novamente."; break;
case Language.Chinese: message = "找不到 Microsoft .NET Framework 4.5,请访问 Microsoft 官网下载安装之后再试。"; break;
}
MessageBox.Show(message + Environment.NewLine + Environment.NewLine + e.ToString(), "Mesen", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
} catch(Exception e) {
string message = "An unexpected error has occurred.\n\nError details:\n{0}";
switch(ResourceHelper.GetCurrentLanguage()) {
case Language.French: message = "Une erreur inattendue s'est produite.\n\nDétails de l'erreur :\n{0}"; break;
case Language.Japanese: message = "予期しないエラーが発生しました。\n\nエラーの詳細:\n{0}"; break;
case Language.Russian: message = "Неизвестная ошибка.&#xA;&#xA;Подробно:&#xA;{0}"; break;
case Language.Spanish: message = "Se ha producido un error inesperado.&#xA;&#xA;Detalles del error:&#xA;{0}"; break;
case Language.Ukrainian: message = "Невідома помилка.&#xA;&#xA;Детально:&#xA;{0}"; break;
case Language.Portuguese: message = "Houve um erro inesperado.&#xA;&#xA;Detalhes do erro:&#xA;{0}"; break;
case Language.Chinese: message = "发生意外错误。\n\n详情:\n{0}"; break;
}
MessageBox.Show(string.Format(message, e.ToString()), "Mesen", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if(!RuntimeChecker.TestDll()) {
return;
}
using(SingleInstance singleInstance = new SingleInstance()) {
//if(singleInstance.FirstInstance || !ConfigManager.Config.PreferenceInfo.SingleInstance) {
frmMain frmMain = new frmMain(args);
singleInstance.ListenForArgumentsFromSuccessiveInstances();
singleInstance.ArgumentsReceived += (object sender, ArgumentsReceivedEventArgs e) => {
if(frmMain.IsHandleCreated) {
frmMain.BeginInvoke((MethodInvoker)(() => {
//frmMain.ProcessCommandLineArguments(CommandLineHelper.PreprocessCommandLineArguments(e.Args, true), false);
//frmMain.LoadGameFromCommandLine(CommandLineHelper.PreprocessCommandLineArguments(e.Args, false));
}));
}
};
Application.Run(frmMain);
/*} else {
if(singleInstance.PassArgumentsToFirstInstance(args)) {
Process current = Process.GetCurrentProcess();
foreach(Process process in Process.GetProcessesByName(current.ProcessName)) {
if(process.Id != current.Id) {
Program.SetForegroundWindow(process.MainWindowHandle);
break;
}
}
} else {
Application.Run(new frmMain(args));
}
}*/
}
} catch(Exception e) {
MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, e.ToString());
}
}
}
}

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Mesen (Beta)")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Mesen")]
[assembly: AssemblyProduct("Mesen (Beta)")]
[assembly: AssemblyCopyright("Copyright © 2019 M. Bibaud")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c8d4fadf-6247-47bc-8cd5-4c2e29812c3c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.*")]
[assembly: AssemblyFileVersion("0.9.7.0")]

1163
UI/Properties/Resources.Designer.cs generated Normal file

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more