mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Label list, call stack
This commit is contained in:
parent
ba2c574f9e
commit
329021c63c
26 changed files with 753 additions and 135 deletions
|
@ -582,7 +582,7 @@ shared_ptr<ScriptManager> Debugger::GetScriptManager()
|
|||
shared_ptr<CallstackManager> Debugger::GetCallstackManager(CpuType cpuType)
|
||||
{
|
||||
if(_debuggers[(int)cpuType].Debugger) {
|
||||
_debuggers[(int)cpuType].Debugger->GetCallstackManager();
|
||||
return _debuggers[(int)cpuType].Debugger->GetCallstackManager();
|
||||
}
|
||||
throw std::runtime_error("GetCallstackManager() - Unsupported CPU type");
|
||||
}
|
||||
|
@ -600,7 +600,7 @@ Emulator* Debugger::GetEmulator()
|
|||
shared_ptr<IAssembler> Debugger::GetAssembler(CpuType cpuType)
|
||||
{
|
||||
if(_debuggers[(int)cpuType].Debugger) {
|
||||
_debuggers[(int)cpuType].Debugger->GetAssembler();
|
||||
return _debuggers[(int)cpuType].Debugger->GetAssembler();
|
||||
}
|
||||
throw std::runtime_error("GetAssembler() - Unsupported CPU type");
|
||||
}
|
||||
|
|
|
@ -293,13 +293,22 @@ CodeLineData Disassembler::GetLineData(DisassemblyResult& row, CpuType type, Sne
|
|||
switch(row.Address.Type) {
|
||||
default: break;
|
||||
case SnesMemoryType::GbPrgRom:
|
||||
case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break;
|
||||
case SnesMemoryType::PrgRom:
|
||||
case SnesMemoryType::NesPrgRom:
|
||||
data.Flags |= (uint8_t)LineFlags::PrgRom;
|
||||
break;
|
||||
|
||||
case SnesMemoryType::GbWorkRam:
|
||||
case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; break;
|
||||
case SnesMemoryType::WorkRam:
|
||||
case SnesMemoryType::NesWorkRam:
|
||||
data.Flags |= (uint8_t)LineFlags::WorkRam;
|
||||
break;
|
||||
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break;
|
||||
case SnesMemoryType::SaveRam:
|
||||
case SnesMemoryType::NesSaveRam:
|
||||
data.Flags |= (uint8_t)LineFlags::SaveRam;
|
||||
break;
|
||||
}
|
||||
|
||||
bool isBlockStartEnd = (data.Flags & (LineFlags::BlockStart | LineFlags::BlockEnd)) != 0;
|
||||
|
@ -511,8 +520,8 @@ uint32_t Disassembler::GetDisassemblyOutput(CpuType type, uint32_t address, Code
|
|||
SnesMemoryType memType = DebugUtilities::GetCpuMemoryType(type);
|
||||
uint32_t maxBank = (_memoryDumper->GetMemorySize(memType) - 1) >> 16;
|
||||
|
||||
uint32_t row;
|
||||
for(row = 0; row < rowCount; row++){
|
||||
int32_t row;
|
||||
for(row = 0; row < (int32_t)rowCount; row++){
|
||||
if(row + i >= rows.size()) {
|
||||
if(bank < maxBank) {
|
||||
bank++;
|
||||
|
|
|
@ -44,51 +44,12 @@ void LabelManager::SetLabel(uint32_t address, SnesMemoryType memType, string lab
|
|||
|
||||
int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType)
|
||||
{
|
||||
switch(memType) {
|
||||
case SnesMemoryType::PrgRom: return absoluteAddr | ((uint64_t)1 << 32);
|
||||
case SnesMemoryType::WorkRam: return absoluteAddr | ((uint64_t)2 << 32);
|
||||
case SnesMemoryType::SaveRam: return absoluteAddr | ((uint64_t)3 << 32);
|
||||
case SnesMemoryType::Register: return absoluteAddr | ((uint64_t)4 << 32);
|
||||
case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32);
|
||||
case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32);
|
||||
case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32);
|
||||
case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32);
|
||||
case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32);
|
||||
case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32);
|
||||
case SnesMemoryType::DspProgramRom: return absoluteAddr | ((uint64_t)11 << 32);
|
||||
case SnesMemoryType::GbPrgRom: return absoluteAddr | ((uint64_t)12 << 32);
|
||||
case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32);
|
||||
case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32);
|
||||
case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32);
|
||||
case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32);
|
||||
case SnesMemoryType::GameboyMemory: return absoluteAddr | ((uint64_t)17 << 32);
|
||||
default: return -1;
|
||||
}
|
||||
return absoluteAddr | ((uint64_t)memType << 32);
|
||||
}
|
||||
|
||||
SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key)
|
||||
{
|
||||
switch(key & ~(uint64_t)0xFFFFFFFF) {
|
||||
case ((uint64_t)1 << 32): return SnesMemoryType::PrgRom; break;
|
||||
case ((uint64_t)2 << 32): return SnesMemoryType::WorkRam; break;
|
||||
case ((uint64_t)3 << 32): return SnesMemoryType::SaveRam; break;
|
||||
case ((uint64_t)4 << 32): return SnesMemoryType::Register; break;
|
||||
case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; break;
|
||||
case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break;
|
||||
case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break;
|
||||
case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break;
|
||||
case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; break;
|
||||
case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; break;
|
||||
case ((uint64_t)11 << 32): return SnesMemoryType::DspProgramRom; break;
|
||||
case ((uint64_t)12 << 32): return SnesMemoryType::GbPrgRom; break;
|
||||
case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; break;
|
||||
case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; break;
|
||||
case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; break;
|
||||
case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; break;
|
||||
case ((uint64_t)17 << 32): return SnesMemoryType::GameboyMemory; break;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid label key");
|
||||
return (SnesMemoryType)(key >> 32);
|
||||
}
|
||||
|
||||
string LabelManager::GetLabel(AddressInfo address)
|
||||
|
|
|
@ -73,6 +73,7 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
|
|||
case SnesMemoryType::Cx4Memory: return 0x1000000;
|
||||
case SnesMemoryType::GameboyMemory: return 0x10000;
|
||||
case SnesMemoryType::NesMemory: return 0x10000;
|
||||
case SnesMemoryType::Register: return 0x10000;
|
||||
default: return _emu->GetMemory(type).Size;
|
||||
}
|
||||
}
|
||||
|
|
41
NewUI/Debugger/DebugUtilities.cs
Normal file
41
NewUI/Debugger/DebugUtilities.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using Mesen.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.Debugger
|
||||
{
|
||||
public static class DebugUtilities
|
||||
{
|
||||
public static uint GetProgramCounter(CpuType cpuType)
|
||||
{
|
||||
switch(cpuType) {
|
||||
case CpuType.Cpu:
|
||||
case CpuType.Sa1: {
|
||||
CpuState state = DebugApi.GetState<CpuState>(cpuType);
|
||||
return (uint)(state.K << 16) | state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Spc: {
|
||||
SpcState state = DebugApi.GetState<SpcState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Gameboy: {
|
||||
GbCpuState state = DebugApi.GetState<GbCpuState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
case CpuType.Nes: {
|
||||
NesCpuState state = DebugApi.GetState<NesCpuState>(cpuType);
|
||||
return (uint)state.PC;
|
||||
}
|
||||
|
||||
default: throw new Exception("Invalid cpu type");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ namespace Mesen.Debugger
|
|||
new SplitterDockable(),
|
||||
new ToolDock {
|
||||
Proportion = 0.33,
|
||||
VisibleDockables = CreateList<IDockable>(new DummyTool() { Id = "Labels", Title = "Labels" })
|
||||
VisibleDockables = CreateList<IDockable>(_context.LabelList)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ namespace Mesen.Debugger
|
|||
new SplitterDockable(),
|
||||
new ToolDock {
|
||||
Proportion = 0.33,
|
||||
VisibleDockables = CreateList<IDockable>(new DummyTool() { Id = "CallStack", Title = "Call Stack" })
|
||||
VisibleDockables = CreateList<IDockable>(_context.CallStack)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Mesen.Interop;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -33,7 +34,7 @@ namespace Mesen.Debugger
|
|||
{
|
||||
if(EffectiveAddress >= 0) {
|
||||
AddressInfo relAddress = new AddressInfo() { Address = EffectiveAddress, Type = _cpuType.ToMemoryType() };
|
||||
/*CodeLabel label = LabelManager.GetLabel(relAddress);
|
||||
CodeLabel? label = LabelManager.GetLabel(relAddress);
|
||||
if(label != null) {
|
||||
if(label.Length > 1) {
|
||||
int gap = DebugApi.GetAbsoluteAddress(relAddress).Address - label.GetAbsoluteAddress().Address;
|
||||
|
@ -42,9 +43,9 @@ namespace Mesen.Debugger
|
|||
}
|
||||
}
|
||||
return "[" + label.Label + "]";
|
||||
} else {*/
|
||||
} else {
|
||||
return "[$" + EffectiveAddress.ToString(format) + "]";
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
using Mesen.Interop;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Mesen.Debugger.Labels
|
||||
{
|
||||
public class CodeLabel
|
||||
public class CodeLabel : ReactiveObject
|
||||
{
|
||||
public UInt32 Address;
|
||||
public SnesMemoryType MemoryType;
|
||||
public string Label = "";
|
||||
public string Comment = "";
|
||||
public CodeLabelFlags Flags;
|
||||
public UInt32 Length = 1;
|
||||
[Reactive] public UInt32 Address { get; set; }
|
||||
[Reactive] public SnesMemoryType MemoryType { get; set; }
|
||||
[Reactive] public string Label { get; set; } = "";
|
||||
[Reactive] public string Comment { get; set; } = "";
|
||||
[Reactive] public CodeLabelFlags Flags { get; set; }
|
||||
[Reactive] public UInt32 Length { get; set; } = 1;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -49,10 +51,10 @@ namespace Mesen.Debugger.Labels
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static char[] _separatar = new char[1] { ':' };
|
||||
private static char[] _separator = new char[1] { ':' };
|
||||
public static CodeLabel? FromString(string data)
|
||||
{
|
||||
string[] rowData = data.Split(_separatar, 4);
|
||||
string[] rowData = data.Split(_separator, 4);
|
||||
if(rowData.Length < 3) {
|
||||
//Invalid row
|
||||
return null;
|
||||
|
@ -151,5 +153,15 @@ namespace Mesen.Debugger.Labels
|
|||
{
|
||||
return (CodeLabel)this.MemberwiseClone();
|
||||
}
|
||||
|
||||
public void CopyFrom(CodeLabel copy)
|
||||
{
|
||||
Address = copy.Address;
|
||||
MemoryType = copy.MemoryType;
|
||||
Label = copy.Label;
|
||||
Comment = copy.Comment;
|
||||
Flags = copy.Flags;
|
||||
Length = copy.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,26 +77,7 @@ namespace Mesen.Debugger.Labels
|
|||
|
||||
private static UInt64 GetKey(UInt32 address, SnesMemoryType memType)
|
||||
{
|
||||
switch(memType) {
|
||||
case SnesMemoryType.PrgRom: return address | ((ulong)1 << 32);
|
||||
case SnesMemoryType.WorkRam: return address | ((ulong)2 << 32);
|
||||
case SnesMemoryType.SaveRam: return address | ((ulong)3 << 32);
|
||||
case SnesMemoryType.Register: return address | ((ulong)4 << 32);
|
||||
case SnesMemoryType.SpcRam: return address | ((ulong)5 << 32);
|
||||
case SnesMemoryType.SpcRom: return address | ((ulong)6 << 32);
|
||||
case SnesMemoryType.Sa1InternalRam: return address | ((ulong)7 << 32);
|
||||
case SnesMemoryType.GsuWorkRam: return address | ((ulong)8 << 32);
|
||||
case SnesMemoryType.BsxPsRam: return address | ((ulong)9 << 32);
|
||||
case SnesMemoryType.BsxMemoryPack: return address | ((ulong)10 << 32);
|
||||
case SnesMemoryType.DspProgramRom: return address | ((ulong)11 << 32);
|
||||
case SnesMemoryType.GbPrgRom: return address | ((ulong)12 << 32);
|
||||
case SnesMemoryType.GbWorkRam: return address | ((ulong)13 << 32);
|
||||
case SnesMemoryType.GbCartRam: return address | ((ulong)14 << 32);
|
||||
case SnesMemoryType.GbHighRam: return address | ((ulong)15 << 32);
|
||||
case SnesMemoryType.GbBootRom: return address | ((ulong)16 << 32);
|
||||
case SnesMemoryType.GameboyMemory: return address | ((ulong)17 << 32);
|
||||
}
|
||||
throw new Exception("Invalid type");
|
||||
return address | ((UInt64)memType << 32);
|
||||
}
|
||||
|
||||
private static void SetLabel(uint address, SnesMemoryType memType, string label, string comment)
|
||||
|
@ -234,6 +215,7 @@ namespace Mesen.Debugger.Labels
|
|||
|
||||
public static void SetDefaultLabels()
|
||||
{
|
||||
SetSnesDefaultLabels();
|
||||
//TODO
|
||||
/*CoprocessorType coproc = EmuApi.GetRomInfo().CoprocessorType;
|
||||
if(coproc == CoprocessorType.SGB) {
|
||||
|
|
86
NewUI/Debugger/ViewModels/CallStackViewModel.cs
Normal file
86
NewUI/Debugger/ViewModels/CallStackViewModel.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
using Dock.Model.ReactiveUI.Controls;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Mesen.Debugger.ViewModels
|
||||
{
|
||||
public class CallStackViewModel : Tool
|
||||
{
|
||||
private CpuType _cpuType;
|
||||
|
||||
[Reactive] public List<StackInfo> StackFrames { get; private set; } = new List<StackInfo>();
|
||||
|
||||
//For designer
|
||||
public CallStackViewModel() : this(CpuType.Cpu) { }
|
||||
|
||||
public CallStackViewModel(CpuType cpuType)
|
||||
{
|
||||
_cpuType = cpuType;
|
||||
Id = "CallStack";
|
||||
Title = "Call Stack";
|
||||
UpdateCallStack();
|
||||
}
|
||||
|
||||
public void UpdateCallStack()
|
||||
{
|
||||
StackFrames = GetStackInfo();
|
||||
}
|
||||
|
||||
private List<StackInfo> GetStackInfo()
|
||||
{
|
||||
StackFrameInfo[] stackFrames = DebugApi.GetCallstack(_cpuType);
|
||||
|
||||
int relDestinationAddr = -1;
|
||||
|
||||
List<StackInfo> stack = new List<StackInfo>();
|
||||
for(int i = 0, len = stackFrames.Length; i < len; i++) {
|
||||
int relSubEntryAddr = i == 0 ? -1 : (int)stackFrames[i - 1].Target;
|
||||
|
||||
stack.Insert(0, new StackInfo() {
|
||||
SubName = this.GetFunctionName(relSubEntryAddr, i == 0 ? StackFrameFlags.None : stackFrames[i - 1].Flags),
|
||||
Address = stackFrames[i].Source,
|
||||
});
|
||||
|
||||
relDestinationAddr = (int)stackFrames[i].Target;
|
||||
}
|
||||
|
||||
//Add current location
|
||||
stack.Insert(0, new StackInfo() {
|
||||
SubName = this.GetFunctionName(relDestinationAddr, stackFrames.Length == 0 ? StackFrameFlags.None : stackFrames[^1].Flags),
|
||||
Address = DebugUtilities.GetProgramCounter(_cpuType),
|
||||
});
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private string GetFunctionName(int relSubEntryAddr, StackFrameFlags flags)
|
||||
{
|
||||
if(relSubEntryAddr < 0) {
|
||||
return "[bottom of stack]";
|
||||
}
|
||||
|
||||
string format = "X" + _cpuType.GetAddressSize();
|
||||
CodeLabel? label = relSubEntryAddr >= 0 ? LabelManager.GetLabel(new AddressInfo() { Address = relSubEntryAddr, Type = _cpuType.ToMemoryType() }) : null;
|
||||
if(label != null) {
|
||||
return label.Label + " ($" + relSubEntryAddr.ToString(format) + ")";
|
||||
} else if(flags == StackFrameFlags.Nmi) {
|
||||
return "[nmi] $" + relSubEntryAddr.ToString(format);
|
||||
} else if(flags == StackFrameFlags.Irq) {
|
||||
return "[irq] $" + relSubEntryAddr.ToString(format);
|
||||
}
|
||||
|
||||
return "$" + relSubEntryAddr.ToString(format);
|
||||
}
|
||||
|
||||
public class StackInfo
|
||||
{
|
||||
public string SubName { get; set; }
|
||||
public UInt32 Address { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Dock.Model.Core;
|
||||
using Dock.Model.ReactiveUI.Controls;
|
||||
using Mesen.Debugger.Disassembly;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
@ -15,6 +16,8 @@ namespace Mesen.Debugger.ViewModels
|
|||
{
|
||||
[Reactive] public DisassemblyViewerViewModel Disassembly { get; private set; }
|
||||
[Reactive] public BreakpointListViewModel BreakpointList { get; private set; }
|
||||
[Reactive] public LabelListViewModel LabelList { get; private set; }
|
||||
[Reactive] public CallStackViewModel CallStack { get; private set; }
|
||||
|
||||
[Reactive] public DebuggerDockFactory DockFactory { get; private set; }
|
||||
[Reactive] public IRootDock DockLayout { get; private set; }
|
||||
|
@ -34,12 +37,7 @@ namespace Mesen.Debugger.ViewModels
|
|||
Disassembly = new DisassemblyViewerViewModel();
|
||||
BreakpointList = new BreakpointListViewModel();
|
||||
|
||||
var factory = new DebuggerDockFactory(this);
|
||||
var layout = factory.CreateLayout();
|
||||
factory.InitLayout(layout);
|
||||
|
||||
DockFactory = factory;
|
||||
DockLayout = layout;
|
||||
DockFactory = new DebuggerDockFactory(this);
|
||||
|
||||
RomInfo romInfo = EmuApi.GetRomInfo();
|
||||
|
||||
|
@ -64,6 +62,14 @@ namespace Mesen.Debugger.ViewModels
|
|||
ConfigApi.SetDebuggerFlag(DebuggerFlags.GbDebuggerEnabled, true);
|
||||
break;
|
||||
}
|
||||
|
||||
LabelManager.SetDefaultLabels();
|
||||
LabelList = new LabelListViewModel(CpuType);
|
||||
|
||||
CallStack = new CallStackViewModel(CpuType);
|
||||
|
||||
DockLayout = DockFactory.CreateLayout();
|
||||
DockFactory.InitLayout(DockLayout);
|
||||
}
|
||||
|
||||
internal void UpdateDisassembly()
|
||||
|
|
66
NewUI/Debugger/ViewModels/LabelEditViewModel.cs
Normal file
66
NewUI/Debugger/ViewModels/LabelEditViewModel.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using Dock.Model.ReactiveUI.Controls;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Mesen.Debugger.ViewModels
|
||||
{
|
||||
public class LabelEditViewModel : ViewModelBase
|
||||
{
|
||||
[Reactive] public CodeLabel Label { get; set; }
|
||||
[ObservableAsProperty] public bool OkEnabled { get; }
|
||||
[ObservableAsProperty] public string MaxAddress { get; }
|
||||
|
||||
//For designer
|
||||
public LabelEditViewModel() : this(new CodeLabel()) { }
|
||||
|
||||
public LabelEditViewModel(CodeLabel label, CodeLabel? originalLabel = null)
|
||||
{
|
||||
Label = label;
|
||||
|
||||
this.WhenAnyValue(x => x.Label.MemoryType, (memoryType) => {
|
||||
int maxAddress = DebugApi.GetMemorySize(memoryType) - 1;
|
||||
if(maxAddress <= 0) {
|
||||
return "(unavailable)";
|
||||
} else {
|
||||
return "(Max: $" + maxAddress.ToString("X4") + ")";
|
||||
}
|
||||
}).ToPropertyEx(this, x => x.MaxAddress);
|
||||
|
||||
this.WhenAnyValue(x => x.Label.Label, x => x.Label.Comment, x => x.Label.Length, x => x.Label.MemoryType, x => x.Label.Address, (label, comment, length, memoryType, address) => {
|
||||
CodeLabel? sameLabel = LabelManager.GetLabel(label);
|
||||
int maxAddress = DebugApi.GetMemorySize(memoryType) - 1;
|
||||
|
||||
for(UInt32 i = 0; i < length; i++) {
|
||||
CodeLabel? sameAddress = LabelManager.GetLabel(address + i, memoryType);
|
||||
if(sameAddress != null) {
|
||||
if(originalLabel == null) {
|
||||
//A label already exists and we're not editing an existing label, so we can't add it
|
||||
return false;
|
||||
} else {
|
||||
if(sameAddress.Label != originalLabel.Label && !sameAddress.Label.StartsWith(originalLabel.Label + "+")) {
|
||||
//A label already exists, we're trying to edit an existing label, but the existing label
|
||||
//and the label we're editing aren't the same label. Can't override an existing label with a different one.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
length >= 1 && length <= 65536 &&
|
||||
address + (length - 1) <= maxAddress &&
|
||||
(sameLabel == null || sameLabel == originalLabel)
|
||||
&& (label.Length > 0 || comment.Length > 0)
|
||||
&& !comment.Contains('\x1')
|
||||
&& (label.Length == 0 || LabelManager.LabelRegex.IsMatch(label));
|
||||
}).ToPropertyEx(this, x => x.OkEnabled);
|
||||
}
|
||||
}
|
||||
}
|
34
NewUI/Debugger/ViewModels/LabelListViewModel.cs
Normal file
34
NewUI/Debugger/ViewModels/LabelListViewModel.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using Dock.Model.ReactiveUI.Controls;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Interop;
|
||||
using Mesen.ViewModels;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Mesen.Debugger.ViewModels
|
||||
{
|
||||
public class LabelListViewModel : Tool
|
||||
{
|
||||
private CpuType _cpuType;
|
||||
|
||||
[Reactive] public List<CodeLabel> Labels { get; private set; } = new List<CodeLabel>();
|
||||
|
||||
//For designer
|
||||
public LabelListViewModel() : this(CpuType.Cpu) { }
|
||||
|
||||
public LabelListViewModel(CpuType cpuType)
|
||||
{
|
||||
_cpuType = cpuType;
|
||||
Id = "Labels";
|
||||
Title = "Labels";
|
||||
UpdateLabelList();
|
||||
}
|
||||
|
||||
public void UpdateLabelList()
|
||||
{
|
||||
Labels = LabelManager.GetLabels(_cpuType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,40 +13,6 @@
|
|||
<vm:BreakpointListViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<UserControl.Styles>
|
||||
<Style Selector="DataGridColumnHeader">
|
||||
<Setter Property="MinHeight" Value="18" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Grid">
|
||||
<Setter Property="Margin" Value="-8 0 0 0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Grid ContentPresenter">
|
||||
<Setter Property="Margin" Value="0 0 -30 0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Path">
|
||||
<Setter Property="Width" Value="0" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="IsVisible" Value="False" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow">
|
||||
<Setter Property="Height" Value="18" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="FontSize" Value="10.5" />
|
||||
<Setter Property="Height" Value="14" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell /template/ ContentPresenter > TextBlock">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell CheckBox">
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell Grid#FocusVisual">
|
||||
<Setter Property="Opacity" Value="0" />
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||
<DataGrid
|
||||
Items="{Binding Breakpoints}"
|
||||
|
|
40
NewUI/Debugger/Views/CallStackView.axaml
Normal file
40
NewUI/Debugger/Views/CallStackView.axaml
Normal file
|
@ -0,0 +1,40 @@
|
|||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:dbg="using:Mesen.Debugger"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="110"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
x:DataType="vm:CallStackViewModel"
|
||||
x:Class="Mesen.Debugger.Views.CallStackView"
|
||||
>
|
||||
<Design.DataContext>
|
||||
<vm:CallStackViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<UserControl.Resources>
|
||||
<dbg:HexConverter x:Key="Hex" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||
<DataGrid
|
||||
Name="DataGrid"
|
||||
Items="{CompiledBinding StackFrames}"
|
||||
CanUserSortColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserReorderColumns="True"
|
||||
SelectionMode="Extended"
|
||||
FontFamily="Microsoft Sans Serif"
|
||||
GridLinesVisibility="All"
|
||||
IsReadOnly="True"
|
||||
>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Function (Entry Address)" Binding="{Binding SubName}" Width="1*" CanUserResize="True" />
|
||||
<DataGridTextColumn Header="PC Address" Binding="{Binding Address, Converter={StaticResource Hex}, ConverterParameter='X4'}}" Width="1*" CanUserResize="True" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Border>
|
||||
</UserControl>
|
27
NewUI/Debugger/Views/CallStackView.axaml.cs
Normal file
27
NewUI/Debugger/Views/CallStackView.axaml.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Mesen.ViewModels;
|
||||
using Mesen.Debugger;
|
||||
using Mesen.Debugger.ViewModels;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Debugger.Windows;
|
||||
using Mesen.Utilities;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace Mesen.Debugger.Views
|
||||
{
|
||||
public class CallStackView : UserControl
|
||||
{
|
||||
public CallStackView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
66
NewUI/Debugger/Views/LabelListView.axaml
Normal file
66
NewUI/Debugger/Views/LabelListView.axaml
Normal file
|
@ -0,0 +1,66 @@
|
|||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:dbg="using:Mesen.Debugger"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="110"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
x:DataType="vm:LabelListViewModel"
|
||||
x:Class="Mesen.Debugger.Views.LabelListView"
|
||||
>
|
||||
<Design.DataContext>
|
||||
<vm:LabelListViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<UserControl.Resources>
|
||||
<dbg:HexConverter x:Key="Hex" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border BorderThickness="1" BorderBrush="LightGray">
|
||||
<DataGrid
|
||||
Name="DataGrid"
|
||||
Items="{CompiledBinding Labels}"
|
||||
CanUserSortColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserReorderColumns="True"
|
||||
SelectionMode="Extended"
|
||||
FontFamily="Microsoft Sans Serif"
|
||||
GridLinesVisibility="All"
|
||||
DoubleTapped="OnGridDoubleClick"
|
||||
Tapped="OnGridClick"
|
||||
CellPointerPressed="OnCellPointerPressed"
|
||||
IsReadOnly="True"
|
||||
>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Label" Binding="{Binding Label}" Width="1*" CanUserResize="True" />
|
||||
<DataGridTextColumn Header="CPU Addr" Width="1*" CanUserResize="True" />
|
||||
<DataGridTextColumn Header="ROM Addr" Binding="{Binding Address, Converter={StaticResource Hex}, ConverterParameter='X4'}}" Width="1*" CanUserResize="True" />
|
||||
<DataGridTextColumn Header="Comment" Binding="{Binding Comment}" Width="1*" CanUserResize="True" />
|
||||
</DataGrid.Columns>
|
||||
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu PlacementMode="Pointer">
|
||||
<MenuItem Header="Add" Click="mnuAddLabel_Click">
|
||||
<MenuItem.Icon>
|
||||
<Image Source="/Assets/Add.png" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Edit" Click="mnuEditLabel_Click">
|
||||
<MenuItem.Icon>
|
||||
<Image Source="/Assets/EditLabel.png" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Delete" Click="mnuDeleteLabel_Click">
|
||||
<MenuItem.Icon>
|
||||
<Image Source="/Assets/Close.png" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
</DataGrid>
|
||||
</Border>
|
||||
</UserControl>
|
94
NewUI/Debugger/Views/LabelListView.axaml.cs
Normal file
94
NewUI/Debugger/Views/LabelListView.axaml.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Mesen.ViewModels;
|
||||
using Mesen.Debugger;
|
||||
using Mesen.Debugger.ViewModels;
|
||||
using Mesen.Debugger.Labels;
|
||||
using Mesen.Debugger.Windows;
|
||||
using Mesen.Utilities;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace Mesen.Debugger.Views
|
||||
{
|
||||
public class LabelListView : UserControl
|
||||
{
|
||||
public LabelListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void OnCellPointerPressed(object sender, DataGridCellPointerPressedEventArgs e)
|
||||
{
|
||||
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||
grid.SelectedIndex = e.Row.GetIndex();
|
||||
}
|
||||
|
||||
private void OnGridClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async void mnuAddLabel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CodeLabel newLabel = new CodeLabel();
|
||||
LabelEditWindow wnd = new LabelEditWindow() {
|
||||
DataContext = new LabelEditViewModel(newLabel)
|
||||
};
|
||||
|
||||
bool result = await wnd.ShowCenteredDialog<bool>(this);
|
||||
if(result) {
|
||||
LabelManager.SetLabel(newLabel, true);
|
||||
((LabelListViewModel)DataContext!).UpdateLabelList();
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuEditLabel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||
CodeLabel ? label = grid.SelectedItem as CodeLabel;
|
||||
if(label != null && grid != null) {
|
||||
EditLabel(label);
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuDeleteLabel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataGrid grid = this.FindControl<DataGrid>("DataGrid");
|
||||
CodeLabel? label = grid.SelectedItem as CodeLabel;
|
||||
if(label != null && grid != null) {
|
||||
LabelManager.DeleteLabel(label, true);
|
||||
((LabelListViewModel)DataContext!).UpdateLabelList();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGridDoubleClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataGrid grid = (DataGrid)sender;
|
||||
CodeLabel? label = grid.SelectedItem as CodeLabel;
|
||||
if(label != null && grid != null) {
|
||||
EditLabel(label);
|
||||
}
|
||||
}
|
||||
|
||||
private async void EditLabel(CodeLabel label)
|
||||
{
|
||||
CodeLabel copy = label.Clone();
|
||||
LabelEditWindow wnd = new LabelEditWindow() {
|
||||
DataContext = new LabelEditViewModel(copy, label)
|
||||
};
|
||||
|
||||
bool result = await wnd.ShowCenteredDialog<bool>(this);
|
||||
if(result) {
|
||||
label.CopyFrom(copy);
|
||||
LabelManager.SetLabel(label, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
<Style Selector="TextBox.h1">
|
||||
<Setter Property="FontFamily" Value="Consolas" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
|
||||
|
@ -39,6 +40,8 @@
|
|||
<TextBlock>Y:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{CompiledBinding RegY, Converter={StaticResource Hex}}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<TextBlock>K:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{CompiledBinding RegK, Converter={StaticResource Hex}}" />
|
||||
<TextBlock>PC:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{CompiledBinding RegPC, Converter={StaticResource Hex}}" />
|
||||
</StackPanel>
|
||||
|
@ -46,20 +49,20 @@
|
|||
</DockPanel>
|
||||
<DockPanel>
|
||||
<TextBlock>D:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{Binding RegD}" />
|
||||
<TextBox Classes="h1" Text="{Binding RegD, Converter={StaticResource Hex}}" />
|
||||
<TextBlock>DB:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{Binding RegDBR}" />
|
||||
<TextBox Classes="h1" Text="{Binding RegDBR, Converter={StaticResource Hex}}" />
|
||||
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<TextBlock>S:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{Binding RegSP}" />
|
||||
<TextBox Classes="h1" Text="{Binding RegSP, Converter={StaticResource Hex}}" />
|
||||
</StackPanel>
|
||||
<TextBlock />
|
||||
</DockPanel>
|
||||
<DockPanel Margin="0 2 0 0">
|
||||
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top">
|
||||
<TextBlock>P:</TextBlock>
|
||||
<TextBox Classes="h1" Text="{Binding RegPS}" />
|
||||
<TextBox Classes="h1" Text="{Binding RegPS, Converter={StaticResource Hex}}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBox
|
||||
|
|
|
@ -9,6 +9,7 @@ using Mesen.Debugger.Disassembly;
|
|||
using Mesen.Interop;
|
||||
using Avalonia.Interactivity;
|
||||
using System.ComponentModel;
|
||||
using Mesen.Debugger.Labels;
|
||||
|
||||
namespace Mesen.Debugger.Windows
|
||||
{
|
||||
|
@ -66,6 +67,7 @@ namespace Mesen.Debugger.Windows
|
|||
if(e.NotificationType == ConsoleNotificationType.CodeBreak) {
|
||||
_model.UpdateCpuState();
|
||||
_model.UpdateDisassembly();
|
||||
_model.CallStack.UpdateCallStack();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
80
NewUI/Debugger/Windows/LabelEditWindow.axaml
Normal file
80
NewUI/Debugger/Windows/LabelEditWindow.axaml
Normal file
|
@ -0,0 +1,80 @@
|
|||
<Window
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:m="clr-namespace:Mesen"
|
||||
xmlns:vm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:sys="using:System"
|
||||
xmlns:v="using:Mesen.Views"
|
||||
xmlns:dbg="using:Mesen.Debugger"
|
||||
xmlns:c="using:Mesen.Controls"
|
||||
xmlns:i="using:Mesen.Interop"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dvm="using:Mesen.Debugger.ViewModels"
|
||||
xmlns:dc="using:Mesen.Debugger.Controls"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="230"
|
||||
x:Class="Mesen.Debugger.Windows.LabelEditWindow"
|
||||
x:DataType="vm:LabelEditViewModel"
|
||||
Icon="/Assets/EditLabel.png"
|
||||
Width="300" Height="230"
|
||||
Title="Edit label..."
|
||||
>
|
||||
<Design.DataContext>
|
||||
<vm:LabelEditViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Window.Resources>
|
||||
<dbg:HexConverter x:Key="Hex" />
|
||||
</Window.Resources>
|
||||
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Width="70" HorizontalContentAlignment="Center" Click="Ok_OnClick" Content="OK" IsEnabled="{CompiledBinding OkEnabled}" />
|
||||
<Button Width="70" HorizontalContentAlignment="Center" IsCancel="True" Click="Cancel_OnClick" Content="Cancel" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid
|
||||
DockPanel.Dock="Right"
|
||||
ColumnDefinitions="Auto,*"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
||||
Margin="5 0 5 0"
|
||||
>
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Text="Memory type:" />
|
||||
<c:EnumComboBox
|
||||
Grid.Column="1" Grid.Row="0"
|
||||
EnumType="{x:Type i:SnesMemoryType}"
|
||||
SelectedItem="{CompiledBinding Label.MemoryType}"
|
||||
/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Text="Address:" />
|
||||
<StackPanel Grid.Column="1" Grid.Row="1" Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 3 0">$</TextBlock>
|
||||
<TextBox Text="{CompiledBinding Label.Address, Converter={StaticResource Hex}, ConverterParameter='X'}" Width="50" />
|
||||
<TextBlock Margin="3 0 0 0" Text="{CompiledBinding MaxAddress}" Foreground="Gray" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" Text="Label:" />
|
||||
<TextBox
|
||||
Grid.Column="1" Grid.Row="2"
|
||||
Text="{CompiledBinding Label.Label}"
|
||||
/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="3" Text="Comment:" />
|
||||
<TextBox
|
||||
Grid.Column="1" Grid.Row="3"
|
||||
AcceptsReturn="True"
|
||||
Height="100"
|
||||
VerticalContentAlignment="Top"
|
||||
Text="{CompiledBinding Label.Comment}"
|
||||
/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="4" Text="Length:" />
|
||||
<NumericUpDown
|
||||
Grid.Column="1" Grid.Row="4"
|
||||
Value="{CompiledBinding Label.Length}"
|
||||
Minimum="1"
|
||||
Maximum="65536"
|
||||
/>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
33
NewUI/Debugger/Windows/LabelEditWindow.axaml.cs
Normal file
33
NewUI/Debugger/Windows/LabelEditWindow.axaml.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Mesen.Debugger.Windows
|
||||
{
|
||||
public class LabelEditWindow : Window
|
||||
{
|
||||
public LabelEditWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void Ok_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
private void Cancel_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -721,7 +721,7 @@ namespace Mesen.Interop
|
|||
Zero = 0x80
|
||||
}
|
||||
|
||||
public struct GbCpuState
|
||||
public struct GbCpuState : BaseState
|
||||
{
|
||||
public UInt16 PC;
|
||||
public UInt16 SP;
|
||||
|
|
|
@ -179,6 +179,12 @@
|
|||
<Compile Update="Controls\OptionSection.axaml.cs">
|
||||
<DependentUpon>OptionSection.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Views\CallStackView.axaml.cs">
|
||||
<DependentUpon>CallStackView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Views\LabelListView.axaml.cs">
|
||||
<DependentUpon>LabelListView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Views\DebuggerDock\StatusToolView.axaml.cs">
|
||||
<DependentUpon>StatusToolView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -191,6 +197,9 @@
|
|||
<Compile Update="Debugger\Views\SnesPpuView.axaml.cs">
|
||||
<DependentUpon>SnesPpuView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Windows\LabelEditWindow.axaml.cs">
|
||||
<DependentUpon>LabelEditWindow.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Debugger\Windows\TileViewerWindow.axaml.cs">
|
||||
<DependentUpon>TileViewerWindow.axaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
|
@ -344,6 +344,55 @@
|
|||
<Setter Property="CornerRadius" Value="0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ContextMenu">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="0"
|
||||
MaxWidth="{TemplateBinding MaxWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
CornerRadius="{DynamicResource OverlayCornerRadius}">
|
||||
<Panel>
|
||||
<Rectangle
|
||||
HorizontalAlignment="Left"
|
||||
Width="24">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="24,0">
|
||||
<GradientStop Color="#fcfcfc" Offset="0.0" />
|
||||
<GradientStop Color="#f1f1f1" Offset="1.0" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
|
||||
<ScrollViewer Classes="menuscroller">
|
||||
<ItemsPresenter Name="PART_ItemsPresenter"
|
||||
Items="{TemplateBinding Items}"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}"
|
||||
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||
Margin="{DynamicResource MenuFlyoutScrollerMargin}"
|
||||
KeyboardNavigation.TabNavigation="Continue"
|
||||
Grid.IsSharedSizeScope="True" />
|
||||
</ScrollViewer>
|
||||
</Panel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ContextMenu > MenuItem">
|
||||
<Setter Property="Height" Value="20" />
|
||||
<Setter Property="Padding" Value="2 0" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ContextMenu > MenuItem:selected /template/ Border">
|
||||
<Setter Property="Background" Value="{DynamicResource MesenMenuBackgroundHighlight}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MesenMenuBorderHighlight}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Height" Value="21" />
|
||||
<Setter Property="Margin" Value="1" />
|
||||
|
@ -491,6 +540,44 @@
|
|||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="ScrollBar">
|
||||
<Setter Property="AllowAutoHide" Value="False" />
|
||||
</Style>
|
||||
|
||||
<!-- Data grid -->
|
||||
<Style Selector="DataGridColumnHeader">
|
||||
<Setter Property="MinHeight" Value="18" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Grid">
|
||||
<Setter Property="Margin" Value="-8 0 0 0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Grid ContentPresenter">
|
||||
<Setter Property="Margin" Value="0 0 -30 0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader Path">
|
||||
<Setter Property="Width" Value="0" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="IsVisible" Value="False" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow">
|
||||
<Setter Property="Height" Value="18" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="FontSize" Value="10.5" />
|
||||
<Setter Property="Height" Value="14" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell /template/ ContentPresenter > TextBlock">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell CheckBox">
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell Grid#FocusVisual">
|
||||
<Setter Property="Opacity" Value="0" />
|
||||
</Style>
|
||||
|
||||
<!-- Disable overlapped scrollbar in scrollviewer -->
|
||||
<Style Selector="ScrollViewer">
|
||||
<Setter Property="Background"
|
||||
|
|
|
@ -10,24 +10,36 @@ namespace Mesen.Utilities
|
|||
{
|
||||
static class WindowExtensions
|
||||
{
|
||||
private static void CenterWindow(Window child, Window parent)
|
||||
private static void CenterWindow(Window child, Control parent)
|
||||
{
|
||||
child.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
Size wndCenter = (parent.ClientSize / 2);
|
||||
PixelPoint screenCenter = new PixelPoint(parent.Position.X + (int)wndCenter.Width, parent.Position.Y + (int)wndCenter.Height);
|
||||
Size wndCenter = new Size(parent.Bounds.Width / 2, parent.Bounds.Height / 2);
|
||||
PixelPoint controlPosition =parent.PointToScreen(new Point(0, 0));
|
||||
PixelPoint screenCenter = new PixelPoint(controlPosition.X + (int)wndCenter.Width, controlPosition.Y + (int)wndCenter.Height);
|
||||
child.Position = new PixelPoint(screenCenter.X - (int)child.Width / 2, screenCenter.Y - (int)child.Height / 2);
|
||||
}
|
||||
|
||||
public static void ShowCentered(this Window child, Window parent)
|
||||
public static void ShowCentered(this Window child, Control parent)
|
||||
{
|
||||
CenterWindow(child, parent);
|
||||
child.Show();
|
||||
}
|
||||
|
||||
public static Task ShowCenteredDialog(this Window child, Window parent)
|
||||
public static Task ShowCenteredDialog(this Window child, Control parent)
|
||||
{
|
||||
return ShowCenteredDialog<object>(child, parent);
|
||||
}
|
||||
|
||||
public static Task<TResult> ShowCenteredDialog<TResult>(this Window child, Control parent)
|
||||
{
|
||||
CenterWindow(child, parent);
|
||||
return child.ShowDialog(parent);
|
||||
|
||||
IControl parentWnd = parent;
|
||||
while(!(parentWnd is Window) && parentWnd != null) {
|
||||
parentWnd = parentWnd.Parent;
|
||||
}
|
||||
|
||||
return child.ShowDialog<TResult>(parentWnd as Window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue