Debugger - Memory viewer now shows changes in red (with mouseover tooltip) + Performance fixes

This commit is contained in:
Souryo 2015-08-09 18:24:24 -04:00
parent cb8ec83408
commit 3b0ab71e92
10 changed files with 190 additions and 62 deletions

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -27,11 +27,13 @@
/// </summary>
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;
}
}

View file

@ -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;
}
}
}
}

View file

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

View file

@ -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
{

View file

@ -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<int, int> _lineNumberIndex = new Dictionary<int,int>();
private Dictionary<int, LineProperties> _lineProperties = new Dictionary<int,LineProperties>();
@ -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<char> wordDelimiters = new List<char>(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<char> wordDelimiters = new List<char>(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);
}
}
}

View file

@ -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;
}
}

View file

@ -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++;
}));
}
}

View file

@ -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)