Debugger: Added toggle breakpoint shortcut + refactoring

This commit is contained in:
Sour 2019-03-23 21:56:35 -04:00
parent c41e3458eb
commit 7cc7d54705
11 changed files with 360 additions and 143 deletions

View file

@ -0,0 +1,46 @@
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class CpuCodeDataProvider : ICodeDataProvider
{
private int _lineCount;
public CpuCodeDataProvider()
{
_lineCount = (int)DebugApi.GetDisassemblyLineCount();
}
public CodeLineData GetCodeLineData(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex);
}
public int GetLineAddress(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex).Address;
}
public int GetLineCount()
{
return _lineCount;
}
public int GetLineIndex(uint cpuAddress)
{
return (int)DebugApi.GetDisassemblyLineIndex(cpuAddress);
}
public bool UseOptimizedSearch { get { return true; } }
public int GetNextResult(string searchString, int startPosition, int endPosition, bool searchBackwards)
{
return DebugApi.SearchDisassembly(searchString, startPosition, endPosition, searchBackwards);
}
}
}

View file

@ -0,0 +1,32 @@
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class CpuDisassemblyManager : IDisassemblyManager
{
private CpuCodeDataProvider _provider;
public ICodeDataProvider Provider { get { return this._provider; } }
public void RefreshCode()
{
this._provider = new CpuCodeDataProvider();
}
public void ToggleBreakpoint(int lineIndex)
{
int address = this._provider.GetLineAddress(lineIndex);
if(address >= 0) {
BreakpointManager.ToggleBreakpoint(new AddressInfo() {
Address = address,
Type = SnesMemoryType.CpuMemory
});
}
}
}
}

View file

@ -0,0 +1,103 @@
using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public class CpuLineStyleProvider : ctrlTextbox.ILineStyleProvider
{
public CpuLineStyleProvider()
{
}
public int? ActiveAddress { get; set; }
public string GetLineComment(int lineNumber)
{
return null;
}
public static void ConfigureActiveStatement(LineProperties props)
{
props.FgColor = Color.Black;
props.TextBgColor = ConfigManager.Config.Debug.CodeActiveStatementColor;
props.Symbol |= LineSymbol.Arrow;
}
public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
{
DebugInfo info = ConfigManager.Config.Debug;
LineProperties props = new LineProperties();
if(lineData.Address >= 0) {
GetBreakpointLineProperties(props, lineData.Address);
}
bool isActiveStatement = ActiveAddress.HasValue && ActiveAddress.Value == lineData.Address;
if(isActiveStatement) {
ConfigureActiveStatement(props);
}
//TODO
/* else if(_code._code.UnexecutedAddresses.Contains(lineNumber)) {
props.LineBgColor = info.CodeUnexecutedCodeColor;
}*/
if(lineData.Flags.HasFlag(LineFlags.PrgRom)) {
props.AddressColor = Color.Gray;
} else if(lineData.Flags.HasFlag(LineFlags.WorkRam)) {
props.AddressColor = Color.DarkBlue;
} else if(lineData.Flags.HasFlag(LineFlags.SaveRam)) {
props.AddressColor = Color.DarkRed;
}
if(lineData.Flags.HasFlag(LineFlags.VerifiedData)) {
props.LineBgColor = info.CodeVerifiedDataColor;
} else if(!lineData.Flags.HasFlag(LineFlags.VerifiedCode)) {
props.LineBgColor = info.CodeUnidentifiedDataColor;
}
return props;
}
public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress)
{
DebugInfo config = ConfigManager.Config.Debug;
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.CpuMemory)) {
Color fgColor = Color.White;
Color? bgColor = null;
Color bpColor = breakpoint.BreakOnExec ? config.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? config.CodeWriteBreakpointColor : config.CodeReadBreakpointColor);
Color outlineColor = bpColor;
LineSymbol symbol;
if(breakpoint.Enabled) {
bgColor = bpColor;
symbol = LineSymbol.Circle;
} else {
fgColor = Color.Black;
symbol = LineSymbol.CircleOutline;
}
if(breakpoint.MarkEvent) {
symbol |= LineSymbol.Mark;
}
if(!string.IsNullOrWhiteSpace(breakpoint.Condition)) {
symbol |= LineSymbol.Plus;
}
props.FgColor = fgColor;
props.TextBgColor = bgColor;
props.OutlineColor = outlineColor;
props.Symbol = symbol;
return;
}
}
}
}
}

View file

@ -0,0 +1,17 @@
using Mesen.GUI.Debugger.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Debugger.Code
{
public interface IDisassemblyManager
{
ICodeDataProvider Provider { get; }
void RefreshCode();
void ToggleBreakpoint(int lineIndex);
}
}

View file

@ -27,13 +27,25 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.ctrlCode = new Mesen.GUI.Debugger.Controls.ctrlScrollableTextbox();
this.ctxMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuAddToWatch = new System.Windows.Forms.ToolStripMenuItem();
this.mnuEditLabel = new System.Windows.Forms.ToolStripMenuItem();
this.mnuEditInMemoryTools = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.mnuGoToLocation = new System.Windows.Forms.ToolStripMenuItem();
this.mnuFindOccurrences = new System.Windows.Forms.ToolStripMenuItem();
this.ctxMenu.SuspendLayout();
this.SuspendLayout();
//
// ctrlCode
//
this.ctrlCode.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ctrlCode.CodeHighlightingEnabled = true;
this.ctrlCode.ContextMenuStrip = this.ctxMenu;
this.ctrlCode.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlCode.HideSelection = false;
this.ctrlCode.Location = new System.Drawing.Point(0, 0);
@ -47,6 +59,77 @@
this.ctrlCode.ShowSingleLineLineNumberNotes = false;
this.ctrlCode.Size = new System.Drawing.Size(465, 398);
this.ctrlCode.TabIndex = 0;
this.ctrlCode.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ctrlCode_MouseDown);
//
// ctxMenu
//
this.ctxMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuToggleBreakpoint,
this.toolStripMenuItem1,
this.mnuAddToWatch,
this.mnuEditLabel,
this.mnuEditInMemoryTools,
this.toolStripMenuItem2,
this.mnuGoToLocation,
this.mnuFindOccurrences});
this.ctxMenu.Name = "ctxMenu";
this.ctxMenu.Size = new System.Drawing.Size(187, 148);
//
// mnuToggleBreakpoint
//
this.mnuToggleBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Breakpoint;
this.mnuToggleBreakpoint.Name = "mnuToggleBreakpoint";
this.mnuToggleBreakpoint.Size = new System.Drawing.Size(186, 22);
this.mnuToggleBreakpoint.Text = "Toggle Breakpoint";
this.mnuToggleBreakpoint.Click += new System.EventHandler(this.mnuToggleBreakpoint_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(183, 6);
//
// mnuAddToWatch
//
this.mnuAddToWatch.Enabled = false;
this.mnuAddToWatch.Name = "mnuAddToWatch";
this.mnuAddToWatch.Size = new System.Drawing.Size(186, 22);
this.mnuAddToWatch.Text = "Add to Watch";
//
// mnuEditLabel
//
this.mnuEditLabel.Enabled = false;
this.mnuEditLabel.Image = global::Mesen.GUI.Properties.Resources.EditLabel;
this.mnuEditLabel.Name = "mnuEditLabel";
this.mnuEditLabel.Size = new System.Drawing.Size(186, 22);
this.mnuEditLabel.Text = "Edit Label";
//
// mnuEditInMemoryTools
//
this.mnuEditInMemoryTools.Enabled = false;
this.mnuEditInMemoryTools.Image = global::Mesen.GUI.Properties.Resources.CheatCode;
this.mnuEditInMemoryTools.Name = "mnuEditInMemoryTools";
this.mnuEditInMemoryTools.Size = new System.Drawing.Size(186, 22);
this.mnuEditInMemoryTools.Text = "Edit in Memory Tools";
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(183, 6);
//
// mnuGoToLocation
//
this.mnuGoToLocation.Enabled = false;
this.mnuGoToLocation.Name = "mnuGoToLocation";
this.mnuGoToLocation.Size = new System.Drawing.Size(186, 22);
this.mnuGoToLocation.Text = "Go to Location";
//
// mnuFindOccurrences
//
this.mnuFindOccurrences.Enabled = false;
this.mnuFindOccurrences.Image = global::Mesen.GUI.Properties.Resources.Find;
this.mnuFindOccurrences.Name = "mnuFindOccurrences";
this.mnuFindOccurrences.Size = new System.Drawing.Size(186, 22);
this.mnuFindOccurrences.Text = "Find Occurrences";
//
// ctrlDisassemblyView
//
@ -55,6 +138,7 @@
this.Controls.Add(this.ctrlCode);
this.Name = "ctrlDisassemblyView";
this.Size = new System.Drawing.Size(465, 398);
this.ctxMenu.ResumeLayout(false);
this.ResumeLayout(false);
}
@ -62,5 +146,14 @@
#endregion
private ctrlScrollableTextbox ctrlCode;
private System.Windows.Forms.ContextMenuStrip ctxMenu;
private System.Windows.Forms.ToolStripMenuItem mnuAddToWatch;
private System.Windows.Forms.ToolStripMenuItem mnuToggleBreakpoint;
private System.Windows.Forms.ToolStripMenuItem mnuEditLabel;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem mnuEditInMemoryTools;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem mnuGoToLocation;
private System.Windows.Forms.ToolStripMenuItem mnuFindOccurrences;
}
}

View file

@ -9,21 +9,50 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Controls;
using Mesen.GUI.Config;
using Mesen.GUI.Debugger.Code;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlDisassemblyView : BaseControl
{
private LineStyleProvider _styleProvider;
private CpuLineStyleProvider _styleProvider;
private IDisassemblyManager _manager;
public ctrlDisassemblyView()
{
InitializeComponent();
if(IsDesignMode) {
return;
}
_styleProvider = new LineStyleProvider();
_manager = new CpuDisassemblyManager();
_manager.RefreshCode();
_styleProvider = new CpuLineStyleProvider();
ctrlCode.StyleProvider = _styleProvider;
ctrlCode.ShowContentNotes = true;
ctrlCode.ShowMemoryValues = true;
InitShortcuts();
BreakpointManager.BreakpointsChanged += BreakpointManager_BreakpointsChanged;
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
BreakpointManager.BreakpointsChanged -= BreakpointManager_BreakpointsChanged;
}
private void BreakpointManager_BreakpointsChanged(object sender, EventArgs e)
{
ctrlCode.Invalidate();
}
private void InitShortcuts()
{
mnuToggleBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint));
}
public void SetActiveAddress(int? address)
@ -38,153 +67,36 @@ namespace Mesen.GUI.Debugger.Controls
private void UpdateCode()
{
CodeDataProvider provider = new CodeDataProvider();
int centerLineIndex = ctrlCode.GetLineIndexAtPosition(0) + ctrlCode.GetNumberVisibleLines() / 2;
int centerLineAddress;
int scrollOffset = -1;
do {
//Save the address at the center of the debug view
centerLineAddress = provider.GetLineAddress(centerLineIndex);
centerLineAddress = _manager.Provider.GetLineAddress(centerLineIndex);
centerLineIndex--;
scrollOffset++;
} while(centerLineAddress < 0 && centerLineIndex > 0);
ctrlCode.DataProvider = provider;
_manager.RefreshCode();
ctrlCode.DataProvider = _manager.Provider;
if(centerLineAddress >= 0) {
//Scroll to the same address as before, to prevent the code view from changing due to setting or banking changes, etc.
int lineIndex = provider.GetLineIndex((UInt32)centerLineAddress) + scrollOffset;
int lineIndex = _manager.Provider.GetLineIndex((UInt32)centerLineAddress) + scrollOffset;
ctrlCode.ScrollToLineIndex(lineIndex, eHistoryType.None, false, true);
}
}
public class CodeDataProvider : ICodeDataProvider
private void mnuToggleBreakpoint_Click(object sender, EventArgs e)
{
private int _lineCount;
public CodeDataProvider()
{
_lineCount = (int)DebugApi.GetDisassemblyLineCount();
}
public CodeLineData GetCodeLineData(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex);
}
public int GetLineAddress(int lineIndex)
{
return DebugApi.GetDisassemblyLineData((UInt32)lineIndex).Address;
}
public int GetLineCount()
{
return _lineCount;
}
public int GetLineIndex(uint cpuAddress)
{
return (int)DebugApi.GetDisassemblyLineIndex(cpuAddress);
}
public bool UseOptimizedSearch { get { return true; } }
public int GetNextResult(string searchString, int startPosition, int endPosition, bool searchBackwards)
{
return DebugApi.SearchDisassembly(searchString, startPosition, endPosition, searchBackwards);
}
_manager.ToggleBreakpoint(ctrlCode.SelectedLine);
}
public class LineStyleProvider : ctrlTextbox.ILineStyleProvider
private void ctrlCode_MouseDown(object sender, MouseEventArgs e)
{
public LineStyleProvider()
{
}
public int? ActiveAddress { get; set; }
public string GetLineComment(int lineNumber)
{
return null;
}
public static void ConfigureActiveStatement(LineProperties props)
{
props.FgColor = Color.Black;
props.TextBgColor = ConfigManager.Config.Debug.CodeActiveStatementColor;
props.Symbol |= LineSymbol.Arrow;
}
public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
{
DebugInfo info = ConfigManager.Config.Debug;
LineProperties props = new LineProperties();
if(lineData.Address >= 0) {
GetBreakpointLineProperties(props, lineData.Address);
}
bool isActiveStatement = ActiveAddress.HasValue && ActiveAddress.Value == lineData.Address;
if(isActiveStatement) {
ConfigureActiveStatement(props);
}
//TODO
/* else if(_code._code.UnexecutedAddresses.Contains(lineNumber)) {
props.LineBgColor = info.CodeUnexecutedCodeColor;
}*/
if(lineData.Flags.HasFlag(LineFlags.PrgRom)) {
props.AddressColor = Color.Gray;
} else if(lineData.Flags.HasFlag(LineFlags.WorkRam)) {
props.AddressColor = Color.DarkBlue;
} else if(lineData.Flags.HasFlag(LineFlags.SaveRam)) {
props.AddressColor = Color.DarkRed;
}
if(lineData.Flags.HasFlag(LineFlags.VerifiedData)) {
props.LineBgColor = info.CodeVerifiedDataColor;
} else if(!lineData.Flags.HasFlag(LineFlags.VerifiedCode)) {
props.LineBgColor = info.CodeUnidentifiedDataColor;
}
return props;
}
public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress)
{
DebugInfo config = ConfigManager.Config.Debug;
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.CpuMemory)) {
Color fgColor = Color.White;
Color? bgColor = null;
Color bpColor = breakpoint.BreakOnExec ? config.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? config.CodeWriteBreakpointColor : config.CodeReadBreakpointColor);
Color outlineColor = bpColor;
LineSymbol symbol;
if(breakpoint.Enabled) {
bgColor = bpColor;
symbol = LineSymbol.Circle;
} else {
fgColor = Color.Black;
symbol = LineSymbol.CircleOutline;
}
if(breakpoint.MarkEvent) {
symbol |= LineSymbol.Mark;
}
if(!string.IsNullOrWhiteSpace(breakpoint.Condition)) {
symbol |= LineSymbol.Plus;
}
props.FgColor = fgColor;
props.TextBgColor = bgColor;
props.OutlineColor = outlineColor;
props.Symbol = symbol;
return;
}
}
if(e.X < 20) {
int lineIndex = ctrlCode.GetLineIndexAtPosition(e.Y);
_manager.ToggleBreakpoint(lineIndex);
}
}
}

View file

@ -117,4 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="ctxMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -31,6 +31,12 @@ namespace Mesen.GUI.Debugger.Controls
remove { this.ctrlTextbox.MouseMove -= value; }
}
public new event MouseEventHandler MouseClick
{
add { this.ctrlTextbox.MouseClick += value; }
remove { this.ctrlTextbox.MouseClick -= value; }
}
public new event MouseEventHandler MouseDown
{
add { this.ctrlTextbox.MouseDown += value; }
@ -79,6 +85,12 @@ namespace Mesen.GUI.Debugger.Controls
this.panelSearch.Location = new System.Drawing.Point(this.Width - this.panelSearch.Width - 20, -1);
}
protected override void OnInvalidated(InvalidateEventArgs e)
{
base.OnInvalidated(e);
ctrlTextbox.Invalidate();
}
public bool ShowScrollbars
{
get
@ -232,11 +244,10 @@ namespace Mesen.GUI.Debugger.Controls
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(!this.cboSearch.Focused) {
//TODO
/*if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.SelectAll) {
if(keyData == ConfigManager.Config.Debug.Shortcuts.SelectAll) {
this.SelectAll();
return true;
}*/
}
switch(keyData) {
case Keys.Right | Keys.Shift:
@ -281,21 +292,19 @@ namespace Mesen.GUI.Debugger.Controls
}
}
//TODO
/*
if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.IncreaseFontSize) {
if(keyData == ConfigManager.Config.Debug.Shortcuts.IncreaseFontSize) {
this.TextZoom += 10;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.DecreaseFontSize) {
} else if(keyData == ConfigManager.Config.Debug.Shortcuts.DecreaseFontSize) {
this.TextZoom -= 10;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.ResetFontSize) {
} else if(keyData == ConfigManager.Config.Debug.Shortcuts.ResetFontSize) {
this.TextZoom = 100;
return true;
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.Find) {
} else if(keyData == ConfigManager.Config.Debug.Shortcuts.Find) {
this.OpenSearchBox(true);
return true;
}*/
}
if(keyData == (Keys.Control | Keys.F)) {
this.OpenSearchBox(true);

View file

@ -46,7 +46,6 @@ namespace Mesen.GUI.Debugger.Controls
private int _marginWidth = 9;
private int _extendedMarginWidth = 16;
private float _maxLineWidth = 0;
private int _maxLineWidthIndex = 0;
private TextboxMessageInfo _message;
public ctrlTextbox()
@ -1017,7 +1016,7 @@ namespace Mesen.GUI.Debugger.Controls
if((circleSize % 2) == 1) {
circleSize++;
}
int circleOffsetY = positionY + 4;
int circleOffsetY = positionY + 2;
int circleOffsetX = 3;
Action<Brush> drawPlus = (Brush b) => {

View file

@ -224,7 +224,6 @@
// mnuRun1000Cycles
//
this.mnuRun1000Cycles.Name = "mnuRun1000Cycles";
this.mnuRun1000Cycles.ShortcutKeys = System.Windows.Forms.Keys.F9;
this.mnuRun1000Cycles.Size = new System.Drawing.Size(212, 22);
this.mnuRun1000Cycles.Text = "Run 1000 CPU cycles";
this.mnuRun1000Cycles.Click += new System.EventHandler(this.mnuRun1000Cycles_Click);

View file

@ -243,6 +243,10 @@
<DependentUpon>frmBreakpoint.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Breakpoints\InteropBreakpoint.cs" />
<Compile Include="Debugger\Code\CpuCodeProvider.cs" />
<Compile Include="Debugger\Code\CpuDisassemblyManager.cs" />
<Compile Include="Debugger\Code\CpuLineStyleProvider.cs" />
<Compile Include="Debugger\Code\IDisassemblyManager.cs" />
<Compile Include="Debugger\Config\DebuggerShortcutsConfig.cs" />
<Compile Include="Debugger\Config\EventViewerInfo.cs" />
<Compile Include="Debugger\Config\HexEditorInfo.cs" />