diff --git a/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs b/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs index 79e8fd31..f1d53e76 100644 --- a/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs +++ b/GUI.NET/Debugger/Controls/BaseScrollableTextboxUserControl.cs @@ -9,14 +9,19 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger.Controls { - public abstract class BaseScrollableTextboxUserControl : UserControl + public class BaseScrollableTextboxUserControl : UserControl { - protected abstract ctrlScrollableTextbox ScrollableTextbox + virtual protected ctrlScrollableTextbox ScrollableTextbox { - get; + get + { + return null; + } } [DefaultValue(13F)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public float FontSize { get { return this.ScrollableTextbox.FontSize; } @@ -57,10 +62,10 @@ namespace Mesen.GUI.Debugger.Controls { this.ScrollableTextbox.ScrollToLineNumber(0); } - - public string GetWordUnderLocation(Point position) + + public string GetWordUnderLocation(Point position, bool useCompareText = false) { - return this.ScrollableTextbox.GetWordUnderLocation(position); + return this.ScrollableTextbox.GetWordUnderLocation(position, useCompareText); } } } diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs index 35230af0..31237edc 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs @@ -151,7 +151,9 @@ namespace Mesen.GUI.Debugger UInt32 address = UInt32.Parse(word.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier); Byte memoryValue = InteropEmu.DebugGetMemoryValue(address); string valueText = "$" + memoryValue.ToString("X"); - toolTip.Show(valueText, ctrlCodeViewer, e.Location.X + 5, e.Location.Y + 5, 3000); + toolTip.Show(valueText, ctrlCodeViewer, e.Location.X + 5, e.Location.Y - 20, 3000); + } else { + toolTip.Hide(ctrlCodeViewer); } _previousLocation = e.Location; } diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.Designer.cs b/GUI.NET/Debugger/Controls/ctrlHexViewer.Designer.cs index 0dd204c3..b582cda4 100644 --- a/GUI.NET/Debugger/Controls/ctrlHexViewer.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.Designer.cs @@ -27,11 +27,13 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.ctrlDataViewer = new Mesen.GUI.Debugger.ctrlScrollableTextbox(); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.lblNumberOfColumns = new System.Windows.Forms.Label(); this.cboNumberColumns = new System.Windows.Forms.ComboBox(); - this.ctrlDataViewer = new Mesen.GUI.Debugger.ctrlScrollableTextbox(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.tableLayoutPanel1.SuspendLayout(); this.flowLayoutPanel1.SuspendLayout(); this.SuspendLayout(); @@ -51,6 +53,17 @@ this.tableLayoutPanel1.Size = new System.Drawing.Size(191, 109); this.tableLayoutPanel1.TabIndex = 0; // + // ctrlDataViewer + // + this.ctrlDataViewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.ctrlDataViewer.Dock = System.Windows.Forms.DockStyle.Fill; + this.ctrlDataViewer.FontSize = 13F; + this.ctrlDataViewer.Location = new System.Drawing.Point(3, 30); + this.ctrlDataViewer.Name = "ctrlDataViewer"; + this.ctrlDataViewer.Size = new System.Drawing.Size(185, 76); + this.ctrlDataViewer.TabIndex = 0; + this.ctrlDataViewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlDataViewer_MouseMove); + // // flowLayoutPanel1 // this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -58,7 +71,7 @@ this.flowLayoutPanel1.Controls.Add(this.lblNumberOfColumns); this.flowLayoutPanel1.Controls.Add(this.cboNumberColumns); this.flowLayoutPanel1.Location = new System.Drawing.Point(27, 0); - this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); + this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; this.flowLayoutPanel1.Size = new System.Drawing.Size(164, 27); this.flowLayoutPanel1.TabIndex = 1; @@ -89,16 +102,6 @@ this.cboNumberColumns.TabIndex = 1; this.cboNumberColumns.SelectedIndexChanged += new System.EventHandler(this.cboNumberColumns_SelectedIndexChanged); // - // ctrlDataViewer - // - this.ctrlDataViewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.ctrlDataViewer.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlDataViewer.FontSize = 13F; - this.ctrlDataViewer.Location = new System.Drawing.Point(3, 30); - this.ctrlDataViewer.Name = "ctrlDataViewer"; - this.ctrlDataViewer.Size = new System.Drawing.Size(185, 76); - this.ctrlDataViewer.TabIndex = 0; - // // ctrlHexViewer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -121,5 +124,6 @@ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.Label lblNumberOfColumns; private System.Windows.Forms.ComboBox cboNumberColumns; + private System.Windows.Forms.ToolTip toolTip; } } diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs index 42e9a608..7ffa5df2 100644 --- a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs +++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs @@ -14,6 +14,8 @@ namespace Mesen.GUI.Debugger.Controls { public event EventHandler ColumnCountChanged; + private string[] _previousHexContent = null; + private int _currentColumnCount; private byte[] _data; public ctrlHexViewer() @@ -36,11 +38,19 @@ namespace Mesen.GUI.Debugger.Controls set { if(value != null) { + if(_currentColumnCount != this.ColumnCount) { + this._previousHexContent = null; + _currentColumnCount = this.ColumnCount; + } + this._data = value; string[] hexContent; int[] lineNumbers; this.ArrayToHex(value, out hexContent, out lineNumbers); + this.ctrlDataViewer.CompareLines = _previousHexContent; this.ctrlDataViewer.TextLines = hexContent; + _previousHexContent = hexContent; + this.ctrlDataViewer.LineNumbers = lineNumbers; if(this.ColumnCount == 16) { this.ctrlDataViewer.Header = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"; @@ -131,5 +141,21 @@ namespace Mesen.GUI.Debugger.Controls this.Data = _data; this.ctrlDataViewer.Focus(); } + + Point _previousLocation; + private void ctrlDataViewer_MouseMove(object sender, MouseEventArgs e) + { + if(_previousLocation != e.Location) { + string currentWord = this.GetWordUnderLocation(e.Location, false); + string originalWord = this.GetWordUnderLocation(e.Location, true); + + if(currentWord != originalWord) { + this.toolTip.Show("Previous Value: $" + originalWord + Environment.NewLine + "Current Value: $" + currentWord, this.ctrlDataViewer, e.Location.X + 5, e.Location.Y - 40, 3000); + } else { + this.toolTip.Hide(this.ctrlDataViewer); + } + _previousLocation = e.Location; + } + } } } diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.resx b/GUI.NET/Debugger/Controls/ctrlHexViewer.resx index 1af7de15..8766f298 100644 --- a/GUI.NET/Debugger/Controls/ctrlHexViewer.resx +++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.resx @@ -117,4 +117,7 @@ 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/ctrlScrollableTextbox.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs index 909e9ef4..d106c0b1 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs @@ -50,9 +50,9 @@ namespace Mesen.GUI.Debugger } } - public string GetWordUnderLocation(Point position) + public string GetWordUnderLocation(Point position, bool useCompareText = false) { - return this.ctrlTextbox.GetWordUnderLocation(position); + return this.ctrlTextbox.GetWordUnderLocation(position, useCompareText); } private void ctrlTextbox_ScrollPositionChanged(object sender, EventArgs e) @@ -170,6 +170,14 @@ namespace Mesen.GUI.Debugger this.vScrollBar.Maximum = this.ctrlTextbox.LineCount + this.vScrollBar.LargeChange; } } + + public string[] CompareLines + { + set + { + this.ctrlTextbox.CompareLines = value; + } + } public int[] LineNumbers { diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index 8b322652..0e0d4d33 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -32,6 +33,7 @@ namespace Mesen.GUI.Debugger public event EventHandler ScrollPositionChanged; private string[] _contents = new string[0]; + private string[] _compareContents = null; private int[] _lineNumbers = new int[0]; private Dictionary _lineNumberIndex = new Dictionary(); private Dictionary _lineProperties = new Dictionary(); @@ -64,6 +66,14 @@ namespace Mesen.GUI.Debugger } } + public string[] CompareLines + { + set + { + _compareContents = value; + } + } + public int LineCount { get @@ -209,39 +219,46 @@ namespace Mesen.GUI.Debugger { return this.ShowLineNumbers ? (int)(g.MeasureString("W", this.Font).Width * 6) : 0; } - - public string GetWordUnderLocation(Point position) + + private bool GetCharIndex(Point position, out int charIndex, out int lineIndex) { + charIndex = -1; using(Graphics g = Graphics.FromHwnd(this.Handle)) { int marginLeft = this.GetMargin(g); int positionX = position.X - marginLeft; - int lineOffset = this.GetLineAtPosition(position.Y); - if(positionX >= 0 && this.ScrollPosition + lineOffset < _contents.Length) { - string text = _contents[this.ScrollPosition + lineOffset]; - int charIndex = -1; + lineIndex = this.ScrollPosition + this.GetLineAtPosition(position.Y); + if(positionX >= 0 && lineIndex < _contents.Length) { + string text = _contents[lineIndex]; int previousWidth = 0; for(int i = 0, len = text.Length; i < len; i++) { int width = (int)g.MeasureString(text.Substring(0, i+1), this.Font).Width; if(width >= positionX && previousWidth <= positionX) { charIndex = i; - break; + return true; } previousWidth = width; } + } + } + return false; + } - if(charIndex >= 0) { - List wordDelimiters = new List(new char[] { ' ', ',' }); - if(wordDelimiters.Contains(text[charIndex])) { - return string.Empty; - } else { - int endIndex = text.IndexOfAny(wordDelimiters.ToArray(), charIndex); - if(endIndex == -1) { - endIndex = text.Length; - } - int startIndex = text.LastIndexOfAny(wordDelimiters.ToArray(), charIndex); - return text.Substring(startIndex + 1, endIndex - startIndex - 1); - } + public string GetWordUnderLocation(Point position, bool useCompareText = false) + { + int charIndex; + int lineIndex; + if(this.GetCharIndex(position, out charIndex, out lineIndex)) { + string text = (useCompareText && _compareContents != null) ? _compareContents[lineIndex] : _contents[lineIndex]; + List wordDelimiters = new List(new char[] { ' ', ',' }); + if(wordDelimiters.Contains(text[charIndex])) { + return string.Empty; + } else { + int endIndex = text.IndexOfAny(wordDelimiters.ToArray(), charIndex); + if(endIndex == -1) { + endIndex = text.Length; } + int startIndex = text.LastIndexOfAny(wordDelimiters.ToArray(), charIndex); + return text.Substring(startIndex + 1, endIndex - startIndex - 1); } } return string.Empty; @@ -401,29 +418,58 @@ namespace Mesen.GUI.Debugger string lineText = _contents[currentLine]; using(Brush fgBrush = new SolidBrush(textColor)) { g.DrawString(lineText, this.Font, fgBrush, marginLeft, positionY); + this.DrawHighlightedSearchString(g, lineText, marginLeft, positionY); + this.DrawHighlightedCompareString(g, lineText, currentLine, marginLeft, positionY); + } + } - int searchIndex; - if(!string.IsNullOrWhiteSpace(this._searchString) && (searchIndex = lineText.ToLowerInvariant().IndexOf(this._searchString)) >= 0) { - //Draw colored search string - int previousSearchIndex = -this._searchString.Length; + private void DrawHighlightedCompareString(Graphics g, string lineText, int currentLine, int marginLeft, int positionY) + { + if(_compareContents != null && _compareContents.Length > currentLine) { + string compareText = _compareContents[currentLine]; + + if(compareText != lineText) { StringBuilder sb = new StringBuilder(); - do { - sb.Append(string.Empty.PadLeft(searchIndex - previousSearchIndex - this._searchString.Length)); - sb.Append(lineText.Substring(searchIndex, this._searchString.Length)); - - previousSearchIndex = searchIndex; - searchIndex = lineText.ToLowerInvariant().IndexOf(this._searchString, searchIndex + this._searchString.Length); - } while(searchIndex >= 0); - - string drawSearchString = sb.ToString(); - using(Brush selBrush = new SolidBrush(Color.White), selBgBrush = new SolidBrush(Color.CornflowerBlue)) { - for(int i = -2; i <= 2; i++) { - for(int j = -2; j <= 2; j++) { - g.DrawString(drawSearchString, this.Font, selBgBrush, marginLeft + i, positionY + j); - } + for(int i = 0, len = lineText.Length; i < len; i++) { + if(lineText[i] == compareText[i]) { + sb.Append(" "); + } else { + sb.Append(lineText[i]); } - g.DrawString(drawSearchString, this.Font, selBrush, marginLeft, positionY); } + + g.DrawString(sb.ToString(), new Font(this.Font, FontStyle.Bold), Brushes.Red, marginLeft, positionY); + } + } + } + + private void DrawHighlightedSearchString(Graphics g, string lineText, int marginLeft, int positionY) + { + int searchIndex; + if(!string.IsNullOrWhiteSpace(this._searchString) && (searchIndex = lineText.ToLowerInvariant().IndexOf(this._searchString)) >= 0) { + //Draw colored search string + int previousSearchIndex = -this._searchString.Length; + string lowerCaseText = lineText.ToLowerInvariant(); + StringBuilder sb = new StringBuilder(); + StringBuilder sbBackground = new StringBuilder(); + do { + sb.Append(string.Empty.PadLeft(searchIndex - previousSearchIndex - this._searchString.Length)); + sbBackground.Append(string.Empty.PadLeft(searchIndex - previousSearchIndex - this._searchString.Length)); + + sb.Append(lineText.Substring(searchIndex, this._searchString.Length)); + sbBackground.Append(string.Empty.PadLeft(this._searchString.Length, '█')); + + previousSearchIndex = searchIndex; + searchIndex = lowerCaseText.IndexOf(this._searchString, searchIndex + this._searchString.Length); + } while(searchIndex >= 0); + + string drawSearchString = sb.ToString(); + string drawSearchStringBg = sbBackground.ToString(); + + using(Brush selBrush = new SolidBrush(Color.White), selBgBrush = new SolidBrush(Color.CornflowerBlue)) { + g.DrawString(drawSearchStringBg, this.Font, selBgBrush, marginLeft-1, positionY); + g.DrawString(drawSearchStringBg, this.Font, selBgBrush, marginLeft+1, positionY); + g.DrawString(drawSearchString, this.Font, selBrush, marginLeft, positionY); } } } diff --git a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs index bf8cab7d..a74cb662 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs @@ -44,6 +44,8 @@ this.mnuIncreaseFontSize = new System.Windows.Forms.ToolStripMenuItem(); this.mnuDecreaseFontSize = new System.Windows.Forms.ToolStripMenuItem(); this.mnuResetFontSize = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFind = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFindNext = new System.Windows.Forms.ToolStripMenuItem(); @@ -130,14 +132,15 @@ // this.mnuView.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuRefresh, - this.fontSizeToolStripMenuItem}); + this.fontSizeToolStripMenuItem, + this.toolStripMenuItem2, + this.mnuAutoRefresh}); this.mnuView.Name = "mnuView"; this.mnuView.Size = new System.Drawing.Size(44, 20); this.mnuView.Text = "View"; // // mnuRefresh // - this.mnuRefresh.CheckOnClick = true; this.mnuRefresh.Name = "mnuRefresh"; this.mnuRefresh.ShortcutKeys = System.Windows.Forms.Keys.F5; this.mnuRefresh.Size = new System.Drawing.Size(152, 22); @@ -181,6 +184,20 @@ this.mnuResetFontSize.Text = "Reset to Default"; this.mnuResetFontSize.Click += new System.EventHandler(this.mnuResetFontSize_Click); // + // toolStripMenuItem2 + // + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + this.toolStripMenuItem2.Size = new System.Drawing.Size(149, 6); + // + // mnuAutoRefresh + // + this.mnuAutoRefresh.Checked = true; + this.mnuAutoRefresh.CheckOnClick = true; + this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked; + this.mnuAutoRefresh.Name = "mnuAutoRefresh"; + this.mnuAutoRefresh.Size = new System.Drawing.Size(152, 22); + this.mnuAutoRefresh.Text = "Auto-refresh"; + // // toolStripMenuItem1 // this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -265,5 +282,7 @@ private System.Windows.Forms.ToolStripMenuItem mnuResetFontSize; private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem mnuClose; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; + private System.Windows.Forms.ToolStripMenuItem mnuAutoRefresh; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs index 6017550c..8042c6e6 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.cs @@ -14,10 +14,16 @@ namespace Mesen.GUI.Debugger public partial class frmMemoryViewer : BaseForm { private InteropEmu.NotificationListener _notifListener; + private int _autoRefreshCounter = 0; public frmMemoryViewer() { InitializeComponent(); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); this.cboMemoryType.SelectedIndex = 0; this.Size = new Size(this.ctrlHexViewer.IdealWidth, this.Height); @@ -30,6 +36,13 @@ namespace Mesen.GUI.Debugger { if(e.NotificationType == InteropEmu.ConsoleNotificationType.CodeBreak) { this.BeginInvoke((MethodInvoker)(() => this.RefreshData())); + } else if(e.NotificationType == InteropEmu.ConsoleNotificationType.PpuFrameDone) { + this.BeginInvoke((MethodInvoker)(() => { + if(_autoRefreshCounter % 4 == 0 && this.mnuAutoRefresh.Checked) { + this.RefreshData(); + } + _autoRefreshCounter++; + })); } } diff --git a/GUI.NET/Debugger/frmPpuViewer.cs b/GUI.NET/Debugger/frmPpuViewer.cs index 416d022a..43e6751d 100644 --- a/GUI.NET/Debugger/frmPpuViewer.cs +++ b/GUI.NET/Debugger/frmPpuViewer.cs @@ -16,6 +16,7 @@ namespace Mesen.GUI.Debugger public partial class frmPpuViewer : BaseForm { private InteropEmu.NotificationListener _notifListener; + private int _autoRefreshCounter = 0; public frmPpuViewer() { @@ -61,9 +62,10 @@ namespace Mesen.GUI.Debugger private void AutoRefresh() { - if(mnuAutoRefresh.Checked) { + if(_autoRefreshCounter % 4 == 0 && this.mnuAutoRefresh.Checked) { this.RefreshViewers(); } + _autoRefreshCounter++; } private void mnuRefresh_Click(object sender, EventArgs e)