Mesen-X/GUI.NET/Debugger/FastColoredTextBox/Hints.cs
2017-08-30 18:31:27 -04:00

364 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
namespace FastColoredTextBoxNS
{
/// <summary>
/// Collection of Hints.
/// This is temporary buffer for currently displayed hints.
/// </summary>
public class Hints : ICollection<Hint>, IDisposable
{
FastColoredTextBox tb;
List<Hint> items = new List<Hint>();
public Hints(FastColoredTextBox tb)
{
this.tb = tb;
tb.TextChanged += OnTextBoxTextChanged;
tb.KeyDown += OnTextBoxKeyDown;
tb.VisibleRangeChanged += OnTextBoxVisibleRangeChanged;
}
protected virtual void OnTextBoxKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyCode == System.Windows.Forms.Keys.Escape && e.Modifiers == System.Windows.Forms.Keys.None)
Clear();
}
protected virtual void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
Clear();
}
public void Dispose()
{
tb.TextChanged -= OnTextBoxTextChanged;
tb.KeyDown -= OnTextBoxKeyDown;
tb.VisibleRangeChanged -= OnTextBoxVisibleRangeChanged;
}
void OnTextBoxVisibleRangeChanged(object sender, EventArgs e)
{
if (items.Count == 0)
return;
tb.NeedRecalc(true);
foreach (var item in items)
{
LayoutHint(item);
item.HostPanel.Invalidate();
}
}
private void LayoutHint(Hint hint)
{
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
{
if (hint.Range.Start.iLine < tb.LineInfos.Count - 1)
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - hint.TopPadding - hint.HostPanel.Height - tb.VerticalScroll.Value;
else
hint.HostPanel.Top = tb.TextHeight + tb.Paddings.Top - hint.HostPanel.Height - tb.VerticalScroll.Value;
}
else
{
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - tb.VerticalScroll.Value;
}
if (hint.Dock == DockStyle.Fill)
{
hint.Width = tb.ClientSize.Width - tb.LeftIndent - 2;
hint.HostPanel.Left = tb.LeftIndent;
}
else
{
var p1 = tb.PlaceToPoint(hint.Range.Start);
var p2 = tb.PlaceToPoint(hint.Range.End);
var cx = (p1.X + p2.X) / 2;
hint.HostPanel.Left = Math.Max( tb.LeftIndent, cx - hint.HostPanel.Width / 2);
}
}
public IEnumerator<Hint> GetEnumerator()
{
foreach (var item in items)
yield return item;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Clears all displayed hints
/// </summary>
public void Clear()
{
items.Clear();
if (tb.Controls.Count != 0)
{
var toDelete = new List<Control>();
foreach (Control item in tb.Controls)
if (item is UnfocusablePanel)
toDelete.Add(item);
foreach (var item in toDelete)
tb.Controls.Remove(item);
for (int i = 0; i < tb.LineInfos.Count; i++)
{
var li = tb.LineInfos[i];
li.bottomPadding = 0;
tb.LineInfos[i] = li;
}
tb.NeedRecalc();
tb.Invalidate();
tb.Select();
tb.ActiveControl = null;
}
}
/// <summary>
/// Add and shows the hint
/// </summary>
/// <param name="hint"></param>
public void Add(Hint hint)
{
items.Add(hint);
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
{
var li = tb.LineInfos[hint.Range.Start.iLine];
hint.TopPadding = li.bottomPadding;
li.bottomPadding += hint.HostPanel.Height;
tb.LineInfos[hint.Range.Start.iLine] = li;
tb.NeedRecalc(true);
}
LayoutHint(hint);
tb.OnVisibleRangeChanged();
hint.HostPanel.Parent = tb;
tb.Select();
tb.ActiveControl = null;
tb.Invalidate();
}
/// <summary>
/// Is collection contains the hint?
/// </summary>
public bool Contains(Hint item)
{
return items.Contains(item);
}
public void CopyTo(Hint[] array, int arrayIndex)
{
items.CopyTo(array, arrayIndex);
}
/// <summary>
/// Count of hints
/// </summary>
public int Count
{
get { return items.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(Hint item)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Hint of FastColoredTextbox
/// </summary>
public class Hint
{
/// <summary>
/// Text of simple hint
/// </summary>
public string Text { get { return HostPanel.Text; } set { HostPanel.Text = value; } }
/// <summary>
/// Linked range
/// </summary>
public Range Range { get; set; }
/// <summary>
/// Backcolor
/// </summary>
public Color BackColor { get { return HostPanel.BackColor; } set { HostPanel.BackColor = value; } }
/// <summary>
/// Second backcolor
/// </summary>
public Color BackColor2 { get { return HostPanel.BackColor2; } set { HostPanel.BackColor2 = value; } }
/// <summary>
/// Border color
/// </summary>
public Color BorderColor { get { return HostPanel.BorderColor; } set { HostPanel.BorderColor = value; } }
/// <summary>
/// Fore color
/// </summary>
public Color ForeColor { get { return HostPanel.ForeColor; } set { HostPanel.ForeColor = value; } }
/// <summary>
/// Text alignment
/// </summary>
public StringAlignment TextAlignment { get { return HostPanel.TextAlignment; } set { HostPanel.TextAlignment = value; } }
/// <summary>
/// Font
/// </summary>
public Font Font { get { return HostPanel.Font; } set { HostPanel.Font = value; } }
/// <summary>
/// Occurs when user click on simple hint
/// </summary>
public event EventHandler Click
{
add { HostPanel.Click += value; }
remove { HostPanel.Click -= value; }
}
/// <summary>
/// Inner control
/// </summary>
public Control InnerControl { get; set; }
/// <summary>
/// Docking (allows None and Fill only)
/// </summary>
public DockStyle Dock { get; set; }
/// <summary>
/// Width of hint (if Dock is None)
/// </summary>
public int Width { get { return HostPanel.Width; } set { HostPanel.Width = value; } }
/// <summary>
/// Height of hint
/// </summary>
public int Height { get { return HostPanel.Height; } set { HostPanel.Height = value; } }
/// <summary>
/// Host panel
/// </summary>
public UnfocusablePanel HostPanel { get; private set; }
internal int TopPadding { get; set; }
/// <summary>
/// Tag
/// </summary>
public object Tag { get; set; }
/// <summary>
/// Cursor
/// </summary>
public Cursor Cursor { get { return HostPanel.Cursor; } set { HostPanel.Cursor = value; } }
/// <summary>
/// Inlining. If True then hint will moves apart text.
/// </summary>
public bool Inline{get; set;}
/// <summary>
/// Scroll textbox to the hint
/// </summary>
public virtual void DoVisible()
{
Range.tb.DoRangeVisible(Range, true);
Range.tb.Invalidate();
}
private Hint(Range range, Control innerControl, string text, bool inline, bool dock)
{
this.Range = range;
this.Inline = inline;
this.InnerControl = innerControl;
Init();
Dock = dock ? DockStyle.Fill : DockStyle.None;
Text = text;
}
/// <summary>
/// Creates Hint
/// </summary>
/// <param name="range">Linked range</param>
/// <param name="text">Text for simple hint</param>
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
/// <param name="dock">Docking. If True then hint will fill whole line</param>
public Hint(Range range, string text, bool inline, bool dock)
: this(range, null, text, inline, dock)
{
}
/// <summary>
/// Creates Hint
/// </summary>
/// <param name="range">Linked range</param>
/// <param name="text">Text for simple hint</param>
public Hint(Range range, string text)
: this(range, null, text, true, true)
{
}
/// <summary>
/// Creates Hint
/// </summary>
/// <param name="range">Linked range</param>
/// <param name="innerControl">Inner control</param>
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
/// <param name="dock">Docking. If True then hint will fill whole line</param>
public Hint(Range range, Control innerControl, bool inline, bool dock)
: this(range, innerControl, null, inline, dock)
{
}
/// <summary>
/// Creates Hint
/// </summary>
/// <param name="range">Linked range</param>
/// <param name="innerControl">Inner control</param>
public Hint(Range range, Control innerControl)
: this(range, innerControl, null, true, true)
{
}
protected virtual void Init()
{
HostPanel = new UnfocusablePanel();
HostPanel.Click += OnClick;
if (InnerControl != null)
{
HostPanel.Controls.Add(InnerControl);
HostPanel.Width = InnerControl.Width + 2;
HostPanel.Height = InnerControl.Height + 2;
InnerControl.Dock = DockStyle.Fill;
InnerControl.Visible = true;
BackColor = SystemColors.Control;
}
else
{
HostPanel.Height = Range.tb.CharHeight + 5;
}
Cursor = Cursors.Default;
BorderColor = Color.Silver;
BackColor2 = Color.White;
BackColor = InnerControl == null ? Color.Silver : SystemColors.Control;
ForeColor = Color.Black;
TextAlignment = StringAlignment.Near;
Font = Range.tb.Parent == null ? Range.tb.Font : Range.tb.Parent.Font;
}
protected virtual void OnClick(object sender, EventArgs e)
{
Range.tb.OnHintClick(this);
}
}
}