diff --git a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs index 5fa4dc2e..f2e526b5 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs @@ -44,6 +44,7 @@ namespace Mesen.GUI.Debugger this.ctrlTextbox.ShowLineNumbers = true; this.ctrlTextbox.ShowLineInHex = true; + this.hScrollBar.ValueChanged += hScrollBar_ValueChanged; this.vScrollBar.ValueChanged += vScrollBar_ValueChanged; this.ctrlTextbox.ScrollPositionChanged += ctrlTextbox_ScrollPositionChanged; @@ -76,6 +77,18 @@ namespace Mesen.GUI.Debugger private void ctrlTextbox_ScrollPositionChanged(object sender, EventArgs e) { this.vScrollBar.Value = this.ctrlTextbox.ScrollPosition; + this.hScrollBar.Value = this.ctrlTextbox.HorizontalScrollPosition; + UpdateHorizontalScrollbar(); + } + + private void UpdateHorizontalScrollbar() + { + this.hScrollBar.Visible = this.ctrlTextbox.HorizontalScrollWidth > 0; + int newMax = this.ctrlTextbox.HorizontalScrollWidth + this.hScrollBar.LargeChange - 1; + if(this.hScrollBar.Value > this.ctrlTextbox.HorizontalScrollWidth) { + this.hScrollBar.Value = this.ctrlTextbox.HorizontalScrollWidth; + } + this.hScrollBar.Maximum = newMax; } public void ClearLineStyles() @@ -195,12 +208,18 @@ namespace Mesen.GUI.Debugger this.ctrlTextbox.ScrollPosition = this.vScrollBar.Value; } + private void hScrollBar_ValueChanged(object sender, EventArgs e) + { + this.ctrlTextbox.HorizontalScrollPosition = this.hScrollBar.Value; + } + public string[] TextLines { set { this.ctrlTextbox.TextLines = value; this.vScrollBar.Maximum = this.ctrlTextbox.LineCount + this.vScrollBar.LargeChange; + UpdateHorizontalScrollbar(); } } diff --git a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.designer.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.designer.cs index 789e3412..05759a15 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.designer.cs @@ -34,6 +34,7 @@ this.picSearchNext = new System.Windows.Forms.PictureBox(); this.picSearchPrevious = new System.Windows.Forms.PictureBox(); this.cboSearch = new System.Windows.Forms.ComboBox(); + this.hScrollBar = new System.Windows.Forms.HScrollBar(); this.ctrlTextbox = new Mesen.GUI.Debugger.ctrlTextbox(); this.panelSearch.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); @@ -48,7 +49,7 @@ this.vScrollBar.LargeChange = 20; this.vScrollBar.Location = new System.Drawing.Point(305, 0); this.vScrollBar.Name = "vScrollBar"; - this.vScrollBar.Size = new System.Drawing.Size(18, 174); + this.vScrollBar.Size = new System.Drawing.Size(18, 156); this.vScrollBar.TabIndex = 0; // // panelSearch @@ -132,15 +133,25 @@ this.cboSearch.TextUpdate += new System.EventHandler(this.cboSearch_TextUpdate); this.cboSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cboSearch_KeyDown); // + // hScrollBar + // + this.hScrollBar.Dock = System.Windows.Forms.DockStyle.Bottom; + this.hScrollBar.Location = new System.Drawing.Point(0, 156); + this.hScrollBar.Name = "hScrollBar"; + this.hScrollBar.Size = new System.Drawing.Size(323, 18); + this.hScrollBar.TabIndex = 3; + // // ctrlTextbox // this.ctrlTextbox.Dock = System.Windows.Forms.DockStyle.Fill; this.ctrlTextbox.Font = new System.Drawing.Font("Consolas", 13F); this.ctrlTextbox.Location = new System.Drawing.Point(0, 0); this.ctrlTextbox.Name = "ctrlTextbox"; + this.ctrlTextbox.ShowContentNotes = false; this.ctrlTextbox.ShowLineInHex = false; + this.ctrlTextbox.ShowLineNumberNotes = false; this.ctrlTextbox.ShowLineNumbers = true; - this.ctrlTextbox.Size = new System.Drawing.Size(305, 174); + this.ctrlTextbox.Size = new System.Drawing.Size(305, 156); this.ctrlTextbox.TabIndex = 1; // // ctrlScrollableTextbox @@ -151,6 +162,7 @@ this.Controls.Add(this.panelSearch); this.Controls.Add(this.ctrlTextbox); this.Controls.Add(this.vScrollBar); + this.Controls.Add(this.hScrollBar); this.Name = "ctrlScrollableTextbox"; this.Size = new System.Drawing.Size(323, 174); this.panelSearch.ResumeLayout(false); @@ -173,6 +185,6 @@ private System.Windows.Forms.PictureBox picSearchNext; private System.Windows.Forms.PictureBox picCloseSearch; private System.Windows.Forms.ComboBox cboSearch; - + private System.Windows.Forms.HScrollBar hScrollBar; } } diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index 77fe5856..ebe85e0c 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -32,6 +32,8 @@ namespace Mesen.GUI.Debugger { public event EventHandler ScrollPositionChanged; + private const float HorizontalScrollFactor = 8; + private string[] _contents = new string[0]; private string[] _contentNotes = new string[0]; private string[] _compareContents = null; @@ -46,10 +48,12 @@ namespace Mesen.GUI.Debugger private bool _showContentNotes = false; private int _cursorPosition = 0; private int _scrollPosition = 0; + private int _horizontalScrollPosition = 0; private string _searchString = null; private string _header = null; private Font _noteFont = null; private int _marginWidth = 6; + private float _maxLineWidth = 0; public ctrlTextbox() { @@ -62,13 +66,25 @@ namespace Mesen.GUI.Debugger { set { + int maxLength = 0; + int maxLengthIndex = 0; + _contents = new string[value.Length]; _lineMargins = new int[value.Length]; for(int i = 0, len = value.Length; i < len; i++) { _contents[i] = value[i].TrimStart(); + if(_contents[i].Length > maxLength) { + maxLength = _contents[i].Length; + maxLengthIndex = i; + } _lineMargins[i] = (value[i].Length - _contents[i].Length) * 10; } + using(Graphics g = this.CreateGraphics()) { + _maxLineWidth = g.MeasureString(_contents[maxLengthIndex], this.Font).Width; + } + UpdateHorizontalScrollWidth(); + _lineNumbers = new int[_contents.Length]; _lineNumberIndex.Clear(); for(int i = _contents.Length - 1; i >=0; i--) { @@ -348,7 +364,7 @@ namespace Mesen.GUI.Debugger int lineIndex; if(this.GetCharIndex(position, out charIndex, out lineIndex)) { string text = ((useCompareText && _compareContents != null) ? _compareContents[lineIndex] : _contents[lineIndex]).Replace("\x2", ""); - List wordDelimiters = new List(new char[] { ' ', ',', '|', ';', '(', ')' }); + List wordDelimiters = new List(new char[] { ' ', ',', '|', ';', '(', ')', '.', '-', ':' }); if(wordDelimiters.Contains(text[charIndex])) { return string.Empty; } else { @@ -420,6 +436,37 @@ namespace Mesen.GUI.Debugger } } + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int HorizontalScrollPosition + { + get { return _horizontalScrollPosition; } + set + { + _horizontalScrollPosition = value; + if(this.ScrollPositionChanged != null) { + ScrollPositionChanged(this, null); + } + this.Invalidate(); + } + } + + public int HorizontalScrollWidth { get; set; } = 0; + + private void UpdateHorizontalScrollWidth() + { + using(Graphics g = this.CreateGraphics()) { + HorizontalScrollWidth = (int)(Math.Max(0, 8 + _maxLineWidth - (this.Width - GetMargin(g))) / HorizontalScrollFactor); + } + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + UpdateHorizontalScrollWidth(); + ScrollPositionChanged?.Invoke(this, e); + } + public bool ShowLineNumbers { get { return _showLineNumbers; } @@ -462,14 +509,9 @@ namespace Mesen.GUI.Debugger float codeStringLength = g.MeasureString(codeString, this.Font).Width; float addressStringLength = g.MeasureString(addressString, this.Font).Width; - if(this.ShowLineNumbers) { - //Show line number - this.DrawLineNumber(g, currentLine, marginLeft, positionY); - } - if(currentLine == this.CursorPosition) { //Highlight current line - g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, this.ClientRectangle.Width - marginLeft, this.LineHeight); + g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, Math.Max(_maxLineWidth, this.ClientRectangle.Width), this.LineHeight); } //Adjust background color highlights based on number of spaces in front of content @@ -491,8 +533,6 @@ namespace Mesen.GUI.Debugger g.DrawRectangle(outlinePen, marginLeft, positionY + 1, codeStringLength, this.LineHeight-1); } } - - this.DrawLineSymbols(g, positionY, lineProperties); } this.DrawLineText(g, currentLine, marginLeft, positionY, codeString, addressString, commentString, codeStringLength, addressStringLength, textColor); @@ -514,21 +554,27 @@ namespace Mesen.GUI.Debugger using(Brush fgBrush = new SolidBrush(textColor)) { if(codeString.StartsWith("--") && codeString.EndsWith("--")) { //Draw block start + g.TranslateTransform(HorizontalScrollPosition * HorizontalScrollFactor, 0); string text = codeString.Substring(2, codeString.Length - 4); float textLength = g.MeasureString(text, this._noteFont).Width; g.DrawString(text, this._noteFont, fgBrush, (marginLeft + this.Width - textLength) / 2, positionY); g.DrawLine(Pens.Black, marginLeft, positionY+this.LineHeight-2, marginLeft+this.Width, positionY+this.LineHeight-2); + g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else if(codeString.StartsWith("__") && codeString.EndsWith("__")) { //Draw block end + g.TranslateTransform(HorizontalScrollPosition * HorizontalScrollFactor, 0); string text = codeString.Substring(2, codeString.Length - 4); float textLength = g.MeasureString(text, this._noteFont).Width; g.DrawString(text, this._noteFont, fgBrush, (marginLeft + this.Width - textLength) / 2, positionY + 4); g.DrawLine(Pens.Black, marginLeft, positionY+2, marginLeft+this.Width, positionY+2); + g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else if(codeString.StartsWith("[[") && codeString.EndsWith("]]")) { //Draw small centered text + g.TranslateTransform(HorizontalScrollPosition * HorizontalScrollFactor, 0); string text = codeString.Substring(2, codeString.Length - 4); float textLength = g.MeasureString(text, this._noteFont).Width; g.DrawString(text, new Font(this._noteFont, FontStyle.Italic), fgBrush, (marginLeft + this.Width - textLength) / 2, positionY + 2); + g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else { //Draw line content g.DrawString(codeString, this.Font, fgBrush, marginLeft, positionY); @@ -631,6 +677,21 @@ namespace Mesen.GUI.Debugger } } + private void DrawMargin(Graphics g, int currentLine, int marginLeft, int positionY) + { + if(this.ShowLineNumbers) { + //Show line number + this.DrawLineNumber(g, currentLine, marginLeft, positionY); + } + + //Adjust background color highlights based on number of spaces in front of content + marginLeft += _lineMargins[currentLine]; + + if(_lineProperties.ContainsKey(currentLine)) { + this.DrawLineSymbols(g, positionY, _lineProperties[currentLine]); + } + } + protected override void OnPaint(PaintEventArgs pe) { pe.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; @@ -639,17 +700,14 @@ namespace Mesen.GUI.Debugger Rectangle rect = this.ClientRectangle; pe.Graphics.FillRectangle(Brushes.White, rect); - int marginLeft = this.GetMargin(pe.Graphics); - if(this.ShowLineNumbers) { - pe.Graphics.FillRectangle(lightGrayBrush, 0, 0, marginLeft, rect.Bottom); - pe.Graphics.DrawLine(grayPen, marginLeft, rect.Top, marginLeft, rect.Bottom); - } + pe.Graphics.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); + int marginLeft = this.GetMargin(pe.Graphics); int currentLine = this.ScrollPosition; int positionY = 0; if(!string.IsNullOrWhiteSpace(this._header)) { - pe.Graphics.FillRectangle(lightGrayBrush, marginLeft, 0, rect.Right, this.LineHeight); + pe.Graphics.FillRectangle(lightGrayBrush, marginLeft, 0, Math.Max(_maxLineWidth, rect.Right), this.LineHeight); pe.Graphics.DrawString(_header, this.Font, Brushes.Gray, marginLeft, positionY); positionY += this.LineHeight; } @@ -659,6 +717,21 @@ namespace Mesen.GUI.Debugger positionY += this.LineHeight; currentLine++; } + + pe.Graphics.TranslateTransform(HorizontalScrollPosition * HorizontalScrollFactor, 0); + + if(this.ShowLineNumbers) { + pe.Graphics.FillRectangle(lightGrayBrush, 0, 0, marginLeft, rect.Bottom); + pe.Graphics.DrawLine(grayPen, marginLeft, rect.Top, marginLeft, rect.Bottom); + } + + currentLine = this.ScrollPosition; + positionY = 0; + while(positionY < rect.Bottom && currentLine < _contents.Length) { + this.DrawMargin(pe.Graphics, currentLine, marginLeft, positionY); + positionY += this.LineHeight; + currentLine++; + } } } }