diff --git a/GUI.NET/Config/DebugInfo.cs b/GUI.NET/Config/DebugInfo.cs index a4877e3b..339ae48e 100644 --- a/GUI.NET/Config/DebugInfo.cs +++ b/GUI.NET/Config/DebugInfo.cs @@ -30,6 +30,7 @@ namespace Mesen.GUI.Config public class DebugViewInfo { + public bool ShowSourceAsComments = false; public ByteCodePosition ByteCodePosition = ByteCodePosition.Hidden; public PrgAddressPosition PrgAddressPosition = PrgAddressPosition.Hidden; public int TextZoom = 100; diff --git a/GUI.NET/Config/DebuggerShortcutsConfig.cs b/GUI.NET/Config/DebuggerShortcutsConfig.cs index 90189761..53071d12 100644 --- a/GUI.NET/Config/DebuggerShortcutsConfig.cs +++ b/GUI.NET/Config/DebuggerShortcutsConfig.cs @@ -124,6 +124,8 @@ namespace Mesen.GUI.Config public XmlKeys CodeWindow_ToggleBreakpoint = Keys.F9; [ShortcutName("Code Window: Disable/Enable Breakpoint")] public XmlKeys CodeWindow_DisableEnableBreakpoint = Keys.Control | Keys.F9; + [ShortcutName("Code Window: Switch View (Disassembly / Source View)")] + public XmlKeys CodeWindow_SwitchView = Keys.Control | Keys.Q; [ShortcutName("Function List: Edit Label")] public XmlKeys FunctionList_EditLabel = Keys.F2; diff --git a/GUI.NET/Debugger/BreakpointManager.cs b/GUI.NET/Debugger/BreakpointManager.cs index 5084ecb7..c2e8957e 100644 --- a/GUI.NET/Debugger/BreakpointManager.cs +++ b/GUI.NET/Debugger/BreakpointManager.cs @@ -84,7 +84,7 @@ namespace Mesen.GUI.Debugger public static void ToggleBreakpoint(int relativeAddress, AddressTypeInfo info, bool toggleEnabled) { - if(relativeAddress >= 0) { + if(relativeAddress >= 0 || info.Address >= 0) { Breakpoint breakpoint = BreakpointManager.GetMatchingBreakpoint(relativeAddress, info); if(breakpoint != null) { if(toggleEnabled) { diff --git a/GUI.NET/Debugger/CodeTooltipManager.cs b/GUI.NET/Debugger/CodeTooltipManager.cs new file mode 100644 index 00000000..96100419 --- /dev/null +++ b/GUI.NET/Debugger/CodeTooltipManager.cs @@ -0,0 +1,184 @@ +using Mesen.GUI.Config; +using Mesen.GUI.Forms; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Mesen.GUI.Debugger +{ + class CodeTooltipManager + { + private bool _preventCloseTooltip = false; + private string _hoverLastWord = ""; + private int _hoverLastLineAddress = -1; + private Point _previousLocation; + private Form _codeTooltip = null; + private Control _owner = null; + private ctrlScrollableTextbox _codeViewer = null; + + public string Code { get; set; } + public Ld65DbgImporter SymbolProvider { get; set; } + + public CodeTooltipManager(Control owner, ctrlScrollableTextbox codeViewer) + { + _owner = owner; + _codeViewer = codeViewer; + } + + public void ShowTooltip(string word, Dictionary values, int lineAddress, AddressTypeInfo? previewAddress) + { + if(_hoverLastWord != word || _hoverLastLineAddress != lineAddress || _codeTooltip == null) { + if(!_preventCloseTooltip && _codeTooltip != null) { + _codeTooltip.Close(); + _codeTooltip = null; + } + + if(ConfigManager.Config.DebugInfo.ShowOpCodeTooltips && frmOpCodeTooltip.IsOpCode(word)) { + _codeTooltip = new frmOpCodeTooltip(word, lineAddress); + } else { + _codeTooltip = new frmCodeTooltip(values, previewAddress.HasValue && previewAddress.Value.Type == AddressType.PrgRom ? previewAddress : null, Code, SymbolProvider); + } + _codeTooltip.Left = Cursor.Position.X + 10; + _codeTooltip.Top = Cursor.Position.Y + 10; + _codeTooltip.Show(_owner); + } + _codeTooltip.Left = Cursor.Position.X + 10; + _codeTooltip.Top = Cursor.Position.Y + 10; + + _preventCloseTooltip = true; + _hoverLastWord = word; + _hoverLastLineAddress = lineAddress; + } + + public void Close(bool forceClose = false) + { + if((!_preventCloseTooltip || forceClose) && _codeTooltip != null) { + _codeTooltip.Close(); + _codeTooltip = null; + } + _preventCloseTooltip = false; + } + + public void DisplayAddressTooltip(string word, UInt32 address) + { + byte byteValue = InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, address); + UInt16 wordValue = (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, address + 1) << 8)); + + var values = new Dictionary() { + { "Address", "$" + address.ToString("X4") }, + { "Value", $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" } + }; + + this.ShowTooltip(word, values, -1, new AddressTypeInfo() { Address = (int)address, Type = AddressType.Register }); + } + + private void DisplayLabelTooltip(string word, CodeLabel label) + { + int relativeAddress = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType); + byte byteValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress) : (byte)0; + UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0; + + var values = new Dictionary() { + { "Label", label.Label }, + { "Address", "$" + relativeAddress.ToString("X4") }, + { "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") }, + }; + + if(!string.IsNullOrWhiteSpace(label.Comment)) { + values["Comment"] = label.Comment; + } + + ShowTooltip(word, values, -1, new AddressTypeInfo() { Address = (int)label.Address, Type = label.AddressType }); + } + + private void DisplaySymbolTooltip(Ld65DbgImporter.SymbolInfo symbol) + { + int relativeAddress = symbol.Address.HasValue ? symbol.Address.Value : -1; + byte byteValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress) : (byte)0; + UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress + 1) << 8)) : (UInt16)0; + + AddressTypeInfo? addressInfo = SymbolProvider.GetSymbolAddressInfo(symbol); + + if(addressInfo != null) { + var values = new Dictionary() { + { "Symbol", symbol.Name } + }; + + if(relativeAddress >= 0) { + values["CPU Address"] = "$" + relativeAddress.ToString("X4"); + }; + + if(addressInfo.Value.Type == AddressType.PrgRom) { + values["PRG Offset"] = "$" + addressInfo.Value.Address.ToString("X4"); + } + + values["Value"] = (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a"); + + ShowTooltip(symbol.Name, values, -1, addressInfo); + } else { + var values = new Dictionary() { + { "Symbol", symbol.Name }, + { "Constant", "$" + relativeAddress.ToString("X2") } + }; + ShowTooltip(symbol.Name, values, -1, addressInfo); + } + } + + public void ProcessMouseMove(Point location) + { + if(_previousLocation != location) { + this.Close(); + + _previousLocation = location; + + string word = _codeViewer.GetWordUnderLocation(location); + if(word.StartsWith("$")) { + try { + UInt32 address = UInt32.Parse(word.Substring(1), NumberStyles.AllowHexSpecifier); + + AddressTypeInfo info = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType(address, ref info); + + if(info.Address >= 0) { + CodeLabel label = LabelManager.GetLabel((UInt32)info.Address, info.Type); + if(label == null) { + DisplayAddressTooltip(word, address); + } else { + DisplayLabelTooltip(word, label); + } + } else { + DisplayAddressTooltip(word, address); + } + } catch { } + } else { + int address = _codeViewer.GetLineNumberAtPosition(location.Y); + if(SymbolProvider != null) { + int rangeStart, rangeEnd; + if(_codeViewer.GetNoteRangeAtLocation(location.Y, out rangeStart, out rangeEnd)) { + Ld65DbgImporter.SymbolInfo symbol = SymbolProvider.GetSymbol(word, rangeStart, rangeEnd); + if(symbol != null) { + DisplaySymbolTooltip(symbol); + return; + } + } + } else { + CodeLabel label = LabelManager.GetLabel(word); + if(label != null) { + DisplayLabelTooltip(word, label); + return; + } + } + + if(ConfigManager.Config.DebugInfo.ShowOpCodeTooltips && frmOpCodeTooltip.IsOpCode(word)) { + ShowTooltip(word, null, -1, new AddressTypeInfo() { Address = address, Type = AddressType.Register }); + } + } + } + } + } +} diff --git a/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs b/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs index d550c876..3dabb920 100644 --- a/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs +++ b/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs @@ -20,20 +20,6 @@ namespace Mesen.GUI.Debugger.Controls } } - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Font BaseFont - { - get { return this.ScrollableTextbox.BaseFont; } - set { this.ScrollableTextbox.BaseFont = value; } - } - - public int TextZoom - { - get { return this.ScrollableTextbox?.TextZoom ?? 100; } - set { this.ScrollableTextbox.TextZoom = value; } - } - public void OpenSearchBox() { this.ScrollableTextbox.OpenSearchBox(); @@ -80,9 +66,9 @@ namespace Mesen.GUI.Debugger.Controls this.ScrollableTextbox.ScrollToLineNumber(0); } - public string GetWordUnderLocation(Point position, bool useCompareText = false) + public string GetWordUnderLocation(Point position) { - return this.ScrollableTextbox.GetWordUnderLocation(position, useCompareText); + return this.ScrollableTextbox.GetWordUnderLocation(position); } } } diff --git a/GUI.NET/Debugger/Controls/CodeViewerActions.Designer.cs b/GUI.NET/Debugger/Controls/CodeViewerActions.Designer.cs new file mode 100644 index 00000000..ed816500 --- /dev/null +++ b/GUI.NET/Debugger/Controls/CodeViewerActions.Designer.cs @@ -0,0 +1,458 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class CodeViewerActions + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.mnuMarkSelectionAs = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuMarkAsCode = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuMarkAsData = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuMarkAsUnidentifiedData = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuEditSelectedCode = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuEditSubroutine = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuUndoPrgChrEdit = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuCopySelection = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuShowNextStatement = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSetNextStatement = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuShowCodeNotes = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowByteCodeOnLeft = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowByteCodeBelow = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuHideByteCode = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowLineNotes = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuPrgShowInline = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuPrgAddressReplace = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuPrgAddressBelow = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuHidePrgAddresses = new System.Windows.Forms.ToolStripMenuItem(); + this.sepEditLabel = new System.Windows.Forms.ToolStripSeparator(); + this.mnuEditLabel = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuEditInMemoryViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.sepAddToWatch = new System.Windows.Forms.ToolStripSeparator(); + this.mnuAddToWatch = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuFindOccurrences = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuGoToLocation = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowInSplitView = new System.Windows.Forms.ToolStripMenuItem(); + this.sepNavigation = new System.Windows.Forms.ToolStripSeparator(); + this.mnuNavigateBackward = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuNavigateForward = new System.Windows.Forms.ToolStripMenuItem(); + this.sepSwitchView = new System.Windows.Forms.ToolStripSeparator(); + this.mnuSwitchView = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuShowSourceAsComments = new System.Windows.Forms.ToolStripMenuItem(); + this.contextMenu.SuspendLayout(); + this.SuspendLayout(); + // + // contextMenu + // + this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuMarkSelectionAs, + this.toolStripMenuItem4, + this.mnuEditSelectedCode, + this.mnuEditSubroutine, + this.mnuUndoPrgChrEdit, + this.mnuCopySelection, + this.toolStripMenuItem7, + this.mnuShowNextStatement, + this.mnuSetNextStatement, + this.toolStripMenuItem1, + this.mnuShowCodeNotes, + this.mnuShowLineNotes, + this.sepEditLabel, + this.mnuEditLabel, + this.mnuEditInMemoryViewer, + this.mnuToggleBreakpoint, + this.sepAddToWatch, + this.mnuAddToWatch, + this.mnuFindOccurrences, + this.toolStripMenuItem2, + this.mnuGoToLocation, + this.mnuShowInSplitView, + this.sepNavigation, + this.mnuNavigateBackward, + this.mnuNavigateForward, + this.sepSwitchView, + this.mnuSwitchView, + this.mnuShowSourceAsComments}); + this.contextMenu.Name = "contextMenuWatch"; + this.contextMenu.Size = new System.Drawing.Size(254, 514); + this.contextMenu.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.contextMenuCode_Closed); + this.contextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuCode_Opening); + // + // mnuMarkSelectionAs + // + this.mnuMarkSelectionAs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuMarkAsCode, + this.mnuMarkAsData, + this.mnuMarkAsUnidentifiedData}); + this.mnuMarkSelectionAs.Name = "mnuMarkSelectionAs"; + this.mnuMarkSelectionAs.Size = new System.Drawing.Size(253, 22); + this.mnuMarkSelectionAs.Text = "Mark selection as..."; + // + // mnuMarkAsCode + // + this.mnuMarkAsCode.Image = global::Mesen.GUI.Properties.Resources.Accept; + this.mnuMarkAsCode.Name = "mnuMarkAsCode"; + this.mnuMarkAsCode.Size = new System.Drawing.Size(199, 22); + this.mnuMarkAsCode.Text = "Verified Code"; + this.mnuMarkAsCode.Click += new System.EventHandler(this.mnuMarkAsCode_Click); + // + // mnuMarkAsData + // + this.mnuMarkAsData.Image = global::Mesen.GUI.Properties.Resources.CheatCode; + this.mnuMarkAsData.Name = "mnuMarkAsData"; + this.mnuMarkAsData.Size = new System.Drawing.Size(199, 22); + this.mnuMarkAsData.Text = "Verified Data"; + this.mnuMarkAsData.Click += new System.EventHandler(this.mnuMarkAsData_Click); + // + // mnuMarkAsUnidentifiedData + // + this.mnuMarkAsUnidentifiedData.Image = global::Mesen.GUI.Properties.Resources.Help; + this.mnuMarkAsUnidentifiedData.Name = "mnuMarkAsUnidentifiedData"; + this.mnuMarkAsUnidentifiedData.Size = new System.Drawing.Size(199, 22); + this.mnuMarkAsUnidentifiedData.Text = "Unidentified Code/Data"; + this.mnuMarkAsUnidentifiedData.Click += new System.EventHandler(this.mnuMarkAsUnidentifiedData_Click); + // + // toolStripMenuItem4 + // + this.toolStripMenuItem4.Name = "toolStripMenuItem4"; + this.toolStripMenuItem4.Size = new System.Drawing.Size(250, 6); + // + // mnuEditSelectedCode + // + this.mnuEditSelectedCode.Image = global::Mesen.GUI.Properties.Resources.Edit; + this.mnuEditSelectedCode.Name = "mnuEditSelectedCode"; + this.mnuEditSelectedCode.Size = new System.Drawing.Size(253, 22); + this.mnuEditSelectedCode.Text = "Edit Selected Code"; + this.mnuEditSelectedCode.Click += new System.EventHandler(this.mnuEditSelectedCode_Click); + // + // mnuEditSubroutine + // + this.mnuEditSubroutine.Image = global::Mesen.GUI.Properties.Resources.Edit; + this.mnuEditSubroutine.Name = "mnuEditSubroutine"; + this.mnuEditSubroutine.Size = new System.Drawing.Size(253, 22); + this.mnuEditSubroutine.Text = "Edit Subroutine"; + this.mnuEditSubroutine.Click += new System.EventHandler(this.mnuEditSubroutine_Click); + // + // mnuUndoPrgChrEdit + // + this.mnuUndoPrgChrEdit.Image = global::Mesen.GUI.Properties.Resources.Undo; + this.mnuUndoPrgChrEdit.Name = "mnuUndoPrgChrEdit"; + this.mnuUndoPrgChrEdit.Size = new System.Drawing.Size(253, 22); + this.mnuUndoPrgChrEdit.Text = "Undo PRG/CHR Edit"; + this.mnuUndoPrgChrEdit.Click += new System.EventHandler(this.mnuUndoPrgChrEdit_Click); + // + // mnuCopySelection + // + this.mnuCopySelection.Image = global::Mesen.GUI.Properties.Resources.Copy; + this.mnuCopySelection.Name = "mnuCopySelection"; + this.mnuCopySelection.Size = new System.Drawing.Size(253, 22); + this.mnuCopySelection.Text = "Copy Selection"; + this.mnuCopySelection.Click += new System.EventHandler(this.mnuCopySelection_Click); + // + // toolStripMenuItem7 + // + this.toolStripMenuItem7.Name = "toolStripMenuItem7"; + this.toolStripMenuItem7.Size = new System.Drawing.Size(250, 6); + // + // mnuShowNextStatement + // + this.mnuShowNextStatement.Name = "mnuShowNextStatement"; + this.mnuShowNextStatement.ShortcutKeyDisplayString = ""; + this.mnuShowNextStatement.Size = new System.Drawing.Size(253, 22); + this.mnuShowNextStatement.Text = "Show Next Statement"; + this.mnuShowNextStatement.Click += new System.EventHandler(this.mnuShowNextStatement_Click); + // + // mnuSetNextStatement + // + this.mnuSetNextStatement.Name = "mnuSetNextStatement"; + this.mnuSetNextStatement.Size = new System.Drawing.Size(253, 22); + this.mnuSetNextStatement.Text = "Set Next Statement"; + this.mnuSetNextStatement.Click += new System.EventHandler(this.mnuSetNextStatement_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(250, 6); + // + // mnuShowCodeNotes + // + this.mnuShowCodeNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuShowByteCodeOnLeft, + this.mnuShowByteCodeBelow, + this.toolStripMenuItem5, + this.mnuHideByteCode}); + this.mnuShowCodeNotes.Name = "mnuShowCodeNotes"; + this.mnuShowCodeNotes.Size = new System.Drawing.Size(253, 22); + this.mnuShowCodeNotes.Text = "Byte Code Display"; + // + // mnuShowByteCodeOnLeft + // + this.mnuShowByteCodeOnLeft.Name = "mnuShowByteCodeOnLeft"; + this.mnuShowByteCodeOnLeft.Size = new System.Drawing.Size(130, 22); + this.mnuShowByteCodeOnLeft.Text = "On the left"; + this.mnuShowByteCodeOnLeft.Click += new System.EventHandler(this.mnuShowByteCodeOnLeft_Click); + // + // mnuShowByteCodeBelow + // + this.mnuShowByteCodeBelow.Name = "mnuShowByteCodeBelow"; + this.mnuShowByteCodeBelow.Size = new System.Drawing.Size(130, 22); + this.mnuShowByteCodeBelow.Text = "Below"; + this.mnuShowByteCodeBelow.Click += new System.EventHandler(this.mnuShowByteCodeBelow_Click); + // + // toolStripMenuItem5 + // + this.toolStripMenuItem5.Name = "toolStripMenuItem5"; + this.toolStripMenuItem5.Size = new System.Drawing.Size(127, 6); + // + // mnuHideByteCode + // + this.mnuHideByteCode.Name = "mnuHideByteCode"; + this.mnuHideByteCode.Size = new System.Drawing.Size(130, 22); + this.mnuHideByteCode.Text = "Hidden"; + this.mnuHideByteCode.Click += new System.EventHandler(this.mnuHideByteCode_Click); + // + // mnuShowLineNotes + // + this.mnuShowLineNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuPrgShowInline, + this.mnuPrgAddressReplace, + this.mnuPrgAddressBelow, + this.toolStripMenuItem6, + this.mnuHidePrgAddresses}); + this.mnuShowLineNotes.Name = "mnuShowLineNotes"; + this.mnuShowLineNotes.Size = new System.Drawing.Size(253, 22); + this.mnuShowLineNotes.Text = "PRG Address Display"; + // + // mnuPrgShowInline + // + this.mnuPrgShowInline.Name = "mnuPrgShowInline"; + this.mnuPrgShowInline.Size = new System.Drawing.Size(196, 22); + this.mnuPrgShowInline.Text = "Inline Compact Display"; + this.mnuPrgShowInline.Click += new System.EventHandler(this.mnuShowInlineCompactDisplay_Click); + // + // mnuPrgAddressReplace + // + this.mnuPrgAddressReplace.Name = "mnuPrgAddressReplace"; + this.mnuPrgAddressReplace.Size = new System.Drawing.Size(196, 22); + this.mnuPrgAddressReplace.Text = "Replace CPU address"; + this.mnuPrgAddressReplace.Click += new System.EventHandler(this.mnuReplaceCpuAddress_Click); + // + // mnuPrgAddressBelow + // + this.mnuPrgAddressBelow.Name = "mnuPrgAddressBelow"; + this.mnuPrgAddressBelow.Size = new System.Drawing.Size(196, 22); + this.mnuPrgAddressBelow.Text = "Below CPU address"; + this.mnuPrgAddressBelow.Click += new System.EventHandler(this.mnuBelowCpuAddress_Click); + // + // toolStripMenuItem6 + // + this.toolStripMenuItem6.Name = "toolStripMenuItem6"; + this.toolStripMenuItem6.Size = new System.Drawing.Size(193, 6); + // + // mnuHidePrgAddresses + // + this.mnuHidePrgAddresses.Name = "mnuHidePrgAddresses"; + this.mnuHidePrgAddresses.Size = new System.Drawing.Size(196, 22); + this.mnuHidePrgAddresses.Text = "Hidden"; + this.mnuHidePrgAddresses.Click += new System.EventHandler(this.mnuHidePrgAddresses_Click); + // + // sepEditLabel + // + this.sepEditLabel.Name = "sepEditLabel"; + this.sepEditLabel.Size = new System.Drawing.Size(250, 6); + // + // mnuEditLabel + // + this.mnuEditLabel.Image = global::Mesen.GUI.Properties.Resources.EditLabel; + this.mnuEditLabel.Name = "mnuEditLabel"; + this.mnuEditLabel.Size = new System.Drawing.Size(253, 22); + this.mnuEditLabel.Text = "Edit Label"; + this.mnuEditLabel.Click += new System.EventHandler(this.mnuEditLabel_Click); + // + // mnuEditInMemoryViewer + // + this.mnuEditInMemoryViewer.Image = global::Mesen.GUI.Properties.Resources.CheatCode; + this.mnuEditInMemoryViewer.Name = "mnuEditInMemoryViewer"; + this.mnuEditInMemoryViewer.Size = new System.Drawing.Size(253, 22); + this.mnuEditInMemoryViewer.Text = "Edit in Memory Viewer"; + this.mnuEditInMemoryViewer.Click += new System.EventHandler(this.mnuEditInMemoryViewer_Click); + // + // mnuToggleBreakpoint + // + this.mnuToggleBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Breakpoint; + this.mnuToggleBreakpoint.Name = "mnuToggleBreakpoint"; + this.mnuToggleBreakpoint.ShortcutKeyDisplayString = ""; + this.mnuToggleBreakpoint.Size = new System.Drawing.Size(253, 22); + this.mnuToggleBreakpoint.Text = "Toggle Breakpoint"; + this.mnuToggleBreakpoint.Click += new System.EventHandler(this.mnuToggleBreakpoint_Click); + // + // sepAddToWatch + // + this.sepAddToWatch.Name = "sepAddToWatch"; + this.sepAddToWatch.Size = new System.Drawing.Size(250, 6); + // + // mnuAddToWatch + // + this.mnuAddToWatch.Name = "mnuAddToWatch"; + this.mnuAddToWatch.ShortcutKeyDisplayString = "Ctrl+Click"; + this.mnuAddToWatch.Size = new System.Drawing.Size(253, 22); + this.mnuAddToWatch.Text = "Add to Watch"; + this.mnuAddToWatch.Click += new System.EventHandler(this.mnuAddToWatch_Click); + // + // mnuFindOccurrences + // + this.mnuFindOccurrences.Image = global::Mesen.GUI.Properties.Resources.Find; + this.mnuFindOccurrences.Name = "mnuFindOccurrences"; + this.mnuFindOccurrences.ShortcutKeyDisplayString = "Alt+Click"; + this.mnuFindOccurrences.Size = new System.Drawing.Size(253, 22); + this.mnuFindOccurrences.Text = "Find Occurrences"; + this.mnuFindOccurrences.Click += new System.EventHandler(this.mnuFindOccurrences_Click); + // + // toolStripMenuItem2 + // + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + this.toolStripMenuItem2.Size = new System.Drawing.Size(250, 6); + // + // mnuGoToLocation + // + this.mnuGoToLocation.Name = "mnuGoToLocation"; + this.mnuGoToLocation.ShortcutKeyDisplayString = "Double Click"; + this.mnuGoToLocation.Size = new System.Drawing.Size(253, 22); + this.mnuGoToLocation.Text = "Go to Location"; + this.mnuGoToLocation.Click += new System.EventHandler(this.mnuGoToLocation_Click); + // + // mnuShowInSplitView + // + this.mnuShowInSplitView.Image = global::Mesen.GUI.Properties.Resources.SplitView; + this.mnuShowInSplitView.Name = "mnuShowInSplitView"; + this.mnuShowInSplitView.ShortcutKeyDisplayString = "Ctrl+Alt+Click"; + this.mnuShowInSplitView.Size = new System.Drawing.Size(253, 22); + this.mnuShowInSplitView.Text = "Show in Split View"; + this.mnuShowInSplitView.Click += new System.EventHandler(this.mnuShowInSplitView_Click); + // + // sepNavigation + // + this.sepNavigation.Name = "sepNavigation"; + this.sepNavigation.Size = new System.Drawing.Size(250, 6); + // + // mnuNavigateBackward + // + this.mnuNavigateBackward.Image = global::Mesen.GUI.Properties.Resources.NavigateBack; + this.mnuNavigateBackward.Name = "mnuNavigateBackward"; + this.mnuNavigateBackward.Size = new System.Drawing.Size(253, 22); + this.mnuNavigateBackward.Text = "Navigate Backward"; + this.mnuNavigateBackward.Click += new System.EventHandler(this.mnuNavigateBackward_Click); + // + // mnuNavigateForward + // + this.mnuNavigateForward.Image = global::Mesen.GUI.Properties.Resources.NavigateForward; + this.mnuNavigateForward.Name = "mnuNavigateForward"; + this.mnuNavigateForward.Size = new System.Drawing.Size(253, 22); + this.mnuNavigateForward.Text = "Navigate Forward"; + this.mnuNavigateForward.Click += new System.EventHandler(this.mnuNavigateForward_Click); + // + // sepSwitchView + // + this.sepSwitchView.Name = "sepSwitchView"; + this.sepSwitchView.Size = new System.Drawing.Size(250, 6); + // + // mnuSwitchView + // + this.mnuSwitchView.Image = global::Mesen.GUI.Properties.Resources.SwitchView; + this.mnuSwitchView.Name = "mnuSwitchView"; + this.mnuSwitchView.Size = new System.Drawing.Size(253, 22); + this.mnuSwitchView.Text = "Switch to Source View"; + this.mnuSwitchView.Click += new System.EventHandler(this.mnuSwitchView_Click); + // + // mnuShowSourceAsComments + // + this.mnuShowSourceAsComments.CheckOnClick = true; + this.mnuShowSourceAsComments.Name = "mnuShowSourceAsComments"; + this.mnuShowSourceAsComments.Size = new System.Drawing.Size(253, 22); + this.mnuShowSourceAsComments.Text = "Show source code as comments"; + this.mnuShowSourceAsComments.Click += new System.EventHandler(this.mnuShowSourceAsComments_Click); + // + // CodeViewerActions + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "CodeViewerActions"; + this.contextMenu.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.ToolStripMenuItem mnuMarkSelectionAs; + private System.Windows.Forms.ToolStripMenuItem mnuMarkAsCode; + private System.Windows.Forms.ToolStripMenuItem mnuMarkAsData; + private System.Windows.Forms.ToolStripMenuItem mnuMarkAsUnidentifiedData; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem4; + private System.Windows.Forms.ToolStripMenuItem mnuEditSelectedCode; + private System.Windows.Forms.ToolStripMenuItem mnuEditSubroutine; + private System.Windows.Forms.ToolStripMenuItem mnuUndoPrgChrEdit; + private System.Windows.Forms.ToolStripMenuItem mnuCopySelection; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7; + private System.Windows.Forms.ToolStripMenuItem mnuShowNextStatement; + private System.Windows.Forms.ToolStripMenuItem mnuSetNextStatement; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem mnuShowCodeNotes; + private System.Windows.Forms.ToolStripMenuItem mnuShowByteCodeOnLeft; + private System.Windows.Forms.ToolStripMenuItem mnuShowByteCodeBelow; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5; + private System.Windows.Forms.ToolStripMenuItem mnuHideByteCode; + private System.Windows.Forms.ToolStripMenuItem mnuShowLineNotes; + private System.Windows.Forms.ToolStripMenuItem mnuPrgShowInline; + private System.Windows.Forms.ToolStripMenuItem mnuPrgAddressReplace; + private System.Windows.Forms.ToolStripMenuItem mnuPrgAddressBelow; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem6; + private System.Windows.Forms.ToolStripMenuItem mnuHidePrgAddresses; + private System.Windows.Forms.ToolStripSeparator sepEditLabel; + private System.Windows.Forms.ToolStripMenuItem mnuEditLabel; + private System.Windows.Forms.ToolStripMenuItem mnuEditInMemoryViewer; + private System.Windows.Forms.ToolStripMenuItem mnuToggleBreakpoint; + private System.Windows.Forms.ToolStripSeparator sepAddToWatch; + private System.Windows.Forms.ToolStripMenuItem mnuAddToWatch; + private System.Windows.Forms.ToolStripMenuItem mnuFindOccurrences; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem mnuGoToLocation; + private System.Windows.Forms.ToolStripMenuItem mnuShowInSplitView; + private System.Windows.Forms.ToolStripSeparator sepNavigation; + private System.Windows.Forms.ToolStripMenuItem mnuNavigateBackward; + private System.Windows.Forms.ToolStripMenuItem mnuNavigateForward; + private System.Windows.Forms.ToolStripSeparator sepSwitchView; + private System.Windows.Forms.ToolStripMenuItem mnuSwitchView; + public System.Windows.Forms.ContextMenuStrip contextMenu; + private System.Windows.Forms.ToolStripMenuItem mnuShowSourceAsComments; + } +} diff --git a/GUI.NET/Debugger/Controls/CodeViewerActions.cs b/GUI.NET/Debugger/Controls/CodeViewerActions.cs new file mode 100644 index 00000000..36388067 --- /dev/null +++ b/GUI.NET/Debugger/Controls/CodeViewerActions.cs @@ -0,0 +1,561 @@ +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; +using System.Globalization; + +namespace Mesen.GUI.Debugger.Controls +{ + public partial class CodeViewerActions : UserControl + { + public event SetNextStatementEventHandler OnSetNextStatement; + public event ShowInSplitViewEventHandler OnShowInSplitView; + public event SwitchToSourceEventHandler OnSwitchView; + + private int _lastClickedAddress = Int32.MaxValue; + private string _newWatchValue = string.Empty; + private string _lastWord = string.Empty; + private Point _lastLocation = Point.Empty; + private DebugViewInfo _config; + + public ICodeViewer Viewer { get; set; } + public bool SourceView { get; set; } + + public CodeViewerActions() + { + InitializeComponent(); + } + + public CodeViewerActions(ICodeViewer viewer, bool isSourceView) : this() + { + Viewer = viewer; + SourceView = isSourceView; + + this.InitShortcuts(); + } + + private void InitShortcuts() + { + mnuEditInMemoryViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer)); + mnuEditLabel.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditLabel)); + mnuSetNextStatement.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_SetNextStatement)); + mnuShowNextStatement.InitShortcut(this, nameof(DebuggerShortcutsConfig.GoToProgramCounter)); + mnuToggleBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint)); + + mnuUndoPrgChrEdit.InitShortcut(this, nameof(DebuggerShortcutsConfig.Undo)); + mnuCopySelection.InitShortcut(this, nameof(DebuggerShortcutsConfig.Copy)); + + mnuSwitchView.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_SwitchView)); + + if(!SourceView) { + mnuNavigateBackward.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateBack)); + mnuNavigateForward.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateForward)); + + mnuEditSelectedCode.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditSelectedCode)); + mnuEditSubroutine.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditSubroutine)); + + mnuMarkAsCode.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsCode)); + mnuMarkAsData.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsData)); + mnuMarkAsUnidentifiedData.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsUnidentified)); + } + } + + public void InitMenu(DebugViewInfo config) + { + _config = config; + mnuPrgShowInline.Checked = false; + mnuPrgAddressReplace.Checked = false; + mnuPrgAddressBelow.Checked = false; + mnuHidePrgAddresses.Checked = false; + + mnuShowByteCodeOnLeft.Checked = false; + mnuShowByteCodeBelow.Checked = false; + mnuHideByteCode.Checked = false; + + mnuShowSourceAsComments.Checked = config.ShowSourceAsComments; + + switch(config.ByteCodePosition) { + case ByteCodePosition.Left: + Viewer.CodeViewer.ShowContentNotes = true; + Viewer.CodeViewer.ShowSingleContentLineNotes = true; + this.mnuShowByteCodeOnLeft.Checked = true; + break; + + case ByteCodePosition.Below: + Viewer.CodeViewer.ShowContentNotes = true; + Viewer.CodeViewer.ShowSingleContentLineNotes = false; + this.mnuShowByteCodeBelow.Checked = true; + break; + + case ByteCodePosition.Hidden: + Viewer.CodeViewer.ShowContentNotes = false; + Viewer.CodeViewer.ShowSingleContentLineNotes = false; + this.mnuHideByteCode.Checked = true; + break; + } + + switch(config.PrgAddressPosition) { + case PrgAddressPosition.Inline: + Viewer.CodeViewer.ShowCompactPrgAddresses = true; + Viewer.CodeViewer.ShowLineNumberNotes = false; + Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; + this.mnuPrgShowInline.Checked = true; + break; + + case PrgAddressPosition.Replace: + Viewer.CodeViewer.ShowCompactPrgAddresses = false; + Viewer.CodeViewer.ShowLineNumberNotes = true; + Viewer.CodeViewer.ShowSingleLineLineNumberNotes = true; + this.mnuPrgAddressReplace.Checked = true; + break; + + case PrgAddressPosition.Below: + Viewer.CodeViewer.ShowCompactPrgAddresses = false; + Viewer.CodeViewer.ShowLineNumberNotes = true; + Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; + this.mnuPrgAddressBelow.Checked = true; + break; + + case PrgAddressPosition.Hidden: + Viewer.CodeViewer.ShowCompactPrgAddresses = false; + Viewer.CodeViewer.ShowLineNumberNotes = false; + Viewer.CodeViewer.ShowSingleLineLineNumberNotes = false; + this.mnuHidePrgAddresses.Checked = true; + break; + } + } + + private void UpdateConfig() + { + this.InitMenu(_config); + ConfigManager.ApplyChanges(); + } + + private void contextMenuCode_Opening(object sender, CancelEventArgs e) + { + UpdateContextMenuItemVisibility(true); + + int startAddress, endAddress; + string range; + GetSelectedAddressRange(out startAddress, out endAddress, out range); + mnuMarkSelectionAs.Enabled = startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress; + if(mnuMarkSelectionAs.Enabled) { + mnuMarkSelectionAs.Text = "Mark selection as... (" + range + ")"; + } else { + mnuMarkSelectionAs.Text = "Mark selection as..."; + } + } + + private void GetSelectedAddressRange(out int start, out int end, out string range) + { + int firstLineOfSelection = Viewer.CodeViewer.SelectionStart; + while(Viewer.CodeViewer.GetLineNumber(firstLineOfSelection) < 0) { + firstLineOfSelection++; + } + int firstLineAfterSelection = Viewer.CodeViewer.SelectionStart + Viewer.CodeViewer.SelectionLength + 1; + while(Viewer.CodeViewer.GetLineNumber(firstLineAfterSelection) < 0) { + firstLineAfterSelection++; + } + start = Viewer.CodeViewer.GetLineNumber(firstLineOfSelection); + end = Viewer.CodeViewer.GetLineNumber(firstLineAfterSelection) - 1; + + range = ""; + if(start >= 0 && end >= 0) { + range = $"${start.ToString("X4")} - ${end.ToString("X4")}"; + start = InteropEmu.DebugGetAbsoluteAddress((UInt32)start); + end = InteropEmu.DebugGetAbsoluteAddress((UInt32)end); + } + } + + private void MarkSelectionAs(CdlPrgFlags type) + { + int startAddress, endAddress; + string range; + GetSelectedAddressRange(out startAddress, out endAddress, out range); + + if(startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress) { + InteropEmu.DebugMarkPrgBytesAs((UInt32)startAddress, (UInt32)endAddress, type); + + frmDebugger debugger = DebugWindowManager.GetDebugger(); + if(debugger != null) { + debugger.UpdateDebugger(false); + } + } + } + + private void mnuMarkAsCode_Click(object sender, EventArgs e) + { + this.MarkSelectionAs(CdlPrgFlags.Code); + } + + private void mnuMarkAsData_Click(object sender, EventArgs e) + { + this.MarkSelectionAs(CdlPrgFlags.Data); + } + + private void mnuMarkAsUnidentifiedData_Click(object sender, EventArgs e) + { + this.MarkSelectionAs(CdlPrgFlags.None); + } + + private void mnuGoToLocation_Click(object sender, EventArgs e) + { + GoToLocation(); + } + + private void GoToLocation() + { + Viewer.ScrollToLineNumber((int)_lastClickedAddress); + } + + private void mnuAddToWatch_Click(object sender, EventArgs e) + { + AddWatch(); + } + + private void AddWatch() + { + WatchManager.AddWatch(_newWatchValue); + } + + private void mnuShowInSplitView_Click(object sender, EventArgs e) + { + ShowInSplitView(); + } + + private void ShowInSplitView() + { + this.OnShowInSplitView?.Invoke(Viewer, new AddressEventArgs() { Address = (UInt32)_lastClickedAddress }); + } + + private void mnuEditLabel_Click(object sender, EventArgs e) + { + if(UpdateContextMenu(_lastLocation)) { + AddressTypeInfo info = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)_lastClickedAddress, ref info); + if(info.Address >= 0) { + ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); + } + } + } + + private void mnuNavigateForward_Click(object sender, EventArgs e) + { + Viewer.CodeViewer.NavigateForward(); + } + + private void mnuNavigateBackward_Click(object sender, EventArgs e) + { + Viewer.CodeViewer.NavigateBackward(); + } + + private void mnuToggleBreakpoint_Click(object sender, EventArgs e) + { + this.ToggleBreakpoint(false); + } + + public void ToggleBreakpoint(bool toggleEnabledFlag) + { + int relativeAddress = Viewer.CodeViewer.CurrentLine; + AddressTypeInfo info = Viewer.GetAddressInfo(Viewer.CodeViewer.SelectedLine); + + BreakpointManager.ToggleBreakpoint(relativeAddress, info, toggleEnabledFlag); + } + + private void mnuShowByteCodeOnLeft_Click(object sender, EventArgs e) + { + _config.ByteCodePosition = ByteCodePosition.Left; + this.UpdateConfig(); + } + + private void mnuShowByteCodeBelow_Click(object sender, EventArgs e) + { + _config.ByteCodePosition = ByteCodePosition.Below; + this.UpdateConfig(); + } + + private void mnuHideByteCode_Click(object sender, EventArgs e) + { + _config.ByteCodePosition = ByteCodePosition.Hidden; + this.UpdateConfig(); + } + + private void mnuShowSourceAsComments_Click(object sender, EventArgs e) + { + _config.ShowSourceAsComments = mnuShowSourceAsComments.Checked; + this.UpdateConfig(); + } + + private void mnuShowInlineCompactDisplay_Click(object sender, EventArgs e) + { + _config.PrgAddressPosition = PrgAddressPosition.Inline; + this.UpdateConfig(); + } + + private void mnuReplaceCpuAddress_Click(object sender, EventArgs e) + { + _config.PrgAddressPosition = PrgAddressPosition.Replace; + this.UpdateConfig(); + } + + private void mnuBelowCpuAddress_Click(object sender, EventArgs e) + { + _config.PrgAddressPosition = PrgAddressPosition.Below; + this.UpdateConfig(); + } + + private void mnuHidePrgAddresses_Click(object sender, EventArgs e) + { + _config.PrgAddressPosition = PrgAddressPosition.Hidden; + this.UpdateConfig(); + } + + private void mnuCopySelection_Click(object sender, EventArgs e) + { + Viewer.CodeViewer.CopySelection(ConfigManager.Config.DebugInfo.CopyAddresses, ConfigManager.Config.DebugInfo.CopyByteCode); + } + + private void mnuShowNextStatement_Click(object sender, EventArgs e) + { + this.ScrollToActiveAddress(); + } + + public void ScrollToActiveAddress() + { + if(Viewer.ActiveAddress.HasValue) { + Viewer.ScrollToLineNumber((int)Viewer.ActiveAddress.Value); + } + } + + private void mnuShowLineNotes_Click(object sender, EventArgs e) + { + Viewer.CodeViewer.ShowLineNumberNotes = this.mnuShowLineNotes.Checked; + this.UpdateConfig(); + } + + private void mnuFindOccurrences_Click(object sender, EventArgs e) + { + Viewer.FindAllOccurrences(_lastWord, true, true); + } + + private void mnuUndoPrgChrEdit_Click(object sender, EventArgs e) + { + if(InteropEmu.DebugHasUndoHistory()) { + InteropEmu.DebugPerformUndo(); + frmDebugger debugger = DebugWindowManager.GetDebugger(); + if(debugger != null) { + debugger.UpdateDebugger(false); + } + } + } + + private void mnuSetNextStatement_Click(object sender, EventArgs e) + { + this.OnSetNextStatement?.Invoke(new AddressEventArgs() { Address = (UInt32)Viewer.CodeViewer.CurrentLine }); + } + + private void mnuEditSubroutine_Click(object sender, EventArgs e) + { + Viewer.EditSubroutine(); + } + + private void mnuEditSelectedCode_Click(object sender, EventArgs e) + { + Viewer.EditSelectedCode(); + } + + private void mnuEditInMemoryViewer_Click(object sender, EventArgs e) + { + if(UpdateContextMenu(_lastLocation)) { + DebugWindowManager.OpenMemoryViewer(_lastClickedAddress, false); + } + } + + private void mnuSwitchView_Click(object sender, EventArgs e) + { + if(Viewer.SymbolProvider != null) { + this.OnSwitchView?.Invoke(Viewer); + } + } + + public void ProcessMouseUp(Point location, MouseButtons button) + { + if(UpdateContextMenu(location)) { + if(button == MouseButtons.Left) { + if(ModifierKeys.HasFlag(Keys.Control) && ModifierKeys.HasFlag(Keys.Alt)) { + ShowInSplitView(); + } else if(ModifierKeys.HasFlag(Keys.Control)) { + AddWatch(); + } else if(ModifierKeys.HasFlag(Keys.Alt)) { + Viewer.FindAllOccurrences(_lastWord, true, true); + } + } + } + } + + public void ProcessMouseDoubleClick(Point location) + { + if(UpdateContextMenu(location) && mnuGoToLocation.Enabled) { + GoToLocation(); + } + } + + private void contextMenuCode_Closed(object sender, ToolStripDropDownClosedEventArgs e) + { + mnuEditSelectedCode.Enabled = true; + mnuEditSubroutine.Enabled = true; + } + + public void UpdateContextMenuItemVisibility(bool? visible = null) + { + mnuUndoPrgChrEdit.Enabled = InteropEmu.DebugHasUndoHistory(); + mnuShowNextStatement.Enabled = Viewer.ActiveAddress.HasValue; + mnuSetNextStatement.Enabled = Viewer.ActiveAddress.HasValue; + mnuEditSelectedCode.Enabled = mnuEditSubroutine.Enabled = InteropEmu.DebugIsExecutionStopped() && Viewer.CodeViewer.CurrentLine >= 0; + + if(visible.HasValue) { + mnuAddToWatch.Visible = visible.Value; + mnuEditLabel.Visible = visible.Value; + mnuGoToLocation.Visible = visible.Value; + mnuToggleBreakpoint.Visible = visible.Value; + sepAddToWatch.Visible = visible.Value; + sepEditLabel.Visible = visible.Value; + mnuFindOccurrences.Visible = visible.Value; + } + + if(SourceView) { + mnuMarkSelectionAs.Visible = false; + mnuShowCodeNotes.Visible = false; + + mnuFindOccurrences.Visible = false; + mnuEditSubroutine.Visible = false; + mnuEditSelectedCode.Visible = false; + mnuNavigateForward.Visible = false; + mnuNavigateBackward.Visible = false; + mnuEditLabel.Visible = false; + sepNavigation.Visible = false; + mnuShowSourceAsComments.Visible = false; + } + + if(Viewer.SymbolProvider == null) { + mnuShowSourceAsComments.Visible = false; + mnuSwitchView.Visible = false; + sepSwitchView.Visible = false; + } + } + + private bool UpdateContextMenu(Point mouseLocation) + { + _lastLocation = mouseLocation; + + UpdateContextMenuItemVisibility(true); + + mnuSwitchView.Text = SourceView ? "Switch to Disassembly View" : "Switch to Source View"; + + string word = Viewer.CodeViewer.GetWordUnderLocation(mouseLocation); + Ld65DbgImporter.SymbolInfo symbol = null; + CodeLabel codeLabel = null; + + if(!word.StartsWith("$")) { + codeLabel = LabelManager.GetLabel(word); + + if(Viewer.SymbolProvider != null) { + int rangeStart, rangeEnd; + if(Viewer.CodeViewer.GetNoteRangeAtLocation(mouseLocation.Y, out rangeStart, out rangeEnd)) { + symbol = Viewer.SymbolProvider.GetSymbol(word, rangeStart, rangeEnd); + if(symbol?.SegmentID == null) { + symbol = null; + } + } + } + } + + if(word.StartsWith("$") || codeLabel != null || symbol != null) { + //Cursor is on a numeric value or label + _lastWord = word; + + if(word.StartsWith("$")) { + //CPU Address + _lastClickedAddress = Int32.Parse(word.Substring(1), NumberStyles.AllowHexSpecifier); + _newWatchValue = "[$" + _lastClickedAddress.ToString("X") + "]"; + } else if(symbol != null) { + //Symbol + AddressTypeInfo addressInfo = (AddressTypeInfo)Viewer.SymbolProvider.GetSymbolAddressInfo(symbol); + _lastClickedAddress = (Int32)InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); + bool matchingLabelExists = codeLabel != null && codeLabel.Label == symbol.Name; + _newWatchValue = matchingLabelExists ? $"[{word}]" : $"[${_lastClickedAddress.ToString("X2")}]"; + } else if(codeLabel != null) { + //Label + _lastClickedAddress = (Int32)InteropEmu.DebugGetRelativeAddress(codeLabel.Address, codeLabel.AddressType); + _newWatchValue = "[" + word + "]"; + } + + mnuGoToLocation.Enabled = true; + mnuGoToLocation.Text = $"Go to Location ({word})"; + + mnuShowInSplitView.Enabled = true; + mnuShowInSplitView.Text = $"Show in Split View ({word})"; + + mnuAddToWatch.Enabled = true; + mnuAddToWatch.Text = $"Add to Watch ({word})"; + + mnuFindOccurrences.Enabled = true; + mnuFindOccurrences.Text = $"Find Occurrences ({word})"; + + mnuEditLabel.Enabled = true; + mnuEditLabel.Text = $"Edit Label ({word})"; + + mnuEditInMemoryViewer.Enabled = true; + mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({word})"; + + return true; + } else { + mnuGoToLocation.Enabled = false; + mnuGoToLocation.Text = "Go to Location"; + mnuShowInSplitView.Enabled = false; + mnuShowInSplitView.Text = "Show in Split View"; + mnuAddToWatch.Enabled = false; + mnuAddToWatch.Text = "Add to Watch"; + mnuFindOccurrences.Enabled = false; + mnuFindOccurrences.Text = "Find Occurrences"; + mnuEditLabel.Enabled = false; + mnuEditLabel.Text = "Edit Label"; + mnuEditInMemoryViewer.Enabled = false; + mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer"; + + if(mouseLocation.X < Viewer.CodeViewer.CodeMargin) { + _lastClickedAddress = Viewer.CodeViewer.GetLineNumberAtPosition(mouseLocation.Y); + } else { + _lastClickedAddress = Viewer.CodeViewer.LastSelectedLine; + } + + if(_lastClickedAddress >= 0) { + //Cursor is in the margin, over an address label + string address = $"${_lastClickedAddress.ToString("X4")}"; + _newWatchValue = $"[{address}]"; + _lastWord = address; + + mnuShowInSplitView.Enabled = true; + mnuShowInSplitView.Text = $"Show in Split View ({address})"; + mnuAddToWatch.Enabled = true; + mnuAddToWatch.Text = $"Add to Watch ({address})"; + mnuFindOccurrences.Enabled = true; + mnuFindOccurrences.Text = $"Find Occurrences ({address})"; + mnuEditLabel.Enabled = true; + mnuEditLabel.Text = $"Edit Label ({address})"; + mnuEditInMemoryViewer.Enabled = true; + mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({address})"; + return true; + } + + return false; + } + } + } +} diff --git a/GUI.NET/Debugger/Controls/CodeViewerActions.resx b/GUI.NET/Debugger/Controls/CodeViewerActions.resx new file mode 100644 index 00000000..9c222a09 --- /dev/null +++ b/GUI.NET/Debugger/Controls/CodeViewerActions.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/GUI.NET/Debugger/Controls/ICodeViewer.cs b/GUI.NET/Debugger/Controls/ICodeViewer.cs new file mode 100644 index 00000000..ccd723ba --- /dev/null +++ b/GUI.NET/Debugger/Controls/ICodeViewer.cs @@ -0,0 +1,38 @@ +using Mesen.GUI.Config; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.GUI.Debugger.Controls +{ + public delegate void SetNextStatementEventHandler(AddressEventArgs args); + public delegate void ShowInSplitViewEventHandler(ICodeViewer sender, AddressEventArgs args); + public delegate void SwitchToSourceEventHandler(ICodeViewer sender); + + public interface ICodeViewer + { + void ScrollToLineNumber(int lineNumber, bool scrollToTop = false); + void ScrollToAddress(AddressTypeInfo addressInfo, bool scrollToTop = false); + void SetConfig(DebugViewInfo config); + void EditSubroutine(); + void EditSelectedCode(); + + CodeViewerActions CodeViewerActions { get; } + ctrlScrollableTextbox CodeViewer { get; } + Ld65DbgImporter SymbolProvider { get; set; } + + UInt32? ActiveAddress { get; } + + void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase); + void SelectActiveAddress(UInt32 activeAddress); + void ClearActiveAddress(); + AddressTypeInfo GetAddressInfo(int lineIndex); + } + + public class AddressEventArgs : EventArgs + { + public UInt32 Address { get; set; } + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlCodeScrollbar.cs b/GUI.NET/Debugger/Controls/ctrlCodeScrollbar.cs index 10c94cea..72c30b5a 100644 --- a/GUI.NET/Debugger/Controls/ctrlCodeScrollbar.cs +++ b/GUI.NET/Debugger/Controls/ctrlCodeScrollbar.cs @@ -176,7 +176,7 @@ namespace Mesen.GUI.Debugger.Controls this._tmrScroll.Stop(); } - frmCodeTooltip _codeTooltip = null; + frmCodePreviewTooltip _codeTooltip = null; int _lastPreviewScrollPosition = -1; protected override void OnMouseMove(MouseEventArgs e) { @@ -269,6 +269,6 @@ namespace Mesen.GUI.Debugger.Controls Color GetMarkerColor(float position, int linesPerPixel); int GetActiveLine(); int GetSelectedLine(); - frmCodeTooltip GetPreview(int lineIndex); + frmCodePreviewTooltip GetPreview(int lineIndex); } } diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs index f5c9824e..a85124bb 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.Designer.cs @@ -28,44 +28,6 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.contextMenuCode = new System.Windows.Forms.ContextMenuStrip(this.components); - this.mnuMarkSelectionAs = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuMarkAsCode = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuMarkAsData = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuMarkAsUnidentifiedData = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuEditSelectedCode = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuEditSubroutine = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuUndoPrgChrEdit = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuCopySelection = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuShowNextStatement = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuSetNextStatement = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuShowCodeNotes = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuShowByteCodeOnLeft = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuShowByteCodeBelow = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuHideByteCode = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuShowLineNotes = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuPrgShowInline = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuPrgAddressReplace = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuPrgAddressBelow = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuHidePrgAddresses = new System.Windows.Forms.ToolStripMenuItem(); - this.sepEditLabel = new System.Windows.Forms.ToolStripSeparator(); - this.mnuEditLabel = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuEditInMemoryViewer = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); - this.sepAddToWatch = new System.Windows.Forms.ToolStripSeparator(); - this.mnuAddToWatch = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuFindOccurrences = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuGoToLocation = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuShowInSplitView = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuNavigateBackward = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuNavigateForward = new System.Windows.Forms.ToolStripMenuItem(); this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.ctrlCodeViewer = new Mesen.GUI.Debugger.ctrlScrollableTextbox(); this.contextMenuMargin = new System.Windows.Forms.ContextMenuStrip(this.components); @@ -73,333 +35,18 @@ this.mnuDisableBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRemoveBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); this.splitContainer = new System.Windows.Forms.SplitContainer(); - this.tlpSearchResults = new System.Windows.Forms.TableLayoutPanel(); - this.lstSearchResult = new System.Windows.Forms.ListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.picCloseOccurrenceList = new System.Windows.Forms.PictureBox(); - this.lblSearchResult = new System.Windows.Forms.Label(); - this.contextMenuCode.SuspendLayout(); + this.ctrlFindOccurrences = new Mesen.GUI.Debugger.Controls.ctrlFindOccurrences(); this.contextMenuMargin.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout(); this.splitContainer.SuspendLayout(); - this.tlpSearchResults.SuspendLayout(); - this.tableLayoutPanel2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picCloseOccurrenceList)).BeginInit(); this.SuspendLayout(); // - // contextMenuCode - // - this.contextMenuCode.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mnuMarkSelectionAs, - this.toolStripMenuItem4, - this.mnuEditSelectedCode, - this.mnuEditSubroutine, - this.mnuUndoPrgChrEdit, - this.mnuCopySelection, - this.toolStripMenuItem7, - this.mnuShowNextStatement, - this.mnuSetNextStatement, - this.toolStripMenuItem1, - this.mnuShowCodeNotes, - this.mnuShowLineNotes, - this.sepEditLabel, - this.mnuEditLabel, - this.mnuEditInMemoryViewer, - this.mnuToggleBreakpoint, - this.sepAddToWatch, - this.mnuAddToWatch, - this.mnuFindOccurrences, - this.toolStripMenuItem2, - this.mnuGoToLocation, - this.mnuShowInSplitView, - this.toolStripMenuItem3, - this.mnuNavigateBackward, - this.mnuNavigateForward}); - this.contextMenuCode.Name = "contextMenuWatch"; - this.contextMenuCode.Size = new System.Drawing.Size(259, 464); - this.contextMenuCode.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.contextMenuCode_Closed); - this.contextMenuCode.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuCode_Opening); - // - // mnuMarkSelectionAs - // - this.mnuMarkSelectionAs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mnuMarkAsCode, - this.mnuMarkAsData, - this.mnuMarkAsUnidentifiedData}); - this.mnuMarkSelectionAs.Name = "mnuMarkSelectionAs"; - this.mnuMarkSelectionAs.Size = new System.Drawing.Size(258, 22); - this.mnuMarkSelectionAs.Text = "Mark selection as..."; - // - // mnuMarkAsCode - // - this.mnuMarkAsCode.Image = global::Mesen.GUI.Properties.Resources.Accept; - this.mnuMarkAsCode.Name = "mnuMarkAsCode"; - this.mnuMarkAsCode.Size = new System.Drawing.Size(199, 22); - this.mnuMarkAsCode.Text = "Verified Code"; - this.mnuMarkAsCode.Click += new System.EventHandler(this.mnuMarkAsCode_Click); - // - // mnuMarkAsData - // - this.mnuMarkAsData.Image = global::Mesen.GUI.Properties.Resources.CheatCode; - this.mnuMarkAsData.Name = "mnuMarkAsData"; - this.mnuMarkAsData.Size = new System.Drawing.Size(199, 22); - this.mnuMarkAsData.Text = "Verified Data"; - this.mnuMarkAsData.Click += new System.EventHandler(this.mnuMarkAsData_Click); - // - // mnuMarkAsUnidentifiedData - // - this.mnuMarkAsUnidentifiedData.Image = global::Mesen.GUI.Properties.Resources.Help; - this.mnuMarkAsUnidentifiedData.Name = "mnuMarkAsUnidentifiedData"; - this.mnuMarkAsUnidentifiedData.Size = new System.Drawing.Size(199, 22); - this.mnuMarkAsUnidentifiedData.Text = "Unidentified Code/Data"; - this.mnuMarkAsUnidentifiedData.Click += new System.EventHandler(this.mnuMarkAsUnidentifiedData_Click); - // - // toolStripMenuItem4 - // - this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - this.toolStripMenuItem4.Size = new System.Drawing.Size(255, 6); - // - // mnuEditSelectedCode - // - this.mnuEditSelectedCode.Image = global::Mesen.GUI.Properties.Resources.Edit; - this.mnuEditSelectedCode.Name = "mnuEditSelectedCode"; - this.mnuEditSelectedCode.Size = new System.Drawing.Size(258, 22); - this.mnuEditSelectedCode.Text = "Edit Selected Code"; - this.mnuEditSelectedCode.Click += new System.EventHandler(this.mnuEditSelectedCode_Click); - // - // mnuEditSubroutine - // - this.mnuEditSubroutine.Image = global::Mesen.GUI.Properties.Resources.Edit; - this.mnuEditSubroutine.Name = "mnuEditSubroutine"; - this.mnuEditSubroutine.Size = new System.Drawing.Size(258, 22); - this.mnuEditSubroutine.Text = "Edit Subroutine"; - this.mnuEditSubroutine.Click += new System.EventHandler(this.mnuEditSubroutine_Click); - // - // mnuUndoPrgChrEdit - // - this.mnuUndoPrgChrEdit.Image = global::Mesen.GUI.Properties.Resources.Undo; - this.mnuUndoPrgChrEdit.Name = "mnuUndoPrgChrEdit"; - this.mnuUndoPrgChrEdit.Size = new System.Drawing.Size(258, 22); - this.mnuUndoPrgChrEdit.Text = "Undo PRG/CHR Edit"; - this.mnuUndoPrgChrEdit.Click += new System.EventHandler(this.mnuUndoPrgChrEdit_Click); - // - // mnuCopySelection - // - this.mnuCopySelection.Image = global::Mesen.GUI.Properties.Resources.Copy; - this.mnuCopySelection.Name = "mnuCopySelection"; - this.mnuCopySelection.Size = new System.Drawing.Size(258, 22); - this.mnuCopySelection.Text = "Copy Selection"; - this.mnuCopySelection.Click += new System.EventHandler(this.mnuCopySelection_Click); - // - // toolStripMenuItem7 - // - this.toolStripMenuItem7.Name = "toolStripMenuItem7"; - this.toolStripMenuItem7.Size = new System.Drawing.Size(255, 6); - // - // mnuShowNextStatement - // - this.mnuShowNextStatement.Name = "mnuShowNextStatement"; - this.mnuShowNextStatement.ShortcutKeyDisplayString = "Alt+*"; - this.mnuShowNextStatement.Size = new System.Drawing.Size(258, 22); - this.mnuShowNextStatement.Text = "Show Next Statement"; - this.mnuShowNextStatement.Click += new System.EventHandler(this.mnuShowNextStatement_Click); - // - // mnuSetNextStatement - // - this.mnuSetNextStatement.Name = "mnuSetNextStatement"; - this.mnuSetNextStatement.Size = new System.Drawing.Size(258, 22); - this.mnuSetNextStatement.Text = "Set Next Statement"; - this.mnuSetNextStatement.Click += new System.EventHandler(this.mnuSetNextStatement_Click); - // - // toolStripMenuItem1 - // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(255, 6); - // - // mnuShowCodeNotes - // - this.mnuShowCodeNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mnuShowByteCodeOnLeft, - this.mnuShowByteCodeBelow, - this.toolStripMenuItem5, - this.mnuHideByteCode}); - this.mnuShowCodeNotes.Name = "mnuShowCodeNotes"; - this.mnuShowCodeNotes.Size = new System.Drawing.Size(258, 22); - this.mnuShowCodeNotes.Text = "Byte Code Display"; - // - // mnuShowByteCodeOnLeft - // - this.mnuShowByteCodeOnLeft.Name = "mnuShowByteCodeOnLeft"; - this.mnuShowByteCodeOnLeft.Size = new System.Drawing.Size(130, 22); - this.mnuShowByteCodeOnLeft.Text = "On the left"; - this.mnuShowByteCodeOnLeft.Click += new System.EventHandler(this.mnuShowByteCodeOnLeft_Click); - // - // mnuShowByteCodeBelow - // - this.mnuShowByteCodeBelow.Name = "mnuShowByteCodeBelow"; - this.mnuShowByteCodeBelow.Size = new System.Drawing.Size(130, 22); - this.mnuShowByteCodeBelow.Text = "Below"; - this.mnuShowByteCodeBelow.Click += new System.EventHandler(this.mnuShowByteCodeBelow_Click); - // - // toolStripMenuItem5 - // - this.toolStripMenuItem5.Name = "toolStripMenuItem5"; - this.toolStripMenuItem5.Size = new System.Drawing.Size(127, 6); - // - // mnuHideByteCode - // - this.mnuHideByteCode.Name = "mnuHideByteCode"; - this.mnuHideByteCode.Size = new System.Drawing.Size(130, 22); - this.mnuHideByteCode.Text = "Hidden"; - this.mnuHideByteCode.Click += new System.EventHandler(this.mnuHideByteCode_Click); - // - // mnuShowLineNotes - // - this.mnuShowLineNotes.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.mnuPrgShowInline, - this.mnuPrgAddressReplace, - this.mnuPrgAddressBelow, - this.toolStripMenuItem6, - this.mnuHidePrgAddresses}); - this.mnuShowLineNotes.Name = "mnuShowLineNotes"; - this.mnuShowLineNotes.Size = new System.Drawing.Size(258, 22); - this.mnuShowLineNotes.Text = "PRG Address Display"; - this.mnuShowLineNotes.Click += new System.EventHandler(this.mnuShowLineNotes_Click); - // - // mnuPrgShowInline - // - this.mnuPrgShowInline.Name = "mnuPrgShowInline"; - this.mnuPrgShowInline.Size = new System.Drawing.Size(196, 22); - this.mnuPrgShowInline.Text = "Inline Compact Display"; - this.mnuPrgShowInline.Click += new System.EventHandler(this.mnuShowInlineCompactDisplay_Click); - // - // mnuPrgAddressReplace - // - this.mnuPrgAddressReplace.Name = "mnuPrgAddressReplace"; - this.mnuPrgAddressReplace.Size = new System.Drawing.Size(196, 22); - this.mnuPrgAddressReplace.Text = "Replace CPU address"; - this.mnuPrgAddressReplace.Click += new System.EventHandler(this.mnuReplaceCpuAddress_Click); - // - // mnuPrgAddressBelow - // - this.mnuPrgAddressBelow.Name = "mnuPrgAddressBelow"; - this.mnuPrgAddressBelow.Size = new System.Drawing.Size(196, 22); - this.mnuPrgAddressBelow.Text = "Below CPU address"; - this.mnuPrgAddressBelow.Click += new System.EventHandler(this.mnuBelowCpuAddress_Click); - // - // toolStripMenuItem6 - // - this.toolStripMenuItem6.Name = "toolStripMenuItem6"; - this.toolStripMenuItem6.Size = new System.Drawing.Size(193, 6); - // - // mnuHidePrgAddresses - // - this.mnuHidePrgAddresses.Name = "mnuHidePrgAddresses"; - this.mnuHidePrgAddresses.Size = new System.Drawing.Size(196, 22); - this.mnuHidePrgAddresses.Text = "Hidden"; - this.mnuHidePrgAddresses.Click += new System.EventHandler(this.mnuHidePrgAddresses_Click); - // - // sepEditLabel - // - this.sepEditLabel.Name = "sepEditLabel"; - this.sepEditLabel.Size = new System.Drawing.Size(255, 6); - // - // mnuEditLabel - // - this.mnuEditLabel.Image = global::Mesen.GUI.Properties.Resources.EditLabel; - this.mnuEditLabel.Name = "mnuEditLabel"; - this.mnuEditLabel.Size = new System.Drawing.Size(258, 22); - this.mnuEditLabel.Text = "Edit Label"; - this.mnuEditLabel.Click += new System.EventHandler(this.mnuEditLabel_Click); - // - // mnuEditInMemoryViewer - // - this.mnuEditInMemoryViewer.Image = global::Mesen.GUI.Properties.Resources.CheatCode; - this.mnuEditInMemoryViewer.Name = "mnuEditInMemoryViewer"; - this.mnuEditInMemoryViewer.Size = new System.Drawing.Size(258, 22); - this.mnuEditInMemoryViewer.Text = "Edit in Memory Viewer"; - this.mnuEditInMemoryViewer.Click += new System.EventHandler(this.mnuEditInMemoryViewer_Click); - // - // mnuToggleBreakpoint - // - this.mnuToggleBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Breakpoint; - this.mnuToggleBreakpoint.Name = "mnuToggleBreakpoint"; - this.mnuToggleBreakpoint.ShortcutKeyDisplayString = "F9"; - this.mnuToggleBreakpoint.Size = new System.Drawing.Size(258, 22); - this.mnuToggleBreakpoint.Text = "Toggle Breakpoint"; - this.mnuToggleBreakpoint.Click += new System.EventHandler(this.mnuToggleBreakpoint_Click); - // - // sepAddToWatch - // - this.sepAddToWatch.Name = "sepAddToWatch"; - this.sepAddToWatch.Size = new System.Drawing.Size(255, 6); - // - // mnuAddToWatch - // - this.mnuAddToWatch.Name = "mnuAddToWatch"; - this.mnuAddToWatch.ShortcutKeyDisplayString = "Ctrl+Click"; - this.mnuAddToWatch.Size = new System.Drawing.Size(258, 22); - this.mnuAddToWatch.Text = "Add to Watch"; - this.mnuAddToWatch.Click += new System.EventHandler(this.mnuAddToWatch_Click); - // - // mnuFindOccurrences - // - this.mnuFindOccurrences.Name = "mnuFindOccurrences"; - this.mnuFindOccurrences.ShortcutKeyDisplayString = "Alt+Click"; - this.mnuFindOccurrences.Size = new System.Drawing.Size(258, 22); - this.mnuFindOccurrences.Text = "Find Occurrences"; - this.mnuFindOccurrences.Click += new System.EventHandler(this.mnuFindOccurrences_Click); - // - // toolStripMenuItem2 - // - this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(255, 6); - // - // mnuGoToLocation - // - this.mnuGoToLocation.Name = "mnuGoToLocation"; - this.mnuGoToLocation.ShortcutKeyDisplayString = "Double Click"; - this.mnuGoToLocation.Size = new System.Drawing.Size(258, 22); - this.mnuGoToLocation.Text = "Go to Location"; - this.mnuGoToLocation.Click += new System.EventHandler(this.mnuGoToLocation_Click); - // - // mnuShowInSplitView - // - this.mnuShowInSplitView.Image = global::Mesen.GUI.Properties.Resources.SplitView; - this.mnuShowInSplitView.Name = "mnuShowInSplitView"; - this.mnuShowInSplitView.ShortcutKeyDisplayString = "Ctrl+Alt+Click"; - this.mnuShowInSplitView.Size = new System.Drawing.Size(258, 22); - this.mnuShowInSplitView.Text = "Show in Split View"; - this.mnuShowInSplitView.Click += new System.EventHandler(this.mnuShowInSplitView_Click); - // - // toolStripMenuItem3 - // - this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - this.toolStripMenuItem3.Size = new System.Drawing.Size(255, 6); - // - // mnuNavigateBackward - // - this.mnuNavigateBackward.Image = global::Mesen.GUI.Properties.Resources.NavigateBack; - this.mnuNavigateBackward.Name = "mnuNavigateBackward"; - this.mnuNavigateBackward.Size = new System.Drawing.Size(258, 22); - this.mnuNavigateBackward.Text = "Navigate Backward"; - this.mnuNavigateBackward.Click += new System.EventHandler(this.mnuNavigateBackward_Click); - // - // mnuNavigateForward - // - this.mnuNavigateForward.Image = global::Mesen.GUI.Properties.Resources.NavigateForward; - this.mnuNavigateForward.Name = "mnuNavigateForward"; - this.mnuNavigateForward.Size = new System.Drawing.Size(258, 22); - this.mnuNavigateForward.Text = "Navigate Forward"; - this.mnuNavigateForward.Click += new System.EventHandler(this.mnuNavigateForward_Click); - // // ctrlCodeViewer // this.ctrlCodeViewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.ctrlCodeViewer.CodeHighlightingEnabled = true; this.ctrlCodeViewer.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlCodeViewer.HideSelection = false; this.ctrlCodeViewer.Location = new System.Drawing.Point(0, 0); @@ -471,94 +118,20 @@ // // splitContainer.Panel2 // - this.splitContainer.Panel2.Controls.Add(this.tlpSearchResults); + this.splitContainer.Panel2.Controls.Add(this.ctrlFindOccurrences); this.splitContainer.Size = new System.Drawing.Size(479, 318); this.splitContainer.SplitterDistance = 150; this.splitContainer.TabIndex = 12; // - // tlpSearchResults + // ctrlFindOccurrences // - this.tlpSearchResults.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; - this.tlpSearchResults.ColumnCount = 1; - this.tlpSearchResults.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpSearchResults.Controls.Add(this.lstSearchResult, 0, 1); - this.tlpSearchResults.Controls.Add(this.tableLayoutPanel2, 0, 0); - this.tlpSearchResults.Dock = System.Windows.Forms.DockStyle.Fill; - this.tlpSearchResults.Location = new System.Drawing.Point(0, 0); - this.tlpSearchResults.Name = "tlpSearchResults"; - this.tlpSearchResults.RowCount = 2; - this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tlpSearchResults.Size = new System.Drawing.Size(479, 164); - this.tlpSearchResults.TabIndex = 12; - // - // lstSearchResult - // - this.lstSearchResult.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.lstSearchResult.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader2}); - this.lstSearchResult.Dock = System.Windows.Forms.DockStyle.Fill; - this.lstSearchResult.FullRowSelect = true; - this.lstSearchResult.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; - this.lstSearchResult.Location = new System.Drawing.Point(1, 24); - this.lstSearchResult.Margin = new System.Windows.Forms.Padding(0); - this.lstSearchResult.Name = "lstSearchResult"; - this.lstSearchResult.Size = new System.Drawing.Size(477, 139); - this.lstSearchResult.TabIndex = 9; - this.lstSearchResult.UseCompatibleStateImageBehavior = false; - this.lstSearchResult.View = System.Windows.Forms.View.Details; - this.lstSearchResult.SizeChanged += new System.EventHandler(this.lstSearchResult_SizeChanged); - this.lstSearchResult.DoubleClick += new System.EventHandler(this.lstSearchResult_DoubleClick); - // - // columnHeader1 - // - this.columnHeader1.Text = ""; - // - // columnHeader2 - // - this.columnHeader2.Text = ""; - this.columnHeader2.Width = 160; - // - // tableLayoutPanel2 - // - this.tableLayoutPanel2.ColumnCount = 2; - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel2.Controls.Add(this.picCloseOccurrenceList, 1, 0); - this.tableLayoutPanel2.Controls.Add(this.lblSearchResult, 0, 0); - this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel2.Location = new System.Drawing.Point(1, 1); - this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0); - this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 1; - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel2.Size = new System.Drawing.Size(477, 22); - this.tableLayoutPanel2.TabIndex = 11; - // - // picCloseOccurrenceList - // - this.picCloseOccurrenceList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.picCloseOccurrenceList.Cursor = System.Windows.Forms.Cursors.Hand; - this.picCloseOccurrenceList.Image = global::Mesen.GUI.Properties.Resources.Close; - this.picCloseOccurrenceList.Location = new System.Drawing.Point(458, 3); - this.picCloseOccurrenceList.Name = "picCloseOccurrenceList"; - this.picCloseOccurrenceList.Size = new System.Drawing.Size(16, 16); - this.picCloseOccurrenceList.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; - this.picCloseOccurrenceList.TabIndex = 10; - this.picCloseOccurrenceList.TabStop = false; - this.picCloseOccurrenceList.Click += new System.EventHandler(this.picCloseOccurrenceList_Click); - // - // lblSearchResult - // - this.lblSearchResult.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.lblSearchResult.AutoSize = true; - this.lblSearchResult.Location = new System.Drawing.Point(3, 4); - this.lblSearchResult.Name = "lblSearchResult"; - this.lblSearchResult.Size = new System.Drawing.Size(95, 13); - this.lblSearchResult.TabIndex = 11; - this.lblSearchResult.Text = "Search results for: "; + this.ctrlFindOccurrences.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlFindOccurrences.Location = new System.Drawing.Point(0, 0); + this.ctrlFindOccurrences.Name = "ctrlFindOccurrences"; + this.ctrlFindOccurrences.Size = new System.Drawing.Size(479, 164); + this.ctrlFindOccurrences.TabIndex = 0; + this.ctrlFindOccurrences.Viewer = null; + this.ctrlFindOccurrences.OnSearchResultsClosed += new System.EventHandler(this.ctrlFindOccurrences_OnSearchResultsClosed); // // ctrlDebuggerCode // @@ -567,16 +140,11 @@ this.Controls.Add(this.splitContainer); this.Name = "ctrlDebuggerCode"; this.Size = new System.Drawing.Size(479, 318); - this.contextMenuCode.ResumeLayout(false); this.contextMenuMargin.ResumeLayout(false); this.splitContainer.Panel1.ResumeLayout(false); this.splitContainer.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); this.splitContainer.ResumeLayout(false); - this.tlpSearchResults.ResumeLayout(false); - this.tableLayoutPanel2.ResumeLayout(false); - this.tableLayoutPanel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picCloseOccurrenceList)).EndInit(); this.ResumeLayout(false); } @@ -584,56 +152,12 @@ #endregion private System.Windows.Forms.ToolTip toolTip; - private System.Windows.Forms.ContextMenuStrip contextMenuCode; - private System.Windows.Forms.ToolStripMenuItem mnuShowNextStatement; - private System.Windows.Forms.ToolStripMenuItem mnuSetNextStatement; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; - private System.Windows.Forms.ToolStripSeparator sepEditLabel; - private System.Windows.Forms.ToolStripMenuItem mnuGoToLocation; - private System.Windows.Forms.ToolStripMenuItem mnuAddToWatch; private Mesen.GUI.Debugger.ctrlScrollableTextbox ctrlCodeViewer; - private System.Windows.Forms.ToolStripMenuItem mnuShowLineNotes; - private System.Windows.Forms.ToolStripMenuItem mnuShowCodeNotes; private System.Windows.Forms.ContextMenuStrip contextMenuMargin; private System.Windows.Forms.ToolStripMenuItem mnuRemoveBreakpoint; private System.Windows.Forms.ToolStripMenuItem mnuEditBreakpoint; private System.Windows.Forms.ToolStripMenuItem mnuDisableBreakpoint; - private System.Windows.Forms.ToolStripMenuItem mnuFindOccurrences; private System.Windows.Forms.SplitContainer splitContainer; - private System.Windows.Forms.TableLayoutPanel tlpSearchResults; - private System.Windows.Forms.ListView lstSearchResult; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; - private System.Windows.Forms.PictureBox picCloseOccurrenceList; - private System.Windows.Forms.Label lblSearchResult; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem3; - private System.Windows.Forms.ToolStripMenuItem mnuNavigateForward; - private System.Windows.Forms.ToolStripMenuItem mnuNavigateBackward; - private System.Windows.Forms.ToolStripMenuItem mnuEditLabel; - private System.Windows.Forms.ToolStripSeparator sepAddToWatch; - private System.Windows.Forms.ToolStripMenuItem mnuToggleBreakpoint; - private System.Windows.Forms.ToolStripMenuItem mnuShowByteCodeOnLeft; - private System.Windows.Forms.ToolStripMenuItem mnuShowByteCodeBelow; - private System.Windows.Forms.ToolStripMenuItem mnuHideByteCode; - private System.Windows.Forms.ToolStripMenuItem mnuPrgAddressReplace; - private System.Windows.Forms.ToolStripMenuItem mnuPrgAddressBelow; - private System.Windows.Forms.ToolStripMenuItem mnuHidePrgAddresses; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem6; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem7; - private System.Windows.Forms.ToolStripMenuItem mnuEditSubroutine; - private System.Windows.Forms.ToolStripMenuItem mnuEditSelectedCode; - private System.Windows.Forms.ToolStripMenuItem mnuCopySelection; - private System.Windows.Forms.ToolStripMenuItem mnuEditInMemoryViewer; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; - private System.Windows.Forms.ToolStripMenuItem mnuShowInSplitView; - private System.Windows.Forms.ToolStripMenuItem mnuMarkSelectionAs; - private System.Windows.Forms.ToolStripMenuItem mnuMarkAsCode; - private System.Windows.Forms.ToolStripMenuItem mnuMarkAsData; - private System.Windows.Forms.ToolStripMenuItem mnuMarkAsUnidentifiedData; - private System.Windows.Forms.ToolStripSeparator toolStripMenuItem4; - private System.Windows.Forms.ToolStripMenuItem mnuUndoPrgChrEdit; - private System.Windows.Forms.ToolStripMenuItem mnuPrgShowInline; + private Controls.ctrlFindOccurrences ctrlFindOccurrences; } } diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs index 15be8bca..8efc1f84 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs @@ -13,83 +13,45 @@ using Mesen.GUI.Controls; namespace Mesen.GUI.Debugger { - public partial class ctrlDebuggerCode : BaseScrollableTextboxUserControl + public partial class ctrlDebuggerCode : BaseScrollableTextboxUserControl, ICodeViewer { - public delegate void AddressEventHandler(ctrlDebuggerCode sender, AddressEventArgs args); - public delegate void WatchEventHandler(WatchEventArgs args); public delegate void AssemblerEventHandler(AssemblerEventArgs args); public event AssemblerEventHandler OnEditCode; - public event AddressEventHandler OnSetNextStatement; - public event AddressEventHandler OnScrollToAddress; - private DebugViewInfo _config; - List _lineNumbers = new List(10000); - List _lineNumberNotes = new List(10000); - List _lineMemoryType = new List(10000); - List _absoluteLineNumbers = new List(10000); - List _codeNotes = new List(10000); - List _codeLines = new List(10000); + private List _lineNumbers = new List(10000); + private List _lineNumberNotes = new List(10000); + private List _lineMemoryType = new List(10000); + private List _absoluteLineNumbers = new List(10000); + private List _codeNotes = new List(10000); + private List _codeLines = new List(10000); private HashSet _unexecutedAddresses = new HashSet(); private HashSet _verifiedDataAddresses = new HashSet(); private HashSet _speculativeCodeAddreses = new HashSet(); - Dictionary _codeContent = new Dictionary(10000); - Dictionary _codeComments = new Dictionary(10000); - Dictionary _codeByteCode = new Dictionary(10000); - List _addressing = new List(10000); - List _comments = new List(10000); - List _lineIndentations = new List(10000); + private Dictionary _codeContent = new Dictionary(10000); + private Dictionary _codeComments = new Dictionary(10000); + private Dictionary _codeByteCode = new Dictionary(10000); + private List _addressing = new List(10000); + private List _comments = new List(10000); + private List _lineIndentations = new List(10000); private UInt32? _currentActiveAddress { get; set; } = null; - private Form _codeTooltip = null; + private Point _previousLocation; + private DebugViewInfo _config; + private CodeTooltipManager _tooltipManager = null; + private CodeViewerActions _codeViewerActions; public ctrlDebuggerCode() { InitializeComponent(); - this.lstSearchResult.Font = new System.Drawing.Font(BaseControl.MonospaceFontFamily, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - splitContainer.Panel2Collapsed = true; + _tooltipManager = new CodeTooltipManager(this, this.ctrlCodeViewer); bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); if(!designMode) { - this.InitShortcuts(); - } - } + _codeViewerActions = new CodeViewerActions(this, false); - private void InitShortcuts() - { - mnuEditInMemoryViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditInMemoryViewer)); - mnuEditLabel.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditLabel)); - mnuEditSelectedCode.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditSelectedCode)); - mnuEditSubroutine.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_EditSubroutine)); - mnuNavigateBackward.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateBack)); - mnuNavigateForward.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_NavigateForward)); - mnuSetNextStatement.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_SetNextStatement)); - mnuShowNextStatement.InitShortcut(this, nameof(DebuggerShortcutsConfig.GoToProgramCounter)); - mnuToggleBreakpoint.InitShortcut(this, nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint)); - - mnuUndoPrgChrEdit.InitShortcut(this, nameof(DebuggerShortcutsConfig.Undo)); - mnuCopySelection.InitShortcut(this, nameof(DebuggerShortcutsConfig.Copy)); - - mnuMarkAsCode.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsCode)); - mnuMarkAsData.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsData)); - mnuMarkAsUnidentifiedData.InitShortcut(this, nameof(DebuggerShortcutsConfig.MarkAsUnidentified)); - } - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public List ContextMenuItems - { - get - { - List items = new List(); - foreach(ToolStripItem item in this.contextMenuCode.Items) { - items.Add(item); - } - return items; - } - - set - { - this.contextMenuCode.Items.AddRange(value.ToArray()); + ctrlFindOccurrences.Viewer = this; + splitContainer.Panel2Collapsed = true; } } @@ -97,67 +59,10 @@ namespace Mesen.GUI.Debugger { _config = config; - mnuPrgShowInline.Checked = false; - mnuPrgAddressReplace.Checked = false; - mnuPrgAddressBelow.Checked = false; - mnuHidePrgAddresses.Checked = false; + _codeViewerActions.InitMenu(config); - mnuShowByteCodeOnLeft.Checked = false; - mnuShowByteCodeBelow.Checked = false; - mnuHideByteCode.Checked = false; - - switch(config.ByteCodePosition) { - case ByteCodePosition.Left: - this.ctrlCodeViewer.ShowContentNotes = true; - this.ctrlCodeViewer.ShowSingleContentLineNotes = true; - this.mnuShowByteCodeOnLeft.Checked = true; - break; - - case ByteCodePosition.Below: - this.ctrlCodeViewer.ShowContentNotes = true; - this.ctrlCodeViewer.ShowSingleContentLineNotes = false; - this.mnuShowByteCodeBelow.Checked = true; - break; - - case ByteCodePosition.Hidden: - this.ctrlCodeViewer.ShowContentNotes = false; - this.ctrlCodeViewer.ShowSingleContentLineNotes = false; - this.mnuHideByteCode.Checked = true; - break; - } - - switch(config.PrgAddressPosition) { - case PrgAddressPosition.Inline: - this.ctrlCodeViewer.ShowCompactPrgAddresses = true; - this.ctrlCodeViewer.ShowLineNumberNotes = false; - this.ctrlCodeViewer.ShowSingleLineLineNumberNotes = false; - this.mnuPrgShowInline.Checked = true; - break; - - case PrgAddressPosition.Replace: - this.ctrlCodeViewer.ShowCompactPrgAddresses = false; - this.ctrlCodeViewer.ShowLineNumberNotes = true; - this.ctrlCodeViewer.ShowSingleLineLineNumberNotes = true; - this.mnuPrgAddressReplace.Checked = true; - break; - - case PrgAddressPosition.Below: - this.ctrlCodeViewer.ShowCompactPrgAddresses = false; - this.ctrlCodeViewer.ShowLineNumberNotes = true; - this.ctrlCodeViewer.ShowSingleLineLineNumberNotes = false; - this.mnuPrgAddressBelow.Checked = true; - break; - - case PrgAddressPosition.Hidden: - this.ctrlCodeViewer.ShowCompactPrgAddresses = false; - this.ctrlCodeViewer.ShowLineNumberNotes = false; - this.ctrlCodeViewer.ShowSingleLineLineNumberNotes = false; - this.mnuHidePrgAddresses.Checked = true; - break; - } - - if(this.TextZoom != config.TextZoom) { - this.TextZoom = config.TextZoom; + if(this.ctrlCodeViewer.TextZoom != config.TextZoom) { + this.ctrlCodeViewer.TextZoom = config.TextZoom; } } @@ -172,6 +77,13 @@ namespace Mesen.GUI.Debugger get { return this.ctrlCodeViewer; } } + private Ld65DbgImporter _symbolProvider; + public Ld65DbgImporter SymbolProvider + { + get { return _symbolProvider; } + set { _symbolProvider = value; } + } + private string _code; private bool _codeChanged; public string Code @@ -182,36 +94,28 @@ namespace Mesen.GUI.Debugger if(value != null) { _codeChanged = true; _code = value; + _tooltipManager.Code = value; UpdateCode(); } } } - public bool ShowScrollbars - { - get { return this.ctrlCodeViewer.ShowScrollbars; } - set { this.ctrlCodeViewer.ShowScrollbars = value; } - } - public bool ShowMemoryValues { get { return this.ctrlCodeViewer.ShowMemoryValues; } set { this.ctrlCodeViewer.ShowMemoryValues = value; } } + public ctrlScrollableTextbox CodeViewer { get { return this.ctrlCodeViewer; } } + public CodeViewerActions CodeViewerActions { get { return _codeViewerActions; } } + public uint? ActiveAddress { get { return _currentActiveAddress; } } + public void SelectActiveAddress(UInt32 address) { this.SetActiveAddress(address); this.ctrlCodeViewer.ScrollToLineNumber((int)address, eHistoryType.OnScroll); } - public void ScrollToActiveAddress() - { - if(_currentActiveAddress.HasValue) { - this.ctrlCodeViewer.ScrollToLineNumber((int)_currentActiveAddress.Value); - } - } - public void SetActiveAddress(UInt32 address) { _currentActiveAddress = address; @@ -225,11 +129,19 @@ namespace Mesen.GUI.Debugger public void UpdateLineColors() { this.ctrlCodeViewer.StyleProvider = new LineStyleProvider(this); - if(this.ShowScrollbars) { + if(this.ctrlCodeViewer.ShowScrollbars) { this.ctrlCodeViewer.ScrollbarColorProvider = new ScrollbarColorProvider(this); } } + public void ScrollToAddress(AddressTypeInfo addressInfo, bool scrollToTop = false) + { + int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); + if(relativeAddress >= 0) { + this.ctrlCodeViewer.ScrollToLineNumber(relativeAddress, eHistoryType.Always , scrollToTop); + } + } + public List GetCode(out int byteLength, ref int startAddress, int endAddress = -1) { List result = new List(); @@ -426,264 +338,41 @@ namespace Mesen.GUI.Debugger } } - #region Events - private Point _previousLocation; - private bool _preventCloseTooltip = false; - private string _hoverLastWord = ""; - private int _hoverLastLineAddress = -1; - - private void ShowTooltip(string word, Dictionary values, int address, int lineAddress) - { - if(_hoverLastWord != word || _hoverLastLineAddress != lineAddress || _codeTooltip == null) { - if(!_preventCloseTooltip && _codeTooltip != null) { - _codeTooltip.Close(); - _codeTooltip = null; - } - - if(ConfigManager.Config.DebugInfo.ShowOpCodeTooltips && frmOpCodeTooltip.IsOpCode(word)) { - _codeTooltip = new frmOpCodeTooltip(word, lineAddress); - } else { - bool isPrgRom = false; - if(address >= 0 && ConfigManager.Config.DebugInfo.ShowCodePreview) { - AddressTypeInfo addressInfo = new AddressTypeInfo(); - InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)address, ref addressInfo); - isPrgRom = addressInfo.Type == AddressType.PrgRom; - } - - _codeTooltip = new frmCodeTooltip(values, isPrgRom ? address : -1, isPrgRom ? _code : null); - } - _codeTooltip.Left = Cursor.Position.X + 10; - _codeTooltip.Top = Cursor.Position.Y + 10; - _codeTooltip.Show(this); - } - _codeTooltip.Left = Cursor.Position.X + 10; - _codeTooltip.Top = Cursor.Position.Y + 10; - - _preventCloseTooltip = true; - _hoverLastWord = word; - _hoverLastLineAddress = lineAddress; - } - private void ctrlCodeViewer_MouseLeave(object sender, EventArgs e) { - if(_codeTooltip != null) { - _codeTooltip.Close(); - _codeTooltip = null; - } + _tooltipManager.Close(true); } private void ctrlCodeViewer_MouseMove(object sender, MouseEventArgs e) { - //Always enable to allow F2 shortcut - mnuEditLabel.Enabled = true; - if(e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { this.ctrlCodeViewer.ContextMenuStrip = contextMenuMargin; } else { - this.ctrlCodeViewer.ContextMenuStrip = contextMenuCode; + this.ctrlCodeViewer.ContextMenuStrip = _codeViewerActions.contextMenu; } - if(_previousLocation != e.Location) { - if(!_preventCloseTooltip && _codeTooltip != null) { - _codeTooltip.Close(); - _codeTooltip = null; - } - _preventCloseTooltip = false; - - string word = GetWordUnderLocation(e.Location); - if(word.StartsWith("$")) { - try { - UInt32 address = UInt32.Parse(word.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier); - - AddressTypeInfo info = new AddressTypeInfo(); - InteropEmu.DebugGetAbsoluteAddressAndType(address, ref info); - - if(info.Address >= 0) { - CodeLabel label = LabelManager.GetLabel((UInt32)info.Address, info.Type); - if(label == null) { - DisplayAddressTooltip(word, address); - } else { - DisplayLabelTooltip(word, label); - } - } else { - DisplayAddressTooltip(word, address); - } - } catch { } - } else { - CodeLabel label = LabelManager.GetLabel(word); - - if(label != null) { - DisplayLabelTooltip(word, label); - } else if(ConfigManager.Config.DebugInfo.ShowOpCodeTooltips && frmOpCodeTooltip.IsOpCode(word)) { - ShowTooltip(word, null, -1, ctrlCodeViewer.GetLineNumberAtPosition(e.Y)); - } - } - _previousLocation = e.Location; - } - } - - private void DisplayAddressTooltip(string word, UInt32 address) - { - byte byteValue = InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, address); - UInt16 wordValue = (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, address+1) << 8)); - - var values = new Dictionary() { - { "Address", "$" + address.ToString("X4") }, - { "Value", $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" } - }; - - ShowTooltip(word, values, (int)address, -1); - } - - private void DisplayLabelTooltip(string word, CodeLabel label) - { - Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType); - byte byteValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress) : (byte)0; - UInt16 wordValue = relativeAddress >= 0 ? (UInt16)(byteValue | (InteropEmu.DebugGetMemoryValue(DebugMemoryType.CpuMemory, (UInt32)relativeAddress+1) << 8)) : (UInt16)0; - int address = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType); - var values = new Dictionary() { - { "Label", label.Label }, - { "Address", "$" + address.ToString("X4") }, - { "Value", (relativeAddress >= 0 ? $"${byteValue.ToString("X2")} (byte){Environment.NewLine}${wordValue.ToString("X4")} (word)" : "n/a") }, - }; - - if(!string.IsNullOrWhiteSpace(label.Comment)) { - values["Comment"] = label.Comment; - } - - ShowTooltip(word, values, address, -1); - } - - private bool UpdateContextMenu(Point mouseLocation) - { - UpdateContextMenuItemVisibility(true); - - string word = GetWordUnderLocation(mouseLocation); - if(word.StartsWith("$") || LabelManager.GetLabel(word) != null) { - //Cursor is on a numeric value or label - _lastWord = word; - - if(word.StartsWith("$")) { - _lastClickedAddress = Int32.Parse(word.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier); - _newWatchValue = "[$" + _lastClickedAddress.ToString("X") + "]"; - } else { - _lastClickedAddress = (Int32)InteropEmu.DebugGetRelativeAddress(LabelManager.GetLabel(word).Address, LabelManager.GetLabel(word).AddressType); - _newWatchValue = "[" + word + "]"; - } - - mnuGoToLocation.Enabled = true; - mnuGoToLocation.Text = $"Go to Location ({word})"; - - mnuShowInSplitView.Enabled = true; - mnuShowInSplitView.Text = $"Show in Split View ({word})"; - - mnuAddToWatch.Enabled = true; - mnuAddToWatch.Text = $"Add to Watch ({word})"; - - mnuFindOccurrences.Enabled = true; - mnuFindOccurrences.Text = $"Find Occurrences ({word})"; - - mnuEditLabel.Enabled = true; - mnuEditLabel.Text = $"Edit Label ({word})"; - - mnuEditInMemoryViewer.Enabled = true; - mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({word})"; - - return true; - } else { - mnuGoToLocation.Enabled = false; - mnuGoToLocation.Text = "Go to Location"; - mnuShowInSplitView.Enabled = false; - mnuShowInSplitView.Text = "Show in Split View"; - mnuAddToWatch.Enabled = false; - mnuAddToWatch.Text = "Add to Watch"; - mnuFindOccurrences.Enabled = false; - mnuFindOccurrences.Text = "Find Occurrences"; - mnuEditLabel.Enabled = false; - mnuEditLabel.Text = "Edit Label"; - mnuEditInMemoryViewer.Enabled = false; - mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer"; - - - if(mouseLocation.X < this.ctrlCodeViewer.CodeMargin) { - _lastClickedAddress = ctrlCodeViewer.GetLineNumberAtPosition(mouseLocation.Y); - } else { - _lastClickedAddress = ctrlCodeViewer.LastSelectedLine; - } - - if(_lastClickedAddress >= 0) { - //Cursor is in the margin, over an address label - string address = $"${_lastClickedAddress.ToString("X4")}"; - _newWatchValue = $"[{address}]"; - _lastWord = address; - - mnuShowInSplitView.Enabled = true; - mnuShowInSplitView.Text = $"Show in Split View ({address})"; - mnuAddToWatch.Enabled = true; - mnuAddToWatch.Text = $"Add to Watch ({address})"; - mnuFindOccurrences.Enabled = true; - mnuFindOccurrences.Text = $"Find Occurrences ({address})"; - mnuEditLabel.Enabled = true; - mnuEditLabel.Text = $"Edit Label ({address})"; - mnuEditInMemoryViewer.Enabled = true; - mnuEditInMemoryViewer.Text = $"Edit in Memory Viewer ({address})"; - return true; - } - - return false; - } + _previousLocation = e.Location; + _tooltipManager.ProcessMouseMove(e.Location); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - this.UpdateContextMenuItemVisibility(mnuAddToWatch.Visible); + _codeViewerActions.UpdateContextMenuItemVisibility(); return base.ProcessCmdKey(ref msg, keyData); } - - public void UpdateContextMenuItemVisibility(bool visible) - { - mnuUndoPrgChrEdit.Enabled = InteropEmu.DebugHasUndoHistory(); - mnuShowNextStatement.Enabled = _currentActiveAddress.HasValue; - mnuSetNextStatement.Enabled = _currentActiveAddress.HasValue; - mnuEditSelectedCode.Enabled = mnuEditSubroutine.Enabled = InteropEmu.DebugIsExecutionStopped() && ctrlCodeViewer.CurrentLine >= 0; - - mnuAddToWatch.Visible = visible; - mnuFindOccurrences.Visible = visible; - mnuEditLabel.Visible = visible; - mnuGoToLocation.Visible = visible; - mnuToggleBreakpoint.Visible = visible; - sepAddToWatch.Visible = visible; - sepEditLabel.Visible = visible; - } - - int _lastClickedAddress = Int32.MaxValue; - string _newWatchValue = string.Empty; - string _lastWord = string.Empty; + private void ctrlCodeViewer_MouseUp(object sender, MouseEventArgs e) { - if(UpdateContextMenu(e.Location)) { - if(e.Button == MouseButtons.Left) { - if(ModifierKeys.HasFlag(Keys.Control) && ModifierKeys.HasFlag(Keys.Alt)) { - ShowInSplitView(); - } else if(ModifierKeys.HasFlag(Keys.Control)) { - AddWatch(); - } else if(ModifierKeys.HasFlag(Keys.Alt)) { - FindAllOccurrences(_lastWord, true, true); - } - } - } + _codeViewerActions.ProcessMouseUp(e.Location, e.Button); } Breakpoint _lineBreakpoint = null; private void ctrlCodeViewer_MouseDown(object sender, MouseEventArgs e) { - if(_codeTooltip != null) { - _codeTooltip.Close(); - _codeTooltip = null; - } + _tooltipManager.Close(true); int relativeAddress = ctrlCodeViewer.GetLineNumberAtPosition(e.Y); - AddressTypeInfo info = GetLineAddressTypeInfo(ctrlCodeViewer.GetLineIndexAtPosition(e.Y)); + AddressTypeInfo info = GetAddressInfo(ctrlCodeViewer.GetLineIndexAtPosition(e.Y)); _lineBreakpoint = BreakpointManager.GetMatchingBreakpoint(relativeAddress, info); if(e.Button == MouseButtons.Left && e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { @@ -691,7 +380,7 @@ namespace Mesen.GUI.Debugger } } - private AddressTypeInfo GetLineAddressTypeInfo(int lineNumber) + public AddressTypeInfo GetAddressInfo(int lineNumber) { AddressTypeInfo info = new AddressTypeInfo(); info.Address = this._absoluteLineNumbers[lineNumber]; @@ -706,26 +395,21 @@ namespace Mesen.GUI.Debugger private void ctrlCodeViewer_ScrollPositionChanged(object sender, EventArgs e) { - if(_codeTooltip != null) { - _codeTooltip.Close(); - _codeTooltip = null; - } + _tooltipManager.Close(true); } private void ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e) { if(e.Location.X > this.ctrlCodeViewer.CodeMargin / 2 && e.Location.X < this.ctrlCodeViewer.CodeMargin) { - AddressTypeInfo info = GetLineAddressTypeInfo(ctrlCodeViewer.GetLineIndexAtPosition(e.Y)); + AddressTypeInfo info = GetAddressInfo(ctrlCodeViewer.GetLineIndexAtPosition(e.Y)); if(info.Address >= 0) { ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); } - } else if(UpdateContextMenu(e.Location) && mnuGoToLocation.Enabled) { - GoToLocation(); + } else{ + _codeViewerActions.ProcessMouseDoubleClick(e.Location); } } - #region Context Menu - private void contextMenuMargin_Opening(object sender, CancelEventArgs e) { if(_lineBreakpoint == null) { @@ -750,202 +434,13 @@ namespace Mesen.GUI.Debugger _lineBreakpoint.SetEnabled(!_lineBreakpoint.Enabled); } - private void contextMenuCode_Opening(object sender, CancelEventArgs e) - { - UpdateContextMenuItemVisibility(true); - - int startAddress, endAddress; - string range; - GetSelectedAddressRange(out startAddress, out endAddress, out range); - mnuMarkSelectionAs.Enabled = startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress; - if(mnuMarkSelectionAs.Enabled) { - mnuMarkSelectionAs.Text = "Mark selection as... (" + range + ")"; - } else { - mnuMarkSelectionAs.Text = "Mark selection as..."; - } - } - - private void contextMenuCode_Closed(object sender, ToolStripDropDownClosedEventArgs e) - { - mnuEditSelectedCode.Enabled = true; - mnuEditSubroutine.Enabled = true; - } - - private void mnuShowNextStatement_Click(object sender, EventArgs e) - { - this.ScrollToActiveAddress(); - } - - private void mnuShowLineNotes_Click(object sender, EventArgs e) - { - this.ctrlCodeViewer.ShowLineNumberNotes = this.mnuShowLineNotes.Checked; - this.UpdateConfig(); - } - - private void mnuGoToLocation_Click(object sender, EventArgs e) - { - GoToLocation(); - } - - private void mnuFindOccurrences_Click(object sender, EventArgs e) - { - this.FindAllOccurrences(_lastWord, true, true); - } - - public void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) - { - this.lstSearchResult.Items.Clear(); - foreach(Tuple searchResult in this.ctrlCodeViewer.FindAllOccurrences(text, matchWholeWord, matchCase)) { - var item = this.lstSearchResult.Items.Add(searchResult.Item1.ToString("X4")); - item.Tag = searchResult.Item2; - item.SubItems.Add(searchResult.Item3); - item.SubItems.Add(""); - } - this.lblSearchResult.Text = $"Search results for: {text} ({this.lstSearchResult.Items.Count} results)"; - this.lstSearchResult.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); - this.lstSearchResult.Columns[0].Width += 20; - this.lstSearchResult.Columns[1].Width = Math.Max(this.lstSearchResult.Columns[1].Width, this.lstSearchResult.Width - this.lstSearchResult.Columns[0].Width - 24); - this.splitContainer.Panel2Collapsed = false; - } - - private void lstSearchResult_SizeChanged(object sender, EventArgs e) - { - this.lstSearchResult.SizeChanged -= lstSearchResult_SizeChanged; - this.lstSearchResult.Columns[1].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); - this.lstSearchResult.Columns[1].Width = Math.Max(this.lstSearchResult.Columns[1].Width, this.lstSearchResult.Width - this.lstSearchResult.Columns[0].Width - 24); - this.lstSearchResult.SizeChanged += lstSearchResult_SizeChanged; - } - - private void picCloseOccurrenceList_Click(object sender, EventArgs e) - { - this.splitContainer.Panel2Collapsed = true; - } - - private void lstSearchResult_DoubleClick(object sender, EventArgs e) - { - if(lstSearchResult.SelectedItems.Count > 0) { - int lineIndex = (int)lstSearchResult.SelectedItems[0].Tag; - this.ctrlCodeViewer.ScrollToLineIndex(lineIndex); - } - } - - private void mnuAddToWatch_Click(object sender, EventArgs e) - { - AddWatch(); - } - - private void GoToLocation() - { - this.ctrlCodeViewer.ScrollToLineNumber((int)_lastClickedAddress); - } - - private void mnuShowInSplitView_Click(object sender, EventArgs e) - { - ShowInSplitView(); - } - - private void ShowInSplitView() - { - this.OnScrollToAddress?.Invoke(this, new AddressEventArgs() { Address = (UInt32)_lastClickedAddress }); - } - - private void AddWatch() - { - WatchManager.AddWatch(_newWatchValue); - } - - private void mnuSetNextStatement_Click(object sender, EventArgs e) - { - this.OnSetNextStatement?.Invoke(this, new AddressEventArgs() { Address = (UInt32)this.ctrlCodeViewer.CurrentLine }); - } - private void ctrlCodeViewer_TextZoomChanged(object sender, EventArgs e) { - _config.TextZoom = this.TextZoom; + _config.TextZoom = this.ctrlCodeViewer.TextZoom; UpdateConfig(); } - private void mnuEditLabel_Click(object sender, EventArgs e) - { - if(UpdateContextMenu(_previousLocation)) { - AddressTypeInfo info = new AddressTypeInfo(); - InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)_lastClickedAddress, ref info); - if(info.Address >= 0) { - ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); - } - } - } - - private void mnuNavigateForward_Click(object sender, EventArgs e) - { - this.ctrlCodeViewer.NavigateForward(); - } - - private void mnuNavigateBackward_Click(object sender, EventArgs e) - { - this.ctrlCodeViewer.NavigateBackward(); - } - - private void mnuToggleBreakpoint_Click(object sender, EventArgs e) - { - this.ToggleBreakpoint(false); - } - - public void ToggleBreakpoint(bool toggleEnabledFlag) - { - int relativeAddress = ctrlCodeViewer.CurrentLine; - AddressTypeInfo info = GetLineAddressTypeInfo(ctrlCodeViewer.SelectedLine); - - BreakpointManager.ToggleBreakpoint(relativeAddress, info, toggleEnabledFlag); - } - - #endregion - - #endregion - - private void mnuShowByteCodeOnLeft_Click(object sender, EventArgs e) - { - _config.ByteCodePosition = ByteCodePosition.Left; - this.UpdateConfig(); - } - - private void mnuShowByteCodeBelow_Click(object sender, EventArgs e) - { - _config.ByteCodePosition = ByteCodePosition.Below; - this.UpdateConfig(); - } - - private void mnuHideByteCode_Click(object sender, EventArgs e) - { - _config.ByteCodePosition = ByteCodePosition.Hidden; - this.UpdateConfig(); - } - - private void mnuShowInlineCompactDisplay_Click(object sender, EventArgs e) - { - _config.PrgAddressPosition = PrgAddressPosition.Inline; - this.UpdateConfig(); - } - - private void mnuReplaceCpuAddress_Click(object sender, EventArgs e) - { - _config.PrgAddressPosition = PrgAddressPosition.Replace; - this.UpdateConfig(); - } - - private void mnuBelowCpuAddress_Click(object sender, EventArgs e) - { - _config.PrgAddressPosition = PrgAddressPosition.Below; - this.UpdateConfig(); - } - - private void mnuHidePrgAddresses_Click(object sender, EventArgs e) - { - _config.PrgAddressPosition = PrgAddressPosition.Hidden; - this.UpdateConfig(); - } - - private void mnuEditSubroutine_Click(object sender, EventArgs e) + public void EditSubroutine() { int currentLine = this.GetCurrentLine(); if(currentLine != -1 && InteropEmu.DebugIsExecutionStopped()) { @@ -955,7 +450,7 @@ namespace Mesen.GUI.Debugger } } - private void mnuEditSelectedCode_Click(object sender, EventArgs e) + public void EditSelectedCode() { int startAddress = this.GetCurrentLine(); int endAddress = this.ctrlCodeViewer.LastSelectedLine; @@ -966,82 +461,18 @@ namespace Mesen.GUI.Debugger } } - private void mnuCopySelection_Click(object sender, EventArgs e) + public void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) { - this.ctrlCodeViewer.CopySelection(ConfigManager.Config.DebugInfo.CopyAddresses, ConfigManager.Config.DebugInfo.CopyByteCode); + ctrlFindOccurrences.FindAllOccurrences(text, matchWholeWord, matchCase); + this.splitContainer.Panel2Collapsed = false; } - private void mnuEditInMemoryViewer_Click(object sender, EventArgs e) + private void ctrlFindOccurrences_OnSearchResultsClosed(object sender, EventArgs e) { - if(UpdateContextMenu(_previousLocation)) { - DebugWindowManager.OpenMemoryViewer(_lastClickedAddress); - } + this.splitContainer.Panel2Collapsed = true; } - private void GetSelectedAddressRange(out int start, out int end, out string range) - { - int firstLineOfSelection = this.ctrlCodeViewer.SelectionStart; - while(this.ctrlCodeViewer.GetLineNumber(firstLineOfSelection) < 0) { - firstLineOfSelection++; - } - int firstLineAfterSelection = this.ctrlCodeViewer.SelectionStart + this.ctrlCodeViewer.SelectionLength + 1; - while(this.ctrlCodeViewer.GetLineNumber(firstLineAfterSelection) < 0) { - firstLineAfterSelection++; - } - start = this.ctrlCodeViewer.GetLineNumber(firstLineOfSelection); - end = this.ctrlCodeViewer.GetLineNumber(firstLineAfterSelection) - 1; - - range = ""; - if(start >= 0 && end >= 0) { - range = $"${start.ToString("X4")} - ${end.ToString("X4")}"; - start = InteropEmu.DebugGetAbsoluteAddress((UInt32)start); - end = InteropEmu.DebugGetAbsoluteAddress((UInt32)end); - } - } - - private void MarkSelectionAs(CdlPrgFlags type) - { - int startAddress, endAddress; - string range; - GetSelectedAddressRange(out startAddress, out endAddress, out range); - - if(startAddress >= 0 && endAddress >= 0 && startAddress <= endAddress) { - InteropEmu.DebugMarkPrgBytesAs((UInt32)startAddress, (UInt32)endAddress, type); - - frmDebugger debugger = DebugWindowManager.GetDebugger(); - if(debugger != null) { - debugger.UpdateDebugger(false); - } - } - } - - private void mnuMarkAsCode_Click(object sender, EventArgs e) - { - this.MarkSelectionAs(CdlPrgFlags.Code); - } - - private void mnuMarkAsData_Click(object sender, EventArgs e) - { - this.MarkSelectionAs(CdlPrgFlags.Data); - } - - private void mnuMarkAsUnidentifiedData_Click(object sender, EventArgs e) - { - this.MarkSelectionAs(CdlPrgFlags.None); - } - - private void mnuUndoPrgChrEdit_Click(object sender, EventArgs e) - { - if(InteropEmu.DebugHasUndoHistory()) { - InteropEmu.DebugPerformUndo(); - frmDebugger debugger = DebugWindowManager.GetDebugger(); - if(debugger != null) { - debugger.UpdateDebugger(false); - } - } - } - - class LineStyleProvider : ctrlTextbox.ILineStyleProvider + public class LineStyleProvider : ctrlTextbox.ILineStyleProvider { private ctrlDebuggerCode _code; @@ -1050,14 +481,29 @@ namespace Mesen.GUI.Debugger _code = code; } + public string GetLineComment(int lineNumber) + { + if(_code.SymbolProvider != null && _code._config.ShowSourceAsComments) { + AddressTypeInfo addressInfo = _code.GetAddressInfo(lineNumber); + if(addressInfo.Type == AddressType.PrgRom) { + return _code.SymbolProvider.GetSourceCodeLine(addressInfo.Address); + } + } + return null; + } + public LineProperties GetLineStyle(int cpuAddress, int lineNumber) { DebugInfo info = ConfigManager.Config.DebugInfo; LineProperties props = new LineProperties(); + AddressTypeInfo addressInfo = _code.GetAddressInfo(lineNumber); + GetBreakpointLineProperties(props, cpuAddress, addressInfo); + bool isActiveStatement = _code._currentActiveAddress.HasValue && _code.ctrlCodeViewer.GetLineIndex((int)_code._currentActiveAddress.Value) == lineNumber; if(isActiveStatement) { + props.FgColor = Color.Black; props.TextBgColor = info.CodeActiveStatementColor; - props.Symbol = LineSymbol.Arrow; + props.Symbol |= LineSymbol.Arrow; } else if(_code._unexecutedAddresses.Contains(lineNumber)) { props.LineBgColor = info.CodeUnexecutedCodeColor; } else if(_code._speculativeCodeAddreses.Contains(lineNumber)) { @@ -1066,8 +512,19 @@ namespace Mesen.GUI.Debugger props.LineBgColor = info.CodeVerifiedDataColor; } - AddressTypeInfo addressInfo = _code.GetLineAddressTypeInfo(lineNumber); + switch(_code._lineMemoryType[lineNumber]) { + case 'P': props.AddressColor = Color.Gray; break; + case 'W': props.AddressColor = Color.DarkBlue; break; + case 'S': props.AddressColor = Color.DarkRed; break; + case 'N': props.AddressColor = Color.DarkGreen; break; + } + return props; + } + + public static void GetBreakpointLineProperties(LineProperties props, int cpuAddress, AddressTypeInfo addressInfo) + { + DebugInfo info = ConfigManager.Config.DebugInfo; foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { if(breakpoint.Matches(cpuAddress, ref addressInfo)) { Color fgColor = Color.White; @@ -1091,31 +548,13 @@ namespace Mesen.GUI.Debugger symbol |= LineSymbol.Plus; } - if(isActiveStatement) { - fgColor = Color.Black; - bgColor = Color.Yellow; - symbol |= LineSymbol.Arrow; - } - - if(props == null) { - props = new LineProperties(); - } props.FgColor = fgColor; props.TextBgColor = bgColor; props.OutlineColor = outlineColor; props.Symbol = symbol; - break; + return; } } - - switch(_code._lineMemoryType[lineNumber]) { - case 'P': props.AddressColor = Color.Gray; break; - case 'W': props.AddressColor = Color.DarkBlue; break; - case 'S': props.AddressColor = Color.DarkRed; break; - case 'N': props.AddressColor = Color.DarkGreen; break; - } - - return props; } } @@ -1133,7 +572,7 @@ namespace Mesen.GUI.Debugger AddressTypeInfo[] addressInfo = new AddressTypeInfo[len]; for(int i = 0; i < len; i++) { - addressInfo[i] = _code.GetLineAddressTypeInfo(i); + addressInfo[i] = _code.GetAddressInfo(i); } foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { @@ -1171,17 +610,13 @@ namespace Mesen.GUI.Debugger return Color.Transparent; } - public frmCodeTooltip GetPreview(int lineIndex) + public frmCodePreviewTooltip GetPreview(int lineIndex) { if(lineIndex < _code._lineNumbers.Count) { - int cpuAddress = -1; - do { - cpuAddress = _code._lineNumbers[lineIndex]; + while(lineIndex > 0 && _code._lineNumbers[lineIndex] < 0) { lineIndex--; - } while(cpuAddress < 0 && lineIndex >= 0); - - frmCodeTooltip frm = new frmCodeTooltip(new Dictionary(), cpuAddress, _code._code); - return frm; + } + return new frmCodePreviewTooltip(lineIndex, _code._code); } else { return null; } @@ -1216,16 +651,6 @@ namespace Mesen.GUI.Debugger } } - public class WatchEventArgs : EventArgs - { - public string WatchValue { get; set; } - } - - public class AddressEventArgs : EventArgs - { - public UInt32 Address { get; set; } - } - public class AssemblerEventArgs : EventArgs { public string Code { get; set; } diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.resx b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.resx index 5c06cb82..d498f27a 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.resx +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 129, 19 - 17, 17 diff --git a/GUI.NET/Debugger/Controls/ctrlFindOccurrences.Designer.cs b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.Designer.cs new file mode 100644 index 00000000..5d2c0abc --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.Designer.cs @@ -0,0 +1,151 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class ctrlFindOccurrences + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tlpSearchResults = new System.Windows.Forms.TableLayoutPanel(); + this.lstSearchResult = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.picCloseOccurrenceList = new System.Windows.Forms.PictureBox(); + this.lblSearchResult = new System.Windows.Forms.Label(); + this.tlpSearchResults.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picCloseOccurrenceList)).BeginInit(); + this.SuspendLayout(); + // + // tlpSearchResults + // + this.tlpSearchResults.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single; + this.tlpSearchResults.ColumnCount = 1; + this.tlpSearchResults.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpSearchResults.Controls.Add(this.lstSearchResult, 0, 1); + this.tlpSearchResults.Controls.Add(this.tableLayoutPanel2, 0, 0); + this.tlpSearchResults.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpSearchResults.Location = new System.Drawing.Point(0, 0); + this.tlpSearchResults.Name = "tlpSearchResults"; + this.tlpSearchResults.RowCount = 2; + this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpSearchResults.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tlpSearchResults.Size = new System.Drawing.Size(394, 136); + this.tlpSearchResults.TabIndex = 13; + // + // lstSearchResult + // + this.lstSearchResult.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.lstSearchResult.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.lstSearchResult.Dock = System.Windows.Forms.DockStyle.Fill; + this.lstSearchResult.FullRowSelect = true; + this.lstSearchResult.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.lstSearchResult.Location = new System.Drawing.Point(1, 24); + this.lstSearchResult.Margin = new System.Windows.Forms.Padding(0); + this.lstSearchResult.Name = "lstSearchResult"; + this.lstSearchResult.Size = new System.Drawing.Size(392, 111); + this.lstSearchResult.TabIndex = 9; + this.lstSearchResult.UseCompatibleStateImageBehavior = false; + this.lstSearchResult.View = System.Windows.Forms.View.Details; + this.lstSearchResult.SizeChanged += new System.EventHandler(this.lstSearchResult_DoubleClick); + this.lstSearchResult.DoubleClick += new System.EventHandler(this.lstSearchResult_DoubleClick); + // + // columnHeader1 + // + this.columnHeader1.Text = ""; + // + // columnHeader2 + // + this.columnHeader2.Text = ""; + this.columnHeader2.Width = 160; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 2; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.picCloseOccurrenceList, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.lblSearchResult, 0, 0); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(1, 1); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 1; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(392, 22); + this.tableLayoutPanel2.TabIndex = 11; + // + // picCloseOccurrenceList + // + this.picCloseOccurrenceList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.picCloseOccurrenceList.Cursor = System.Windows.Forms.Cursors.Hand; + this.picCloseOccurrenceList.Image = global::Mesen.GUI.Properties.Resources.Close; + this.picCloseOccurrenceList.Location = new System.Drawing.Point(373, 3); + this.picCloseOccurrenceList.Name = "picCloseOccurrenceList"; + this.picCloseOccurrenceList.Size = new System.Drawing.Size(16, 16); + this.picCloseOccurrenceList.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.picCloseOccurrenceList.TabIndex = 10; + this.picCloseOccurrenceList.TabStop = false; + this.picCloseOccurrenceList.Click += new System.EventHandler(this.picCloseOccurrenceList_Click); + // + // lblSearchResult + // + this.lblSearchResult.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblSearchResult.AutoSize = true; + this.lblSearchResult.Location = new System.Drawing.Point(3, 4); + this.lblSearchResult.Name = "lblSearchResult"; + this.lblSearchResult.Size = new System.Drawing.Size(95, 13); + this.lblSearchResult.TabIndex = 11; + this.lblSearchResult.Text = "Search results for: "; + // + // ctrlFindOccurrences + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tlpSearchResults); + this.Name = "ctrlFindOccurrences"; + this.Size = new System.Drawing.Size(394, 136); + this.tlpSearchResults.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picCloseOccurrenceList)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tlpSearchResults; + private System.Windows.Forms.ListView lstSearchResult; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.PictureBox picCloseOccurrenceList; + private System.Windows.Forms.Label lblSearchResult; + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlFindOccurrences.cs b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.cs new file mode 100644 index 00000000..708ed81c --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.cs @@ -0,0 +1,62 @@ +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.Debugger.Controls +{ + public partial class ctrlFindOccurrences : UserControl + { + public event EventHandler OnSearchResultsClosed; + + public ctrlFindOccurrences() + { + InitializeComponent(); + this.lstSearchResult.Font = new System.Drawing.Font(BaseControl.MonospaceFontFamily, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + } + + public ICodeViewer Viewer { get; set; } + + public void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) + { + this.lstSearchResult.Items.Clear(); + foreach(Tuple searchResult in Viewer.CodeViewer.FindAllOccurrences(text, matchWholeWord, matchCase)) { + var item = this.lstSearchResult.Items.Add(searchResult.Item1.ToString("X4")); + item.Tag = searchResult.Item2; + item.SubItems.Add(searchResult.Item3); + item.SubItems.Add(""); + } + this.lblSearchResult.Text = $"Search results for: {text} ({this.lstSearchResult.Items.Count} results)"; + this.lstSearchResult.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); + this.lstSearchResult.Columns[0].Width += 20; + this.lstSearchResult.Columns[1].Width = Math.Max(this.lstSearchResult.Columns[1].Width, this.lstSearchResult.Width - this.lstSearchResult.Columns[0].Width - 24); + } + + private void lstSearchResult_SizeChanged(object sender, EventArgs e) + { + this.lstSearchResult.SizeChanged -= lstSearchResult_SizeChanged; + this.lstSearchResult.Columns[1].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); + this.lstSearchResult.Columns[1].Width = Math.Max(this.lstSearchResult.Columns[1].Width, this.lstSearchResult.Width - this.lstSearchResult.Columns[0].Width - 24); + this.lstSearchResult.SizeChanged += lstSearchResult_SizeChanged; + } + + private void picCloseOccurrenceList_Click(object sender, EventArgs e) + { + OnSearchResultsClosed?.Invoke(null, EventArgs.Empty); + } + + private void lstSearchResult_DoubleClick(object sender, EventArgs e) + { + if(lstSearchResult.SelectedItems.Count > 0) { + int lineIndex = (int)lstSearchResult.SelectedItems[0].Tag; + Viewer.CodeViewer.ScrollToLineIndex(lineIndex); + } + } + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlFindOccurrences.resx b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlFindOccurrences.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs index 1251f148..3d69f1a5 100644 --- a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs +++ b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs @@ -94,6 +94,11 @@ namespace Mesen.GUI.Debugger.Controls _addresses = addresses; } + public string GetLineComment(int lineIndex) + { + return null; + } + public LineProperties GetLineStyle(int cpuAddress, int lineIndex) { if(_addresses.Contains(cpuAddress)) { diff --git a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs index 1a55fd7e..2b61e889 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs @@ -10,6 +10,7 @@ using System.Windows.Forms; using Mesen.GUI.Controls; using Mesen.GUI.Debugger.Controls; using Mesen.GUI.Config; +using System.Globalization; namespace Mesen.GUI.Debugger { @@ -55,20 +56,23 @@ namespace Mesen.GUI.Debugger { InitializeComponent(); - 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); + 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; + this.ctrlTextbox.ShowLineNumbers = true; + this.ctrlTextbox.ShowLineInHex = true; - new ToolTip().SetToolTip(picCloseSearch, "Close"); - new ToolTip().SetToolTip(picSearchNext, "Find Next (F3)"); - new ToolTip().SetToolTip(picSearchPrevious, "Find Previous (Shift-F3)"); + 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) @@ -128,9 +132,9 @@ namespace Mesen.GUI.Debugger } } - public string GetWordUnderLocation(Point position, bool useCompareText = false) + public string GetWordUnderLocation(Point position) { - return this.ctrlTextbox.GetWordUnderLocation(position, useCompareText); + return this.ctrlTextbox.GetWordUnderLocation(position); } private void ctrlTextbox_ScrollPositionChanged(object sender, EventArgs e) @@ -171,6 +175,15 @@ namespace Mesen.GUI.Debugger 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); @@ -181,9 +194,9 @@ namespace Mesen.GUI.Debugger return this.GetLineNumber(this.GetLineIndexAtPosition(yPos)); } - public void ScrollToLineIndex(int lineIndex) + public void ScrollToLineIndex(int lineIndex, bool scrollToTop = false) { - this.ctrlTextbox.ScrollToLineIndex(lineIndex); + this.ctrlTextbox.ScrollToLineIndex(lineIndex, eHistoryType.Always, scrollToTop); } public void ScrollToLineNumber(int lineNumber, eHistoryType historyType = eHistoryType.Always, bool scrollToTop = false) @@ -411,7 +424,13 @@ namespace Mesen.GUI.Debugger 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; } } @@ -529,5 +548,22 @@ namespace Mesen.GUI.Debugger { this.ctrlTextbox.NavigateBackward(); } + + public bool GetNoteRangeAtLocation(int yPos, out int rangeStart, out int rangeEnd) + { + rangeStart = -1; + rangeEnd = -1; + int lineIndex = GetLineIndexAtPosition(yPos); + if(Int32.TryParse(GetLineNoteAtLineIndex(lineIndex), NumberStyles.AllowHexSpecifier, null, out rangeStart)) { + while(lineIndex < LineCount - 2 && string.IsNullOrWhiteSpace(GetLineNoteAtLineIndex(lineIndex + 1))) { + lineIndex++; + } + if(Int32.TryParse(GetLineNoteAtLineIndex(lineIndex + 1), NumberStyles.AllowHexSpecifier, null, out rangeEnd)) { + rangeEnd--; + return true; + } + } + return false; + } } } diff --git a/GUI.NET/Debugger/Controls/ctrlSourceViewer.Designer.cs b/GUI.NET/Debugger/Controls/ctrlSourceViewer.Designer.cs new file mode 100644 index 00000000..6915bd5a --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlSourceViewer.Designer.cs @@ -0,0 +1,168 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class ctrlSourceViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblFile = new System.Windows.Forms.Label(); + this.cboFile = new System.Windows.Forms.ComboBox(); + this.ctrlCodeViewer = new Mesen.GUI.Debugger.ctrlScrollableTextbox(); + this.contextMenuMargin = new System.Windows.Forms.ContextMenuStrip(this.components); + this.mnuEditBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuDisableBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRemoveBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); + this.tableLayoutPanel1.SuspendLayout(); + this.contextMenuMargin.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + 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.lblFile, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.cboFile, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.ctrlCodeViewer, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(463, 275); + this.tableLayoutPanel1.TabIndex = 0; + // + // lblFile + // + this.lblFile.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblFile.AutoSize = true; + this.lblFile.Location = new System.Drawing.Point(3, 7); + this.lblFile.Name = "lblFile"; + this.lblFile.Size = new System.Drawing.Size(26, 13); + this.lblFile.TabIndex = 0; + this.lblFile.Text = "File:"; + // + // cboFile + // + this.cboFile.Dock = System.Windows.Forms.DockStyle.Fill; + this.cboFile.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboFile.FormattingEnabled = true; + this.cboFile.Location = new System.Drawing.Point(35, 3); + this.cboFile.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); + this.cboFile.Name = "cboFile"; + this.cboFile.Size = new System.Drawing.Size(428, 21); + this.cboFile.TabIndex = 1; + this.cboFile.SelectedIndexChanged += new System.EventHandler(this.cboFile_SelectedIndexChanged); + // + // ctrlCodeViewer + // + this.ctrlCodeViewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.ctrlCodeViewer.CodeHighlightingEnabled = false; + this.tableLayoutPanel1.SetColumnSpan(this.ctrlCodeViewer, 2); + this.ctrlCodeViewer.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlCodeViewer.HideSelection = false; + this.ctrlCodeViewer.Location = new System.Drawing.Point(0, 27); + this.ctrlCodeViewer.Margin = new System.Windows.Forms.Padding(0); + this.ctrlCodeViewer.Name = "ctrlCodeViewer"; + this.ctrlCodeViewer.ShowCompactPrgAddresses = false; + this.ctrlCodeViewer.ShowContentNotes = false; + this.ctrlCodeViewer.ShowLineNumberNotes = false; + this.ctrlCodeViewer.ShowMemoryValues = false; + this.ctrlCodeViewer.ShowScrollbars = true; + this.ctrlCodeViewer.ShowSingleContentLineNotes = true; + this.ctrlCodeViewer.ShowSingleLineLineNumberNotes = false; + this.ctrlCodeViewer.Size = new System.Drawing.Size(463, 248); + this.ctrlCodeViewer.TabIndex = 2; + this.ctrlCodeViewer.ScrollPositionChanged += new System.EventHandler(this.ctrlCodeViewer_ScrollPositionChanged); + this.ctrlCodeViewer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseUp); + this.ctrlCodeViewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseMove); + this.ctrlCodeViewer.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseDown); + this.ctrlCodeViewer.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ctrlCodeViewer_MouseDoubleClick); + this.ctrlCodeViewer.MouseLeave += new System.EventHandler(this.ctrlCodeViewer_MouseLeave); + this.ctrlCodeViewer.TextZoomChanged += new System.EventHandler(this.ctrlCodeViewer_TextZoomChanged); + // + // contextMenuMargin + // + this.contextMenuMargin.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuEditBreakpoint, + this.mnuDisableBreakpoint, + this.mnuRemoveBreakpoint}); + this.contextMenuMargin.Name = "contextMenuMargin"; + this.contextMenuMargin.Size = new System.Drawing.Size(178, 70); + this.contextMenuMargin.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuMargin_Opening); + // + // mnuEditBreakpoint + // + this.mnuEditBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Edit; + this.mnuEditBreakpoint.Name = "mnuEditBreakpoint"; + this.mnuEditBreakpoint.Size = new System.Drawing.Size(177, 22); + this.mnuEditBreakpoint.Text = "Edit breakpoint"; + this.mnuEditBreakpoint.Click += new System.EventHandler(this.mnuEditBreakpoint_Click); + // + // mnuDisableBreakpoint + // + this.mnuDisableBreakpoint.Image = global::Mesen.GUI.Properties.Resources.BreakpointEnableDisable; + this.mnuDisableBreakpoint.Name = "mnuDisableBreakpoint"; + this.mnuDisableBreakpoint.Size = new System.Drawing.Size(177, 22); + this.mnuDisableBreakpoint.Text = "Disable breakpoint"; + this.mnuDisableBreakpoint.Click += new System.EventHandler(this.mnuDisableBreakpoint_Click); + // + // mnuRemoveBreakpoint + // + this.mnuRemoveBreakpoint.Image = global::Mesen.GUI.Properties.Resources.Close; + this.mnuRemoveBreakpoint.Name = "mnuRemoveBreakpoint"; + this.mnuRemoveBreakpoint.Size = new System.Drawing.Size(177, 22); + this.mnuRemoveBreakpoint.Text = "Remove breakpoint"; + this.mnuRemoveBreakpoint.Click += new System.EventHandler(this.mnuRemoveBreakpoint_Click); + // + // ctrlSourceViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ctrlSourceViewer"; + this.Size = new System.Drawing.Size(463, 275); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.contextMenuMargin.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblFile; + private System.Windows.Forms.ComboBox cboFile; + private ctrlScrollableTextbox ctrlCodeViewer; + private System.Windows.Forms.ContextMenuStrip contextMenuMargin; + private System.Windows.Forms.ToolStripMenuItem mnuEditBreakpoint; + private System.Windows.Forms.ToolStripMenuItem mnuDisableBreakpoint; + private System.Windows.Forms.ToolStripMenuItem mnuRemoveBreakpoint; + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlSourceViewer.cs b/GUI.NET/Debugger/Controls/ctrlSourceViewer.cs new file mode 100644 index 00000000..a0539049 --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlSourceViewer.cs @@ -0,0 +1,497 @@ +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 static Mesen.GUI.Debugger.Ld65DbgImporter; +using System.IO; +using Mesen.GUI.Config; + +namespace Mesen.GUI.Debugger.Controls +{ + public partial class ctrlSourceViewer : UserControl, ICodeViewer + { + private UInt32? _currentActiveAddress { get; set; } = null; + private CodeTooltipManager _tooltipManager = null; + private CodeViewerActions _codeViewerActions; + private DebugViewInfo _config; + private Ld65DbgImporter.FileInfo _selectedFile = null; + + public ctrlSourceViewer() + { + InitializeComponent(); + + bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); + if(!designMode) { + _codeViewerActions = new CodeViewerActions(this, true); + _tooltipManager = new CodeTooltipManager(this, this.ctrlCodeViewer); + } + } + + public new void Focus() + { + base.Focus(); + this.ctrlCodeViewer.Focus(); + } + + public void SetConfig(DebugViewInfo config) + { + _config = config; + _codeViewerActions.InitMenu(config); + if(this.ctrlCodeViewer.TextZoom != config.TextZoom) { + this.ctrlCodeViewer.TextZoom = config.TextZoom; + } + } + + private List _lineNumberNotes = new List(); + private void UpdateCode() + { + List indents = new List(); + List addressing = new List(); + List comments = new List(); + List lineNumbers = new List(); + List lineNotes = new List(); + _lineNumberNotes = new List(); + List codeLines = new List(); + + bool isC = CurrentFile.Name.EndsWith(".h") || CurrentFile.Name.EndsWith(".c"); + int index = 0; + foreach(string line in CurrentFile.Data) { + string l = line.Replace("\t", " "); + + addressing.Add(""); + + int prgAddress = _symbolProvider.GetPrgAddress(CurrentFile.ID, index); + int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)prgAddress, AddressType.PrgRom); + lineNumbers.Add(relativeAddress); + lineNotes.Add(""); + _lineNumberNotes.Add(prgAddress >= 0 ? prgAddress.ToString("X4") : ""); + + string trimmed = l.TrimStart(); + int margin = (l.Length - trimmed.Length) * 10; + indents.Add(margin); + + int commentIndex; + if(isC) { + commentIndex = trimmed.IndexOf("//"); + } else { + commentIndex = trimmed.IndexOfAny(new char[] { ';', '.' }); + } + + if(commentIndex >= 0) { + comments.Add(trimmed.Substring(commentIndex)); + codeLines.Add(trimmed.Substring(0, commentIndex)); + } else { + comments.Add(""); + codeLines.Add(trimmed); + } + index++; + } + + ctrlCodeViewer.CodeHighlightingEnabled = !isC; + ctrlCodeViewer.LineIndentations = indents.ToArray(); + ctrlCodeViewer.Addressing = addressing.ToArray(); + ctrlCodeViewer.Comments = comments.ToArray(); + + ctrlCodeViewer.LineNumbers = lineNumbers.ToArray(); + ctrlCodeViewer.TextLineNotes = lineNotes.ToArray(); + ctrlCodeViewer.LineNumberNotes = _lineNumberNotes.ToArray(); + ctrlCodeViewer.TextLines = codeLines.ToArray(); + + this.RefreshViewer(); + } + + public void RefreshViewer() + { + if(_symbolProvider != null) { + ctrlCodeViewer.ScrollbarColorProvider = new ScrollbarColorProvider(this); + ctrlCodeViewer.StyleProvider = new LineStyleProvider(this); + } else { + ctrlCodeViewer.ScrollbarColorProvider = null; + ctrlCodeViewer.StyleProvider = null; + } + } + + Ld65DbgImporter _symbolProvider; + public Ld65DbgImporter SymbolProvider + { + get { return _symbolProvider; } + set + { + if(_symbolProvider != value) { + _symbolProvider = value; + + cboFile.BeginUpdate(); + cboFile.Items.Clear(); + cboFile.Sorted = false; + if(_symbolProvider != null) { + foreach(Ld65DbgImporter.FileInfo file in _symbolProvider.Files.Values) { + if(file.Data != null && file.Data.Length > 0 && !file.Name.ToLower().EndsWith(".chr")) { + cboFile.Items.Add(file); + } + } + } + cboFile.Sorted = true; + cboFile.EndUpdate(); + + if(cboFile.Items.Count > 0) { + cboFile.SelectedIndex = 0; + } + + _tooltipManager.SymbolProvider = value; + } + } + } + + public Ld65DbgImporter.FileInfo CurrentFile + { + get { return (Ld65DbgImporter.FileInfo)_selectedFile; } + set + { + cboFile.SelectedItem = value; + _selectedFile = value; + } + } + + public bool HideFileDropdown { set { cboFile.Visible = !value; lblFile.Visible = !value; } } + + public ctrlScrollableTextbox CodeViewer { get { return this.ctrlCodeViewer; } } + public CodeViewerActions CodeViewerActions { get { return _codeViewerActions; } } + public UInt32? ActiveAddress { get { return _currentActiveAddress; } } + + private void mnuToggleBreakpoint_Click(object sender, EventArgs e) + { + ToggleBreakpoint(); + } + + public AddressTypeInfo GetAddressInfo(int lineIndex) + { + return new AddressTypeInfo() { + Address = _symbolProvider.GetPrgAddress(CurrentFile.ID, lineIndex), + Type = AddressType.PrgRom + }; + } + + public void SetActiveAddress(UInt32 address) + { + _currentActiveAddress = address; + this.RefreshViewer(); + } + + public void SelectActiveAddress(UInt32 address) + { + if(_symbolProvider == null) { + return; + } + + _currentActiveAddress = address; + + ScrollToLineNumber((int)address); + this.RefreshViewer(); + } + + public void ClearActiveAddress() + { + _currentActiveAddress = null; + this.RefreshViewer(); + } + + private void cboFile_SelectedIndexChanged(object sender, EventArgs e) + { + if(cboFile.SelectedIndex >= 0) { + _selectedFile = cboFile.SelectedItem as Ld65DbgImporter.FileInfo; + this.ctrlCodeViewer.ScrollToLineIndex(0, true); + this.UpdateCode(); + } else { + _selectedFile = null; + } + } + + public void ToggleBreakpoint() + { + AddressTypeInfo info = GetAddressInfo(ctrlCodeViewer.SelectedLine); + if(info.Address >= 0) { + BreakpointManager.ToggleBreakpoint(-1, info, false); + } + } + + private void ctrlCodeViewer_MouseMove(object sender, MouseEventArgs e) + { + if(e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { + this.ctrlCodeViewer.ContextMenuStrip = contextMenuMargin; + } else { + this.ctrlCodeViewer.ContextMenuStrip = _codeViewerActions.contextMenu; + } + + _tooltipManager.ProcessMouseMove(e.Location); + } + + private void ctrlCodeViewer_MouseDown(object sender, MouseEventArgs e) + { + if(e.Button == MouseButtons.Left && e.Location.X < this.ctrlCodeViewer.CodeMargin / 4) { + ToggleBreakpoint(); + } + } + + private void ctrlCodeViewer_MouseUp(object sender, MouseEventArgs e) + { + _codeViewerActions.ProcessMouseUp(e.Location, e.Button); + } + + private void ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e) + { + _codeViewerActions.ProcessMouseDoubleClick(e.Location); + } + + private void ctrlCodeViewer_TextZoomChanged(object sender, EventArgs e) + { + _config.TextZoom = this.ctrlCodeViewer.TextZoom; + ConfigManager.ApplyChanges(); + } + + private Breakpoint GetCurrentLineBreakpoint() + { + AddressTypeInfo addressInfo = GetAddressInfo(ctrlCodeViewer.SelectedLine); + if(addressInfo.Address >= 0) { + int relativeAddress = InteropEmu.DebugGetRelativeAddress((uint)addressInfo.Address, addressInfo.Type); + return BreakpointManager.GetMatchingBreakpoint(relativeAddress, addressInfo); + } + return null; + } + + private void mnuEditBreakpoint_Click(object sender, EventArgs e) + { + Breakpoint bp = GetCurrentLineBreakpoint(); + if(bp != null) { + BreakpointManager.EditBreakpoint(bp); + } + } + + private void mnuDisableBreakpoint_Click(object sender, EventArgs e) + { + Breakpoint bp = GetCurrentLineBreakpoint(); + bp.SetEnabled(!bp.Enabled); + } + + private void mnuRemoveBreakpoint_Click(object sender, EventArgs e) + { + Breakpoint bp = GetCurrentLineBreakpoint(); + if(bp != null) { + BreakpointManager.RemoveBreakpoint(bp); + } + } + + private void contextMenuMargin_Opening(object sender, CancelEventArgs e) + { + Breakpoint bp = GetCurrentLineBreakpoint(); + if(bp != null) { + mnuDisableBreakpoint.Text = bp.Enabled ? "Disable breakpoint" : "Enable breakpoint"; + } else { + e.Cancel = true; + } + } + + private void ctrlCodeViewer_MouseLeave(object sender, EventArgs e) + { + _tooltipManager.Close(true); + } + + private void ctrlCodeViewer_ScrollPositionChanged(object sender, EventArgs e) + { + _tooltipManager.Close(true); + } + + public void ScrollToAddress(AddressTypeInfo addressInfo, bool scrollToTop = false) + { + if(addressInfo.Address >= 0 && addressInfo.Type == AddressType.PrgRom) { + LineInfo line = _symbolProvider.GetSourceCodeLineInfo(addressInfo.Address); + if(line != null) { + foreach(Ld65DbgImporter.FileInfo fileInfo in cboFile.Items) { + if(fileInfo.ID == line.FileID) { + cboFile.SelectedItem = fileInfo; + break; + } + } + ctrlCodeViewer.ScrollToLineIndex(line.LineNumber, scrollToTop); + } + } + } + + private bool CurrentFileContainsAddress(int cpuAddress) + { + if(CurrentFile == null) { + return false; + } + + AddressTypeInfo addressInfo = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType((uint)cpuAddress, ref addressInfo); + if(addressInfo.Address >= 0 && addressInfo.Type == AddressType.PrgRom) { + LineInfo line = _symbolProvider.GetSourceCodeLineInfo(addressInfo.Address); + return CurrentFile.ID == line?.FileID; + } + return false; + } + + public void ScrollToLineNumber(int lineNumber, bool scrollToTop = false) + { + AddressTypeInfo addressInfo = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType((uint)lineNumber, ref addressInfo); + ScrollToAddress(addressInfo, scrollToTop); + } + + public void EditSubroutine() + { + //Not supported + } + + public void EditSelectedCode() + { + //Not supported + } + + public void FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) + { + //Not supported (yet?) + } + + #region Scrollbar / Code highlighting + + class LineStyleProvider : ctrlTextbox.ILineStyleProvider + { + private ctrlSourceViewer _viewer; + + public LineStyleProvider(ctrlSourceViewer viewer) + { + _viewer = viewer; + } + + public string GetLineComment(int lineNumber) + { + return null; + } + + public LineProperties GetLineStyle(int cpuAddress, int lineIndex) + { + DebugInfo info = ConfigManager.Config.DebugInfo; + LineProperties props = new LineProperties(); + + int nextLineIndex = lineIndex + 1; + int nextCpuAddress; + do { + nextCpuAddress = _viewer.CodeViewer.GetLineNumber(nextLineIndex); + nextLineIndex++; + } while(nextCpuAddress < 0); + + bool isActiveStatement = ( + cpuAddress >= 0 && + _viewer._currentActiveAddress.HasValue && ( + (_viewer._currentActiveAddress >= cpuAddress && _viewer._currentActiveAddress < nextCpuAddress && nextCpuAddress > cpuAddress) || + (_viewer._currentActiveAddress == cpuAddress && nextCpuAddress < cpuAddress) + ) + ); + + int prgAddress = _viewer._symbolProvider.GetPrgAddress(_viewer.CurrentFile.ID, lineIndex); + + if(prgAddress >= 0) { + AddressTypeInfo addressInfo = new AddressTypeInfo(); + addressInfo.Address = prgAddress; + addressInfo.Type = AddressType.PrgRom; + + ctrlDebuggerCode.LineStyleProvider.GetBreakpointLineProperties(props, cpuAddress, addressInfo); + } + + if(isActiveStatement) { + props.FgColor = Color.Black; + props.TextBgColor = info.CodeActiveStatementColor; + props.Symbol |= LineSymbol.Arrow; + } + + return props; + } + } + + class ScrollbarColorProvider : IScrollbarColorProvider + { + private Color _nesRamColor = Color.FromArgb(163, 222, 171); + private Dictionary _breakpointColors = new Dictionary(); + + private ctrlSourceViewer _viewer; + public ScrollbarColorProvider(ctrlSourceViewer viewer) + { + _viewer = viewer; + + DebugInfo info = ConfigManager.Config.DebugInfo; + int len = viewer.ctrlCodeViewer.LineCount; + + int[] relativeAddresses = new int[len]; + AddressTypeInfo[] addressInfo = new AddressTypeInfo[len]; + for(int i = 0; i < len; i++) { + addressInfo[i] = _viewer.GetAddressInfo(i); + if(addressInfo[i].Address >= 0) { + relativeAddresses[i] = InteropEmu.DebugGetRelativeAddress((uint)addressInfo[i].Address, AddressType.PrgRom); + } else { + relativeAddresses[i] = -1; + } + } + + foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { + for(int i = 0; i < len; i++) { + if(breakpoint.Matches(relativeAddresses[i], ref addressInfo[i])) { + Color bpColor = breakpoint.BreakOnExec ? info.CodeExecBreakpointColor : (breakpoint.BreakOnWrite ? info.CodeWriteBreakpointColor : info.CodeReadBreakpointColor); + _breakpointColors[i] = bpColor; + } + } + } + } + + public Color GetBackgroundColor(float position) + { + return Color.Transparent; + } + + public frmCodePreviewTooltip GetPreview(int lineIndex) + { + if(lineIndex < _viewer.CodeViewer.LineCount) { + while(lineIndex > 0 && _viewer.CodeViewer.GetLineNumber(lineIndex) < 0) { + lineIndex--; + } + return new frmCodePreviewTooltip(lineIndex, null, _viewer.SymbolProvider, _viewer.CurrentFile); + } else { + return null; + } + } + + public int GetActiveLine() + { + if(_viewer._currentActiveAddress.HasValue && _viewer.CurrentFileContainsAddress((int)_viewer._currentActiveAddress.Value)) { + return _viewer.ctrlCodeViewer.GetLineIndex((int)_viewer._currentActiveAddress.Value); + } else { + return -1; + } + } + + public int GetSelectedLine() + { + return _viewer.ctrlCodeViewer.SelectedLine; + } + + public Color GetMarkerColor(float position, int linesPerPixel) + { + int lineIndex = (int)((_viewer.ctrlCodeViewer.LineCount - 1) * position); + + Color bpColor; + for(int i = 0; i < linesPerPixel; i++) { + if(_breakpointColors.TryGetValue(lineIndex + i, out bpColor)) { + return bpColor; + } + } + return Color.Transparent; + } + } + #endregion + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlSourceViewer.resx b/GUI.NET/Debugger/Controls/ctrlSourceViewer.resx new file mode 100644 index 00000000..105fd63b --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlSourceViewer.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 178, 13 + + \ No newline at end of file diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index 7a0e1463..c6d3789e 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -44,7 +44,7 @@ namespace Mesen.GUI.Debugger public partial class ctrlTextbox : Control { - private Regex _codeRegex = new Regex("([a-z]{3})([*]{0,1})[ ]{0,1}([(]{0,1})(([#]{0,1}[$][0-9a-f]*)|([@_a-z]([@_a-z0-9])*)){0,1}([)]{0,1})(,X|,Y){0,1}([)]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private Regex _codeRegex = new Regex("^([a-z]{3})([*]{0,1})($|[ ])+([(]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*)){0,1}([)]{0,1})(,X|,Y){0,1}([)]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled); public event EventHandler ScrollPositionChanged; public event EventHandler SelectedLineChanged; private bool _disableScrollPositionChangedEvent; @@ -291,6 +291,10 @@ namespace Mesen.GUI.Debugger _lineNumberNotes = value; this.Invalidate(); } + get + { + return _lineNumberNotes; + } } public string Header @@ -311,6 +315,8 @@ namespace Mesen.GUI.Debugger } } + public bool CodeHighlightingEnabled { get; set; } = true; + public List> FindAllOccurrences(string text, bool matchWholeWord, bool matchCase) { List> result = new List>(); @@ -398,6 +404,7 @@ namespace Mesen.GUI.Debugger public interface ILineStyleProvider { LineProperties GetLineStyle(int cpuAddress, int lineIndex); + string GetLineComment(int lineIndex); } private ILineStyleProvider _styleProvider; @@ -451,10 +458,17 @@ namespace Mesen.GUI.Debugger //Line isn't currently visible, scroll it to the middle of the viewport if(scrollToTop) { int scrollPos = lineIndex; - while(scrollPos > 0 && _lineNumbers[scrollPos - 1] < 0) { + while(scrollPos > 0 && _lineNumbers[scrollPos - 1] < 0 && string.IsNullOrWhiteSpace(_lineNumberNotes[scrollPos - 1])) { //Make sure any comment for the line is in scroll view + bool emptyLine = string.IsNullOrWhiteSpace(_contents[scrollPos]) && string.IsNullOrWhiteSpace(this.Comments[scrollPos]); + if(emptyLine) { + //If there's a blank line, stop scrolling up + scrollPos++; + break; + } + scrollPos--; - if(_contents[scrollPos].StartsWith("--") || _contents[scrollPos].StartsWith("__")) { + if(emptyLine || _contents[scrollPos].StartsWith("--") || _contents[scrollPos].StartsWith("__")) { //Reached the start of a block, stop going back up break; } @@ -533,7 +547,7 @@ namespace Mesen.GUI.Debugger } if(positionX >= 0 && lineIndex < _contents.Length) { - string text = this.GetFullWidthString(lineIndex); + string text = this.GetFullWidthString(lineIndex).Trim(); //Adjust background color highlights based on number of spaces in front of content positionX -= (LineIndentations != null ? LineIndentations[lineIndex] : 0); @@ -551,21 +565,22 @@ namespace Mesen.GUI.Debugger return false; } - public string GetWordUnderLocation(Point position, bool useCompareText = false) + char[] _wordDelimiters = new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':', '+', '<', '>', '#', '*', '/', '&', '[', ']', '~', '%' }; + public string GetWordUnderLocation(Point position) { int charIndex; int lineIndex; if(this.GetCharIndex(position, out charIndex, out lineIndex)) { - string text = (useCompareText && _compareContents != null) ? _compareContents[lineIndex] : this.GetFullWidthString(lineIndex); - List wordDelimiters = new List(new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':' }); - if(wordDelimiters.Contains(text[charIndex])) { + string text = this.GetFullWidthString(lineIndex).Trim(); + + if(_wordDelimiters.Contains(text[charIndex])) { return string.Empty; } else { - int endIndex = text.IndexOfAny(wordDelimiters.ToArray(), charIndex); + int endIndex = text.IndexOfAny(_wordDelimiters, charIndex); if(endIndex == -1) { endIndex = text.Length; } - int startIndex = text.LastIndexOfAny(wordDelimiters.ToArray(), charIndex); + int startIndex = text.LastIndexOfAny(_wordDelimiters, charIndex); return text.Substring(startIndex + 1, endIndex - startIndex - 1); } } @@ -805,7 +820,6 @@ namespace Mesen.GUI.Debugger bool _mouseDragging; protected override void OnMouseDown(MouseEventArgs e) { - base.OnMouseDown(e); this.Focus(); if(e.Button == MouseButtons.XButton1) { @@ -835,6 +849,7 @@ namespace Mesen.GUI.Debugger this.SelectionLength = 0; } } + base.OnMouseDown(e); } protected override void OnMouseUp(MouseEventArgs e) @@ -1028,20 +1043,34 @@ namespace Mesen.GUI.Debugger } g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else { + if(StyleProvider != null) { + string symbolComment = StyleProvider.GetLineComment(currentLine); + if(symbolComment != null) { + symbolComment = symbolComment.Replace("\t", " "); + } + + if(symbolComment != _lastSymbolComment) { + commentString = symbolComment ?? commentString; + if(symbolComment != null) { + _lastSymbolComment = symbolComment; + } + } + } + //Draw line content int characterCount = 0; Color defaultColor = Color.FromArgb(60, 60, 60); if(codeString.Length > 0) { - Match match = _codeRegex.Match(codeString); - if(match.Success && !codeString.EndsWith(":")) { + Match match = CodeHighlightingEnabled ? _codeRegex.Match(codeString) : null; + if(match != null && match.Success && !codeString.EndsWith(":")) { string opcode = match.Groups[1].Value; string invalidStar = match.Groups[2].Value; - string paren1 = match.Groups[3].Value; - string operand = match.Groups[4].Value; - string paren2 = match.Groups[8].Value; - string indirect = match.Groups[9].Value; - string paren3 = match.Groups[10].Value; - string rest = match.Groups[11].Value; + string paren1 = match.Groups[4].Value; + string operand = match.Groups[5].Value; + string paren2 = match.Groups[10].Value; + string indirect = match.Groups[11].Value; + string paren3 = match.Groups[12].Value; + string rest = match.Groups[13].Value; Color operandColor = operand.Length > 0 ? (operand[0] == '#' ? (Color)info.AssemblerImmediateColor : (operand[0] == '$' ? (Color)info.AssemblerAddressColor : (Color)info.AssemblerLabelDefinitionColor)) : Color.Black; List colors = new List() { info.AssemblerOpcodeColor, defaultColor, defaultColor, defaultColor, operandColor, defaultColor, defaultColor, defaultColor }; int codePartCount = colors.Count; @@ -1080,7 +1109,7 @@ namespace Mesen.GUI.Debugger float xOffset = 0; for(int i = 0; i < parts.Count; i++) { - using(Brush b = new SolidBrush(textColor.HasValue && i < codePartCount ? textColor.Value : colors[i])) { + using(Brush b = new SolidBrush(textColor.HasValue && (i < codePartCount || i == parts.Count - 1) ? textColor.Value : colors[i])) { g.DrawString(parts[i], this.Font, b, marginLeft + xOffset, positionY, StringFormat.GenericTypographic); xOffset += g.MeasureString("".PadLeft(parts[i].Length, 'w'), this.Font, Point.Empty, StringFormat.GenericTypographic).Width; characterCount += parts[i].Length; @@ -1095,7 +1124,6 @@ namespace Mesen.GUI.Debugger } } - if(!string.IsNullOrWhiteSpace(commentString)) { using(Brush commentBrush = new SolidBrush(info.AssemblerCommentColor)) { int padding = Math.Max(CommentSpacingCharCount, characterCount + 1); @@ -1114,6 +1142,7 @@ namespace Mesen.GUI.Debugger this.DrawHighlightedCompareString(g, codeString, currentLine, marginLeft, positionY); } } + string _lastSymbolComment = null; private void DrawLineSymbols(Graphics g, int positionY, LineProperties lineProperties, int lineHeight) { @@ -1262,6 +1291,7 @@ namespace Mesen.GUI.Debugger protected override void OnPaint(PaintEventArgs pe) { + _lastSymbolComment = null; int lineHeight = this.LineHeight; pe.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; Rectangle rect = this.ClientRectangle; diff --git a/GUI.NET/Debugger/DbgImporter.cs b/GUI.NET/Debugger/DbgImporter.cs index b5b1c29a..b48d1756 100644 --- a/GUI.NET/Debugger/DbgImporter.cs +++ b/GUI.NET/Debugger/DbgImporter.cs @@ -11,7 +11,7 @@ using Mesen.GUI.Forms; namespace Mesen.GUI.Debugger { - class Ld65DbgImporter + public class Ld65DbgImporter { private const int iNesHeaderSize = 16; @@ -20,7 +20,9 @@ namespace Mesen.GUI.Debugger private Dictionary _lines = new Dictionary(); private Dictionary _spans = new Dictionary(); private Dictionary _symbols = new Dictionary(); + private Dictionary _cSymbols = new Dictionary(); + private HashSet _usedFileIds = new HashSet(); private HashSet _usedLabels = new HashSet(); private Dictionary _ramLabels = new Dictionary(); private Dictionary _romLabels = new Dictionary(); @@ -28,18 +30,126 @@ namespace Mesen.GUI.Debugger private HashSet _filesNotFound = new HashSet(); private int _errorCount = 0; - private static Regex _segmentRegex = new Regex("seg\tid=([0-9]+),.*start=0x([0-9a-fA-F]+),.*size=0x([0-9A-Fa-f]+)", RegexOptions.Compiled); - private static Regex _segmentPrgRomRegex = new Regex("seg\tid=([0-9]+),.*start=0x([0-9a-fA-F]+),.*size=0x([0-9A-Fa-f]+),.*ooffs=([0-9]+)", RegexOptions.Compiled); - private static Regex _lineRegex = new Regex("line\tid=([0-9]+),.*file=([0-9]+),.*line=([0-9]+),.*span=([0-9]+)", RegexOptions.Compiled); - private static Regex _fileRegex = new Regex("file\tid=([0-9]+),.*name=\"([^\"]+)\"", RegexOptions.Compiled); - private static Regex _spanRegex = new Regex("span\tid=([0-9]+),.*seg=([0-9]+),.*start=([0-9]+),.*size=([0-9]+)(,.*type=([0-9]+)){0,1}", RegexOptions.Compiled); - private static Regex _symbolRegex = new Regex("sym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_]+)\",.*val=0x([0-9a-fA-F]+),.*seg=([0-9a-zA-Z]+)", RegexOptions.Compiled); + private static Regex _segmentRegex = new Regex("^seg\tid=([0-9]+),.*start=0x([0-9a-fA-F]+),.*size=0x([0-9A-Fa-f]+)", RegexOptions.Compiled); + private static Regex _segmentPrgRomRegex = new Regex("^seg\tid=([0-9]+),.*start=0x([0-9a-fA-F]+),.*size=0x([0-9A-Fa-f]+),.*ooffs=([0-9]+)", RegexOptions.Compiled); + private static Regex _lineRegex = new Regex("^line\tid=([0-9]+),.*file=([0-9]+),.*line=([0-9]+)(,.*type=([0-9]+)){0,1}(,.*span=([0-9]+)){0,1}", RegexOptions.Compiled); + private static Regex _fileRegex = new Regex("^file\tid=([0-9]+),.*name=\"([^\"]+)\"", RegexOptions.Compiled); + private static Regex _spanRegex = new Regex("^span\tid=([0-9]+),.*seg=([0-9]+),.*start=([0-9]+),.*size=([0-9]+)(,.*type=([0-9]+)){0,1}", RegexOptions.Compiled); + private static Regex _symbolRegex = new Regex("^sym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_-]+)\"(,.*def=([0-9+]+)){0,1}(,.*ref=([0-9+]+)){0,1}(,.*val=0x([0-9a-fA-F]+)){0,1}(,.*seg=([0-9]+)){0,1}(,.*exp=([0-9]+)){0,1}", RegexOptions.Compiled); + private static Regex _cSymbolRegex = new Regex("^csym\tid=([0-9]+).*name=\"([0-9a-zA-Z@_-]+)\"(,.*sym=([0-9+]+)){0,1}", RegexOptions.Compiled); private static Regex _asmFirstLineRegex = new Regex(";(.*)", RegexOptions.Compiled); private static Regex _asmPreviousLinesRegex = new Regex("^\\s*;(.*)", RegexOptions.Compiled); private static Regex _cFirstLineRegex = new Regex("(.*)", RegexOptions.Compiled); private static Regex _cPreviousLinesRegex = new Regex("^\\s*//(.*)", RegexOptions.Compiled); + private Dictionary _linesByPrgAddress = new Dictionary(); + private Dictionary _prgAddressByLine = new Dictionary(); + + public Dictionary Files { get { return _files; } } + + public int GetPrgAddress(int fileID, int lineIndex) + { + int prgAddress; + if(_prgAddressByLine.TryGetValue(fileID.ToString() + "_" + lineIndex.ToString(), out prgAddress)) { + return prgAddress; + } + return -1; + } + + public LineInfo GetSourceCodeLineInfo(int prgRomAddress) + { + LineInfo line; + if(_linesByPrgAddress.TryGetValue(prgRomAddress, out line)) { + return line; + } + return null; + } + + public string GetSourceCodeLine(int prgRomAddress) + { + if(prgRomAddress >= 0) { + try { + LineInfo line; + if(_linesByPrgAddress.TryGetValue(prgRomAddress, out line)) { + string output = ""; + FileInfo file = _files[line.FileID]; + if(file.Data == null) { + return string.Empty; + } + + output += file.Data[line.LineNumber]; + return output; + } + } catch { } + } + return null; + } + + private SymbolInfo GetMatchingSymbol(SymbolInfo symbol, int rangeStart, int rangeEnd) + { + foreach(int reference in symbol.References) { + LineInfo line = _lines[reference]; + if(line.SpanID == null) { + continue; + } + + SpanInfo span = _spans[line.SpanID.Value]; + SegmentInfo seg = _segments[span.SegmentID]; + + if(!seg.IsRam) { + int spanPrgOffset = seg.FileOffset - iNesHeaderSize + span.Offset; + if(rangeStart < spanPrgOffset + span.Size && rangeEnd >= spanPrgOffset) { + if(symbol.ExportSymbolID != null && symbol.Address == null) { + return _symbols[symbol.ExportSymbolID.Value]; + } else { + return symbol; + } + } + } + } + return null; + } + + internal SymbolInfo GetSymbol(string word, int prgStartAddress, int prgEndAddress) + { + try { + foreach(CSymbolInfo symbol in _cSymbols.Values) { + if(symbol.Name == word && symbol.SymbolID.HasValue) { + SymbolInfo matchingSymbol = GetMatchingSymbol(_symbols[symbol.SymbolID.Value], prgStartAddress, prgEndAddress); + if(matchingSymbol != null) { + return matchingSymbol; + } + } + } + + foreach(SymbolInfo symbol in _symbols.Values) { + if(symbol.Name == word) { + SymbolInfo matchingSymbol = GetMatchingSymbol(symbol, prgStartAddress, prgEndAddress); + if(matchingSymbol != null) { + return matchingSymbol; + } + } + } + } catch { } + + return null; + } + + public AddressTypeInfo? GetSymbolAddressInfo(SymbolInfo symbol) + { + if(symbol.SegmentID == null || symbol.Address == null) { + return null; + } + + SegmentInfo segment = _segments[symbol.SegmentID.Value]; + if(segment.IsRam) { + return new AddressTypeInfo() { Address = symbol.Address.Value, Type = AddressType.Register }; + } else { + return new AddressTypeInfo() { Address = symbol.Address.Value - segment.Start + segment.FileOffset - iNesHeaderSize, Type = AddressType.PrgRom }; + } + } + private bool LoadSegments(string row) { Match match = _segmentRegex.Match(row); @@ -52,13 +162,15 @@ namespace Mesen.GUI.Debugger }; match = _segmentPrgRomRegex.Match(row); - if(match.Success) { + if(match.Success && !row.Contains("type=rw")) { segment.FileOffset = Int32.Parse(match.Groups[4].Value); segment.IsRam = false; } _segments.Add(segment.ID, segment); return true; + } else if(row.StartsWith("seg")) { + System.Diagnostics.Debug.Fail("Regex doesn't match seg"); } return false; @@ -73,27 +185,10 @@ namespace Mesen.GUI.Debugger Name = Path.GetFullPath(Path.Combine(basePath, match.Groups[2].Value.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar))).Replace(basePath + Path.DirectorySeparatorChar, "") }; - try { - string sourceFile = Path.Combine(basePath, file.Name); - while(!File.Exists(sourceFile)) { - //Go back up folder structure to attempt to find the file - string oldPath = basePath; - basePath = Path.GetDirectoryName(basePath); - if(basePath == null || basePath == oldPath) { - break; - } - sourceFile = Path.Combine(basePath, file.Name); - } - - if(File.Exists(sourceFile)) { - file.Data = File.ReadAllLines(sourceFile); - } - } catch { - _errorCount++; - } - _files.Add(file.ID, file); return true; + } else if(row.StartsWith("file")) { + System.Diagnostics.Debug.Fail("Regex doesn't match file"); } return false; @@ -107,11 +202,15 @@ namespace Mesen.GUI.Debugger ID = Int32.Parse(match.Groups[1].Value), FileID = Int32.Parse(match.Groups[2].Value), LineNumber = Int32.Parse(match.Groups[3].Value) - 1, - SpanID = Int32.Parse(match.Groups[4].Value) + Type = match.Groups[5].Success ? (LineType)Int32.Parse(match.Groups[5].Value) : LineType.Assembly, + SpanID = match.Groups[7].Success ? (int?)Int32.Parse(match.Groups[7].Value) : null }; + _usedFileIds.Add(line.FileID); _lines.Add(line.ID, line); return true; + } else if(row.StartsWith("line")) { + System.Diagnostics.Debug.Fail("Regex doesn't match line"); } return false; @@ -131,6 +230,26 @@ namespace Mesen.GUI.Debugger _spans.Add(span.ID, span); return true; + } else if(row.StartsWith("span")) { + System.Diagnostics.Debug.Fail("Regex doesn't match span"); + } + + return false; + } + + private bool LoadCSymbols(string row) + { + Match match = _cSymbolRegex.Match(row); + if(match.Success) { + CSymbolInfo span = new CSymbolInfo() { + ID = Int32.Parse(match.Groups[1].Value), + Name = match.Groups[2].Value, + SymbolID = match.Groups[4].Success ? (int?)Int32.Parse(match.Groups[4].Value) : null, + }; + _cSymbols.Add(span.ID, span); + return true; + } else if(row.StartsWith("csym")) { + System.Diagnostics.Debug.Fail("Regex doesn't match csym"); } return false; @@ -143,12 +262,27 @@ namespace Mesen.GUI.Debugger SymbolInfo symbol = new SymbolInfo() { ID = Int32.Parse(match.Groups[1].Value), Name = match.Groups[2].Value, - Address = Int32.Parse(match.Groups[3].Value, NumberStyles.HexNumber), - SegmentID = Int32.Parse(match.Groups[4].Value) + Address = match.Groups[8].Success ? (int?)Int32.Parse(match.Groups[8].Value, NumberStyles.HexNumber) : null, + SegmentID = match.Groups[10].Success ? (int?)Int32.Parse(match.Groups[10].Value) : null, + ExportSymbolID = match.Groups[12].Success ? (int?)Int32.Parse(match.Groups[12].Value) : null }; + if(match.Groups[4].Success) { + symbol.Definitions = match.Groups[4].Value.Split('+').Select(o => Int32.Parse(o)).ToList(); + } else { + symbol.Definitions = new List(); + } + + if(match.Groups[6].Success) { + symbol.References = match.Groups[6].Value.Split('+').Select(o => Int32.Parse(o)).ToList(); + } else { + symbol.References = new List(); + } + _symbols.Add(symbol.ID, symbol); return true; + } else if(row.StartsWith("sym")) { + System.Diagnostics.Debug.Fail("Regex doesn't match sym"); } return false; @@ -159,23 +293,27 @@ namespace Mesen.GUI.Debugger foreach(KeyValuePair kvp in _symbols) { try { SymbolInfo symbol = kvp.Value; - if(_segments.ContainsKey(symbol.SegmentID)) { - SegmentInfo segment = _segments[symbol.SegmentID]; + if(symbol.SegmentID == null) { + continue; + } + + if(_segments.ContainsKey(symbol.SegmentID.Value)) { + SegmentInfo segment = _segments[symbol.SegmentID.Value]; int count = 2; string orgSymbolName = symbol.Name; - while(!_usedLabels.Add(symbol.Name)) { + string newName = symbol.Name; + while(!_usedLabels.Add(newName)) { //Ensure labels are unique - symbol.Name = orgSymbolName + "_" + count.ToString(); + newName = orgSymbolName + "_" + count.ToString(); count++; } - + + int address = GetSymbolAddressInfo(symbol).Value.Address; if(segment.IsRam) { - int address = symbol.Address; - _ramLabels[address] = new CodeLabel() { Label = symbol.Name, Address = (UInt32)address, AddressType = AddressType.InternalRam, Comment = string.Empty }; + _ramLabels[address] = new CodeLabel() { Label = newName, Address = (UInt32)address, AddressType = AddressType.InternalRam, Comment = string.Empty }; } else { - int address = symbol.Address - segment.Start + segment.FileOffset - iNesHeaderSize; - _romLabels[address] = new CodeLabel() { Label = symbol.Name, Address = (UInt32)address, AddressType = AddressType.PrgRom, Comment = string.Empty }; + _romLabels[address] = new CodeLabel() { Label = newName, Address = (UInt32)address, AddressType = AddressType.PrgRom, Comment = string.Empty }; } } } catch { @@ -189,7 +327,11 @@ namespace Mesen.GUI.Debugger foreach(KeyValuePair kvp in _lines) { try { LineInfo line = kvp.Value; - SpanInfo span = _spans[line.SpanID]; + if(line.SpanID == null) { + continue; + } + + SpanInfo span = _spans[line.SpanID.Value]; SegmentInfo segment = _segments[span.SegmentID]; if(_files[line.FileID].Data == null) { @@ -254,6 +396,33 @@ namespace Mesen.GUI.Debugger } } + private void LoadFileData(string path) + { + foreach(FileInfo file in _files.Values) { + if(_usedFileIds.Contains(file.ID)) { + try { + string basePath = path; + string sourceFile = Path.Combine(basePath, file.Name); + while(!File.Exists(sourceFile)) { + //Go back up folder structure to attempt to find the file + string oldPath = basePath; + basePath = Path.GetDirectoryName(basePath); + if(basePath == null || basePath == oldPath) { + break; + } + sourceFile = Path.Combine(basePath, file.Name); + } + + if(File.Exists(sourceFile)) { + file.Data = File.ReadAllLines(sourceFile); + } + } catch { + _errorCount++; + } + } + } + } + public void Import(string path, bool silent = false) { string[] fileRows = File.ReadAllLines(path); @@ -261,7 +430,7 @@ namespace Mesen.GUI.Debugger string basePath = Path.GetDirectoryName(path); foreach(string row in fileRows) { try { - if(LoadSegments(row) || LoadLines(row) || LoadSpans(row) || LoadFiles(row, basePath) || LoadSymbols(row)) { + if(LoadLines(row) || LoadSpans(row) || LoadSymbols(row) || LoadCSymbols(row) || LoadFiles(row, basePath) || LoadSegments(row)) { continue; } } catch { @@ -269,6 +438,8 @@ namespace Mesen.GUI.Debugger } } + LoadFileData(basePath); + LoadLabels(); LoadComments(); @@ -296,6 +467,32 @@ namespace Mesen.GUI.Debugger InteropEmu.DebugSetCdlData(cdlFile); } + foreach(LineInfo line in _lines.Values) { + if(line.SpanID == null) { + continue; + } + + FileInfo file = _files[line.FileID]; + SpanInfo span = _spans[line.SpanID.Value]; + SegmentInfo segment = _segments[span.SegmentID]; + if(!segment.IsRam) { + for(int i = 0; i < span.Size; i++) { + int prgAddress = segment.FileOffset - iNesHeaderSize + span.Offset + i; + + LineInfo existingLine; + if(_linesByPrgAddress.TryGetValue(prgAddress, out existingLine) && existingLine.Type == LineType.External) { + //Give priority to lines that come from C files + continue; + } + + _linesByPrgAddress[prgAddress] = line; + if(i == 0) { + _prgAddressByLine[file.ID.ToString() + "_" + line.LineNumber.ToString()] = prgAddress; + } + } + } + } + LabelManager.SetLabels(_romLabels.Values); LabelManager.SetLabels(_ramLabels.Values); @@ -329,22 +526,41 @@ namespace Mesen.GUI.Debugger public bool IsRam; } - private class FileInfo + public class FileInfo { public int ID; public string Name; public string[] Data; + + public override string ToString() + { + string folderName = Path.GetDirectoryName(Name); + string fileName = Path.GetFileName(Name); + if(string.IsNullOrWhiteSpace(folderName)) { + return fileName; + } else { + return $"{fileName} ({folderName})"; + } + } } - private class LineInfo + public class LineInfo { public int ID; public int FileID; - public int SpanID; + public int? SpanID; + public LineType Type; public int LineNumber; } + public enum LineType + { + Assembly = 0, + External = 1, //i.e C source file + Macro = 2 + } + private class SpanInfo { public int ID; @@ -354,12 +570,22 @@ namespace Mesen.GUI.Debugger public bool IsData; } - private class SymbolInfo + public class SymbolInfo { public int ID; public string Name; - public int Address; - public int SegmentID; + public int? Address; + public int? SegmentID; + public int? ExportSymbolID; + public List References; + public List Definitions; + } + + public class CSymbolInfo + { + public int ID; + public string Name; + public int? SymbolID; } } } diff --git a/GUI.NET/Debugger/DebugWindowManager.cs b/GUI.NET/Debugger/DebugWindowManager.cs index df509889..4df77df0 100644 --- a/GUI.NET/Debugger/DebugWindowManager.cs +++ b/GUI.NET/Debugger/DebugWindowManager.cs @@ -43,7 +43,7 @@ namespace Mesen.GUI.Debugger frm.Show(); } - public static void OpenMemoryViewer(int address) + public static void OpenMemoryViewer(int address, bool usePrgRom) { frmMemoryViewer frm = GetMemoryViewer(); if(frm == null) { @@ -52,7 +52,7 @@ namespace Mesen.GUI.Debugger _openedWindows.Add(frm); } frm.Show(); - frm.ShowAddress(address); + frm.ShowAddress(address, usePrgRom); } public static void OpenScriptWindow(bool forceBlank) diff --git a/GUI.NET/Debugger/frmCodePreviewTooltip.Designer.cs b/GUI.NET/Debugger/frmCodePreviewTooltip.Designer.cs new file mode 100644 index 00000000..561fec60 --- /dev/null +++ b/GUI.NET/Debugger/frmCodePreviewTooltip.Designer.cs @@ -0,0 +1,91 @@ +namespace Mesen.GUI.Debugger +{ + partial class frmCodePreviewTooltip + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.tlpMain = new System.Windows.Forms.TableLayoutPanel(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.AutoSize = true; + this.panel1.BackColor = System.Drawing.SystemColors.Info; + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel1.Controls.Add(this.tlpMain); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(10, 10); + this.panel1.TabIndex = 0; + // + // tlpMain + // + this.tlpMain.AutoSize = true; + this.tlpMain.ColumnCount = 2; + this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpMain.Location = new System.Drawing.Point(0, 0); + this.tlpMain.Name = "tlpMain"; + this.tlpMain.RowCount = 2; + this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tlpMain.Size = new System.Drawing.Size(8, 8); + this.tlpMain.TabIndex = 0; + // + // frmCodeTooltip + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.ClientSize = new System.Drawing.Size(10, 10); + this.ControlBox = false; + this.Controls.Add(this.panel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "frmCodeTooltip"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "frmCodeTooltip"; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TableLayoutPanel tlpMain; + } +} \ No newline at end of file diff --git a/GUI.NET/Debugger/frmCodePreviewTooltip.cs b/GUI.NET/Debugger/frmCodePreviewTooltip.cs new file mode 100644 index 00000000..2d89b172 --- /dev/null +++ b/GUI.NET/Debugger/frmCodePreviewTooltip.cs @@ -0,0 +1,83 @@ +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; +using Mesen.GUI.Controls; +using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; + +namespace Mesen.GUI.Debugger +{ + public partial class frmCodePreviewTooltip : Form + { + private ICodeViewer _codeViewer; + + private int _lineIndex; + private string _code; + private Ld65DbgImporter _symbolProvider; + private Ld65DbgImporter.FileInfo _selectedFile; + + protected override bool ShowWithoutActivation + { + get { return true; } + } + + public frmCodePreviewTooltip(int lineIndex, string code = null, Ld65DbgImporter symbolProvider = null, Ld65DbgImporter.FileInfo selectedFile = null) + { + _code = code; + _symbolProvider = symbolProvider; + _lineIndex = lineIndex; + _selectedFile = selectedFile; + InitializeComponent(); + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + tlpMain.SuspendLayout(); + tlpMain.RowStyles.Insert(1, new RowStyle()); + + if(_code != null) { + _codeViewer = new ctrlDebuggerCode(); + _codeViewer.SymbolProvider = _symbolProvider; + (_codeViewer as ctrlDebuggerCode).Code = _code; + } else { + _codeViewer = new ctrlSourceViewer(); + + //Must set symbol provider before setting CurrentFile + _codeViewer.SymbolProvider = _symbolProvider; + + (_codeViewer as ctrlSourceViewer).HideFileDropdown = true; + (_codeViewer as ctrlSourceViewer).CurrentFile = _selectedFile; + } + + _codeViewer.CodeViewer.HideSelection = true; + _codeViewer.CodeViewer.ShowScrollbars = false; + _codeViewer.CodeViewer.ScrollToLineIndex(_lineIndex, true); + _codeViewer.SetConfig(ConfigManager.Config.DebugInfo.LeftView); + + Control control = _codeViewer as Control; + control.Dock = DockStyle.Fill; + tlpMain.SetRow(control, 0); + tlpMain.SetColumn(control, 0); + tlpMain.SetColumnSpan(control, 2); + tlpMain.Controls.Add(control); + + tlpMain.ResumeLayout(); + this.Width = this.tlpMain.Width; + this.Height = this.tlpMain.Height; + } + + public void ScrollToLineIndex(int lineIndex) + { + _codeViewer?.CodeViewer.ScrollToLineIndex(0); + _codeViewer?.CodeViewer.ScrollToLineIndex(lineIndex); + } + } +} diff --git a/GUI.NET/Debugger/frmCodePreviewTooltip.resx b/GUI.NET/Debugger/frmCodePreviewTooltip.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/GUI.NET/Debugger/frmCodePreviewTooltip.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GUI.NET/Debugger/frmCodeTooltip.cs b/GUI.NET/Debugger/frmCodeTooltip.cs index ff219f3e..b2d5fc61 100644 --- a/GUI.NET/Debugger/frmCodeTooltip.cs +++ b/GUI.NET/Debugger/frmCodeTooltip.cs @@ -9,26 +9,29 @@ using System.Threading.Tasks; using System.Windows.Forms; using Mesen.GUI.Controls; using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; namespace Mesen.GUI.Debugger { public partial class frmCodeTooltip : Form { - private ctrlDebuggerCode _codeWindow; + private ICodeViewer _codeViewer; private Dictionary _values; - private int _previewAddress; + private AddressTypeInfo? _previewAddress; private string _code; + private Ld65DbgImporter _symbolProvider; protected override bool ShowWithoutActivation { get { return true; } } - public frmCodeTooltip(Dictionary values, int previewAddress = -1, string code = null) + public frmCodeTooltip(Dictionary values, AddressTypeInfo? previewAddress = null, string code = null, Ld65DbgImporter symbolProvider = null) { _values = values; _previewAddress = previewAddress; _code = code; + _symbolProvider = symbolProvider; InitializeComponent(); } @@ -61,31 +64,33 @@ namespace Mesen.GUI.Debugger i++; } - if(_previewAddress >= 0) { + if(_previewAddress.HasValue) { tlpMain.RowStyles.Insert(1, new RowStyle()); - _codeWindow = new ctrlDebuggerCode(); - _codeWindow.HideSelection = true; - _codeWindow.SetConfig(ConfigManager.Config.DebugInfo.LeftView); - _codeWindow.Code = _code; - _codeWindow.Dock = DockStyle.Fill; - _codeWindow.ShowScrollbars = false; - _codeWindow.ScrollToLineNumber(_previewAddress, true); + if(_code != null) { + _codeViewer = new ctrlDebuggerCode(); + (_codeViewer as ctrlDebuggerCode).Code = _code; + } else { + _codeViewer = new ctrlSourceViewer(); + (_codeViewer as ctrlSourceViewer).HideFileDropdown = true; + } - tlpMain.SetRow(_codeWindow, i); - tlpMain.SetColumn(_codeWindow, 0); - tlpMain.SetColumnSpan(_codeWindow, 2); - tlpMain.Controls.Add(_codeWindow); + _codeViewer.SymbolProvider = _symbolProvider; + _codeViewer.CodeViewer.HideSelection = true; + _codeViewer.CodeViewer.ShowScrollbars = false; + _codeViewer.ScrollToAddress(_previewAddress.Value, true); + _codeViewer.SetConfig(ConfigManager.Config.DebugInfo.LeftView); + + Control control = _codeViewer as Control; + control.Dock = DockStyle.Fill; + tlpMain.SetRow(control, i); + tlpMain.SetColumn(control, 0); + tlpMain.SetColumnSpan(control, 2); + tlpMain.Controls.Add(control); } tlpMain.ResumeLayout(); this.Width = this.tlpMain.Width; this.Height = this.tlpMain.Height; } - - public void ScrollToLineIndex(int lineIndex) - { - _codeWindow?.ScrollToLineIndex(0); - _codeWindow?.ScrollToLineIndex(lineIndex); - } } } diff --git a/GUI.NET/Debugger/frmDbgPreferences.cs b/GUI.NET/Debugger/frmDbgPreferences.cs index ba2aa156..c2f4d938 100644 --- a/GUI.NET/Debugger/frmDbgPreferences.cs +++ b/GUI.NET/Debugger/frmDbgPreferences.cs @@ -19,7 +19,7 @@ namespace Mesen.GUI.Debugger { InitializeComponent(); - ctrlDbgShortcutsShared.Shortcuts = new FieldInfo[24] { + ctrlDbgShortcutsShared.Shortcuts = new FieldInfo[] { GetMember(nameof(DebuggerShortcutsConfig.IncreaseFontSize)), GetMember(nameof(DebuggerShortcutsConfig.DecreaseFontSize)), GetMember(nameof(DebuggerShortcutsConfig.ResetFontSize)), @@ -47,7 +47,7 @@ namespace Mesen.GUI.Debugger GetMember(nameof(DebuggerShortcutsConfig.OpenTraceLogger)) }; - ctrlDbgShortcutsMemoryViewer.Shortcuts = new FieldInfo[7] { + ctrlDbgShortcutsMemoryViewer.Shortcuts = new FieldInfo[] { GetMember(nameof(DebuggerShortcutsConfig.MemoryViewer_Freeze)), GetMember(nameof(DebuggerShortcutsConfig.MemoryViewer_Unfreeze)), GetMember(nameof(DebuggerShortcutsConfig.MemoryViewer_AddToWatch)), @@ -57,14 +57,14 @@ namespace Mesen.GUI.Debugger GetMember(nameof(DebuggerShortcutsConfig.MemoryViewer_Export)) }; - ctrlDbgShortcutsScriptWindow.Shortcuts = new FieldInfo[4] { + ctrlDbgShortcutsScriptWindow.Shortcuts = new FieldInfo[] { GetMember(nameof(DebuggerShortcutsConfig.ScriptWindow_OpenScript)), GetMember(nameof(DebuggerShortcutsConfig.ScriptWindow_SaveScript)), GetMember(nameof(DebuggerShortcutsConfig.ScriptWindow_RunScript)), GetMember(nameof(DebuggerShortcutsConfig.ScriptWindow_StopScript)) }; - ctrlDbgShortcutsDebugger.Shortcuts = new FieldInfo[43] { + ctrlDbgShortcutsDebugger.Shortcuts = new FieldInfo[] { GetMember(nameof(DebuggerShortcutsConfig.Continue)), GetMember(nameof(DebuggerShortcutsConfig.Break)), GetMember(nameof(DebuggerShortcutsConfig.ToggleBreakContinue)), @@ -88,6 +88,7 @@ namespace Mesen.GUI.Debugger GetMember(nameof(DebuggerShortcutsConfig.CodeWindow_NavigateForward)), GetMember(nameof(DebuggerShortcutsConfig.CodeWindow_ToggleBreakpoint)), GetMember(nameof(DebuggerShortcutsConfig.CodeWindow_DisableEnableBreakpoint)), + GetMember(nameof(DebuggerShortcutsConfig.CodeWindow_SwitchView)), GetMember(nameof(DebuggerShortcutsConfig.FunctionList_EditLabel)), GetMember(nameof(DebuggerShortcutsConfig.FunctionList_AddBreakpoint)), GetMember(nameof(DebuggerShortcutsConfig.FunctionList_FindOccurrences)), diff --git a/GUI.NET/Debugger/frmDebugger.Designer.cs b/GUI.NET/Debugger/frmDebugger.Designer.cs index 430f4fca..c36b28b6 100644 --- a/GUI.NET/Debugger/frmDebugger.Designer.cs +++ b/GUI.NET/Debugger/frmDebugger.Designer.cs @@ -34,8 +34,12 @@ namespace Mesen.GUI.Debugger this.splitContainer = new Mesen.GUI.Controls.ctrlSplitContainer(); this.ctrlSplitContainerTop = new Mesen.GUI.Controls.ctrlSplitContainer(); this.tlpTop = new System.Windows.Forms.TableLayoutPanel(); - this.ctrlDebuggerCode = new Mesen.GUI.Debugger.ctrlDebuggerCode(); this.ctrlConsoleStatus = new Mesen.GUI.Debugger.ctrlConsoleStatus(); + this.panel1 = new System.Windows.Forms.Panel(); + this.ctrlSourceViewer = new Mesen.GUI.Debugger.Controls.ctrlSourceViewer(); + this.ctrlDebuggerCode = new Mesen.GUI.Debugger.ctrlDebuggerCode(); + this.panel2 = new System.Windows.Forms.Panel(); + this.ctrlSourceViewerSplit = new Mesen.GUI.Debugger.Controls.ctrlSourceViewer(); this.ctrlDebuggerCodeSplit = new Mesen.GUI.Debugger.ctrlDebuggerCode(); this.tlpFunctionLabelLists = new System.Windows.Forms.TableLayoutPanel(); this.grpLabels = new System.Windows.Forms.GroupBox(); @@ -86,6 +90,7 @@ namespace Mesen.GUI.Debugger this.mnuRunOneFrame = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem8 = new System.Windows.Forms.ToolStripSeparator(); this.mnuBreakIn = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuBreakOn = new System.Windows.Forms.ToolStripMenuItem(); this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFind = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFindNext = new System.Windows.Forms.ToolStripMenuItem(); @@ -186,7 +191,6 @@ namespace Mesen.GUI.Debugger this.ctrlPpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.ctrlCpuMemoryMapping = new Mesen.GUI.Debugger.Controls.ctrlMemoryMapping(); this.tsToolbar = new Mesen.GUI.Controls.ctrlMesenToolStrip(); - this.mnuBreakOn = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout(); @@ -196,6 +200,8 @@ namespace Mesen.GUI.Debugger this.ctrlSplitContainerTop.Panel2.SuspendLayout(); this.ctrlSplitContainerTop.SuspendLayout(); this.tlpTop.SuspendLayout(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); this.tlpFunctionLabelLists.SuspendLayout(); this.grpLabels.SuspendLayout(); this.grpFunctions.SuspendLayout(); @@ -231,8 +237,8 @@ namespace Mesen.GUI.Debugger this.splitContainer.Panel2.Controls.Add(this.picWatchHelp); this.splitContainer.Panel2.Controls.Add(this.tableLayoutPanel10); this.splitContainer.Panel2MinSize = 100; - this.splitContainer.Size = new System.Drawing.Size(1172, 573); - this.splitContainer.SplitterDistance = 400; + this.splitContainer.Size = new System.Drawing.Size(1075, 576); + this.splitContainer.SplitterDistance = 413; this.splitContainer.SplitterWidth = 7; this.splitContainer.TabIndex = 1; this.splitContainer.TabStop = false; @@ -255,7 +261,7 @@ namespace Mesen.GUI.Debugger // this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists); this.ctrlSplitContainerTop.Panel2MinSize = 150; - this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1172, 400); + this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1075, 413); this.ctrlSplitContainerTop.SplitterDistance = 750; this.ctrlSplitContainerTop.SplitterWidth = 7; this.ctrlSplitContainerTop.TabIndex = 3; @@ -269,61 +275,99 @@ namespace Mesen.GUI.Debugger this.tlpTop.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 0F)); this.tlpTop.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tlpTop.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tlpTop.Controls.Add(this.ctrlDebuggerCode, 0, 0); this.tlpTop.Controls.Add(this.ctrlConsoleStatus, 2, 0); - this.tlpTop.Controls.Add(this.ctrlDebuggerCodeSplit, 1, 0); + this.tlpTop.Controls.Add(this.panel1, 0, 0); + this.tlpTop.Controls.Add(this.panel2, 1, 0); this.tlpTop.Dock = System.Windows.Forms.DockStyle.Fill; this.tlpTop.Location = new System.Drawing.Point(0, 0); this.tlpTop.Name = "tlpTop"; this.tlpTop.RowCount = 1; this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tlpTop.Size = new System.Drawing.Size(750, 400); + this.tlpTop.Size = new System.Drawing.Size(750, 413); this.tlpTop.TabIndex = 2; // - // ctrlDebuggerCode - // - this.ctrlDebuggerCode.Code = null; - this.ctrlDebuggerCode.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlDebuggerCode.HideSelection = false; - this.ctrlDebuggerCode.Location = new System.Drawing.Point(3, 3); - this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; - this.ctrlDebuggerCode.ShowMemoryValues = false; - this.ctrlDebuggerCode.ShowScrollbars = true; - this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 394); - this.ctrlDebuggerCode.TabIndex = 2; - this.ctrlDebuggerCode.TextZoom = 100; - this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); - this.ctrlDebuggerCode.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement); - this.ctrlDebuggerCode.OnScrollToAddress += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnScrollToAddress); - this.ctrlDebuggerCode.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); - // // ctrlConsoleStatus // this.ctrlConsoleStatus.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlConsoleStatus.Location = new System.Drawing.Point(292, 0); this.ctrlConsoleStatus.Margin = new System.Windows.Forms.Padding(0); this.ctrlConsoleStatus.Name = "ctrlConsoleStatus"; - this.ctrlConsoleStatus.Size = new System.Drawing.Size(458, 400); + this.ctrlConsoleStatus.Size = new System.Drawing.Size(458, 413); this.ctrlConsoleStatus.TabIndex = 3; this.ctrlConsoleStatus.OnGotoLocation += new System.EventHandler(this.ctrlConsoleStatus_OnGotoLocation); // + // panel1 + // + this.panel1.Controls.Add(this.ctrlSourceViewer); + this.panel1.Controls.Add(this.ctrlDebuggerCode); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(3, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(286, 413); + this.panel1.TabIndex = 5; + // + // ctrlSourceViewer + // + this.ctrlSourceViewer.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlSourceViewer.Location = new System.Drawing.Point(0, 0); + this.ctrlSourceViewer.Name = "ctrlSourceViewer"; + this.ctrlSourceViewer.Size = new System.Drawing.Size(286, 413); + this.ctrlSourceViewer.SymbolProvider = null; + this.ctrlSourceViewer.TabIndex = 7; + this.ctrlSourceViewer.Visible = false; + this.ctrlSourceViewer.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); + // + // ctrlDebuggerCode + // + this.ctrlDebuggerCode.Code = null; + this.ctrlDebuggerCode.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlDebuggerCode.HideSelection = false; + this.ctrlDebuggerCode.Location = new System.Drawing.Point(0, 0); + this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; + this.ctrlDebuggerCode.ShowMemoryValues = false; + this.ctrlDebuggerCode.Size = new System.Drawing.Size(286, 413); + this.ctrlDebuggerCode.SymbolProvider = null; + this.ctrlDebuggerCode.TabIndex = 2; + this.ctrlDebuggerCode.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); + this.ctrlDebuggerCode.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); + // + // panel2 + // + this.panel2.Controls.Add(this.ctrlSourceViewerSplit); + this.panel2.Controls.Add(this.ctrlDebuggerCodeSplit); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(292, 0); + this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(1, 413); + this.panel2.TabIndex = 6; + // + // ctrlSourceViewerSplit + // + this.ctrlSourceViewerSplit.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlSourceViewerSplit.Location = new System.Drawing.Point(0, 0); + this.ctrlSourceViewerSplit.Name = "ctrlSourceViewerSplit"; + this.ctrlSourceViewerSplit.Size = new System.Drawing.Size(1, 413); + this.ctrlSourceViewerSplit.SymbolProvider = null; + this.ctrlSourceViewerSplit.TabIndex = 8; + this.ctrlSourceViewerSplit.Visible = false; + this.ctrlSourceViewerSplit.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); + // // ctrlDebuggerCodeSplit // this.ctrlDebuggerCodeSplit.Code = null; this.ctrlDebuggerCodeSplit.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlDebuggerCodeSplit.HideSelection = false; - this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(295, 3); + this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(0, 0); this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit"; this.ctrlDebuggerCodeSplit.ShowMemoryValues = false; - this.ctrlDebuggerCodeSplit.ShowScrollbars = true; - this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 394); + this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 413); + this.ctrlDebuggerCodeSplit.SymbolProvider = null; this.ctrlDebuggerCodeSplit.TabIndex = 4; - this.ctrlDebuggerCodeSplit.TextZoom = 100; this.ctrlDebuggerCodeSplit.Visible = false; this.ctrlDebuggerCodeSplit.OnEditCode += new Mesen.GUI.Debugger.ctrlDebuggerCode.AssemblerEventHandler(this.ctrlDebuggerCode_OnEditCode); - this.ctrlDebuggerCodeSplit.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement); - this.ctrlDebuggerCodeSplit.OnScrollToAddress += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnScrollToAddress); - this.ctrlDebuggerCodeSplit.Enter += new System.EventHandler(this.ctrlDebuggerCodeSplit_Enter); + this.ctrlDebuggerCodeSplit.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); // // tlpFunctionLabelLists // @@ -338,16 +382,16 @@ namespace Mesen.GUI.Debugger this.tlpFunctionLabelLists.RowCount = 2; this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tlpFunctionLabelLists.Size = new System.Drawing.Size(418, 400); + this.tlpFunctionLabelLists.Size = new System.Drawing.Size(318, 413); this.tlpFunctionLabelLists.TabIndex = 5; // // grpLabels // this.grpLabels.Controls.Add(this.ctrlLabelList); this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpLabels.Location = new System.Drawing.Point(3, 203); + this.grpLabels.Location = new System.Drawing.Point(3, 209); this.grpLabels.Name = "grpLabels"; - this.grpLabels.Size = new System.Drawing.Size(412, 194); + this.grpLabels.Size = new System.Drawing.Size(312, 201); this.grpLabels.TabIndex = 6; this.grpLabels.TabStop = false; this.grpLabels.Text = "Labels"; @@ -357,7 +401,7 @@ namespace Mesen.GUI.Debugger this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlLabelList.Location = new System.Drawing.Point(3, 16); this.ctrlLabelList.Name = "ctrlLabelList"; - this.ctrlLabelList.Size = new System.Drawing.Size(406, 175); + this.ctrlLabelList.Size = new System.Drawing.Size(306, 182); this.ctrlLabelList.TabIndex = 0; this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence); this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected); @@ -368,7 +412,7 @@ namespace Mesen.GUI.Debugger this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill; this.grpFunctions.Location = new System.Drawing.Point(3, 3); this.grpFunctions.Name = "grpFunctions"; - this.grpFunctions.Size = new System.Drawing.Size(412, 194); + this.grpFunctions.Size = new System.Drawing.Size(312, 200); this.grpFunctions.TabIndex = 5; this.grpFunctions.TabStop = false; this.grpFunctions.Text = "Functions"; @@ -378,7 +422,7 @@ namespace Mesen.GUI.Debugger this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16); this.ctrlFunctionList.Name = "ctrlFunctionList"; - this.ctrlFunctionList.Size = new System.Drawing.Size(406, 175); + this.ctrlFunctionList.Size = new System.Drawing.Size(306, 181); this.ctrlFunctionList.TabIndex = 0; this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence); this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected); @@ -409,7 +453,7 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel10.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel10.Size = new System.Drawing.Size(1172, 166); + this.tableLayoutPanel10.Size = new System.Drawing.Size(1075, 156); this.tableLayoutPanel10.TabIndex = 0; // // grpWatch @@ -418,7 +462,7 @@ namespace Mesen.GUI.Debugger this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.grpWatch.Location = new System.Drawing.Point(3, 3); this.grpWatch.Name = "grpWatch"; - this.grpWatch.Size = new System.Drawing.Size(384, 160); + this.grpWatch.Size = new System.Drawing.Size(352, 150); this.grpWatch.TabIndex = 2; this.grpWatch.TabStop = false; this.grpWatch.Text = "Watch"; @@ -428,16 +472,16 @@ namespace Mesen.GUI.Debugger this.ctrlWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlWatch.Location = new System.Drawing.Point(3, 16); this.ctrlWatch.Name = "ctrlWatch"; - this.ctrlWatch.Size = new System.Drawing.Size(378, 141); + this.ctrlWatch.Size = new System.Drawing.Size(346, 131); this.ctrlWatch.TabIndex = 0; // // grpBreakpoints // this.grpBreakpoints.Controls.Add(this.ctrlBreakpoints); this.grpBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpBreakpoints.Location = new System.Drawing.Point(393, 3); + this.grpBreakpoints.Location = new System.Drawing.Point(361, 3); this.grpBreakpoints.Name = "grpBreakpoints"; - this.grpBreakpoints.Size = new System.Drawing.Size(384, 160); + this.grpBreakpoints.Size = new System.Drawing.Size(352, 150); this.grpBreakpoints.TabIndex = 3; this.grpBreakpoints.TabStop = false; this.grpBreakpoints.Text = "Breakpoints"; @@ -447,7 +491,7 @@ namespace Mesen.GUI.Debugger this.ctrlBreakpoints.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlBreakpoints.Location = new System.Drawing.Point(3, 16); this.ctrlBreakpoints.Name = "ctrlBreakpoints"; - this.ctrlBreakpoints.Size = new System.Drawing.Size(378, 141); + this.ctrlBreakpoints.Size = new System.Drawing.Size(346, 131); this.ctrlBreakpoints.TabIndex = 0; this.ctrlBreakpoints.BreakpointNavigation += new System.EventHandler(this.ctrlBreakpoints_BreakpointNavigation); // @@ -455,9 +499,9 @@ namespace Mesen.GUI.Debugger // this.grpCallstack.Controls.Add(this.ctrlCallstack); this.grpCallstack.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpCallstack.Location = new System.Drawing.Point(783, 3); + this.grpCallstack.Location = new System.Drawing.Point(719, 3); this.grpCallstack.Name = "grpCallstack"; - this.grpCallstack.Size = new System.Drawing.Size(386, 160); + this.grpCallstack.Size = new System.Drawing.Size(353, 150); this.grpCallstack.TabIndex = 4; this.grpCallstack.TabStop = false; this.grpCallstack.Text = "Call Stack"; @@ -467,7 +511,7 @@ namespace Mesen.GUI.Debugger this.ctrlCallstack.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlCallstack.Location = new System.Drawing.Point(3, 16); this.ctrlCallstack.Name = "ctrlCallstack"; - this.ctrlCallstack.Size = new System.Drawing.Size(380, 141); + this.ctrlCallstack.Size = new System.Drawing.Size(347, 131); this.ctrlCallstack.TabIndex = 0; this.ctrlCallstack.FunctionSelected += new System.EventHandler(this.ctrlCallstack_FunctionSelected); // @@ -482,7 +526,7 @@ namespace Mesen.GUI.Debugger this.toolsToolStripMenuItem}); this.menuStrip.Location = new System.Drawing.Point(0, 0); this.menuStrip.Name = "menuStrip"; - this.menuStrip.Size = new System.Drawing.Size(1172, 24); + this.menuStrip.Size = new System.Drawing.Size(1075, 24); this.menuStrip.TabIndex = 2; this.menuStrip.Text = "menuStrip1"; // @@ -775,6 +819,13 @@ namespace Mesen.GUI.Debugger this.mnuBreakIn.Text = "Break in..."; this.mnuBreakIn.Click += new System.EventHandler(this.mnuBreakIn_Click); // + // mnuBreakOn + // + this.mnuBreakOn.Name = "mnuBreakOn"; + this.mnuBreakOn.Size = new System.Drawing.Size(212, 22); + this.mnuBreakOn.Text = "Break on..."; + this.mnuBreakOn.Click += new System.EventHandler(this.mnuBreakOn_Click); + // // searchToolStripMenuItem // this.searchToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -1524,9 +1575,9 @@ namespace Mesen.GUI.Debugger this.toolStripStatusLabel1, this.lblCyclesElapsedCount, this.lblCyclesElapsed}); - this.statusStrip.Location = new System.Drawing.Point(0, 663); + this.statusStrip.Location = new System.Drawing.Point(0, 666); this.statusStrip.Name = "statusStrip"; - this.statusStrip.Size = new System.Drawing.Size(1172, 24); + this.statusStrip.Size = new System.Drawing.Size(1075, 24); this.statusStrip.TabIndex = 3; this.statusStrip.Text = "statusStrip1"; // @@ -1560,7 +1611,7 @@ namespace Mesen.GUI.Debugger // toolStripStatusLabel1 // this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(437, 19); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(340, 19); this.toolStripStatusLabel1.Spring = true; // // lblCyclesElapsedCount @@ -1579,9 +1630,9 @@ namespace Mesen.GUI.Debugger // ctrlPpuMemoryMapping // this.ctrlPpuMemoryMapping.Dock = System.Windows.Forms.DockStyle.Bottom; - this.ctrlPpuMemoryMapping.Location = new System.Drawing.Point(0, 630); + this.ctrlPpuMemoryMapping.Location = new System.Drawing.Point(0, 633); this.ctrlPpuMemoryMapping.Name = "ctrlPpuMemoryMapping"; - this.ctrlPpuMemoryMapping.Size = new System.Drawing.Size(1172, 33); + this.ctrlPpuMemoryMapping.Size = new System.Drawing.Size(1075, 33); this.ctrlPpuMemoryMapping.TabIndex = 5; this.ctrlPpuMemoryMapping.Text = "ctrlMemoryMapping1"; this.ctrlPpuMemoryMapping.Visible = false; @@ -1589,9 +1640,9 @@ namespace Mesen.GUI.Debugger // ctrlCpuMemoryMapping // this.ctrlCpuMemoryMapping.Dock = System.Windows.Forms.DockStyle.Bottom; - this.ctrlCpuMemoryMapping.Location = new System.Drawing.Point(0, 597); + this.ctrlCpuMemoryMapping.Location = new System.Drawing.Point(0, 600); this.ctrlCpuMemoryMapping.Name = "ctrlCpuMemoryMapping"; - this.ctrlCpuMemoryMapping.Size = new System.Drawing.Size(1172, 33); + this.ctrlCpuMemoryMapping.Size = new System.Drawing.Size(1075, 33); this.ctrlCpuMemoryMapping.TabIndex = 4; this.ctrlCpuMemoryMapping.Text = "ctrlMemoryMapping1"; this.ctrlCpuMemoryMapping.Visible = false; @@ -1600,23 +1651,16 @@ namespace Mesen.GUI.Debugger // this.tsToolbar.Location = new System.Drawing.Point(0, 24); this.tsToolbar.Name = "tsToolbar"; - this.tsToolbar.Size = new System.Drawing.Size(1172, 25); + this.tsToolbar.Size = new System.Drawing.Size(1075, 25); this.tsToolbar.TabIndex = 6; this.tsToolbar.Text = "toolStrip1"; this.tsToolbar.Visible = false; // - // mnuBreakOn - // - this.mnuBreakOn.Name = "mnuBreakOn"; - this.mnuBreakOn.Size = new System.Drawing.Size(212, 22); - this.mnuBreakOn.Text = "Break on..."; - this.mnuBreakOn.Click += new System.EventHandler(this.mnuBreakOn_Click); - // // frmDebugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1172, 687); + this.ClientSize = new System.Drawing.Size(1075, 690); this.Controls.Add(this.splitContainer); this.Controls.Add(this.ctrlCpuMemoryMapping); this.Controls.Add(this.ctrlPpuMemoryMapping); @@ -1636,6 +1680,8 @@ namespace Mesen.GUI.Debugger ((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainerTop)).EndInit(); this.ctrlSplitContainerTop.ResumeLayout(false); this.tlpTop.ResumeLayout(false); + this.panel1.ResumeLayout(false); + this.panel2.ResumeLayout(false); this.tlpFunctionLabelLists.ResumeLayout(false); this.grpLabels.ResumeLayout(false); this.grpFunctions.ResumeLayout(false); @@ -1798,6 +1844,10 @@ namespace Mesen.GUI.Debugger private System.Windows.Forms.ToolStripSeparator toolStripMenuItem20; private System.Windows.Forms.ToolStripMenuItem mnuBringToFrontOnPause; private System.Windows.Forms.ToolStripMenuItem mnuBringToFrontOnBreak; + private ctrlSourceViewer ctrlSourceViewer; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel2; + private ctrlSourceViewer ctrlSourceViewerSplit; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem21; private System.Windows.Forms.ToolStripMenuItem mnuSelectFont; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem22; diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index 82d00d1c..c14e7804 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -24,7 +24,7 @@ namespace Mesen.GUI.Debugger private int _previousCycle = 0; private InteropEmu.NotificationListener _notifListener; - private ctrlDebuggerCode _lastCodeWindow; + private ICodeViewer _lastCodeWindow; private Size _minimumSize; public frmDebugger() @@ -51,9 +51,27 @@ namespace Mesen.GUI.Debugger BreakpointManager.BreakpointsChanged += BreakpointManager_BreakpointsChanged; ctrlProfiler.OnFunctionSelected += ctrlProfiler_OnFunctionSelected; + ctrlDebuggerCode.CodeViewerActions.OnSetNextStatement += ctrlDebuggerCode_OnSetNextStatement; + ctrlDebuggerCode.CodeViewerActions.OnShowInSplitView += ctrlDebuggerCode_OnShowInSplitView; + ctrlDebuggerCode.CodeViewerActions.OnSwitchView += ctrlDebuggerCode_OnSwitchView; + + ctrlDebuggerCodeSplit.CodeViewerActions.OnSetNextStatement += ctrlDebuggerCode_OnSetNextStatement; + ctrlDebuggerCodeSplit.CodeViewerActions.OnShowInSplitView += ctrlDebuggerCode_OnShowInSplitView; + ctrlDebuggerCodeSplit.CodeViewerActions.OnSwitchView += ctrlDebuggerCode_OnSwitchView; + + ctrlSourceViewer.CodeViewerActions.OnSetNextStatement += ctrlDebuggerCode_OnSetNextStatement; + ctrlSourceViewer.CodeViewerActions.OnShowInSplitView += ctrlDebuggerCode_OnShowInSplitView; + ctrlSourceViewer.CodeViewerActions.OnSwitchView += ctrlDebuggerCode_OnSwitchView; + + ctrlSourceViewerSplit.CodeViewerActions.OnSetNextStatement += ctrlDebuggerCode_OnSetNextStatement; + ctrlSourceViewerSplit.CodeViewerActions.OnShowInSplitView += ctrlDebuggerCode_OnShowInSplitView; + ctrlSourceViewerSplit.CodeViewerActions.OnSwitchView += ctrlDebuggerCode_OnSwitchView; + Font font = new Font(ConfigManager.Config.DebugInfo.FontFamily, ConfigManager.Config.DebugInfo.FontSize, ConfigManager.Config.DebugInfo.FontStyle); - ctrlDebuggerCode.BaseFont = font; - ctrlDebuggerCodeSplit.BaseFont = font; + ctrlDebuggerCode.CodeViewer.BaseFont = font; + ctrlDebuggerCodeSplit.CodeViewer.BaseFont = font; + ctrlSourceViewer.CodeViewer.BaseFont = font; + ctrlSourceViewerSplit.CodeViewer.BaseFont = font; this.InitShortcuts(); this.InitToolbar(); @@ -127,7 +145,9 @@ namespace Mesen.GUI.Debugger _lastCodeWindow = ctrlDebuggerCode; this.ctrlDebuggerCode.SetConfig(ConfigManager.Config.DebugInfo.LeftView); + this.ctrlSourceViewer.SetConfig(ConfigManager.Config.DebugInfo.LeftView); this.ctrlDebuggerCodeSplit.SetConfig(ConfigManager.Config.DebugInfo.RightView); + this.ctrlSourceViewerSplit.SetConfig(ConfigManager.Config.DebugInfo.RightView); this.toolTip.SetToolTip(this.picWatchHelp, frmBreakpoint.GetConditionTooltip(true)); @@ -214,7 +234,8 @@ namespace Mesen.GUI.Debugger mnuToggleBreakpoint, mnuDisableEnableBreakpoint, null, mnuFind, mnuFindPrev, mnuFindNext, null, mnuApuViewer, mnuAssembler, mnuMemoryViewer, mnuEventViewer, mnuPpuViewer, mnuScriptWindow, mnuTraceLogger, null, - mnuEditHeader, null + mnuEditHeader, null, + mnuSplitView, null ); AddItemToToolbar(mnuShowVerifiedData, "Show Verified Data"); AddItemToToolbar(mnuShowUnidentifiedData, "Show Unidentified Code/Data"); @@ -316,12 +337,16 @@ namespace Mesen.GUI.Debugger private void AutoLoadDbgFiles(bool silent) { + ctrlSourceViewer.SymbolProvider = null; + ctrlSourceViewerSplit.SymbolProvider = null; + ctrlDebuggerCode.SymbolProvider = null; + ctrlDebuggerCodeSplit.SymbolProvider = null; + if(ConfigManager.Config.DebugInfo.AutoLoadDbgFiles) { RomInfo info = InteropEmu.GetRomInfo(); string dbgPath = Path.Combine(info.RomFile.Folder, info.GetRomName() + ".dbg"); if(File.Exists(dbgPath)) { - Ld65DbgImporter dbgImporter = new Ld65DbgImporter(); - dbgImporter.Import(dbgPath, silent); + ImportDbgFile(dbgPath, silent); } else { string mlbPath = Path.Combine(info.RomFile.Folder, info.GetRomName() + ".mlb"); if(File.Exists(mlbPath)) { @@ -329,6 +354,24 @@ namespace Mesen.GUI.Debugger } } } + + if(ctrlSourceViewer.SymbolProvider == null) { + ctrlSourceViewer.Visible = false; + ctrlSourceViewerSplit.Visible = false; + ctrlDebuggerCode.Visible = true; + ctrlDebuggerCodeSplit.Visible = true; + ctrlDebuggerCode.Focus(); + } + } + + private void ImportDbgFile(string dbgPath, bool silent) + { + Ld65DbgImporter dbgImporter = new Ld65DbgImporter(); + dbgImporter.Import(dbgPath, silent); + ctrlDebuggerCode.SymbolProvider = dbgImporter; + ctrlDebuggerCodeSplit.SymbolProvider = dbgImporter; + ctrlSourceViewer.SymbolProvider = dbgImporter; + ctrlSourceViewerSplit.SymbolProvider = dbgImporter; } private void UpdateWorkspace() @@ -479,7 +522,7 @@ namespace Mesen.GUI.Debugger } ctrlDebuggerCodeSplit.UpdateCode(true); } else { - _lastCodeWindow = ctrlDebuggerCode; + _lastCodeWindow = ctrlSourceViewer.Visible ? (ICodeViewer)ctrlSourceViewer : (ICodeViewer)ctrlDebuggerCode; } if(updateActiveAddress) { @@ -487,10 +530,12 @@ namespace Mesen.GUI.Debugger } ctrlDebuggerCode.SetActiveAddress(state.CPU.DebugPC); + ctrlSourceViewer.SetActiveAddress(state.CPU.DebugPC); ctrlDebuggerCode.UpdateLineColors(); if(UpdateSplitView()) { ctrlDebuggerCodeSplit.SetActiveAddress(state.CPU.DebugPC); + ctrlSourceViewerSplit.SetActiveAddress(state.CPU.DebugPC); ctrlDebuggerCodeSplit.UpdateLineColors(); } @@ -520,6 +565,9 @@ namespace Mesen.GUI.Debugger ctrlDebuggerCode.UpdateLineColors(); ctrlDebuggerCodeSplit.ClearActiveAddress(); ctrlDebuggerCodeSplit.UpdateLineColors(); + + ctrlSourceViewer.ClearActiveAddress(); + ctrlSourceViewerSplit.ClearActiveAddress(); } public void TogglePause() @@ -534,7 +582,7 @@ namespace Mesen.GUI.Debugger private void ToggleBreakpoint(bool toggleEnabled) { - _lastCodeWindow.ToggleBreakpoint(toggleEnabled); + _lastCodeWindow.CodeViewerActions.ToggleBreakpoint(toggleEnabled); } private void ResumeExecution() @@ -611,42 +659,88 @@ namespace Mesen.GUI.Debugger InteropEmu.DebugPpuStep(89341); } - private void ctrlDebuggerCode_OnScrollToAddress(ctrlDebuggerCode sender, AddressEventArgs args) + private void ctrlDebuggerCode_OnShowInSplitView(ICodeViewer sender, AddressEventArgs args) { + if(!ConfigManager.Config.DebugInfo.SplitView) { + mnuSplitView.Checked = true; + ConfigManager.Config.DebugInfo.SplitView = true; + ConfigManager.ApplyChanges(); + UpdateDebugger(false); + } + UInt16 addr = (UInt16)args.Address; - if(sender == ctrlDebuggerCode) { - if(!ConfigManager.Config.DebugInfo.SplitView) { - mnuSplitView.Checked = true; - ConfigManager.Config.DebugInfo.SplitView = true; - ConfigManager.ApplyChanges(); - UpdateDebugger(false); + if(sender == ctrlDebuggerCode || sender == ctrlSourceViewer) { + if(ctrlSourceViewerSplit.Visible) { + ctrlSourceViewerSplit.ScrollToLineNumber(addr); + } else { + ctrlDebuggerCodeSplit.ScrollToLineNumber(addr); } - ctrlDebuggerCodeSplit.ScrollToLineNumber(addr); } else { - ctrlDebuggerCode.ScrollToLineNumber(addr); + if(ctrlSourceViewer.Visible) { + ctrlSourceViewer.ScrollToLineNumber(addr); + } else { + ctrlDebuggerCode.ScrollToLineNumber(addr); + } } } - private void ctrlDebuggerCode_OnSetNextStatement(ctrlDebuggerCode sender, AddressEventArgs args) + private void ctrlDebuggerCode_OnSetNextStatement(AddressEventArgs args) { UInt16 addr = (UInt16)args.Address; InteropEmu.DebugSetNextStatement(addr); this.UpdateDebugger(); } + private void ctrlDebuggerCode_OnSwitchView(ICodeViewer sender) + { + if(ctrlDebuggerCode == sender) { + ctrlDebuggerCode.Visible = false; + ctrlSourceViewer.Visible = true; + if(ctrlDebuggerCode.CodeViewer.CurrentLine >= 0) { + ctrlSourceViewer.ScrollToLineNumber(ctrlDebuggerCode.CodeViewer.CurrentLine); + } + ctrlSourceViewer.Focus(); + ctrlSourceViewer.SetConfig(ConfigManager.Config.DebugInfo.LeftView); + } else if(ctrlSourceViewer == sender) { + ctrlSourceViewer.Visible = false; + ctrlDebuggerCode.Visible = true; + if(ctrlDebuggerCode.CodeViewer.CurrentLine >= 0) { + ctrlDebuggerCode.ScrollToLineNumber(ctrlDebuggerCode.CodeViewer.CurrentLine); + } + ctrlDebuggerCode.Focus(); + ctrlDebuggerCode.SetConfig(ConfigManager.Config.DebugInfo.LeftView); + } else if(ctrlSourceViewerSplit == sender) { + ctrlSourceViewerSplit.Visible = false; + ctrlDebuggerCodeSplit.Visible = true; + if(ctrlSourceViewerSplit.CodeViewer.CurrentLine >= 0) { + ctrlDebuggerCodeSplit.ScrollToLineNumber(ctrlSourceViewerSplit.CodeViewer.CurrentLine); + } + ctrlDebuggerCodeSplit.Focus(); + ctrlDebuggerCodeSplit.SetConfig(ConfigManager.Config.DebugInfo.RightView); + } else { + ctrlDebuggerCodeSplit.Visible = false; + ctrlSourceViewerSplit.Visible = true; + if(ctrlDebuggerCodeSplit.CodeViewer.CurrentLine >= 0) { + ctrlSourceViewerSplit.ScrollToLineNumber(ctrlDebuggerCodeSplit.CodeViewer.CurrentLine); + } + ctrlSourceViewerSplit.Focus(); + ctrlSourceViewerSplit.SetConfig(ConfigManager.Config.DebugInfo.RightView); + } + } + private void mnuFind_Click(object sender, EventArgs e) { - _lastCodeWindow.OpenSearchBox(); + _lastCodeWindow.CodeViewer.OpenSearchBox(); } private void mnuFindNext_Click(object sender, EventArgs e) { - _lastCodeWindow.FindNext(); + _lastCodeWindow.CodeViewer.FindNext(); } private void mnuFindPrev_Click(object sender, EventArgs e) { - _lastCodeWindow.FindPrevious(); + _lastCodeWindow.CodeViewer.FindPrevious(); } private void mnuSplitView_Click(object sender, EventArgs e) @@ -671,21 +765,19 @@ namespace Mesen.GUI.Debugger { ctrlDebuggerCodeSplit.UpdateLineColors(); ctrlDebuggerCode.UpdateLineColors(); + + ctrlSourceViewer.RefreshViewer(); + ctrlSourceViewerSplit.RefreshViewer(); } private void ctrlDebuggerCode_Enter(object sender, EventArgs e) { - _lastCodeWindow = ctrlDebuggerCode; - } - - private void ctrlDebuggerCodeSplit_Enter(object sender, EventArgs e) - { - _lastCodeWindow = ctrlDebuggerCodeSplit; + _lastCodeWindow = (ICodeViewer)sender; } private void mnuGoToAddress_Click(object sender, EventArgs e) { - _lastCodeWindow.GoToAddress(); + _lastCodeWindow.CodeViewer.GoToAddress(); } private void mnuGoToIrqHandler_Click(object sender, EventArgs e) @@ -708,24 +800,22 @@ namespace Mesen.GUI.Debugger private void mnuGoToProgramCount_Click(object sender, EventArgs e) { - DebugState state = new DebugState(); - InteropEmu.DebugGetState(ref state); - _lastCodeWindow.ScrollToActiveAddress(); + _lastCodeWindow.CodeViewerActions.ScrollToActiveAddress(); } private void mnuIncreaseFontSize_Click(object sender, EventArgs e) { - _lastCodeWindow.TextZoom += 10; + _lastCodeWindow.CodeViewer.TextZoom += 10; } private void mnuDecreaseFontSize_Click(object sender, EventArgs e) { - _lastCodeWindow.TextZoom -= 10; + _lastCodeWindow.CodeViewer.TextZoom -= 10; } private void mnuResetFontSize_Click(object sender, EventArgs e) { - _lastCodeWindow.TextZoom = 100; + _lastCodeWindow.CodeViewer.TextZoom = 100; } private void mnuClose_Click(object sender, EventArgs e) @@ -755,9 +845,9 @@ namespace Mesen.GUI.Debugger } InteropEmu.DebugRun(); - ConfigManager.Config.DebugInfo.FontFamily = ctrlDebuggerCode.BaseFont.FontFamily.Name; - ConfigManager.Config.DebugInfo.FontStyle = ctrlDebuggerCode.BaseFont.Style; - ConfigManager.Config.DebugInfo.FontSize = ctrlDebuggerCode.BaseFont.Size; + ConfigManager.Config.DebugInfo.FontFamily = ctrlDebuggerCode.CodeViewer.BaseFont.FontFamily.Name; + ConfigManager.Config.DebugInfo.FontStyle = ctrlDebuggerCode.CodeViewer.BaseFont.Style; + ConfigManager.Config.DebugInfo.FontSize = ctrlDebuggerCode.CodeViewer.BaseFont.Size; ConfigManager.Config.DebugInfo.WindowWidth = this.WindowState == FormWindowState.Maximized ? this.RestoreBounds.Width : this.Width; ConfigManager.Config.DebugInfo.WindowHeight = this.WindowState == FormWindowState.Maximized ? this.RestoreBounds.Height : this.Height; ConfigManager.Config.DebugInfo.TopPanelHeight = this.splitContainer.GetSplitterDistance(); @@ -1034,8 +1124,7 @@ namespace Mesen.GUI.Debugger if(ext == ".mlb") { MesenLabelFile.Import(ofd.FileName); } else { - Ld65DbgImporter dbgImporter = new Ld65DbgImporter(); - dbgImporter.Import(ofd.FileName); + ImportDbgFile(ofd.FileName, false); } } } @@ -1253,8 +1342,13 @@ namespace Mesen.GUI.Debugger private void mnuCode_DropDownOpening(object sender, EventArgs e) { - this._lastCodeWindow.UpdateContextMenuItemVisibility(false); - mnuCode.DropDownItems.AddRange(this._lastCodeWindow.ContextMenuItems.ToArray()); + this._lastCodeWindow.CodeViewerActions.UpdateContextMenuItemVisibility(false); + + List items = new List(); + foreach(ToolStripItem item in this._lastCodeWindow.CodeViewerActions.contextMenu.Items) { + items.Add(item); + } + mnuCode.DropDownItems.AddRange(items.ToArray()); } private void mnuCode_DropDownClosed(object sender, EventArgs e) @@ -1263,7 +1357,7 @@ namespace Mesen.GUI.Debugger foreach(ToolStripItem item in mnuCode.DropDownItems) { items.Add(item); } - this._lastCodeWindow.ContextMenuItems = items; + this._lastCodeWindow.CodeViewerActions.contextMenu.Items.AddRange(items.ToArray()); } private void mnuCdlStripUsedData_Click(object sender, EventArgs e) @@ -1287,8 +1381,10 @@ namespace Mesen.GUI.Debugger private void mnuSelectFont_Click(object sender, EventArgs e) { - ctrlDebuggerCode.BaseFont = FontDialogHelper.SelectFont(ctrlDebuggerCode.Font); - ctrlDebuggerCodeSplit.BaseFont = ctrlDebuggerCode.BaseFont; + ctrlDebuggerCode.CodeViewer.BaseFont = FontDialogHelper.SelectFont(ctrlDebuggerCode.CodeViewer.BaseFont); + ctrlDebuggerCodeSplit.CodeViewer.BaseFont = ctrlDebuggerCode.CodeViewer.BaseFont; + ctrlSourceViewer.CodeViewer.BaseFont = ctrlDebuggerCode.CodeViewer.BaseFont; + ctrlSourceViewerSplit.CodeViewer.BaseFont = ctrlDebuggerCode.CodeViewer.BaseFont; } private void mnuPreferences_Click(object sender, EventArgs e) diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs index dd0c6245..025ff419 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.cs @@ -165,13 +165,18 @@ namespace Mesen.GUI.Debugger } } - public void ShowAddress(int address) + public void ShowAddress(int address, bool usePrgRom) { tabMain.SelectedTab = tpgMemoryViewer; - cboMemoryType.SelectedIndex = 0; //Select CPU Memory - ctrlHexViewer.GoToAddress(address); + if(usePrgRom) { + cboMemoryType.SetEnumValue(DebugMemoryType.PrgRom); + ctrlHexViewer.GoToAddress(address); + } else { + cboMemoryType.SetEnumValue(DebugMemoryType.CpuMemory); + ctrlHexViewer.GoToAddress(address); + } } - + private void InitTblMappings() { DebugWorkspace workspace = DebugWorkspaceManager.GetWorkspace(); diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index 140b3126..62aec5eb 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -323,6 +323,7 @@ + UserControl @@ -362,6 +363,12 @@ UserControl + + UserControl + + + CodeViewerActions.cs + Component @@ -392,6 +399,12 @@ ctrlDbgShortcuts.cs + + UserControl + + + ctrlFindOccurrences.cs + UserControl @@ -438,6 +451,12 @@ ctrlPaletteViewer.cs + + UserControl + + + ctrlSourceViewer.cs + UserControl @@ -502,6 +521,7 @@ ctrlWatch.cs + UserControl @@ -599,6 +619,12 @@ frmBreakOn.cs + + Form + + + frmCodePreviewTooltip.cs + Form @@ -1134,6 +1160,7 @@ + @@ -1174,15 +1201,24 @@ ctrlSquareInfo.cs + + CodeViewerActions.cs + ctrlDbgShortcuts.cs + + ctrlFindOccurrences.cs + ctrlFlagStatus.cs ctrlEventViewerPpuView.cs + + ctrlSourceViewer.cs + @@ -1302,6 +1338,9 @@ frmBreakOn.cs + + frmCodePreviewTooltip.cs + frmDbgPreferences.cs diff --git a/GUI.NET/Properties/Resources.Designer.cs b/GUI.NET/Properties/Resources.Designer.cs index 6bb9374b..21000e64 100644 --- a/GUI.NET/Properties/Resources.Designer.cs +++ b/GUI.NET/Properties/Resources.Designer.cs @@ -890,6 +890,16 @@ namespace Mesen.GUI.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap SwitchView { + get { + object obj = ResourceManager.GetObject("SwitchView", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/GUI.NET/Properties/Resources.resx b/GUI.NET/Properties/Resources.resx index cb5c8812..55343396 100644 --- a/GUI.NET/Properties/Resources.resx +++ b/GUI.NET/Properties/Resources.resx @@ -397,4 +397,7 @@ ..\Resources\SelectAll.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\SwitchView.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/GUI.NET/Resources/SwitchView.png b/GUI.NET/Resources/SwitchView.png new file mode 100644 index 00000000..50431475 Binary files /dev/null and b/GUI.NET/Resources/SwitchView.png differ