mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
270 lines
8.8 KiB
C#
270 lines
8.8 KiB
C#
using Dock.Avalonia.Controls;
|
|
using Dock.Model.Core;
|
|
using Mesen.Debugger.ViewModels;
|
|
using Mesen.Debugger.ViewModels.DebuggerDock;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Dock.Model.Controls;
|
|
using Mesen.Debugger.StatusViews;
|
|
using Dock.Model.Mvvm;
|
|
using Dock.Model.Mvvm.Controls;
|
|
using Dock.Model.Mvvm.Core;
|
|
|
|
namespace Mesen.Debugger
|
|
{
|
|
public class DebuggerDockFactory : Factory
|
|
{
|
|
public ToolContainerViewModel<DisassemblyViewModel> DisassemblyTool { get; private set; }
|
|
public ToolContainerViewModel<SourceViewViewModel> SourceViewTool { get; private set; }
|
|
public ToolContainerViewModel<BaseConsoleStatusViewModel> StatusTool { get; private set; }
|
|
public ToolContainerViewModel<BreakpointListViewModel> BreakpointListTool { get; private set; }
|
|
public ToolContainerViewModel<WatchListViewModel> WatchListTool { get; private set; }
|
|
public ToolContainerViewModel<CallStackViewModel> CallStackTool { get; private set; }
|
|
public ToolContainerViewModel<LabelListViewModel> LabelListTool { get; private set; }
|
|
public ToolContainerViewModel<FunctionListViewModel> FunctionListTool { get; private set; }
|
|
public ToolContainerViewModel<FindResultListViewModel> FindResultListTool { get; private set; }
|
|
public ToolContainerViewModel<ControllerListViewModel> ControllerListTool { get; private set; }
|
|
|
|
private DockEntryDefinition? _savedRootDef;
|
|
|
|
public DebuggerDockFactory(DockEntryDefinition? savedRootDef)
|
|
{
|
|
DisassemblyTool = new("Disassembly");
|
|
DisassemblyTool.CanClose = false;
|
|
SourceViewTool = new("Source View");
|
|
SourceViewTool.CanClose = false;
|
|
|
|
StatusTool = new("Status");
|
|
BreakpointListTool = new("Breakpoints");
|
|
WatchListTool = new("Watch");
|
|
CallStackTool = new("Call Stack");
|
|
LabelListTool = new("Labels");
|
|
FunctionListTool = new("Functions");
|
|
FindResultListTool = new("Find Results");
|
|
ControllerListTool = new("Controllers");
|
|
|
|
_savedRootDef = savedRootDef;
|
|
}
|
|
|
|
public override IRootDock CreateLayout()
|
|
{
|
|
if(_savedRootDef != null) {
|
|
//Restore previous layout
|
|
try {
|
|
if(FromDockDefinition(_savedRootDef) is IRootDock savedRootLayout) {
|
|
return savedRootLayout;
|
|
}
|
|
} catch {
|
|
//Reset layout if any error occurs
|
|
}
|
|
}
|
|
|
|
return GetDefaultLayout();
|
|
}
|
|
|
|
public IRootDock GetDefaultLayout()
|
|
{
|
|
var mainLayout = new ProportionalDock {
|
|
Orientation = Orientation.Vertical,
|
|
VisibleDockables = CreateList<IDockable>(
|
|
new ProportionalDock {
|
|
Proportion = 0.75,
|
|
Orientation = Orientation.Horizontal,
|
|
ActiveDockable = null,
|
|
VisibleDockables = CreateList<IDockable>(
|
|
new ToolDock {
|
|
Proportion = 0.60,
|
|
VisibleDockables = CreateList<IDockable>(DisassemblyTool, SourceViewTool)
|
|
},
|
|
new MesenProportionalDockSplitter(),
|
|
new ProportionalDock {
|
|
Proportion = 0.40,
|
|
Orientation = Orientation.Vertical,
|
|
VisibleDockables = CreateList<IDockable>(
|
|
new ToolDock {
|
|
Proportion = 0.5,
|
|
VisibleDockables = CreateList<IDockable>(StatusTool)
|
|
},
|
|
new MesenProportionalDockSplitter(),
|
|
new ToolDock {
|
|
Proportion = 0.5,
|
|
VisibleDockables = CreateList<IDockable>(LabelListTool, FunctionListTool, FindResultListTool, ControllerListTool)
|
|
}
|
|
)
|
|
}
|
|
)
|
|
},
|
|
new MesenProportionalDockSplitter(),
|
|
new ProportionalDock {
|
|
Proportion = 0.25,
|
|
Orientation = Orientation.Horizontal,
|
|
VisibleDockables = CreateList<IDockable>(
|
|
new ToolDock {
|
|
Proportion = 0.33,
|
|
VisibleDockables = CreateList<IDockable>(WatchListTool)
|
|
},
|
|
new MesenProportionalDockSplitter(),
|
|
new ToolDock {
|
|
Proportion = 0.33,
|
|
VisibleDockables = CreateList<IDockable>(BreakpointListTool)
|
|
},
|
|
new MesenProportionalDockSplitter(),
|
|
new ToolDock {
|
|
Proportion = 0.33,
|
|
VisibleDockables = CreateList<IDockable>(CallStackTool)
|
|
}
|
|
)
|
|
}
|
|
)
|
|
};
|
|
|
|
var root = CreateRootDock();
|
|
root.ActiveDockable = mainLayout;
|
|
root.DefaultDockable = mainLayout;
|
|
root.VisibleDockables = CreateList<IDockable>(mainLayout);
|
|
return root;
|
|
}
|
|
|
|
public override IProportionalDockSplitter CreateProportionalDockSplitter()
|
|
{
|
|
return new MesenProportionalDockSplitter();
|
|
}
|
|
|
|
public override void InitLayout(IDockable layout)
|
|
{
|
|
this.ContextLocator = new Dictionary<string, Func<object?>> {
|
|
};
|
|
|
|
this.HostWindowLocator = new Dictionary<string, Func<IHostWindow?>> {
|
|
[nameof(IDockWindow)] = () => new HostWindow()
|
|
};
|
|
|
|
this.DockableLocator = new Dictionary<string, Func<IDockable?>> { };
|
|
|
|
base.InitLayout(layout);
|
|
}
|
|
|
|
public DockEntryDefinition ToDockDefinition(IDockable dockable)
|
|
{
|
|
DockEntryDefinition entry = new();
|
|
if(dockable is MesenProportionalDockSplitter) {
|
|
entry.Type = DockEntryType.Splitter;
|
|
} else if(dockable is IDock dock) {
|
|
if(dock is IRootDock) {
|
|
entry.Type = DockEntryType.Root;
|
|
} else if(dock is IProportionalDock propDock) {
|
|
entry.Type = DockEntryType.ProportionalDock;
|
|
entry.Orientation = propDock.Orientation;
|
|
} else {
|
|
entry.Type = DockEntryType.ToolDock;
|
|
}
|
|
entry.Name = dock.Title;
|
|
entry.Proportion = double.IsNaN(dock.Proportion) ? 0 : dock.Proportion;
|
|
entry.Children = new();
|
|
if(dock.VisibleDockables != null) {
|
|
if(dock is IProportionalDock propDock && dock.VisibleDockables.Count == 1) {
|
|
//Remove empty proportional docks (these seem to get created when moving things around)
|
|
DockEntryDefinition innerEntry = ToDockDefinition(dock.VisibleDockables[0]);
|
|
|
|
//Keep the outer layer's proportion (inner will be set to 1, which will cause issues)
|
|
innerEntry.Proportion = entry.Proportion;
|
|
return innerEntry;
|
|
}
|
|
|
|
if(dock.ActiveDockable != null) {
|
|
int index = dock.VisibleDockables.IndexOf(dock.ActiveDockable);
|
|
if(index >= 0) {
|
|
entry.SelectedIndex = index;
|
|
}
|
|
}
|
|
foreach(IDockable child in dock.VisibleDockables) {
|
|
entry.Children.Add(ToDockDefinition(child));
|
|
}
|
|
}
|
|
} else if(dockable is ITool tool) {
|
|
entry.Type = DockEntryType.Tool;
|
|
entry.Name = tool.Title;
|
|
entry.ToolTypeName = tool.GetType().GetGenericArguments()[0].Name;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
public IDockable? FromDockDefinition(DockEntryDefinition def)
|
|
{
|
|
IDockable? dockable = null;
|
|
switch(def.Type) {
|
|
case DockEntryType.Splitter: return CreateProportionalDockSplitter();
|
|
case DockEntryType.Root: dockable = CreateRootDock(); break;
|
|
case DockEntryType.ToolDock: dockable = CreateToolDock(); break;
|
|
|
|
case DockEntryType.ProportionalDock: {
|
|
IProportionalDock propDock = CreateProportionalDock();
|
|
propDock.Orientation = def.Orientation;
|
|
dockable = propDock;
|
|
break;
|
|
}
|
|
|
|
case DockEntryType.Tool:
|
|
switch(def.ToolTypeName) {
|
|
case nameof(DisassemblyViewModel): return DisassemblyTool;
|
|
case nameof(SourceViewViewModel): return SourceViewTool;
|
|
case nameof(BaseConsoleStatusViewModel): return StatusTool;
|
|
case nameof(BreakpointListViewModel): return BreakpointListTool;
|
|
case nameof(WatchListViewModel): return WatchListTool;
|
|
case nameof(CallStackViewModel): return CallStackTool;
|
|
case nameof(LabelListViewModel): return LabelListTool;
|
|
case nameof(FunctionListViewModel): return FunctionListTool;
|
|
case nameof(FindResultListViewModel): return FindResultListTool;
|
|
case nameof(ControllerListViewModel): return ControllerListTool;
|
|
}
|
|
break;
|
|
}
|
|
|
|
IDock? dock = dockable as IDock;
|
|
if(dock != null && def.Proportion != 0) {
|
|
dock.Proportion = def.Proportion;
|
|
}
|
|
|
|
if(dock != null && def.Children != null) {
|
|
dock.VisibleDockables = CreateList<IDockable>();
|
|
foreach(DockEntryDefinition childDef in def.Children) {
|
|
IDockable? child = FromDockDefinition(childDef);
|
|
if(child != null) {
|
|
dock.VisibleDockables.Add(child);
|
|
}
|
|
}
|
|
dock.ActiveDockable = def.SelectedIndex < dock.VisibleDockables.Count ? dock.VisibleDockables[def.SelectedIndex] : dock.VisibleDockables[0];
|
|
dock.DefaultDockable = dock.VisibleDockables[0];
|
|
}
|
|
|
|
return dockable;
|
|
}
|
|
}
|
|
|
|
public enum DockEntryType
|
|
{
|
|
Root,
|
|
ProportionalDock,
|
|
ToolDock,
|
|
Splitter,
|
|
Tool
|
|
}
|
|
|
|
public class DockEntryDefinition
|
|
{
|
|
public DockEntryType Type { get; set; }
|
|
public double Proportion { get; set; } = 0;
|
|
public Orientation Orientation { get; set; } = Orientation.Horizontal;
|
|
public string Name { get; set; } = "";
|
|
public string ToolTypeName { get; set; } = "";
|
|
public int SelectedIndex { get; set; } = 0;
|
|
public List<DockEntryDefinition>? Children { get; set; }
|
|
}
|
|
}
|
|
|
|
public class MesenProportionalDockSplitter : DockBase, IProportionalDockSplitter
|
|
{
|
|
//The regular ProportionalDockSplitter in Dock.Model.Mvvm.Controls inherits from DockableBase, which causes an exception when styles are applied
|
|
}
|