From 584b46dfee4e861f54b27f1e2dc68182468aaf29 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Sun, 1 Feb 2015 01:03:41 +0100 Subject: [PATCH 01/36] CompletionList and RichToolTip refactoring WIP. Allow for them to appear outside of the main form if needed, and appear above floating panels. --- PluginCore/PluginCore.csproj | 3 + .../PluginCore/Controls/CompletionList.cs | 81 ++++++++++--------- .../PluginCore/Controls/InactiveForm.cs | 31 +++++++ PluginCore/PluginCore/Controls/RichToolTip.cs | 72 ++++++++++------- 4 files changed, 119 insertions(+), 68 deletions(-) create mode 100644 PluginCore/PluginCore/Controls/InactiveForm.cs diff --git a/PluginCore/PluginCore.csproj b/PluginCore/PluginCore.csproj index 3af00e32df..9eab87963e 100644 --- a/PluginCore/PluginCore.csproj +++ b/PluginCore/PluginCore.csproj @@ -311,6 +311,9 @@ Component + + Form + diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 109ed5aaed..4623f081e2 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -23,6 +23,7 @@ public class CompletionList private static System.Timers.Timer tempo; private static System.Timers.Timer tempoTip; private static System.Windows.Forms.ListBox completionList; + private static System.Windows.Forms.Form listHost; #region State Properties @@ -73,15 +74,21 @@ public static void CreateControl(IMainForm mainForm) completionList = new ListBox(); completionList.Font = new System.Drawing.Font(PluginBase.Settings.DefaultFont, FontStyle.Regular); - completionList.Visible = false; - completionList.Location = new Point(400,200); completionList.ItemHeight = completionList.Font.Height + 2; - completionList.Size = new Size(180, 100); + completionList.Dock = DockStyle.Fill; completionList.DrawMode = DrawMode.OwnerDrawFixed; completionList.DrawItem += new DrawItemEventHandler(CLDrawListItem); completionList.Click += new EventHandler(CLClick); completionList.DoubleClick += new EventHandler(CLDoubleClick); - mainForm.Controls.Add(completionList); + + listHost = new InactiveForm(); + listHost.StartPosition = FormStartPosition.Manual; + listHost.FormBorderStyle = FormBorderStyle.None; + listHost.ShowIcon = false; + listHost.ShowInTaskbar = false; + listHost.Size = new Size(180, 100); + + listHost.Controls.Add(completionList); } #endregion @@ -159,7 +166,6 @@ static public void Show(List itemList, bool autoHide) ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; if (!doc.IsEditable) return; ScintillaControl sci = doc.SciControl; - ListBox cl = completionList; try { if ((itemList == null) || (itemList.Count == 0)) @@ -254,36 +260,36 @@ static private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) if (!doc.IsEditable) return; ScintillaControl sci = doc.SciControl; ListBox cl = completionList; - if (cl.Items.Count == 0) return; + Form host = listHost; + if (cl.Items.Count == 0) return; // measure control - if (needResize && widestLabel != null && widestLabel.Length > 0) + if (needResize && !string.IsNullOrEmpty(widestLabel)) { needResize = false; Graphics g = cl.CreateGraphics(); SizeF size = g.MeasureString(widestLabel, cl.Font); - cl.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); + host.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); } int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; - if (newHeight != cl.Height) cl.Height = newHeight; + if (newHeight != host.Height) host.Height = newHeight; // place control Point coord = new Point(sci.PointXFromPosition(startPos), sci.PointYFromPosition(startPos)); - listUp = UITools.CallTip.CallTipActive || (coord.Y+cl.Height > (sci as Control).Height); + listUp = UITools.CallTip.CallTipActive || (coord.Y+host.Height > (sci as Control).Height); coord = sci.PointToScreen(coord); - coord = ((Form)PluginBase.MainForm).PointToClient(coord); - cl.Left = coord.X-20 + sci.Left; - if (listUp) cl.Top = coord.Y-cl.Height; - else cl.Top = coord.Y + UITools.Manager.LineHeight(sci); + host.Left = coord.X + sci.Left; + var screen = Screen.FromHandle(PluginBase.MainForm.Handle); + if (listUp) host.Top = coord.Y-host.Height; + else host.Top = coord.Y + UITools.Manager.LineHeight(sci); // Keep on control area - if (cl.Right > ((Form)PluginBase.MainForm).ClientRectangle.Right) + if (host.Right > screen.WorkingArea.Right) { - cl.Left = ((Form)PluginBase.MainForm).ClientRectangle.Right - cl.Width; + host.Left = screen.WorkingArea.Right - host.Width; } - if (!cl.Visible) + if (!host.Visible) { Redraw(); - cl.Show(); - cl.BringToFront(); + host.Show(PluginBase.MainForm); if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(sci); } } @@ -305,7 +311,7 @@ static public void Hide() isActive = false; fullList = false; faded = false; - completionList.Visible = false; + listHost.Visible = false; if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; allItems = null; @@ -398,22 +404,23 @@ static public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) UITools.Tip.SetText(currentItem.Description ?? "", false); UITools.Tip.Redraw(false); - int rightWidth = ((Form)PluginBase.MainForm).ClientRectangle.Right - completionList.Right - 10; - int leftWidth = completionList.Left; - - Point posTarget = new Point(completionList.Right, completionList.Top); + var screen = Screen.FromControl(listHost); + int rightWidth = screen.WorkingArea.Right - listHost.Right - 10; + int leftWidth = listHost.Left; + + Point posTarget = new Point(listHost.Right, listHost.Top); int widthTarget = rightWidth; if (rightWidth < 220 && leftWidth > 220) { widthTarget = leftWidth; - posTarget = new Point(0, completionList.Top); + posTarget = new Point(0, listHost.Top); } UITools.Tip.Location = posTarget; UITools.Tip.AutoSize(widthTarget, 500); if (widthTarget == leftWidth) - UITools.Tip.Location = new Point(completionList.Left - UITools.Tip.Size.Width, posTarget.Y); + UITools.Tip.Location = new Point(listHost.Left - UITools.Tip.Size.Width, posTarget.Y); UITools.Tip.Show(); } @@ -926,15 +933,15 @@ static public bool HandleKeys(ScintillaControl sci, Keys key) return true; case Keys.Space: - if (noAutoInsert) CompletionList.Hide(); + if (noAutoInsert) Hide(); return false; case Keys.Up: noAutoInsert = false; // the list was hidden and it should not appear - if (!completionList.Visible) + if (!listHost.Visible) { - CompletionList.Hide(); + Hide(); if (key == Keys.Up) sci.LineUp(); else sci.CharLeft(); return false; @@ -958,9 +965,9 @@ static public bool HandleKeys(ScintillaControl sci, Keys key) case Keys.Down: noAutoInsert = false; // the list was hidden and it should not appear - if (!completionList.Visible) + if (!listHost.Visible) { - CompletionList.Hide(); + Hide(); if (key == Keys.Down) sci.LineDown(); else sci.CharRight(); return false; @@ -984,9 +991,9 @@ static public bool HandleKeys(ScintillaControl sci, Keys key) case Keys.PageUp: noAutoInsert = false; // the list was hidden and it should not appear - if (!completionList.Visible) + if (!listHost.Visible) { - CompletionList.Hide(); + Hide(); sci.PageUp(); return false; } @@ -1003,9 +1010,9 @@ static public bool HandleKeys(ScintillaControl sci, Keys key) case Keys.PageDown: noAutoInsert = false; // the list was hidden and it should not appear - if (!completionList.Visible) + if (!listHost.Visible) { - CompletionList.Hide(); + Hide(); sci.PageDown(); return false; } @@ -1056,14 +1063,14 @@ internal static void FadeOut() if (faded) return; faded = true; UITools.Tip.Hide(); - completionList.Visible = false; + listHost.Visible = false; } internal static void FadeIn() { if (!faded) return; faded = false; - completionList.Visible = true; + listHost.Visible = true; } #endregion diff --git a/PluginCore/PluginCore/Controls/InactiveForm.cs b/PluginCore/PluginCore/Controls/InactiveForm.cs new file mode 100644 index 0000000000..5a75bde35c --- /dev/null +++ b/PluginCore/PluginCore/Controls/InactiveForm.cs @@ -0,0 +1,31 @@ +using System.Windows.Forms; + +namespace PluginCore.Controls +{ + /// + /// A form that, unless forced directly by code, does not become the foreground window when shown or clicked + /// + public class InactiveForm : Form + { + + private const int WS_EX_NOACTIVATE = 0x8000000; + + protected override bool ShowWithoutActivation + { + get { return true; } + } + + protected override CreateParams CreateParams + { + get + { + CreateParams p = base.CreateParams; + + p.ExStyle |= WS_EX_NOACTIVATE; + + return p; + } + } + + } +} diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index d2c85b9987..219a47bcf5 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -23,6 +23,7 @@ public class RichToolTip public event UpdateTipHandler OnUpdateSimpleTip; // controls + protected InactiveForm host; protected Panel toolTip; protected RichTextBox toolTipRTB; protected string rawText; @@ -32,23 +33,25 @@ public class RichToolTip protected List rtfCacheList; protected Point mousePos; + protected IWin32Window owner; + #region Public Properties public bool Visible { - get { return toolTip.Visible; } + get { return host.Visible; } } public Size Size { - get { return toolTip.Size; } - set { toolTip.Size = value; } + get { return host.Size; } + set { host.Size = value; } } public Point Location { - get { return toolTip.Location; } - set { toolTip.Location = value; } + get { return host.Location; } + set { host.Location = value; } } public string Text @@ -64,16 +67,23 @@ public string Text #region Control creation - public RichToolTip(IMainForm mainForm) + public RichToolTip(IWin32Window owner) { + // host + host = new InactiveForm(); + host.FormBorderStyle = FormBorderStyle.None; + host.ShowInTaskbar = false; + + this.owner = owner; + // panel toolTip = new Panel(); toolTip.Location = new System.Drawing.Point(0,0); toolTip.BackColor = System.Drawing.SystemColors.Info; toolTip.ForeColor = System.Drawing.SystemColors.InfoText; toolTip.BorderStyle = BorderStyle.FixedSingle; - toolTip.Visible = false; - (mainForm as Form).Controls.Add(toolTip); + toolTip.Dock = DockStyle.Fill; + host.Controls.Add(toolTip); // text toolTipRTB = new System.Windows.Forms.RichTextBox(); toolTipRTB.Location = new System.Drawing.Point(2,1); @@ -112,14 +122,15 @@ public bool AutoSize(int availableWidth, int maxWidth) Size txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, toolTipRTB.Width, toolTipRTB.Height, false); // tooltip larger than the window: wrap - int limitLeft = ((Form)PluginBase.MainForm).ClientRectangle.Left + 10; - int limitRight = ((Form)PluginBase.MainForm).ClientRectangle.Right - 10; - int limitBottom = ((Form)PluginBase.MainForm).ClientRectangle.Bottom - 26; + var screenArea = Screen.FromHandle(owner.Handle).WorkingArea; + int limitLeft = screenArea.Left + 10; + int limitRight = screenArea.Right - 10; + int limitBottom = screenArea.Bottom - 26; // int maxW = availableWidth > 0 ? availableWidth : limitRight - limitLeft; if (maxW > maxWidth && maxWidth > 0) maxW = maxWidth; - + int w = txtSize.Width + 4; if (w > maxW) { @@ -138,10 +149,10 @@ public bool AutoSize(int availableWidth, int maxWidth) int h = txtSize.Height + 2; int dh = 1; int dw = 2; - if (h > (limitBottom - toolTip.Top)) + if (h > (limitBottom - host.Top)) { w += 15; - h = limitBottom - toolTip.Top; + h = limitBottom - host.Top; dh = 4; dw = 5; @@ -149,13 +160,13 @@ public bool AutoSize(int availableWidth, int maxWidth) } toolTipRTB.Size = new Size(w, h); - toolTip.Size = new Size(w + dw, h + dh); + host.Size = new Size(w + dw, h + dh); - if (toolTip.Left < limitLeft) - toolTip.Left = limitLeft; + if (host.Left < limitLeft) + host.Left = limitLeft; - if (toolTip.Left + toolTip.Width > limitRight) - toolTip.Left = limitRight - toolTip.Width; + if (host.Left + host.Width > limitRight) + host.Left = limitRight - host.Width; if (toolTipRTB.WordWrap != wordWrap) toolTipRTB.WordWrap = wordWrap; @@ -167,7 +178,7 @@ public void ShowAtMouseLocation(string text) { if (text != Text) { - toolTip.Visible = false; + host.Visible = false; Text = text; } ShowAtMouseLocation(); @@ -176,15 +187,15 @@ public void ShowAtMouseLocation(string text) public void ShowAtMouseLocation() { //ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - mousePos = ((Form)PluginBase.MainForm).PointToClient(Control.MousePosition); - toolTip.Left = mousePos.X;// +sci.Left; - if (toolTip.Right > ((Form)PluginBase.MainForm).ClientRectangle.Right) + mousePos = Control.MousePosition; + host.Left = mousePos.X;// +sci.Left; + var screen = Screen.FromPoint(mousePos); + if (host.Right > screen.WorkingArea.Right) { - toolTip.Left -= (toolTip.Right - ((Form)PluginBase.MainForm).ClientRectangle.Right); + host.Left -= (host.Right - screen.WorkingArea.Right); } - toolTip.Top = mousePos.Y - toolTip.Height - 10;// +sci.Top; - toolTip.Show(); - toolTip.BringToFront(); + host.Top = mousePos.Y - host.Height - 10;// +sci.Top; + host.Show(owner); } public void UpdateTip(ScintillaControl sci) @@ -194,17 +205,16 @@ public void UpdateTip(ScintillaControl sci) public virtual void Hide() { - if (toolTip.Visible) + if (host.Visible) { - toolTip.Visible = false; + host.Visible = false; toolTipRTB.ResetText(); } } public virtual void Show() { - toolTip.Visible = true; - toolTip.BringToFront(); + host.Show(owner); } public void SetText(String rawText, bool redraw) From 0d7411707ebc3b4591cac07c2f57233b71bce571 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Sun, 1 Feb 2015 13:18:44 +0100 Subject: [PATCH 02/36] Correct tooltip start position --- PluginCore/PluginCore/Controls/CompletionList.cs | 2 +- PluginCore/PluginCore/Controls/RichToolTip.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 4623f081e2..1f0f52ec4c 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -413,7 +413,7 @@ static public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) if (rightWidth < 220 && leftWidth > 220) { widthTarget = leftWidth; - posTarget = new Point(0, listHost.Top); + posTarget.X = 0; } UITools.Tip.Location = posTarget; diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index 219a47bcf5..7bd0f22cb5 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -73,6 +73,7 @@ public RichToolTip(IWin32Window owner) host = new InactiveForm(); host.FormBorderStyle = FormBorderStyle.None; host.ShowInTaskbar = false; + host.StartPosition = FormStartPosition.Manual; this.owner = owner; From cffc83fabd3d89f740a5c716c9c7e73680947d81 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Sun, 1 Feb 2015 15:53:53 +0100 Subject: [PATCH 03/36] Fixed MethodCallTip --- .../PluginCore/Controls/MethodCallTip.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index f6217de8c8..658f1aa908 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -72,10 +72,10 @@ public void CallTipShow(ScintillaControl sci, int position, string text) } public void CallTipShow(ScintillaControl sci, int position, string text, bool redraw) { - if (toolTip.Visible && position == memberPos && text == currentText) + if (host.Visible && position == memberPos && text == currentText) return; - toolTip.Visible = false; + host.Visible = false; currentText = text; SetText(text, true); @@ -95,18 +95,17 @@ public void PositionControl(ScintillaControl sci) { // compute control location Point p = new Point(sci.PointXFromPosition(memberPos), sci.PointYFromPosition(memberPos)); - p = ((Form)PluginBase.MainForm).PointToClient(((Control)sci).PointToScreen(p)); - toolTip.Left = p.X /*+ sci.Left*/; + p = sci.PointToScreen(p); + host.Left = p.X /*+ sci.Left*/; bool hasListUp = !CompletionList.Active || CompletionList.listUp; - if (currentLine > sci.LineFromPosition(memberPos) || !hasListUp) toolTip.Top = p.Y - toolTip.Height /*+ sci.Top*/; - else toolTip.Top = p.Y + UITools.Manager.LineHeight(sci) /*+ sci.Top*/; + if (currentLine > sci.LineFromPosition(memberPos) || !hasListUp) host.Top = p.Y - host.Height /*+ sci.Top*/; + else host.Top = p.Y + UITools.Manager.LineHeight(sci) /*+ sci.Top*/; // Keep on control area - if (toolTip.Right > ((Form)PluginBase.MainForm).ClientRectangle.Right) + if (host.Right > ((Form)PluginBase.MainForm).ClientRectangle.Right) { - toolTip.Left = ((Form)PluginBase.MainForm).ClientRectangle.Right - toolTip.Width; + host.Left = ((Form)PluginBase.MainForm).ClientRectangle.Right - host.Width; } - toolTip.Show(); - toolTip.BringToFront(); + host.Show(owner); } public void CallTipSetHlt(int start, int end) @@ -238,7 +237,7 @@ internal void FadeOut() if (faded) return; faded = true; //base.Hide(); - toolTip.Visible = false; + host.Visible = false; } internal void FadeIn() @@ -246,7 +245,7 @@ internal void FadeIn() if (!faded) return; faded = false; //base.Show(); - toolTip.Visible = true; + host.Visible = true; } #endregion } From 4ed1f7dc5216dda1b1553ceadb56924ca9e5fe70 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 2 Feb 2015 01:59:33 +0100 Subject: [PATCH 04/36] Some further refactoring: Created CompletionList control Avoid RichToolTip from appearing outside the top of the screen. --- PluginCore/PluginCore.csproj | 1 + .../PluginCore/Controls/CompletionList.cs | 948 +------------- .../Controls/CompletionListControl.cs | 1090 +++++++++++++++++ PluginCore/PluginCore/Controls/RichToolTip.cs | 5 +- 4 files changed, 1143 insertions(+), 901 deletions(-) create mode 100644 PluginCore/PluginCore/Controls/CompletionListControl.cs diff --git a/PluginCore/PluginCore.csproj b/PluginCore/PluginCore.csproj index 9eab87963e..e2c9c19119 100644 --- a/PluginCore/PluginCore.csproj +++ b/PluginCore/PluginCore.csproj @@ -311,6 +311,7 @@ Component + Form diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 1f0f52ec4c..6fa5d06f44 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -10,9 +10,8 @@ namespace PluginCore.Controls { - public delegate void InsertedTextHandler(ScintillaControl sender, int position, string text, char trigger, ICompletionListItem item); - public class CompletionList + public static class CompletionList { static public event InsertedTextHandler OnInsert; static public event InsertedTextHandler OnCancel; @@ -20,32 +19,14 @@ public class CompletionList /// /// Properties of the class /// - private static System.Timers.Timer tempo; - private static System.Timers.Timer tempoTip; - private static System.Windows.Forms.ListBox completionList; - private static System.Windows.Forms.Form listHost; + private static CompletionListControl completionList; #region State Properties - private static bool disableSmartMatch; - private static ICompletionListItem currentItem; - private static List allItems; - private static Boolean exactMatchInList; - private static Boolean smartMatchInList; - private static Boolean autoHideList; - private static Boolean noAutoInsert; - private static Boolean isActive; - internal static Boolean listUp; - private static Boolean fullList; - private static Int32 startPos; - private static Int32 currentPos; - private static Int32 lastIndex; - private static String currentWord; - private static String word; - private static Boolean needResize; - private static String widestLabel; - private static long showTime; - private static ICompletionListItem defaultItem; + internal static Boolean listUp + { + get { return completionList.listUp; } + } /// /// Set to 0 after calling .Show to keep the completion list active @@ -61,35 +42,11 @@ public class CompletionList /// Creates the control /// public static void CreateControl(IMainForm mainForm) - { - tempo = new System.Timers.Timer(); - tempo.SynchronizingObject = (Form)mainForm; - tempo.Elapsed += new System.Timers.ElapsedEventHandler(DisplayList); - tempo.AutoReset = false; - tempoTip = new System.Timers.Timer(); - tempoTip.SynchronizingObject = (Form)mainForm; - tempoTip.Elapsed += new System.Timers.ElapsedEventHandler(UpdateTip); - tempoTip.AutoReset = false; - tempoTip.Interval = 800; - - completionList = new ListBox(); - completionList.Font = new System.Drawing.Font(PluginBase.Settings.DefaultFont, FontStyle.Regular); - completionList.ItemHeight = completionList.Font.Height + 2; - completionList.Dock = DockStyle.Fill; - completionList.DrawMode = DrawMode.OwnerDrawFixed; - completionList.DrawItem += new DrawItemEventHandler(CLDrawListItem); - completionList.Click += new EventHandler(CLClick); - completionList.DoubleClick += new EventHandler(CLDoubleClick); - - listHost = new InactiveForm(); - listHost.StartPosition = FormStartPosition.Manual; - listHost.FormBorderStyle = FormBorderStyle.None; - listHost.ShowIcon = false; - listHost.ShowInTaskbar = false; - listHost.Size = new Size(180, 100); - - listHost.Controls.Add(completionList); - } + { + completionList = new CompletionListControl(mainForm); + completionList.OnCancel += OnCancel; + completionList.OnInsert += OnInsert; + } #endregion @@ -100,7 +57,7 @@ public static void CreateControl(IMainForm mainForm) /// public static Boolean Active { - get { return isActive; } + get { return completionList.Active; } } /// @@ -110,8 +67,7 @@ public static Boolean HasMouseIn { get { - if (!isActive || completionList == null) return false; - return completionList.ClientRectangle.Contains(completionList.PointToClient(Control.MousePosition)); + return completionList.HasMouseIn; } } @@ -122,9 +78,7 @@ public static string SelectedLabel { get { - if (completionList == null) return null; - ICompletionListItem selected = completionList.SelectedItem as ICompletionListItem; - return (selected == null) ? null : selected.Label; + return completionList.SelectedLabel; } } @@ -137,7 +91,7 @@ public static string SelectedLabel /// public static Boolean CheckPosition(Int32 position) { - return position == currentPos; + return completionList.CheckPosition(position); } /// @@ -145,76 +99,20 @@ public static Boolean CheckPosition(Int32 position) /// static public void Show(List itemList, Boolean autoHide, String select) { - if (!string.IsNullOrEmpty(select)) - { - int maxLen = 0; - foreach (ICompletionListItem item in itemList) - if (item.Label.Length > maxLen) maxLen = item.Label.Length; - maxLen = Math.Min(256, maxLen); - if (select.Length > maxLen) select = select.Substring(0, maxLen); - currentWord = select; - } - else currentWord = null; - Show(itemList, autoHide); + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) return; + completionList.Show(itemList, autoHide); } /// /// Shows the completion list /// static public void Show(List itemList, bool autoHide) - { + { ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; if (!doc.IsEditable) return; ScintillaControl sci = doc.SciControl; - try - { - if ((itemList == null) || (itemList.Count == 0)) - { - if (isActive) Hide(); - return; - } - if (sci == null) - { - if (isActive) Hide(); - return; - } - } - catch (Exception ex) - { - ErrorManager.ShowError(ex); - } - // state - allItems = itemList; - autoHideList = autoHide; - noAutoInsert = false; - word = ""; - if (currentWord != null) - { - word = currentWord; - currentWord = null; - } - MinWordLength = 1; - fullList = (word.Length == 0) || !autoHide || !PluginBase.MainForm.Settings.AutoFilterList; - lastIndex = 0; - exactMatchInList = false; - if (sci.SelectionStart == sci.SelectionEnd) - startPos = sci.CurrentPos - word.Length; - else - startPos = sci.SelectionStart; - currentPos = sci.SelectionEnd; // sci.CurrentPos; - defaultItem = null; - // populate list - needResize = true; - tempo.Enabled = autoHide && (PluginBase.MainForm.Settings.DisplayDelay > 0); - if (tempo.Enabled) tempo.Interval = PluginBase.MainForm.Settings.DisplayDelay; - FindWordStartingWith(word); - // state - isActive = true; - tempoTip.Enabled = false; - showTime = DateTime.Now.Ticks; - disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; - UITools.Manager.LockControl(sci); - faded = false; + completionList.Show(itemList, autoHide); } /// @@ -222,25 +120,7 @@ static public void Show(List itemList, bool autoHide) /// static public void SelectItem(String name) { - int p = name.IndexOf('<'); - if (p > 1) name = name.Substring(0, p) + ""; - string pname = (name.IndexOf('.') < 0) ? "." + name : null; - ICompletionListItem found = null; - foreach (ICompletionListItem item in completionList.Items) - { - if (item.Label == name) - { - defaultItem = item; - completionList.SelectedItem = item; - return; - } - if (pname != null && item.Label.EndsWith(pname)) found = item; - } - if (found != null) - { - defaultItem = found; - completionList.SelectedItem = found; - } + completionList.SelectItem(name); } /// @@ -248,547 +128,57 @@ static public void SelectItem(String name) /// public static void DisableAutoInsertion() { - noAutoInsert = true; + completionList.DisableAutoInsertion(); } - /// - /// - /// - static private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) - { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - ScintillaControl sci = doc.SciControl; - ListBox cl = completionList; - Form host = listHost; - if (cl.Items.Count == 0) return; - - // measure control - if (needResize && !string.IsNullOrEmpty(widestLabel)) - { - needResize = false; - Graphics g = cl.CreateGraphics(); - SizeF size = g.MeasureString(widestLabel, cl.Font); - host.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); - } - int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; - if (newHeight != host.Height) host.Height = newHeight; - // place control - Point coord = new Point(sci.PointXFromPosition(startPos), sci.PointYFromPosition(startPos)); - listUp = UITools.CallTip.CallTipActive || (coord.Y+host.Height > (sci as Control).Height); - coord = sci.PointToScreen(coord); - host.Left = coord.X + sci.Left; - var screen = Screen.FromHandle(PluginBase.MainForm.Handle); - if (listUp) host.Top = coord.Y-host.Height; - else host.Top = coord.Y + UITools.Manager.LineHeight(sci); - // Keep on control area - if (host.Right > screen.WorkingArea.Right) - { - host.Left = screen.WorkingArea.Right - host.Width; - } - if (!host.Visible) - { - Redraw(); - host.Show(PluginBase.MainForm); - if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(sci); - } - } - static public void Redraw() { - Color back = PluginBase.MainForm.GetThemeColor("CompletionList.BackColor"); - completionList.BackColor = back == Color.Empty ? System.Drawing.SystemColors.Window : back; + completionList.Redraw(); } /// /// Hide completion list /// static public void Hide() - { - if (completionList != null && isActive) - { - tempo.Enabled = false; - isActive = false; - fullList = false; - faded = false; - listHost.Visible = false; - if (completionList.Items.Count > 0) completionList.Items.Clear(); - currentItem = null; - allItems = null; - UITools.Tip.Hide(); - if (!UITools.CallTip.CallTipActive) UITools.Manager.UnlockControl(); - } - } + { + completionList.Hide(); + } /// /// Cancel completion list with event /// static public void Hide(char trigger) { - if (completionList != null && isActive) - { - Hide(); - if (OnCancel != null) - { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - OnCancel(doc.SciControl, currentPos, currentWord, trigger, null); - } - } + completionList.Hide(trigger); } /// /// /// static public void SelectWordInList(String tail) - { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) - { - Hide(); - return; - } - ScintillaControl sci = doc.SciControl; - currentWord = tail; - currentPos += tail.Length; - sci.SetSel(currentPos, currentPos); - } - - /// - /// - /// - static private void CLDrawListItem(Object sender, System.Windows.Forms.DrawItemEventArgs e) - { - ICompletionListItem item = completionList.Items[e.Index] as ICompletionListItem; - e.DrawBackground(); - Color fore = PluginBase.MainForm.GetThemeColor("CompletionList.ForeColor"); - bool selected = (e.State & DrawItemState.Selected) > 0; - Brush textBrush = (selected) ? SystemBrushes.HighlightText : fore == Color.Empty ? SystemBrushes.WindowText : new SolidBrush(fore); - Brush packageBrush = Brushes.Gray; - Rectangle tbounds = new Rectangle(ScaleHelper.Scale(18), e.Bounds.Top, e.Bounds.Width, e.Bounds.Height); - if (item != null) - { - Graphics g = e.Graphics; - float newHeight = e.Bounds.Height - 2; - g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - g.DrawImage(item.Icon, 1, e.Bounds.Top + ((e.Bounds.Height - newHeight) / 2), newHeight, newHeight); - int p = item.Label.LastIndexOf('.'); - if (p > 0 && !selected) - { - string package = item.Label.Substring(0, p + 1); - g.DrawString(package, e.Font, packageBrush, tbounds, StringFormat.GenericDefault); - int left = tbounds.Left + DrawHelper.MeasureDisplayStringWidth(e.Graphics, package, e.Font) - 2; - if (left < tbounds.Right) g.DrawString(item.Label.Substring(p + 1), e.Font, textBrush, left, tbounds.Top, StringFormat.GenericDefault); - } - else g.DrawString(item.Label, e.Font, textBrush, tbounds, StringFormat.GenericDefault); - } - e.DrawFocusRectangle(); - if ((item != null) && ((e.State & DrawItemState.Selected) > 0)) - { - UITools.Tip.Hide(); - currentItem = item; - tempoTip.Stop(); - tempoTip.Start(); - } + { + completionList.SelectWordInList(tail); } /// /// Display item information in tooltip /// static public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) - { - tempoTip.Stop(); - if (currentItem == null || faded) - return; - - UITools.Tip.SetText(currentItem.Description ?? "", false); - UITools.Tip.Redraw(false); - - var screen = Screen.FromControl(listHost); - int rightWidth = screen.WorkingArea.Right - listHost.Right - 10; - int leftWidth = listHost.Left; - - Point posTarget = new Point(listHost.Right, listHost.Top); - int widthTarget = rightWidth; - if (rightWidth < 220 && leftWidth > 220) - { - widthTarget = leftWidth; - posTarget.X = 0; - } - - UITools.Tip.Location = posTarget; - UITools.Tip.AutoSize(widthTarget, 500); - - if (widthTarget == leftWidth) - UITools.Tip.Location = new Point(listHost.Left - UITools.Tip.Size.Width, posTarget.Y); - - UITools.Tip.Show(); - } - - /// - /// - /// - static private void CLClick(Object sender, System.EventArgs e) - { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) - { - Hide(); - return; - } - doc.SciControl.Focus(); - } - - /// - /// - /// - static private void CLDoubleClick(Object sender, System.EventArgs e) - { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) - { - Hide(); - return; - } - ScintillaControl sci = doc.SciControl; - sci.Focus(); - ReplaceText(sci, '\0'); - } - - /// - /// Filter the completion list with the letter typed - /// - static public void FindWordStartingWith(String word) - { - if (word == null) word = ""; - Int32 len = word.Length; - Int32 maxLen = 0; - Int32 lastScore = 0; - /// - /// FILTER ITEMS - /// - if (PluginBase.MainForm.Settings.AutoFilterList || fullList) - { - List found; - if (len == 0) - { - found = allItems; - lastIndex = 0; - exactMatchInList = false; - smartMatchInList = true; - } - else - { - List temp = new List(allItems.Count); - Int32 n = allItems.Count; - Int32 i = 0; - Int32 score; - lastScore = 99; - ICompletionListItem item; - exactMatchInList = false; - smartMatchInList = false; - while (i < n) - { - item = allItems[i]; - // compare item's label with the searched word - score = SmartMatch(item.Label, word, len); - if (score > 0) - { - // first match found - if (!smartMatchInList || score < lastScore) - { - lastScore = score; - lastIndex = temp.Count; - smartMatchInList = true; - exactMatchInList = score < 5 && word == CompletionList.word; - } - temp.Add(new ItemMatch(score, item)); - if (item.Label.Length > maxLen) - { - widestLabel = item.Label; - maxLen = widestLabel.Length; - } - } - else if (fullList) temp.Add(new ItemMatch(0, item)); - i++; - } - // filter - found = new List(temp.Count); - for (int j = 0; j < temp.Count; j++) - { - if (j == lastIndex) lastIndex = found.Count; - if (temp[j].Score - lastScore < 3) found.Add(temp[j].Item); - } - } - // no match? - if (!smartMatchInList) - { - if (autoHideList && PluginBase.MainForm.Settings.EnableAutoHide && (len == 0 || len > 255)) - { - Hide('\0'); - } - else - { - // smart match - if (word.Length > 0) - { - FindWordStartingWith(word.Substring(0, len - 1)); - } - if (!smartMatchInList && autoHideList && PluginBase.MainForm.Settings.EnableAutoHide) - { - Hide('\0'); - } - } - return; - } - fullList = false; - // reset timer - if (tempo.Enabled) - { - tempo.Enabled = false; - tempo.Enabled = true; - } - // is update needed? - if (completionList.Items.Count == found.Count) - { - int n = completionList.Items.Count; - bool changed = false; - for (int i = 0; i < n; i++) - { - if (completionList.Items[i] != found[i]) - { - changed = true; - break; - } - } - if (!changed) - { - // preselected item - if (defaultItem != null) - { - if (lastScore > 3 || (lastScore > 2 && defaultItem.Label.StartsWith(word, StringComparison.OrdinalIgnoreCase))) - { - lastIndex = lastIndex = TestDefaultItem(lastIndex, word, len); - } - } - completionList.SelectedIndex = lastIndex; - return; - } - } - // update - try - { - completionList.BeginUpdate(); - completionList.Items.Clear(); - foreach (ICompletionListItem item in found) - { - completionList.Items.Add(item); - if (item.Label.Length > maxLen) - { - widestLabel = item.Label; - maxLen = widestLabel.Length; - } - } - Int32 topIndex = lastIndex; - if (defaultItem != null) - { - if (lastScore > 3 || (lastScore > 2 && defaultItem.Label.StartsWith(word, StringComparison.OrdinalIgnoreCase))) - { - lastIndex = TestDefaultItem(lastIndex, word, len); - } - } - // select first item - completionList.TopIndex = topIndex; - completionList.SelectedIndex = lastIndex; - } - catch (Exception ex) - { - Hide('\0'); - ErrorManager.ShowError(/*"Completion list populate error.", */ ex); - return; - } - finally - { - completionList.EndUpdate(); - } - // update list - if (!tempo.Enabled) DisplayList(null, null); - } - /// - /// NO FILTER - /// - else - { - int n = completionList.Items.Count; - ICompletionListItem item; - while (lastIndex < n) - { - item = completionList.Items[lastIndex] as ICompletionListItem; - if (String.Compare(item.Label, 0, word, 0, len, true) == 0) - { - completionList.SelectedIndex = lastIndex; - completionList.TopIndex = lastIndex; - exactMatchInList = true; - return; - } - lastIndex++; - } - // no match - if (autoHideList && PluginBase.MainForm.Settings.EnableAutoHide) Hide('\0'); - else exactMatchInList = false; - } - } - - private static int TestDefaultItem(Int32 index, String word, Int32 len) { - if (defaultItem != null && completionList.Items.Contains(defaultItem)) - { - Int32 score = (len == 0) ? 1 : SmartMatch(defaultItem.Label, word, len); - if (score > 0 && score < 6) return completionList.Items.IndexOf(defaultItem); - } - return index; + completionList.UpdateTip(sender, e); } static public int SmartMatch(string label, string word, int len) { - if (label.Length < len) return 0; - - // simple matching - if (disableSmartMatch) - { - if (label.StartsWith(word, StringComparison.OrdinalIgnoreCase)) - { - if (label.StartsWith(word)) return 1; - else return 5; - } - return 0; - } - - // try abbreviation - bool firstUpper = Char.IsUpper(word[0]); - if (firstUpper) - { - int abbr = IsAbbreviation(label, word); - if (abbr > 0) return abbr; - } - - int p = label.IndexOf(word, StringComparison.OrdinalIgnoreCase); - if (p >= 0) - { - int p2; - if (firstUpper) // try case sensitive search - { - p2 = label.IndexOf(word); - if (p2 >= 0) - { - int p3 = label.LastIndexOf("." + word); // in qualified type name - if (p3 > 0) - { - if (p3 == label.LastIndexOf('.')) - { - if (label.EndsWith("." + word)) return 1; - else return 3; - } - else return 4; - } - } - if (p2 == 0) - { - if (word == label) return 1; - else return 2; - } - else if (p2 > 0) return 4; - } - - p2 = label.LastIndexOf("." + word, StringComparison.OrdinalIgnoreCase); // in qualified type name - if (p2 > 0) - { - if (p2 == label.LastIndexOf('.')) - { - if (label.EndsWith("." + word, StringComparison.OrdinalIgnoreCase)) return 2; - else return 4; - } - else return 5; - } - if (p == 0) - { - if (label.Equals(word, StringComparison.OrdinalIgnoreCase)) - { - if (label.Equals(word)) return 1; - else return 2; - } - else return 3; - } - else - { - int p4 = label.IndexOf(':'); - if (p4 > 0) return SmartMatch(label.Substring(p4 + 1), word, len); - return 5; - } - } - - // loose - int n = label.Length; - int firstChar = label.IndexOf(word[0].ToString(), StringComparison.OrdinalIgnoreCase); - int i = 1; - p = firstChar; - while (i < len && p >= 0) - { - p = label.IndexOf(word[i++].ToString(), p + 1, StringComparison.OrdinalIgnoreCase); - } - return (p > 0) ? 7 : 0; + return completionList.SmartMatch(label, word, len); } - static public int IsAbbreviation(string label, string word) + /// + /// Filter the completion list with the letter typed + /// + static public void FindWordStartingWith(String word) { - int len = word.Length; - int i = 1; - char c = word[0]; - int p; - int p2; - int score = 0; - if (label[0] == c) { p2 = 0; score = 1; } - else if (label.IndexOf('.') < 0) - { - p2 = label.IndexOf(c); - if (p2 < 0) return 0; - score = 3; - } - else - { - p2 = label.IndexOf("." + c); - if (p2 >= 0) { score = 2; p2++; } - else - { - p2 = label.IndexOf(c); - if (p2 < 0) return 0; - score = 4; - } - } - int dist = 0; - - while (i < len) - { - p = p2; - c = word[i++]; - if (Char.IsUpper(c)) p2 = label.IndexOf(c.ToString(), p + 1); - else p2 = label.IndexOf(c.ToString(), p + 1, StringComparison.OrdinalIgnoreCase); - if (p2 < 0) return 0; - - int ups = 0; - for (int i2 = p + 1; i2 < p2; i2++) - if (label[i2] == '_') { ups = 0; } - else if (Char.IsUpper(label[i2])) ups++; - score += Math.Min(3, ups); // malus if skipped upper chars - - dist += p2 - p; - } - if (dist == len - 1) - { - if (label == word || label.EndsWith("." + word)) return 1; - return score; - } - else return score + 2; + completionList.FindWordStartingWith(word); } /// @@ -803,44 +193,8 @@ static public bool ReplaceText(ScintillaControl sci, char trigger) /// /// static public bool ReplaceText(ScintillaControl sci, String tail, char trigger) - { - sci.BeginUndoAction(); - try - { - String triggers = PluginBase.Settings.InsertionTriggers ?? ""; - if (triggers.Length > 0 && Regex.Unescape(triggers).IndexOf(trigger) < 0) return false; - - ICompletionListItem item = null; - if (completionList.SelectedIndex >= 0) - { - item = completionList.Items[completionList.SelectedIndex] as ICompletionListItem; - } - Hide(); - if (item != null) - { - String replace = item.Value; - if (replace != null) - { - sci.SetSel(startPos, sci.CurrentPos); - if (word != null && tail.Length > 0) - { - if (replace.StartsWith(word, StringComparison.OrdinalIgnoreCase) && replace.IndexOf(tail) >= word.Length) - { - replace = replace.Substring(0, replace.IndexOf(tail)); - } - } - sci.ReplaceSel(replace); - if (OnInsert != null) OnInsert(sci, startPos, replace, trigger, item); - if (tail.Length > 0) sci.ReplaceSel(tail); - } - return true; - } - return false; - } - finally - { - sci.EndUndoAction(); - } + { + return completionList.ReplaceText(sci, tail, trigger); } #endregion @@ -852,241 +206,35 @@ static public bool ReplaceText(ScintillaControl sci, String tail, char trigger) /// static public IntPtr GetHandle() { - return completionList.Handle; - } - - /// - /// - /// - static public void OnChar(ScintillaControl sci, int value) - { - char c = (char)value; - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; - if (characterClass.IndexOf(c) >= 0) - { - word += c; - currentPos++; - FindWordStartingWith(word); - return; - } - else if (noAutoInsert) - { - CompletionList.Hide('\0'); - // handle this char - UITools.Manager.SendChar(sci, value); - } - else - { - // check for fast typing - long millis = (DateTime.Now.Ticks - showTime) / 10000; - if (!exactMatchInList && (word.Length > 0 || (millis < 400 && defaultItem == null))) - { - CompletionList.Hide('\0'); - } - else if (word.Length == 0 && (currentItem == null || currentItem == allItems[0]) && defaultItem == null) - { - CompletionList.Hide('\0'); - } - else if (word.Length > 0 || c == '.' || c == '(' || c == '[' || c == '<' || c == ',' || c == ';') - { - ReplaceText(sci, c.ToString(), c); - } - // handle this char - UITools.Manager.SendChar(sci, value); - } + return completionList.GetHandle(); } - /// - /// - /// - static public bool HandleKeys(ScintillaControl sci, Keys key) - { - int index; - switch (key) - { - case Keys.Back: - if (!UITools.CallTip.CallTipActive) sci.DeleteBack(); - if (word.Length > MinWordLength) - { - word = word.Substring(0, word.Length-1); - currentPos = sci.CurrentPos; - lastIndex = 0; - FindWordStartingWith(word); - } - else CompletionList.Hide((char)8); - return true; - - case Keys.Enter: - if (noAutoInsert || !ReplaceText(sci, '\n')) - { - CompletionList.Hide(); - return false; - } - return true; - - case Keys.Tab: - if (!ReplaceText(sci, '\t')) - { - CompletionList.Hide(); - return false; - } - return true; - - case Keys.Space: - if (noAutoInsert) Hide(); - return false; - - case Keys.Up: - noAutoInsert = false; - // the list was hidden and it should not appear - if (!listHost.Visible) - { - Hide(); - if (key == Keys.Up) sci.LineUp(); - else sci.CharLeft(); - return false; - } - // go up the list - if (completionList.SelectedIndex > 0) - { - RefreshTip(); - index = completionList.SelectedIndex-1; - completionList.SelectedIndex = index; - } - // wrap - else if (PluginBase.MainForm.Settings.WrapList) - { - RefreshTip(); - index = completionList.Items.Count-1; - completionList.SelectedIndex = index; - } - break; - - case Keys.Down: - noAutoInsert = false; - // the list was hidden and it should not appear - if (!listHost.Visible) - { - Hide(); - if (key == Keys.Down) sci.LineDown(); - else sci.CharRight(); - return false; - } - // go down the list - if (completionList.SelectedIndex < completionList.Items.Count-1) - { - RefreshTip(); - index = completionList.SelectedIndex+1; - completionList.SelectedIndex = index; - } - // wrap - else if (PluginBase.MainForm.Settings.WrapList) - { - RefreshTip(); - index = 0; - completionList.SelectedIndex = index; - } - break; - - case Keys.PageUp: - noAutoInsert = false; - // the list was hidden and it should not appear - if (!listHost.Visible) - { - Hide(); - sci.PageUp(); - return false; - } - // go up the list - if (completionList.SelectedIndex > 0) - { - RefreshTip(); - index = completionList.SelectedIndex-completionList.Height/completionList.ItemHeight; - if (index < 0) index = 0; - completionList.SelectedIndex = index; - } - break; - - case Keys.PageDown: - noAutoInsert = false; - // the list was hidden and it should not appear - if (!listHost.Visible) - { - Hide(); - sci.PageDown(); - return false; - } - // go down the list - if (completionList.SelectedIndex < completionList.Items.Count-1) - { - RefreshTip(); - index = completionList.SelectedIndex+completionList.Height/completionList.ItemHeight; - if (index > completionList.Items.Count-1) index = completionList.Items.Count-1; - completionList.SelectedIndex = index; - } - break; - - case (Keys.Control | Keys.Space): - break; - - case Keys.Left: - sci.CharLeft(); - CompletionList.Hide(); - break; - - case Keys.Right: - sci.CharRight(); - CompletionList.Hide(); - break; - - default: - CompletionList.Hide(); - return false; - } - return true; - } + static public void OnChar(ScintillaControl sci, int value) + { + completionList.OnChar(sci, value); + } - private static void RefreshTip() + static public bool HandleKeys(ScintillaControl sci, Keys key) { - UITools.Tip.Hide(); - tempoTip.Enabled = false; + return completionList.HandleKeys(sci, key); } - + #endregion #region Controls fading on Control key - private static bool faded; - internal static void FadeOut() { - if (faded) return; - faded = true; - UITools.Tip.Hide(); - listHost.Visible = false; + completionList.FadeOut(); } internal static void FadeIn() { - if (!faded) return; - faded = false; - listHost.Visible = true; + completionList.FadeIn(); } #endregion } - struct ItemMatch - { - public int Score; - public ICompletionListItem Item; - - public ItemMatch(int score, ICompletionListItem item) - { - Score = score; - Item = item; - } - } - } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs new file mode 100644 index 0000000000..d23acf20bb --- /dev/null +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -0,0 +1,1090 @@ +using System; +using System.Drawing; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using PluginCore.Managers; +using PluginCore.Helpers; +using ScintillaNet; + +namespace PluginCore.Controls +{ + public delegate void InsertedTextHandler(ScintillaControl sender, int position, string text, char trigger, ICompletionListItem item); + + public class CompletionListControl + { + public event InsertedTextHandler OnInsert; + public event InsertedTextHandler OnCancel; + + /// + /// Properties of the class + /// + private System.Timers.Timer tempo; + private System.Timers.Timer tempoTip; + private System.Windows.Forms.ListBox completionList; + private System.Windows.Forms.Form listHost; + + #region State Properties + + private bool disableSmartMatch; + private ICompletionListItem currentItem; + private List allItems; + private bool exactMatchInList; + private bool smartMatchInList; + private bool autoHideList; + private bool noAutoInsert; + private bool isActive; + internal bool listUp; + private bool fullList; + private int startPos; + private int currentPos; + private int lastIndex; + private string currentWord; + private string word; + private bool needResize; + private string widestLabel; + private long showTime; + private ICompletionListItem defaultItem; + + /// + /// Set to 0 after calling .Show to keep the completion list active + /// when the text was erased completely (using backspace) + /// + public int MinWordLength; + + #endregion + + #region Control Creation + + /// + /// Creates the control + /// + public CompletionListControl(IMainForm mainForm) + { + tempo = new System.Timers.Timer(); + tempo.SynchronizingObject = (Form)mainForm; + tempo.Elapsed += new System.Timers.ElapsedEventHandler(DisplayList); + tempo.AutoReset = false; + tempoTip = new System.Timers.Timer(); + tempoTip.SynchronizingObject = (Form)mainForm; + tempoTip.Elapsed += new System.Timers.ElapsedEventHandler(UpdateTip); + tempoTip.AutoReset = false; + tempoTip.Interval = 800; + + completionList = new ListBox(); + completionList.Font = new System.Drawing.Font(PluginBase.Settings.DefaultFont, FontStyle.Regular); + completionList.ItemHeight = completionList.Font.Height + 2; + completionList.Dock = DockStyle.Fill; + completionList.DrawMode = DrawMode.OwnerDrawFixed; + completionList.DrawItem += new DrawItemEventHandler(CLDrawListItem); + completionList.Click += new EventHandler(CLClick); + completionList.DoubleClick += new EventHandler(CLDoubleClick); + + listHost = new InactiveForm(); + listHost.StartPosition = FormStartPosition.Manual; + listHost.FormBorderStyle = FormBorderStyle.None; + listHost.ShowIcon = false; + listHost.ShowInTaskbar = false; + listHost.Size = new Size(180, 100); + + listHost.Controls.Add(completionList); + } + + #endregion + + #region Public List Properties + + /// + /// Is the control active? + /// + public bool Active + { + get { return isActive; } + } + + /// + /// + /// + public bool HasMouseIn + { + get + { + if (!isActive || completionList == null) return false; + return completionList.ClientRectangle.Contains(completionList.PointToClient(Control.MousePosition)); + } + } + + /// + /// Retrieves the currently selected label, or null if none selected + /// + public string SelectedLabel + { + get + { + if (completionList == null) return null; + ICompletionListItem selected = completionList.SelectedItem as ICompletionListItem; + return (selected == null) ? null : selected.Label; + } + } + + #endregion + + #region CompletionList Methods + + /// + /// Checks if the position is valid + /// + public bool CheckPosition(int position) + { + return position == currentPos; + } + + /// + /// Shows the completion list + /// + public void Show(List itemList, bool autoHide, string select) + { + if (!string.IsNullOrEmpty(select)) + { + int maxLen = 0; + foreach (ICompletionListItem item in itemList) + if (item.Label.Length > maxLen) maxLen = item.Label.Length; + maxLen = Math.Min(256, maxLen); + if (select.Length > maxLen) select = select.Substring(0, maxLen); + currentWord = select; + } + else currentWord = null; + Show(itemList, autoHide); + } + + /// + /// Shows the completion list + /// + public void Show(List itemList, bool autoHide) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) return; + ScintillaControl sci = doc.SciControl; + try + { + if ((itemList == null) || (itemList.Count == 0)) + { + if (isActive) Hide(); + return; + } + if (sci == null) + { + if (isActive) Hide(); + return; + } + } + catch (Exception ex) + { + ErrorManager.ShowError(ex); + } + // state + allItems = itemList; + autoHideList = autoHide; + noAutoInsert = false; + word = ""; + if (currentWord != null) + { + word = currentWord; + currentWord = null; + } + MinWordLength = 1; + fullList = (word.Length == 0) || !autoHide || !PluginBase.MainForm.Settings.AutoFilterList; + lastIndex = 0; + exactMatchInList = false; + if (sci.SelectionStart == sci.SelectionEnd) + startPos = sci.CurrentPos - word.Length; + else + startPos = sci.SelectionStart; + currentPos = sci.SelectionEnd; // sci.CurrentPos; + defaultItem = null; + // populate list + needResize = true; + tempo.Enabled = autoHide && (PluginBase.MainForm.Settings.DisplayDelay > 0); + if (tempo.Enabled) tempo.Interval = PluginBase.MainForm.Settings.DisplayDelay; + FindWordStartingWith(word); + // state + isActive = true; + tempoTip.Enabled = false; + showTime = DateTime.Now.Ticks; + disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; + UITools.Manager.LockControl(sci); + faded = false; + } + + /// + /// Set default selected item in completion list + /// + public void SelectItem(string name) + { + int p = name.IndexOf('<'); + if (p > 1) name = name.Substring(0, p) + ""; + string pname = (name.IndexOf('.') < 0) ? "." + name : null; + ICompletionListItem found = null; + foreach (ICompletionListItem item in completionList.Items) + { + if (item.Label == name) + { + defaultItem = item; + completionList.SelectedItem = item; + return; + } + if (pname != null && item.Label.EndsWith(pname)) found = item; + } + if (found != null) + { + defaultItem = found; + completionList.SelectedItem = found; + } + } + + /// + /// Require that completion items are explicitely inserted (Enter, Tab, mouse-click) + /// + public void DisableAutoInsertion() + { + noAutoInsert = true; + } + + /// + /// + /// + private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) return; + ScintillaControl sci = doc.SciControl; + ListBox cl = completionList; + Form host = listHost; + if (cl.Items.Count == 0) return; + + // measure control + if (needResize && !string.IsNullOrEmpty(widestLabel)) + { + needResize = false; + Graphics g = cl.CreateGraphics(); + SizeF size = g.MeasureString(widestLabel, cl.Font); + host.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); + } + int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; + if (newHeight != host.Height) host.Height = newHeight; + // place control + Point coord = new Point(sci.PointXFromPosition(startPos), sci.PointYFromPosition(startPos)); + listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > (sci as Control).Height); + coord = sci.PointToScreen(coord); + host.Left = coord.X + sci.Left; + var screen = Screen.FromHandle(PluginBase.MainForm.Handle); + if (listUp) host.Top = coord.Y - host.Height; + else host.Top = coord.Y + UITools.Manager.LineHeight(sci); + // Keep on screen area + if (host.Right > screen.WorkingArea.Right) + { + host.Left = screen.WorkingArea.Right - host.Width; + } + if (!host.Visible) + { + Redraw(); + host.Show(PluginBase.MainForm); + if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(sci); + } + } + + public void Redraw() + { + Color back = PluginBase.MainForm.GetThemeColor("CompletionList.BackColor"); + completionList.BackColor = back == Color.Empty ? System.Drawing.SystemColors.Window : back; + } + + /// + /// Hide completion list + /// + public void Hide() + { + if (completionList != null && isActive) + { + tempo.Enabled = false; + isActive = false; + fullList = false; + faded = false; + listHost.Visible = false; + if (completionList.Items.Count > 0) completionList.Items.Clear(); + currentItem = null; + allItems = null; + UITools.Tip.Hide(); + if (!UITools.CallTip.CallTipActive) UITools.Manager.UnlockControl(); + } + } + + /// + /// Cancel completion list with event + /// + public void Hide(char trigger) + { + if (completionList != null && isActive) + { + Hide(); + if (OnCancel != null) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) return; + OnCancel(doc.SciControl, currentPos, currentWord, trigger, null); + } + } + } + + /// + /// + /// + public void SelectWordInList(string tail) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) + { + Hide(); + return; + } + ScintillaControl sci = doc.SciControl; + currentWord = tail; + currentPos += tail.Length; + sci.SetSel(currentPos, currentPos); + } + + /// + /// + /// + private void CLDrawListItem(Object sender, System.Windows.Forms.DrawItemEventArgs e) + { + ICompletionListItem item = completionList.Items[e.Index] as ICompletionListItem; + e.DrawBackground(); + Color fore = PluginBase.MainForm.GetThemeColor("CompletionList.ForeColor"); + bool selected = (e.State & DrawItemState.Selected) > 0; + Brush textBrush = (selected) ? SystemBrushes.HighlightText : fore == Color.Empty ? SystemBrushes.WindowText : new SolidBrush(fore); + Brush packageBrush = Brushes.Gray; + Rectangle tbounds = new Rectangle(ScaleHelper.Scale(18), e.Bounds.Top, e.Bounds.Width, e.Bounds.Height); + if (item != null) + { + Graphics g = e.Graphics; + float newHeight = e.Bounds.Height - 2; + g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + g.DrawImage(item.Icon, 1, e.Bounds.Top + ((e.Bounds.Height - newHeight) / 2), newHeight, newHeight); + int p = item.Label.LastIndexOf('.'); + if (p > 0 && !selected) + { + string package = item.Label.Substring(0, p + 1); + g.DrawString(package, e.Font, packageBrush, tbounds, StringFormat.GenericDefault); + int left = tbounds.Left + DrawHelper.MeasureDisplayStringWidth(e.Graphics, package, e.Font) - 2; + if (left < tbounds.Right) g.DrawString(item.Label.Substring(p + 1), e.Font, textBrush, left, tbounds.Top, StringFormat.GenericDefault); + } + else g.DrawString(item.Label, e.Font, textBrush, tbounds, StringFormat.GenericDefault); + } + e.DrawFocusRectangle(); + if ((item != null) && ((e.State & DrawItemState.Selected) > 0)) + { + UITools.Tip.Hide(); + currentItem = item; + tempoTip.Stop(); + tempoTip.Start(); + } + } + + /// + /// Display item information in tooltip + /// + public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) + { + tempoTip.Stop(); + if (currentItem == null || faded) + return; + + UITools.Tip.SetText(currentItem.Description ?? "", false); + UITools.Tip.Redraw(false); + + var screen = Screen.FromControl(listHost); + int rightWidth = screen.WorkingArea.Right - listHost.Right - 10; + int leftWidth = listHost.Left; + + Point posTarget = new Point(listHost.Right, listHost.Top); + int widthTarget = rightWidth; + if (rightWidth < 220 && leftWidth > 220) + { + widthTarget = leftWidth; + posTarget.X = 0; + } + + UITools.Tip.Location = posTarget; + UITools.Tip.AutoSize(widthTarget, 500); + + if (widthTarget == leftWidth) + UITools.Tip.Location = new Point(listHost.Left - UITools.Tip.Size.Width, posTarget.Y); + + UITools.Tip.Show(); + } + + /// + /// + /// + private void CLClick(Object sender, System.EventArgs e) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) + { + Hide(); + return; + } + doc.SciControl.Focus(); + } + + /// + /// + /// + private void CLDoubleClick(Object sender, System.EventArgs e) + { + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; + if (!doc.IsEditable) + { + Hide(); + return; + } + ScintillaControl sci = doc.SciControl; + sci.Focus(); + //ReplaceText(sci, '\0'); + } + + /// + /// Filter the completion list with the letter typed + /// + public void FindWordStartingWith(string word) + { + if (word == null) word = ""; + int len = word.Length; + int maxLen = 0; + int lastScore = 0; + // FILTER ITEMS + if (PluginBase.MainForm.Settings.AutoFilterList || fullList) + { + List found; + if (len == 0) + { + found = allItems; + lastIndex = 0; + exactMatchInList = false; + smartMatchInList = true; + } + else + { + List temp = new List(allItems.Count); + int n = allItems.Count; + int i = 0; + int score; + lastScore = 99; + ICompletionListItem item; + exactMatchInList = false; + smartMatchInList = false; + while (i < n) + { + item = allItems[i]; + // compare item's label with the searched word + score = SmartMatch(item.Label, word, len); + if (score > 0) + { + // first match found + if (!smartMatchInList || score < lastScore) + { + lastScore = score; + lastIndex = temp.Count; + smartMatchInList = true; + exactMatchInList = score < 5 && word == this.word; + } + temp.Add(new ItemMatch(score, item)); + if (item.Label.Length > maxLen) + { + widestLabel = item.Label; + maxLen = widestLabel.Length; + } + } + else if (fullList) temp.Add(new ItemMatch(0, item)); + i++; + } + // filter + found = new List(temp.Count); + for (int j = 0; j < temp.Count; j++) + { + if (j == lastIndex) lastIndex = found.Count; + if (temp[j].Score - lastScore < 3) found.Add(temp[j].Item); + } + } + // no match? + if (!smartMatchInList) + { + if (autoHideList && PluginBase.MainForm.Settings.EnableAutoHide && (len == 0 || len > 255)) + { + Hide('\0'); + } + else + { + // smart match + if (word.Length > 0) + { + FindWordStartingWith(word.Substring(0, len - 1)); + } + if (!smartMatchInList && autoHideList && PluginBase.MainForm.Settings.EnableAutoHide) + { + Hide('\0'); + } + } + return; + } + fullList = false; + // reset timer + if (tempo.Enabled) + { + tempo.Enabled = false; + tempo.Enabled = true; + } + // is update needed? + if (completionList.Items.Count == found.Count) + { + int n = completionList.Items.Count; + bool changed = false; + for (int i = 0; i < n; i++) + { + if (completionList.Items[i] != found[i]) + { + changed = true; + break; + } + } + if (!changed) + { + // preselected item + if (defaultItem != null) + { + if (lastScore > 3 || (lastScore > 2 && defaultItem.Label.StartsWith(word, StringComparison.OrdinalIgnoreCase))) + { + lastIndex = lastIndex = TestDefaultItem(lastIndex, word, len); + } + } + completionList.SelectedIndex = lastIndex; + return; + } + } + // update + try + { + completionList.BeginUpdate(); + completionList.Items.Clear(); + foreach (ICompletionListItem item in found) + { + completionList.Items.Add(item); + if (item.Label.Length > maxLen) + { + widestLabel = item.Label; + maxLen = widestLabel.Length; + } + } + int topIndex = lastIndex; + if (defaultItem != null) + { + if (lastScore > 3 || (lastScore > 2 && defaultItem.Label.StartsWith(word, StringComparison.OrdinalIgnoreCase))) + { + lastIndex = TestDefaultItem(lastIndex, word, len); + } + } + // select first item + completionList.TopIndex = topIndex; + completionList.SelectedIndex = lastIndex; + } + catch (Exception ex) + { + Hide('\0'); + ErrorManager.ShowError(/*"Completion list populate error.", */ ex); + return; + } + finally + { + completionList.EndUpdate(); + } + // update list + if (!tempo.Enabled) DisplayList(null, null); + } + /// + /// NO FILTER + /// + else + { + int n = completionList.Items.Count; + ICompletionListItem item; + while (lastIndex < n) + { + item = completionList.Items[lastIndex] as ICompletionListItem; + if (string.Compare(item.Label, 0, word, 0, len, true) == 0) + { + completionList.SelectedIndex = lastIndex; + completionList.TopIndex = lastIndex; + exactMatchInList = true; + return; + } + lastIndex++; + } + // no match + if (autoHideList && PluginBase.MainForm.Settings.EnableAutoHide) Hide('\0'); + else exactMatchInList = false; + } + } + + private int TestDefaultItem(int index, string word, int len) + { + if (defaultItem != null && completionList.Items.Contains(defaultItem)) + { + int score = (len == 0) ? 1 : SmartMatch(defaultItem.Label, word, len); + if (score > 0 && score < 6) return completionList.Items.IndexOf(defaultItem); + } + return index; + } + + public int SmartMatch(string label, string word, int len) + { + if (label.Length < len) return 0; + + // simple matching + if (disableSmartMatch) + { + if (label.StartsWith(word, StringComparison.OrdinalIgnoreCase)) + { + if (label.StartsWith(word)) return 1; + else return 5; + } + return 0; + } + + // try abbreviation + bool firstUpper = char.IsUpper(word[0]); + if (firstUpper) + { + int abbr = IsAbbreviation(label, word); + if (abbr > 0) return abbr; + } + + int p = label.IndexOf(word, StringComparison.OrdinalIgnoreCase); + if (p >= 0) + { + int p2; + if (firstUpper) // try case sensitive search + { + p2 = label.IndexOf(word); + if (p2 >= 0) + { + int p3 = label.LastIndexOf("." + word); // in qualified type name + if (p3 > 0) + { + if (p3 == label.LastIndexOf('.')) + { + if (label.EndsWith("." + word)) return 1; + else return 3; + } + else return 4; + } + } + if (p2 == 0) + { + if (word == label) return 1; + else return 2; + } + else if (p2 > 0) return 4; + } + + p2 = label.LastIndexOf("." + word, StringComparison.OrdinalIgnoreCase); // in qualified type name + if (p2 > 0) + { + if (p2 == label.LastIndexOf('.')) + { + if (label.EndsWith("." + word, StringComparison.OrdinalIgnoreCase)) return 2; + else return 4; + } + else return 5; + } + if (p == 0) + { + if (label.Equals(word, StringComparison.OrdinalIgnoreCase)) + { + if (label.Equals(word)) return 1; + else return 2; + } + else return 3; + } + else + { + int p4 = label.IndexOf(':'); + if (p4 > 0) return SmartMatch(label.Substring(p4 + 1), word, len); + return 5; + } + } + + // loose + int n = label.Length; + int firstChar = label.IndexOf(word[0].ToString(), StringComparison.OrdinalIgnoreCase); + int i = 1; + p = firstChar; + while (i < len && p >= 0) + { + p = label.IndexOf(word[i++].ToString(), p + 1, StringComparison.OrdinalIgnoreCase); + } + return (p > 0) ? 7 : 0; + } + + public int IsAbbreviation(string label, string word) + { + int len = word.Length; + int i = 1; + char c = word[0]; + int p; + int p2; + int score = 0; + if (label[0] == c) { p2 = 0; score = 1; } + else if (label.IndexOf('.') < 0) + { + p2 = label.IndexOf(c); + if (p2 < 0) return 0; + score = 3; + } + else + { + p2 = label.IndexOf("." + c); + if (p2 >= 0) { score = 2; p2++; } + else + { + p2 = label.IndexOf(c); + if (p2 < 0) return 0; + score = 4; + } + } + int dist = 0; + + while (i < len) + { + p = p2; + c = word[i++]; + if (char.IsUpper(c)) p2 = label.IndexOf(c.ToString(), p + 1); + else p2 = label.IndexOf(c.ToString(), p + 1, StringComparison.OrdinalIgnoreCase); + if (p2 < 0) return 0; + + int ups = 0; + for (int i2 = p + 1; i2 < p2; i2++) + if (label[i2] == '_') { ups = 0; } + else if (char.IsUpper(label[i2])) ups++; + score += Math.Min(3, ups); // malus if skipped upper chars + + dist += p2 - p; + } + if (dist == len - 1) + { + if (label == word || label.EndsWith("." + word)) return 1; + return score; + } + else return score + 2; + } + + /// + /// + /// + public bool ReplaceText(ScintillaControl sci, char trigger) + { + return ReplaceText(sci, "", trigger); + } + + /// + /// + /// + public bool ReplaceText(ScintillaControl sci, String tail, char trigger) + { + sci.BeginUndoAction(); + try + { + String triggers = PluginBase.Settings.InsertionTriggers ?? ""; + if (triggers.Length > 0 && Regex.Unescape(triggers).IndexOf(trigger) < 0) return false; + + ICompletionListItem item = null; + if (completionList.SelectedIndex >= 0) + { + item = completionList.Items[completionList.SelectedIndex] as ICompletionListItem; + } + Hide(); + if (item != null) + { + String replace = item.Value; + if (replace != null) + { + sci.SetSel(startPos, sci.CurrentPos); + if (word != null && tail.Length > 0) + { + if (replace.StartsWith(word, StringComparison.OrdinalIgnoreCase) && replace.IndexOf(tail) >= word.Length) + { + replace = replace.Substring(0, replace.IndexOf(tail)); + } + } + sci.ReplaceSel(replace); + if (OnInsert != null) OnInsert(sci, startPos, replace, trigger, item); + if (tail.Length > 0) sci.ReplaceSel(tail); + } + return true; + } + return false; + } + finally + { + sci.EndUndoAction(); + } + } + + #endregion + + #region Event Handling + + /// + /// + /// + public IntPtr GetHandle() + { + return completionList.Handle; + } + + /// + /// + /// + public void OnChar(ScintillaControl sci, int value) + { + char c = (char)value; + string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + if (characterClass.IndexOf(c) >= 0) + { + word += c; + currentPos++; + FindWordStartingWith(word); + return; + } + else if (noAutoInsert) + { + Hide('\0'); + // handle this char + UITools.Manager.SendChar(sci, value); + } + else + { + // check for fast typing + long millis = (DateTime.Now.Ticks - showTime) / 10000; + if (!exactMatchInList && (word.Length > 0 || (millis < 400 && defaultItem == null))) + { + Hide('\0'); + } + else if (word.Length == 0 && (currentItem == null || currentItem == allItems[0]) && defaultItem == null) + { + Hide('\0'); + } + else if (word.Length > 0 || c == '.' || c == '(' || c == '[' || c == '<' || c == ',' || c == ';') + { + ReplaceText(sci, c.ToString(), c); + } + // handle this char + UITools.Manager.SendChar(sci, value); + } + } + + /// + /// + /// + public bool HandleKeys(ScintillaControl sci, Keys key) + { + int index; + switch (key) + { + case Keys.Back: + if (!UITools.CallTip.CallTipActive) sci.DeleteBack(); + if (word.Length > MinWordLength) + { + word = word.Substring(0, word.Length - 1); + currentPos = sci.CurrentPos; + lastIndex = 0; + FindWordStartingWith(word); + } + else Hide((char)8); + return true; + + case Keys.Enter: + if (noAutoInsert || !ReplaceText(sci, '\n')) + { + Hide(); + return false; + } + return true; + + case Keys.Tab: + if (!ReplaceText(sci, '\t')) + { + Hide(); + return false; + } + return true; + + case Keys.Space: + if (noAutoInsert) Hide(); + return false; + + case Keys.Up: + noAutoInsert = false; + // the list was hidden and it should not appear + if (!listHost.Visible) + { + Hide(); + if (key == Keys.Up) sci.LineUp(); + else sci.CharLeft(); + return false; + } + // go up the list + if (completionList.SelectedIndex > 0) + { + RefreshTip(); + index = completionList.SelectedIndex - 1; + completionList.SelectedIndex = index; + } + // wrap + else if (PluginBase.MainForm.Settings.WrapList) + { + RefreshTip(); + index = completionList.Items.Count - 1; + completionList.SelectedIndex = index; + } + break; + + case Keys.Down: + noAutoInsert = false; + // the list was hidden and it should not appear + if (!listHost.Visible) + { + Hide(); + if (key == Keys.Down) sci.LineDown(); + else sci.CharRight(); + return false; + } + // go down the list + if (completionList.SelectedIndex < completionList.Items.Count - 1) + { + RefreshTip(); + index = completionList.SelectedIndex + 1; + completionList.SelectedIndex = index; + } + // wrap + else if (PluginBase.MainForm.Settings.WrapList) + { + RefreshTip(); + index = 0; + completionList.SelectedIndex = index; + } + break; + + case Keys.PageUp: + noAutoInsert = false; + // the list was hidden and it should not appear + if (!listHost.Visible) + { + Hide(); + sci.PageUp(); + return false; + } + // go up the list + if (completionList.SelectedIndex > 0) + { + RefreshTip(); + index = completionList.SelectedIndex - completionList.Height / completionList.ItemHeight; + if (index < 0) index = 0; + completionList.SelectedIndex = index; + } + break; + + case Keys.PageDown: + noAutoInsert = false; + // the list was hidden and it should not appear + if (!listHost.Visible) + { + Hide(); + sci.PageDown(); + return false; + } + // go down the list + if (completionList.SelectedIndex < completionList.Items.Count - 1) + { + RefreshTip(); + index = completionList.SelectedIndex + completionList.Height / completionList.ItemHeight; + if (index > completionList.Items.Count - 1) index = completionList.Items.Count - 1; + completionList.SelectedIndex = index; + } + break; + + case (Keys.Control | Keys.Space): + break; + + case Keys.Left: + sci.CharLeft(); + Hide(); + break; + + case Keys.Right: + sci.CharRight(); + Hide(); + break; + + default: + Hide(); + return false; + } + return true; + } + + private void RefreshTip() + { + UITools.Tip.Hide(); + tempoTip.Enabled = false; + } + + #endregion + + #region Controls fading on Control key + + private bool faded; + + internal void FadeOut() + { + if (faded) return; + faded = true; + UITools.Tip.Hide(); + listHost.Visible = false; + } + + internal void FadeIn() + { + if (!faded) return; + faded = false; + listHost.Visible = true; + } + + #endregion + + } + + struct ItemMatch + { + public int Score; + public ICompletionListItem Item; + + public ItemMatch(int score, ICompletionListItem item) + { + Score = score; + Item = item; + } + } + +} diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index 7bd0f22cb5..b1f8a22f77 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -196,6 +196,8 @@ public void ShowAtMouseLocation() host.Left -= (host.Right - screen.WorkingArea.Right); } host.Top = mousePos.Y - host.Height - 10;// +sci.Top; + if (host.Top < 5) + host.Top = mousePos.Y + 10; host.Show(owner); } @@ -215,7 +217,8 @@ public virtual void Hide() public virtual void Show() { - host.Show(owner); + if (!host.Visible) + host.Show(owner); } public void SetText(String rawText, bool redraw) From ccd2fb9f42b73f4c2291fdda495ebda63b7ea3d3 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Wed, 11 Feb 2015 23:29:58 +0100 Subject: [PATCH 05/36] Some more CompletionList decoupling. --- PluginCore/PluginCore.csproj | 1 + .../PluginCore/Controls/CompletionList.cs | 138 ++++++++++++--- .../Controls/CompletionListControl.cs | 159 +++++++++--------- .../Controls/ICompletionListTarget.cs | 28 +++ 4 files changed, 220 insertions(+), 106 deletions(-) create mode 100644 PluginCore/PluginCore/Controls/ICompletionListTarget.cs diff --git a/PluginCore/PluginCore.csproj b/PluginCore/PluginCore.csproj index e2c9c19119..aa15bc2965 100644 --- a/PluginCore/PluginCore.csproj +++ b/PluginCore/PluginCore.csproj @@ -312,6 +312,7 @@ Component + Form diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 6fa5d06f44..6568fad0f7 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -1,17 +1,15 @@ using System; using System.Drawing; using System.Collections.Generic; -using System.Drawing.Imaging; -using System.Text.RegularExpressions; using System.Windows.Forms; -using PluginCore.Managers; -using PluginCore.Helpers; using ScintillaNet; namespace PluginCore.Controls { - public static class CompletionList + public delegate void InsertedTextHandler(ScintillaControl sender, int position, string text, char trigger, ICompletionListItem item); + + public static class CompletionList { static public event InsertedTextHandler OnInsert; static public event InsertedTextHandler OnCancel; @@ -26,13 +24,18 @@ public static class CompletionList internal static Boolean listUp { get { return completionList.listUp; } + set { completionList.listUp = value; } } /// /// Set to 0 after calling .Show to keep the completion list active /// when the text was erased completely (using backspace) /// - public static Int32 MinWordLength; + public static Int32 MinWordLength + { + get { return completionList.MinWordLength; } + set { completionList.MinWordLength = value; } + } #endregion @@ -43,12 +46,12 @@ internal static Boolean listUp /// public static void CreateControl(IMainForm mainForm) { - completionList = new CompletionListControl(mainForm); - completionList.OnCancel += OnCancel; - completionList.OnInsert += OnInsert; + completionList = new CompletionListControl(new ScintillaTarget()); + completionList.OnCancel += OnCancelHandler; + completionList.OnInsert += OnInsertHandler; } - - #endregion + + #endregion #region Public List Properties @@ -99,9 +102,7 @@ public static Boolean CheckPosition(Int32 position) /// static public void Show(List itemList, Boolean autoHide, String select) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - completionList.Show(itemList, autoHide); + completionList.Show(itemList, autoHide, select); } /// @@ -109,9 +110,6 @@ static public void Show(List itemList, Boolean autoHide, St /// static public void Show(List itemList, bool autoHide) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - ScintillaControl sci = doc.SciControl; completionList.Show(itemList, autoHide); } @@ -186,7 +184,7 @@ static public void FindWordStartingWith(String word) /// static public bool ReplaceText(ScintillaControl sci, char trigger) { - return ReplaceText(sci, "", trigger); + return completionList.ReplaceText("", trigger); } /// @@ -194,7 +192,7 @@ static public bool ReplaceText(ScintillaControl sci, char trigger) /// static public bool ReplaceText(ScintillaControl sci, String tail, char trigger) { - return completionList.ReplaceText(sci, tail, trigger); + return completionList.ReplaceText(tail, trigger); } #endregion @@ -211,15 +209,27 @@ static public IntPtr GetHandle() static public void OnChar(ScintillaControl sci, int value) { - completionList.OnChar(sci, value); + completionList.OnChar(value); } static public bool HandleKeys(ScintillaControl sci, Keys key) { - return completionList.HandleKeys(sci, key); + return completionList.HandleKeys(key); } - #endregion + private static void OnCancelHandler(Control sender, Int32 position, String text, Char trigger, ICompletionListItem item) + { + if (OnCancel != null) + OnCancel((ScintillaControl)sender, position, text, trigger, item); + } + + private static void OnInsertHandler(Control sender, Int32 position, String text, Char trigger, ICompletionListItem item) + { + if (OnInsert != null) + OnInsert((ScintillaControl)sender, position, text, trigger, item); + } + + #endregion #region Controls fading on Control key @@ -235,6 +245,88 @@ internal static void FadeIn() #endregion - } + private class ScintillaTarget : ICompletionListTarget + { + + public event EventHandler LostFocus; + public event ScrollEventHandler Scroll; + public event KeyEventHandler KeyDown; + public event MouseEventHandler MouseDown; + public Control Owner + { + get { return PluginBase.MainForm.CurrentDocument.SciControl; } + } + + public string Text + { + get { throw new NotImplementedException(); } + } + + public string SelectedText + { + get + { + return PluginBase.MainForm.CurrentDocument.SciControl.SelText; + } + set + { + throw new NotImplementedException(); + } + } + + public int SelectionEnd + { + get + { + return PluginBase.MainForm.CurrentDocument.SciControl.SelectionEnd; + } + set + { + PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; + } + } + + public int SelectionStart + { + get + { + return PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart; + } + set + { + PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; + } + } + + public int CurrentPos + { + get { return PluginBase.MainForm.CurrentDocument.SciControl.CurrentPos; } + } + + public int GetLineHeight() + { + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + return UITools.Manager.LineHeight(sci); + } + + public Point GetPositionFromCharIndex(int pos) + { + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + return new Point(sci.PointXFromPosition(pos), sci.PointYFromPosition(pos)); + } + + public void SetSelection(int start, int end) + { + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + sci.SetSel(start, end); + } + + public bool IsEditable + { + get { return PluginBase.MainForm.CurrentDocument.IsEditable && PluginBase.MainForm.CurrentDocument.SciControl != null; } + } + + } + } } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index d23acf20bb..c7c5b5957c 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1,21 +1,24 @@ using System; using System.Drawing; using System.Collections.Generic; -using System.Drawing.Imaging; using System.Text.RegularExpressions; using System.Windows.Forms; using PluginCore.Managers; using PluginCore.Helpers; using ScintillaNet; +// TODO: Remove all direct references to ScintillaControl +// TODO: Extract ToolTip reference +// TODO: Extract CallTip reference + namespace PluginCore.Controls { - public delegate void InsertedTextHandler(ScintillaControl sender, int position, string text, char trigger, ICompletionListItem item); + public delegate void CompletionListInsertedTextHandler(Control sender, int position, string text, char trigger, ICompletionListItem item); public class CompletionListControl { - public event InsertedTextHandler OnInsert; - public event InsertedTextHandler OnCancel; + public event CompletionListInsertedTextHandler OnInsert; + public event CompletionListInsertedTextHandler OnCancel; /// /// Properties of the class @@ -47,6 +50,8 @@ public class CompletionListControl private long showTime; private ICompletionListItem defaultItem; + private ICompletionListTarget target; + /// /// Set to 0 after calling .Show to keep the completion list active /// when the text was erased completely (using backspace) @@ -60,14 +65,23 @@ public class CompletionListControl /// /// Creates the control /// - public CompletionListControl(IMainForm mainForm) + public CompletionListControl(ICompletionListTarget target) { + this.target = target; + + listHost = new InactiveForm(); + listHost.StartPosition = FormStartPosition.Manual; + listHost.FormBorderStyle = FormBorderStyle.None; + listHost.ShowIcon = false; + listHost.ShowInTaskbar = false; + listHost.Size = new Size(180, 100); + tempo = new System.Timers.Timer(); - tempo.SynchronizingObject = (Form)mainForm; + tempo.SynchronizingObject = (Form)PluginBase.MainForm; tempo.Elapsed += new System.Timers.ElapsedEventHandler(DisplayList); tempo.AutoReset = false; tempoTip = new System.Timers.Timer(); - tempoTip.SynchronizingObject = (Form)mainForm; + tempoTip.SynchronizingObject = (Form)PluginBase.MainForm; tempoTip.Elapsed += new System.Timers.ElapsedEventHandler(UpdateTip); tempoTip.AutoReset = false; tempoTip.Interval = 800; @@ -81,13 +95,6 @@ public CompletionListControl(IMainForm mainForm) completionList.Click += new EventHandler(CLClick); completionList.DoubleClick += new EventHandler(CLDoubleClick); - listHost = new InactiveForm(); - listHost.StartPosition = FormStartPosition.Manual; - listHost.FormBorderStyle = FormBorderStyle.None; - listHost.ShowIcon = false; - listHost.ShowInTaskbar = false; - listHost.Size = new Size(180, 100); - listHost.Controls.Add(completionList); } @@ -163,17 +170,14 @@ public void Show(List itemList, bool autoHide, string selec /// public void Show(List itemList, bool autoHide) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - ScintillaControl sci = doc.SciControl; try { - if ((itemList == null) || (itemList.Count == 0)) + if (!target.IsEditable) { if (isActive) Hide(); return; } - if (sci == null) + if ((itemList == null) || (itemList.Count == 0)) { if (isActive) Hide(); return; @@ -197,11 +201,11 @@ public void Show(List itemList, bool autoHide) fullList = (word.Length == 0) || !autoHide || !PluginBase.MainForm.Settings.AutoFilterList; lastIndex = 0; exactMatchInList = false; - if (sci.SelectionStart == sci.SelectionEnd) - startPos = sci.CurrentPos - word.Length; + if (target.SelectionStart == target.SelectionEnd) + startPos = target.CurrentPos - word.Length; else - startPos = sci.SelectionStart; - currentPos = sci.SelectionEnd; // sci.CurrentPos; + startPos = target.SelectionStart; + currentPos = target.SelectionEnd; // sci.CurrentPos; defaultItem = null; // populate list needResize = true; @@ -213,7 +217,7 @@ public void Show(List itemList, bool autoHide) tempoTip.Enabled = false; showTime = DateTime.Now.Ticks; disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; - UITools.Manager.LockControl(sci); + UITools.Manager.LockControl(((ScintillaControl)target.Owner)); faded = false; } @@ -256,9 +260,7 @@ public void DisableAutoInsertion() /// private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - ScintillaControl sci = doc.SciControl; + if (!target.IsEditable) return; ListBox cl = completionList; Form host = listHost; if (cl.Items.Count == 0) return; @@ -274,13 +276,13 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; if (newHeight != host.Height) host.Height = newHeight; // place control - Point coord = new Point(sci.PointXFromPosition(startPos), sci.PointYFromPosition(startPos)); - listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > (sci as Control).Height); - coord = sci.PointToScreen(coord); - host.Left = coord.X + sci.Left; + Point coord = target.GetPositionFromCharIndex(startPos); + listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > target.Owner.Height); + coord = target.Owner.PointToScreen(coord); + host.Left = coord.X + target.Owner.Left; var screen = Screen.FromHandle(PluginBase.MainForm.Handle); if (listUp) host.Top = coord.Y - host.Height; - else host.Top = coord.Y + UITools.Manager.LineHeight(sci); + else host.Top = coord.Y + target.GetLineHeight(); // Keep on screen area if (host.Right > screen.WorkingArea.Right) { @@ -289,8 +291,8 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) if (!host.Visible) { Redraw(); - host.Show(PluginBase.MainForm); - if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(sci); + host.Show(target.Owner); + if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(((ScintillaControl)target.Owner)); } } @@ -311,7 +313,7 @@ public void Hide() isActive = false; fullList = false; faded = false; - listHost.Visible = false; + listHost.Hide(); if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; allItems = null; @@ -330,9 +332,8 @@ public void Hide(char trigger) Hide(); if (OnCancel != null) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) return; - OnCancel(doc.SciControl, currentPos, currentWord, trigger, null); + if (!target.IsEditable) return; + OnCancel(target.Owner, currentPos, currentWord, trigger, null); } } } @@ -342,16 +343,14 @@ public void Hide(char trigger) /// public void SelectWordInList(string tail) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) + if (!target.IsEditable) { Hide(); return; } - ScintillaControl sci = doc.SciControl; currentWord = tail; currentPos += tail.Length; - sci.SetSel(currentPos, currentPos); + target.SetSelection(currentPos, currentPos); } /// @@ -430,13 +429,12 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) /// private void CLClick(Object sender, System.EventArgs e) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) + if (!target.IsEditable) { Hide(); return; } - doc.SciControl.Focus(); + target.Owner.Focus(); } /// @@ -444,15 +442,13 @@ private void CLClick(Object sender, System.EventArgs e) /// private void CLDoubleClick(Object sender, System.EventArgs e) { - ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - if (!doc.IsEditable) + if (!target.IsEditable) { Hide(); return; } - ScintillaControl sci = doc.SciControl; - sci.Focus(); - //ReplaceText(sci, '\0'); + target.Owner.Focus(); + ReplaceText('\0'); } /// @@ -612,9 +608,7 @@ public void FindWordStartingWith(string word) // update list if (!tempo.Enabled) DisplayList(null, null); } - /// - /// NO FILTER - /// + // NO FILTER else { int n = completionList.Items.Count; @@ -792,22 +786,21 @@ public int IsAbbreviation(string label, string word) /// /// /// - public bool ReplaceText(ScintillaControl sci, char trigger) + public bool ReplaceText(char trigger) { - return ReplaceText(sci, "", trigger); + return ReplaceText("", trigger); } /// /// /// - public bool ReplaceText(ScintillaControl sci, String tail, char trigger) + public bool ReplaceText(string tail, char trigger) { - sci.BeginUndoAction(); + String triggers = PluginBase.Settings.InsertionTriggers ?? ""; + if (triggers.Length > 0 && Regex.Unescape(triggers).IndexOf(trigger) < 0) return false; + try { - String triggers = PluginBase.Settings.InsertionTriggers ?? ""; - if (triggers.Length > 0 && Regex.Unescape(triggers).IndexOf(trigger) < 0) return false; - ICompletionListItem item = null; if (completionList.SelectedIndex >= 0) { @@ -819,7 +812,6 @@ public bool ReplaceText(ScintillaControl sci, String tail, char trigger) String replace = item.Value; if (replace != null) { - sci.SetSel(startPos, sci.CurrentPos); if (word != null && tail.Length > 0) { if (replace.StartsWith(word, StringComparison.OrdinalIgnoreCase) && replace.IndexOf(tail) >= word.Length) @@ -827,9 +819,11 @@ public bool ReplaceText(ScintillaControl sci, String tail, char trigger) replace = replace.Substring(0, replace.IndexOf(tail)); } } - sci.ReplaceSel(replace); - if (OnInsert != null) OnInsert(sci, startPos, replace, trigger, item); - if (tail.Length > 0) sci.ReplaceSel(tail); + ((ScintillaControl)target.Owner).BeginUndoAction(); + ((ScintillaControl)target.Owner).SetSel(startPos, ((ScintillaControl)target.Owner).CurrentPos); + ((ScintillaControl)target.Owner).ReplaceSel(replace); + if (OnInsert != null) OnInsert(target.Owner, startPos, replace, trigger, item); + if (tail.Length > 0) ((ScintillaControl)target.Owner).ReplaceSel(tail); } return true; } @@ -837,7 +831,7 @@ public bool ReplaceText(ScintillaControl sci, String tail, char trigger) } finally { - sci.EndUndoAction(); + ((ScintillaControl)target.Owner).EndUndoAction(); } } @@ -856,10 +850,11 @@ public IntPtr GetHandle() /// /// /// - public void OnChar(ScintillaControl sci, int value) + public void OnChar(int value) { char c = (char)value; - string characterClass = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage).characterclass.Characters; + // TODO: Inject these values + string characterClass = ScintillaControl.Configuration.GetLanguage(PluginBase.MainForm.CurrentDocument.SciControl.ConfigurationLanguage).characterclass.Characters; if (characterClass.IndexOf(c) >= 0) { word += c; @@ -871,7 +866,7 @@ public void OnChar(ScintillaControl sci, int value) { Hide('\0'); // handle this char - UITools.Manager.SendChar(sci, value); + UITools.Manager.SendChar((ScintillaControl)target.Owner, value); } else { @@ -887,27 +882,27 @@ public void OnChar(ScintillaControl sci, int value) } else if (word.Length > 0 || c == '.' || c == '(' || c == '[' || c == '<' || c == ',' || c == ';') { - ReplaceText(sci, c.ToString(), c); + ReplaceText(c.ToString(), c); } // handle this char - UITools.Manager.SendChar(sci, value); + UITools.Manager.SendChar((ScintillaControl)target.Owner, value); } } /// /// /// - public bool HandleKeys(ScintillaControl sci, Keys key) + public bool HandleKeys(Keys key) { int index; switch (key) { case Keys.Back: - if (!UITools.CallTip.CallTipActive) sci.DeleteBack(); + if (!UITools.CallTip.CallTipActive) ((ScintillaControl)target.Owner).DeleteBack(); if (word.Length > MinWordLength) { word = word.Substring(0, word.Length - 1); - currentPos = sci.CurrentPos; + currentPos = target.CurrentPos; lastIndex = 0; FindWordStartingWith(word); } @@ -915,7 +910,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) return true; case Keys.Enter: - if (noAutoInsert || !ReplaceText(sci, '\n')) + if (noAutoInsert || !ReplaceText('\n')) { Hide(); return false; @@ -923,7 +918,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) return true; case Keys.Tab: - if (!ReplaceText(sci, '\t')) + if (!ReplaceText('\t')) { Hide(); return false; @@ -940,8 +935,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) if (!listHost.Visible) { Hide(); - if (key == Keys.Up) sci.LineUp(); - else sci.CharLeft(); + //sci.LineUp(); return false; } // go up the list @@ -966,8 +960,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) if (!listHost.Visible) { Hide(); - if (key == Keys.Down) sci.LineDown(); - else sci.CharRight(); + //sci.LineDown(); return false; } // go down the list @@ -992,7 +985,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) if (!listHost.Visible) { Hide(); - sci.PageUp(); + //sci.PageUp(); return false; } // go up the list @@ -1011,7 +1004,7 @@ public bool HandleKeys(ScintillaControl sci, Keys key) if (!listHost.Visible) { Hide(); - sci.PageDown(); + //sci.PageDown(); return false; } // go down the list @@ -1028,12 +1021,12 @@ public bool HandleKeys(ScintillaControl sci, Keys key) break; case Keys.Left: - sci.CharLeft(); + //sci.CharLeft(); Hide(); break; case Keys.Right: - sci.CharRight(); + //sci.CharRight(); Hide(); break; diff --git a/PluginCore/PluginCore/Controls/ICompletionListTarget.cs b/PluginCore/PluginCore/Controls/ICompletionListTarget.cs new file mode 100644 index 0000000000..9829d1492f --- /dev/null +++ b/PluginCore/PluginCore/Controls/ICompletionListTarget.cs @@ -0,0 +1,28 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace PluginCore.Controls +{ + public interface ICompletionListTarget + { + + event EventHandler LostFocus; + event ScrollEventHandler Scroll; + event KeyEventHandler KeyDown; + event MouseEventHandler MouseDown; + + Control Owner { get; } + string Text { get; } + string SelectedText { get; set; } + int SelectionEnd { get; set; } + int SelectionStart { get; set; } + int CurrentPos { get; } + bool IsEditable { get; } + + Point GetPositionFromCharIndex(int pos); + int GetLineHeight(); + void SetSelection(int start, int end); + + } +} From 9b76b42ea117e69480196573c16269efbd1f856a Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Wed, 18 Feb 2015 12:41:33 +0100 Subject: [PATCH 06/36] Some more work Fixed MethodCallTip display if it's already visible. Some more decoupling from Scintilla. Changes to the Immediate Panel to use CompletionListControl and serve as an example, as well, and help define the needs we may have. Changed behaviour of navigation through immediate panel, and allow to better navigate through the previous entered commands with the keyboard. --- .../FlashDebugger/Controls/ImmediateUI.cs | 198 ++++++++++++++++-- .../PluginCore/Controls/CompletionList.cs | 3 +- .../Controls/CompletionListControl.cs | 22 +- .../PluginCore/Controls/MethodCallTip.cs | 3 +- 4 files changed, 198 insertions(+), 28 deletions(-) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index cc5d84887c..c3bae202f0 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; -using System.Data; using System.Text; using System.Windows.Forms; using flash.tools.debugger; using flash.tools.debugger.expression; +using PluginCore.Controls; namespace FlashDebugger.Controls { @@ -15,33 +14,49 @@ public partial class ImmediateUI : DockPanelControl private List history; private int historyPos; + private CompletionListControl completionList; + public ImmediateUI() { this.InitializeComponent(); this.contextMenuStrip.Renderer = new DockPanelStripRenderer(false); + var completionTarget = new TextBoxTarget(textBox); + this.completionList = new CompletionListControl(completionTarget); + completionTarget.CompletionList = completionList; this.history = new List(); } private void textBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Back && this.textBox.GetFirstCharIndexOfCurrentLine() == this.textBox.SelectionStart) e.SuppressKeyPress = true; - if (e.KeyCode == Keys.Up && this.historyPos > 0) + if (e.KeyCode == Keys.Up) { - this.historyPos--; - this.textBox.Select(this.textBox.Text.Length, 0); - this.textBox.Text = this.textBox.Text.Substring(0, this.textBox.GetFirstCharIndexOfCurrentLine()) + this.history[this.historyPos]; - this.textBox.Select(this.textBox.Text.Length, 0); - this.textBox.ScrollToCaret(); + if (textBox.GetLineFromCharIndex(textBox.SelectionStart) != textBox.Lines.Length - 1 || e.Modifiers > 0) + return; + if (this.historyPos > 0) + { + this.historyPos--; + this.textBox.Select(this.textBox.Text.Length, 0); + this.textBox.Text = this.textBox.Text.Substring(0, this.textBox.GetFirstCharIndexOfCurrentLine()) + this.history[this.historyPos]; + this.textBox.Select(this.textBox.Text.Length, 0); + this.textBox.ScrollToCaret(); + } + e.SuppressKeyPress = true; } - if (e.KeyCode == Keys.Down && this.historyPos + 1 < this.history.Count) + if (e.KeyCode == Keys.Down) { - this.historyPos++; - this.textBox.Select(this.textBox.Text.Length, 0); - this.textBox.Text = this.textBox.Text.Substring(0, this.textBox.GetFirstCharIndexOfCurrentLine()) + this.history[this.historyPos]; - this.textBox.Select(this.textBox.Text.Length, 0); - this.textBox.ScrollToCaret(); + if (textBox.GetLineFromCharIndex(textBox.SelectionStart) != textBox.Lines.Length - 1 || e.Modifiers > 0) + return; + if (this.historyPos + 1 < this.history.Count) + { + this.historyPos++; + this.textBox.Select(this.textBox.Text.Length, 0); + this.textBox.Text = this.textBox.Text.Substring(0, this.textBox.GetFirstCharIndexOfCurrentLine()) + this.history[this.historyPos]; + this.textBox.Select(this.textBox.Text.Length, 0); + this.textBox.ScrollToCaret(); + } + e.SuppressKeyPress = true; } - if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) e.SuppressKeyPress = true; if (e.KeyCode == Keys.Enter) { e.SuppressKeyPress = true; @@ -100,6 +115,45 @@ private void textBox_KeyDown(object sender, KeyEventArgs e) } } + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before + if ((keyData & Keys.KeyCode) == Keys.Space && (keyData & Keys.Modifiers & Keys.Control) > 0) + { + var debugger = PluginMain.debugManager.FlashInterface; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended) return true; + var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); + string file = PluginMain.debugManager.GetLocalPath(location.getFile()); + if (file == null) return true; + var info = PluginCore.Helpers.FileHelper.GetEncodingFileInfo(file); + if (info.CodePage == -1) return true; + using (var sci = new ScintillaNet.ScintillaControl()) + { + sci.Text = info.Contents; + sci.CodePage = info.CodePage; + sci.Encoding = Encoding.GetEncoding(info.CodePage); + sci.ConfigurationLanguage = PluginCore.PluginBase.CurrentProject.Language; + + sci.CurrentPos = sci.PositionFromLine(location.getLine()); + + ASCompletion.Completion.ASExpr expr = + ASCompletion.Completion.ASComplete.GetExpressionType(sci, sci.CurrentPos).Context; + var list = new List(); + if (expr.Value != null) + { + ASCompletion.Model.MemberList locals = ASCompletion.Completion.ASComplete.ParseLocalVars(expr); + foreach (ASCompletion.Model.MemberModel local in locals) + list.Add(new ASCompletion.Completion.MemberItem(local)); + } + + completionList.Show(list, false); + } + + return true; + } + return base.ProcessCmdKey(ref msg, keyData); + } + private string processSwfs() { StringBuilder ret = new StringBuilder(); @@ -155,5 +209,119 @@ private void pasteToolStripMenuItem_Click(object sender, EventArgs e) this.textBox.Paste(); } + private class TextBoxTarget : ICompletionListTarget + { + + #region ICompletionListTarget Members + + public event EventHandler LostFocus; + + public event ScrollEventHandler Scroll; + + public event KeyEventHandler KeyDown; + + public event MouseEventHandler MouseDown; + + private TextBox _owner; + public Control Owner + { + get { return _owner; } + } + + public string Text + { + get { return _owner.Text; } + } + + public string SelectedText + { + get + { + return _owner.SelectedText; + } + set + { + _owner.SelectedText = value; + } + } + + public int SelectionEnd + { + get + { + return _owner.SelectionStart + _owner.SelectionLength; + } + set + { + _owner.SelectionLength = value - _owner.SelectionStart; + } + } + + public int SelectionStart + { + get + { + return _owner.SelectionStart; + } + set + { + _owner.SelectionStart = value; + } + } + + public int CurrentPos + { + get { return _owner.SelectionStart; } + } + + public bool IsEditable + { + get { return !_owner.ReadOnly; } + } + + private CompletionListControl _completionList; + public CompletionListControl CompletionList + { + get { return _completionList; } + set + { + _completionList = value; + } + } + + public TextBoxTarget(TextBox owner) + { + _owner = owner; + _owner.KeyDown += Owner_KeyDown; + } + + public Point GetPositionFromCharIndex(int pos) + { + return _owner.GetPositionFromCharIndex(pos); + } + + public int GetLineHeight() + { + using (Graphics g = _owner.CreateGraphics()) + { + SizeF textSize = g.MeasureString("S", _owner.Font); + return (int)Math.Ceiling(textSize.Height); + } + } + + public void SetSelection(int start, int end) + { + throw new NotImplementedException(); + } + + #endregion + + private void Owner_KeyDown(object sender, KeyEventArgs e) + { + e.SuppressKeyPress = _completionList.HandleKeys(e.KeyData); + } + } + + } } diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 6568fad0f7..74a0802bb3 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -209,7 +209,8 @@ static public IntPtr GetHandle() static public void OnChar(ScintillaControl sci, int value) { - completionList.OnChar(value); + if (!completionList.OnChar(value)) + UITools.Manager.SendChar(sci, value); } static public bool HandleKeys(ScintillaControl sci, Keys key) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index c7c5b5957c..afe4aca107 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -820,7 +820,7 @@ public bool ReplaceText(string tail, char trigger) } } ((ScintillaControl)target.Owner).BeginUndoAction(); - ((ScintillaControl)target.Owner).SetSel(startPos, ((ScintillaControl)target.Owner).CurrentPos); + ((ScintillaControl)target.Owner).SetSel(startPos, target.CurrentPos); ((ScintillaControl)target.Owner).ReplaceSel(replace); if (OnInsert != null) OnInsert(target.Owner, startPos, replace, trigger, item); if (tail.Length > 0) ((ScintillaControl)target.Owner).ReplaceSel(tail); @@ -850,7 +850,7 @@ public IntPtr GetHandle() /// /// /// - public void OnChar(int value) + public bool OnChar(int value) { char c = (char)value; // TODO: Inject these values @@ -860,13 +860,13 @@ public void OnChar(int value) word += c; currentPos++; FindWordStartingWith(word); - return; + return true; } else if (noAutoInsert) { Hide('\0'); // handle this char - UITools.Manager.SendChar((ScintillaControl)target.Owner, value); + return false; } else { @@ -885,7 +885,7 @@ public void OnChar(int value) ReplaceText(c.ToString(), c); } // handle this char - UITools.Manager.SendChar((ScintillaControl)target.Owner, value); + return false; } } @@ -935,7 +935,7 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - //sci.LineUp(); + ((ScintillaControl)target.Owner).LineUp(); return false; } // go up the list @@ -960,7 +960,7 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - //sci.LineDown(); + ((ScintillaControl)target.Owner).LineDown(); return false; } // go down the list @@ -985,7 +985,7 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - //sci.PageUp(); + ((ScintillaControl)target.Owner).PageUp(); return false; } // go up the list @@ -1004,7 +1004,7 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - //sci.PageDown(); + ((ScintillaControl)target.Owner).PageDown(); return false; } // go down the list @@ -1021,12 +1021,12 @@ public bool HandleKeys(Keys key) break; case Keys.Left: - //sci.CharLeft(); + ((ScintillaControl)target.Owner).CharLeft(); Hide(); break; case Keys.Right: - //sci.CharRight(); + ((ScintillaControl)target.Owner).CharRight(); Hide(); break; diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index 658f1aa908..b910e5acfe 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -105,7 +105,8 @@ public void PositionControl(ScintillaControl sci) { host.Left = ((Form)PluginBase.MainForm).ClientRectangle.Right - host.Width; } - host.Show(owner); + if (!host.Visible) + host.Show(owner); } public void CallTipSetHlt(int start, int end) From f49dd4db2cad4d362ed693ec4c29aa6b346aa422 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 10:14:54 +0100 Subject: [PATCH 07/36] Scintilla creation modification More similar to modern ScintillaNet. It allows to catch more messages easily, and therefore have more control over Scintilla. Optimized the IgnoredKeys collection. Some native messages still need to be checked. --- FlashDevelop/MainForm.cs | 2 +- PluginCore/ScintillaNet/ScintillaControl.cs | 78 ++++++++++----------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/FlashDevelop/MainForm.cs b/FlashDevelop/MainForm.cs index a3b959e7b7..103bf01dc1 100644 --- a/FlashDevelop/MainForm.cs +++ b/FlashDevelop/MainForm.cs @@ -1515,7 +1515,7 @@ public Boolean PreFilterMessage(ref Message m) Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam); return true; } - else if (doc != null && doc.IsEditable && (hWnd == doc.SplitSci1.HandleSci || hWnd == doc.SplitSci2.HandleSci)) + else if (doc != null && doc.IsEditable && (hWnd == doc.SplitSci1.Handle || hWnd == doc.SplitSci2.Handle)) { Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam); return true; diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index aba80c3171..02b73c6d39 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -21,8 +21,7 @@ public class ScintillaControl : Control { private bool saveBOM; private Encoding encoding; - private int directPointer; - private IntPtr hwndScintilla; + private IntPtr directPointer; private bool hasHighlights = false; private bool ignoreAllKeys = false; private bool isBraceMatching = true; @@ -33,7 +32,7 @@ public class ScintillaControl : Control private static Dictionary shortcutOverrides = new Dictionary(); private Enums.IndentView indentView = Enums.IndentView.Real; private Enums.SmartIndent smartIndent = Enums.SmartIndent.CPP; - private Hashtable ignoredKeys = new Hashtable(); + private HashSet ignoredKeys = new HashSet(); private string configLanguage = String.Empty; private string fileName = String.Empty; private int lastSelectionLength = 0; @@ -51,19 +50,25 @@ public ScintillaControl(string fullpath) { try { + // We don't want .NET to use GetWindowText because we manage ('cache') our own text + SetStyle(ControlStyles.CacheText, true); + + // Necessary control styles (see TextBoxBase) + SetStyle(ControlStyles.StandardClick + | ControlStyles.StandardDoubleClick + | ControlStyles.UseTextForAccessibility + | ControlStyles.UserPaint, + false); + if (Win32.ShouldUseWin32()) { IntPtr lib = LoadLibrary(fullpath); - hwndScintilla = CreateWindowEx(0, "Scintilla", "", WS_CHILD_VISIBLE_TABSTOP, 0, 0, this.Width, this.Height, this.Handle, 0, new IntPtr(0), null); - directPointer = (int)SlowPerform(2185, 0, 0); - directPointer = DirectPointer; } UpdateUI += new UpdateUIHandler(OnUpdateUI); UpdateUI += new UpdateUIHandler(OnBraceMatch); UpdateUI += new UpdateUIHandler(OnCancelHighlight); DoubleClick += new DoubleClickHandler(OnBlockSelect); CharAdded += new CharAddedHandler(OnSmartIndent); - Resize += new EventHandler(OnResize); } catch (Exception ex) { @@ -77,9 +82,16 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - public void OnResize(object sender, EventArgs e) + protected override CreateParams CreateParams { - if (Win32.ShouldUseWin32()) SetWindowPos(this.hwndScintilla, 0, this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width, this.ClientRectangle.Height, 0); + get + { + // Per Scintilla documentation, the Window Class name... + CreateParams cp = base.CreateParams; + cp.ClassName = "Scintilla"; + + return cp; + } } #endregion @@ -132,14 +144,6 @@ public void OnResize(object sender, EventArgs e) #region Scintilla Properties - /// - /// Gets the sci handle - /// - public IntPtr HandleSci - { - get { return hwndScintilla; } - } - /// /// Current used configuration /// @@ -1549,11 +1553,13 @@ public int DirectFunction /// Retrieve a pointer value to use as the first argument when calling /// the function returned by GetDirectFunction. /// - public int DirectPointer + public IntPtr DirectPointer { - get + get { - return (int)SPerform(2185, 0, 0); + if (directPointer == IntPtr.Zero) + directPointer = SendMessage(Handle, 2185, 0, 0); + return directPointer; } } @@ -2227,7 +2233,7 @@ public bool ScrollWidthTracking /// public virtual void AddIgnoredKeys(Keys keys) { - ignoredKeys.Add((int)keys, (int)keys); + ignoredKeys.Add((int)keys); } /// @@ -2251,15 +2257,7 @@ public virtual void ClearIgnoredKeys() /// public virtual bool ContainsIgnoredKeys(Keys keys) { - return ignoredKeys.ContainsKey((int)keys); - } - - /// - /// Sets the focud to the control - /// - public new bool Focus() - { - return SetFocus(hwndScintilla) != IntPtr.Zero; + return ignoredKeys.Contains((int)keys); } /// @@ -4942,6 +4940,8 @@ public int ContractedFoldNext(int lineStart) #region Scintilla Constants private const int WM_NOTIFY = 0x004e; + private const int WM_USER = 0x0400; + private const int WM_REFLECT = WM_USER + 0x1C00; private const int WM_SYSCHAR = 0x106; private const int WM_COMMAND = 0x0111; private const int WM_KEYDOWN = 0x0100; @@ -5041,7 +5041,7 @@ public ShortcutOverride(Keys keys, Action action) public static extern int GetDeviceCaps(IntPtr hdc, Int32 capindex); [DllImport("user32.dll")] - public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); + public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); [DllImport("user32.dll")] public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); @@ -5056,15 +5056,11 @@ public ShortcutOverride(Keys keys, Action action) public static extern void DragAcceptFiles(IntPtr hwnd, int accept); [DllImport("scilexer.dll", EntryPoint = "Scintilla_DirectFunction")] - public static extern int Perform(int directPointer, UInt32 message, UInt32 wParam, UInt32 lParam); + public static extern int Perform(IntPtr directPointer, UInt32 message, UInt32 wParam, UInt32 lParam); - public UInt32 SlowPerform(UInt32 message, UInt32 wParam, UInt32 lParam) - { - return (UInt32)SendMessage((int)hwndScintilla, message, (int)wParam, (int)lParam); - } public UInt32 SPerform(UInt32 message, UInt32 wParam, UInt32 lParam) { - if (Win32.ShouldUseWin32()) return (UInt32)Perform(directPointer, message, wParam, lParam); + if (Win32.ShouldUseWin32()) return (UInt32)Perform(DirectPointer, message, wParam, lParam); else return (UInt32)Encoding.ASCII.CodePage; } @@ -5075,7 +5071,7 @@ public override bool PreProcessMessage(ref Message m) case WM_KEYDOWN: { Int32 keys = (Int32)Control.ModifierKeys + (Int32)m.WParam; - if (!IsFocus || ignoreAllKeys || ignoredKeys.ContainsKey(keys)) + if (!IsFocus || ignoreAllKeys || ignoredKeys.Contains(keys)) { if (this.ExecuteShortcut(keys) || base.PreProcessMessage(ref m)) return true; } @@ -5104,7 +5100,7 @@ public override bool PreProcessMessage(ref Message m) protected override void WndProc(ref System.Windows.Forms.Message m) { - if (m.Msg == WM_COMMAND) + /*if (m.Msg == WM_COMMAND) { Int32 message = (m.WParam.ToInt32() >> 16) & 0xffff; if (message == (int)Enums.Command.SetFocus || message == (int)Enums.Command.KillFocus) @@ -5112,10 +5108,10 @@ protected override void WndProc(ref System.Windows.Forms.Message m) if (FocusChanged != null) FocusChanged(this); } } - else if (m.Msg == WM_NOTIFY) + else */if (m.Msg == WM_NOTIFY + WM_REFLECT) { SCNotification scn = (SCNotification)Marshal.PtrToStructure(m.LParam, typeof(SCNotification)); - if (scn.nmhdr.hwndFrom == hwndScintilla && !this.DisableAllSciEvents) + if (!this.DisableAllSciEvents) { switch (scn.nmhdr.code) { From 9c9242913410471a1ea2b2a44c93591fe6a1fef2 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 10:17:46 +0100 Subject: [PATCH 08/36] Removed Completion.Delete shortcut I don't think it makes sense to customize this key, and in fact, it wasn't even being used. NOTE: Completion.ShowHelp isn't being used at all. It was a recent addition that wasn't working 100% right, and then it was replaced, it either should be fixed or removed. --- External/Plugins/ASCompletion/PluginMain.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/External/Plugins/ASCompletion/PluginMain.cs b/External/Plugins/ASCompletion/PluginMain.cs index ae0226d4f7..7e7adf3e2f 100644 --- a/External/Plugins/ASCompletion/PluginMain.cs +++ b/External/Plugins/ASCompletion/PluginMain.cs @@ -735,7 +735,6 @@ private void AddEventHandlers() PluginBase.MainForm.IgnoredKeys.Add(Keys.Control | Keys.Enter); PluginBase.MainForm.IgnoredKeys.Add(Keys.Space | Keys.Control | Keys.Alt); // complete project types PluginBase.MainForm.RegisterShortcutItem("Completion.ShowHelp", Keys.F1); - PluginBase.MainForm.RegisterShortcutItem("Completion.Delete", Keys.Back); // application events EventManager.AddEventHandler(this, eventMask); From d66396a1730bb0203f9ddc1ca2003d54c242690d Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 10:53:34 +0100 Subject: [PATCH 09/36] Some more CompletionList decoupling Completion list is only shown when launched from the control, and instead to push keys and chars to scintilla, the keys are consumed and suppressed in a more standard way. WIP. Some decissions still need to be taken, --- .../PluginCore/Controls/CompletionList.cs | 2 + .../Controls/CompletionListControl.cs | 44 +++++++++----- PluginCore/PluginCore/Controls/UITools.cs | 59 +++++++++++-------- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 74a0802bb3..cbf5146e1e 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -1,3 +1,5 @@ +// NOTE: We may well dump this static class, or mark it as deprecated, and create UITools.CompletionList, it would make the code look bit more organized and in line with some other controls + using System; using System.Drawing; using System.Collections.Generic; diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index afe4aca107..34a3448a61 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -19,6 +19,8 @@ public class CompletionListControl { public event CompletionListInsertedTextHandler OnInsert; public event CompletionListInsertedTextHandler OnCancel; + public event EventHandler OnShowing; + public event EventHandler OnHidden; /// /// Properties of the class @@ -67,6 +69,9 @@ public class CompletionListControl /// public CompletionListControl(ICompletionListTarget target) { + if (target == null) + throw new ArgumentNullException("target"); + this.target = target; listHost = new InactiveForm(); @@ -111,7 +116,7 @@ public bool Active } /// - /// + /// Gets if the mouse is currently inside the completion list control /// public bool HasMouseIn { @@ -135,6 +140,14 @@ public string SelectedLabel } } + /// + /// Gets the target of the current completion list control + /// + public ICompletionListTarget Target + { + get { return target; } + } + #endregion #region CompletionList Methods @@ -217,7 +230,8 @@ public void Show(List itemList, bool autoHide) tempoTip.Enabled = false; showTime = DateTime.Now.Ticks; disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; - UITools.Manager.LockControl(((ScintillaControl)target.Owner)); + //TODO: Check & Remove + //UITools.Manager.LockControl(((ScintillaControl)target.Owner)); faded = false; } @@ -291,6 +305,7 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) if (!host.Visible) { Redraw(); + if (OnShowing != null) OnShowing(this, EventArgs.Empty); host.Show(target.Owner); if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(((ScintillaControl)target.Owner)); } @@ -318,7 +333,9 @@ public void Hide() currentItem = null; allItems = null; UITools.Tip.Hide(); - if (!UITools.CallTip.CallTipActive) UITools.Manager.UnlockControl(); + //TODO: Check & Remove + //if (!UITools.CallTip.CallTipActive) UITools.Manager.UnlockControl(); + if (OnHidden != null) OnHidden(this, EventArgs.Empty); } } @@ -898,16 +915,17 @@ public bool HandleKeys(Keys key) switch (key) { case Keys.Back: - if (!UITools.CallTip.CallTipActive) ((ScintillaControl)target.Owner).DeleteBack(); + //TODO: Check & Remove + //if (!UITools.CallTip.CallTipActive) ((ScintillaControl)target.Owner).DeleteBack(); if (word.Length > MinWordLength) { word = word.Substring(0, word.Length - 1); - currentPos = target.CurrentPos; + currentPos = target.CurrentPos - 1; lastIndex = 0; FindWordStartingWith(word); } else Hide((char)8); - return true; + return false; case Keys.Enter: if (noAutoInsert || !ReplaceText('\n')) @@ -935,7 +953,6 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - ((ScintillaControl)target.Owner).LineUp(); return false; } // go up the list @@ -960,7 +977,6 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - ((ScintillaControl)target.Owner).LineDown(); return false; } // go down the list @@ -985,7 +1001,6 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - ((ScintillaControl)target.Owner).PageUp(); return false; } // go up the list @@ -1004,7 +1019,6 @@ public bool HandleKeys(Keys key) if (!listHost.Visible) { Hide(); - ((ScintillaControl)target.Owner).PageDown(); return false; } // go down the list @@ -1021,17 +1035,19 @@ public bool HandleKeys(Keys key) break; case Keys.Left: - ((ScintillaControl)target.Owner).CharLeft(); Hide(); - break; + return false; case Keys.Right: - ((ScintillaControl)target.Owner).CharRight(); Hide(); + return false; + + case Keys.Escape: + Hide((char) 27); break; default: - Hide(); + //Hide(); return false; } return true; diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 14593c3566..568b899f57 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -165,6 +165,7 @@ public void ListenTo(ScintillaControl sci) sci.UpdateUI += new UpdateUIHandler(OnUIRefresh); sci.TextInserted += new TextInsertedHandler(OnTextInserted); sci.TextDeleted += new TextDeletedHandler(OnTextDeleted); + sci.KeyDown += OnKeyDown; } /// @@ -326,14 +327,14 @@ private void OnChar(ScintillaControl sci, int value) SendChar(sci, value); return; } - if (lockedSciControl != null && lockedSciControl.IsAlive) sci = (ScintillaControl)lockedSciControl.Target; - else - { - callTip.Hide(); - CompletionList.Hide(); - SendChar(sci, value); - return; - } + //if (lockedSciControl != null && lockedSciControl.IsAlive) sci = (ScintillaControl)lockedSciControl.Target; + //else + //{ + // callTip.Hide(); + // CompletionList.Hide(); + // SendChar(sci, value); + // return; + //} if (callTip.CallTipActive) callTip.OnChar(sci, value); if (CompletionList.Active) CompletionList.OnChar(sci, value); @@ -341,6 +342,29 @@ private void OnChar(ScintillaControl sci, int value) return; } + private void OnKeyDown(object sender, KeyEventArgs e) + { + if (e.KeyData == (Keys.Control | Keys.Space) || e.KeyData == (Keys.Shift | Keys.Control | Keys.Space)) + { + ignoreKeys = true; + KeyEvent ke = new KeyEvent(EventType.Keys, e.KeyData); + EventManager.DispatchEvent(this, ke); + ignoreKeys = false; + // if not handled - show snippets + if (!ke.Handled && PluginBase.MainForm.CurrentDocument.IsEditable + && !PluginBase.MainForm.CurrentDocument.SciControl.IsSelectionRectangle) + { + PluginBase.MainForm.CallCommand("InsertSnippet", "null"); + } + + e.SuppressKeyPress = true; + } + else if (CompletionList.Active) + { + e.SuppressKeyPress = CompletionList.HandleKeys((ScintillaControl) sender, e.KeyData); + } + } + public void SendChar(ScintillaControl sci, int value) { if (OnCharAdded != null) OnCharAdded(sci, value); @@ -354,24 +378,7 @@ private bool HandleKeys(Keys key) // list/tip shortcut dispatching if ((key == (Keys.Control | Keys.Space)) || (key == (Keys.Shift | Keys.Control | Keys.Space))) { - /*if (CompletionList.Active || callTip.CallTipActive) - { - UnlockControl(); - CompletionList.Hide(); - callTip.Hide(); - }*/ - // offer to handle the shortcut - ignoreKeys = true; - KeyEvent ke = new KeyEvent(EventType.Keys, key); - EventManager.DispatchEvent(this, ke); - ignoreKeys = false; - // if not handled - show snippets - if (!ke.Handled && PluginBase.MainForm.CurrentDocument.IsEditable - && !PluginBase.MainForm.CurrentDocument.SciControl.IsSelectionRectangle) - { - PluginBase.MainForm.CallCommand("InsertSnippet", "null"); - } - return true; + return false; } // toggle "long-description" for the hover tooltip From 38869874f656686abdd8b0fa8b8ecfe97b5da5b4 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 10:53:52 +0100 Subject: [PATCH 10/36] Better completion list positioning in Immediate Panel --- External/Plugins/FlashDebugger/Controls/ImmediateUI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index c3bae202f0..0187efb3d1 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -297,7 +297,7 @@ public TextBoxTarget(TextBox owner) public Point GetPositionFromCharIndex(int pos) { - return _owner.GetPositionFromCharIndex(pos); + return _owner.GetPositionFromCharIndex(pos == _owner.TextLength ? pos - 1 : pos); } public int GetLineHeight() From dd21e41478fb1bc41173c453742711611c80841c Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 12:41:04 +0100 Subject: [PATCH 11/36] Restore list visibility on Control key press Also, tweaked a bit mouse wheel support in Scintilla and completion list. --- FlashDevelop/MainForm.cs | 16 ++++--- .../Controls/CompletionListControl.cs | 46 ++++++++++++++++--- PluginCore/ScintillaNet/ScintillaControl.cs | 10 +--- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/FlashDevelop/MainForm.cs b/FlashDevelop/MainForm.cs index 103bf01dc1..d4844f4bc1 100644 --- a/FlashDevelop/MainForm.cs +++ b/FlashDevelop/MainForm.cs @@ -1512,13 +1512,15 @@ public Boolean PreFilterMessage(ref Message m) ITabbedDocument doc = Globals.CurrentDocument; if (Control.FromHandle(hWnd) != null) { - Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam); - return true; - } - else if (doc != null && doc.IsEditable && (hWnd == doc.SplitSci1.Handle || hWnd == doc.SplitSci2.Handle)) - { - Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam); - return true; + if (hWnd == doc.SplitSci1.Handle || hWnd == doc.SplitSci2.Handle) + { + if (doc != null && doc.IsEditable) + { + Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam); + return true; + } + } + else return Win32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam) != IntPtr.Zero; } } } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 34a3448a61..fdd96249df 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -15,7 +15,7 @@ namespace PluginCore.Controls { public delegate void CompletionListInsertedTextHandler(Control sender, int position, string text, char trigger, ICompletionListItem item); - public class CompletionListControl + public class CompletionListControl : IMessageFilter { public event CompletionListInsertedTextHandler OnInsert; public event CompletionListInsertedTextHandler OnCancel; @@ -230,8 +230,6 @@ public void Show(List itemList, bool autoHide) tempoTip.Enabled = false; showTime = DateTime.Now.Ticks; disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; - //TODO: Check & Remove - //UITools.Manager.LockControl(((ScintillaControl)target.Owner)); faded = false; } @@ -308,6 +306,7 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) if (OnShowing != null) OnShowing(this, EventArgs.Empty); host.Show(target.Owner); if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(((ScintillaControl)target.Owner)); + Application.AddMessageFilter(this); } } @@ -324,6 +323,7 @@ public void Hide() { if (completionList != null && isActive) { + Application.RemoveMessageFilter(this); tempo.Enabled = false; isActive = false; fullList = false; @@ -333,8 +333,6 @@ public void Hide() currentItem = null; allItems = null; UITools.Tip.Hide(); - //TODO: Check & Remove - //if (!UITools.CallTip.CallTipActive) UITools.Manager.UnlockControl(); if (OnHidden != null) OnHidden(this, EventArgs.Empty); } } @@ -915,8 +913,6 @@ public bool HandleKeys(Keys key) switch (key) { case Keys.Back: - //TODO: Check & Remove - //if (!UITools.CallTip.CallTipActive) ((ScintillaControl)target.Owner).DeleteBack(); if (word.Length > MinWordLength) { word = word.Substring(0, word.Length - 1); @@ -1082,6 +1078,42 @@ internal void FadeIn() #endregion + #region Global Hook + + public bool PreFilterMessage(ref Message m) + { + if (m.Msg == Win32.WM_MOUSEWHEEL) // capture all MouseWheel events + { + if (!UITools.CallTip.CallTipActive || !UITools.CallTip.Focused) + { + if (Win32.ShouldUseWin32()) + { + Win32.SendMessage(completionList.Handle, m.Msg, (Int32)m.WParam, (Int32)m.LParam); + return true; + } + else return false; + } + else return false; + } + else if (m.Msg == Win32.WM_KEYDOWN) + { + if ((int)m.WParam == 17) // Ctrl + { + if (CompletionList.Active) CompletionList.FadeOut(); + } + } + else if (m.Msg == Win32.WM_KEYUP) + { + if ((int)m.WParam == 17 || (int)m.WParam == 18) // Ctrl / AltGr + { + if (CompletionList.Active) CompletionList.FadeIn(); + } + } + return false; + } + + #endregion + } struct ItemMatch diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 02b73c6d39..6addbe40c7 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -5100,15 +5100,7 @@ public override bool PreProcessMessage(ref Message m) protected override void WndProc(ref System.Windows.Forms.Message m) { - /*if (m.Msg == WM_COMMAND) - { - Int32 message = (m.WParam.ToInt32() >> 16) & 0xffff; - if (message == (int)Enums.Command.SetFocus || message == (int)Enums.Command.KillFocus) - { - if (FocusChanged != null) FocusChanged(this); - } - } - else */if (m.Msg == WM_NOTIFY + WM_REFLECT) + if (m.Msg == WM_NOTIFY + WM_REFLECT) { SCNotification scn = (SCNotification)Marshal.PtrToStructure(m.LParam, typeof(SCNotification)); if (!this.DisableAllSciEvents) From 30269a065ffdbd1646d320588772f0dbe0ffb561 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 20 Feb 2015 12:47:06 +0100 Subject: [PATCH 12/36] Completion list visibility was pointing to the global list --- PluginCore/PluginCore/Controls/CompletionListControl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index fdd96249df..10d2788902 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1099,14 +1099,14 @@ public bool PreFilterMessage(ref Message m) { if ((int)m.WParam == 17) // Ctrl { - if (CompletionList.Active) CompletionList.FadeOut(); + if (Active) FadeOut(); } } else if (m.Msg == Win32.WM_KEYUP) { if ((int)m.WParam == 17 || (int)m.WParam == 18) // Ctrl / AltGr { - if (CompletionList.Active) CompletionList.FadeIn(); + if (Active) FadeIn(); } } return false; From d2a6c392910545597db0d8495bfcd358f777fcc0 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 23 Feb 2015 23:18:20 +0100 Subject: [PATCH 13/36] Only display the completion list if the editor is focused --- External/Plugins/ASCompletion/Completion/ASComplete.cs | 6 +++--- External/Plugins/BasicCompletion/PluginMain.cs | 8 +++++--- External/Plugins/CssCompletion/PluginMain.cs | 7 ++++--- External/Plugins/XMLCompletion/XMLComplete.cs | 1 + 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/External/Plugins/ASCompletion/Completion/ASComplete.cs b/External/Plugins/ASCompletion/Completion/ASComplete.cs index 59812059de..0cb71043bd 100644 --- a/External/Plugins/ASCompletion/Completion/ASComplete.cs +++ b/External/Plugins/ASCompletion/Completion/ASComplete.cs @@ -242,7 +242,7 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) // dot complete if (keys == (Keys.Control | Keys.Space)) { - if (ASContext.HasContext && ASContext.Context.IsFileValid) + if (ASContext.HasContext && ASContext.Context.IsFileValid && Sci.ContainsFocus) { // try to get completion as if we had just typed the previous char if (OnChar(Sci, Sci.CharAt(Sci.PositionBefore(Sci.CurrentPos)), false)) @@ -262,7 +262,7 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) return false; } // show calltip - else if (keys == (Keys.Control | Keys.Shift | Keys.Space)) + else if (keys == (Keys.Control | Keys.Shift | Keys.Space) && Sci.ContainsFocus) { if (ASContext.HasContext && ASContext.Context.IsFileValid) { @@ -276,7 +276,7 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) // project types completion else if (keys == (Keys.Control | Keys.Alt | Keys.Space)) { - if (ASContext.HasContext && ASContext.Context.IsFileValid && !ASContext.Context.Settings.LazyClasspathExploration) + if (ASContext.HasContext && ASContext.Context.IsFileValid && !ASContext.Context.Settings.LazyClasspathExploration && Sci.ContainsFocus) { int position = Sci.CurrentPos-1; string tail = GetWordLeft(Sci, ref position); diff --git a/External/Plugins/BasicCompletion/PluginMain.cs b/External/Plugins/BasicCompletion/PluginMain.cs index 871b9fd5c3..1497a685ba 100644 --- a/External/Plugins/BasicCompletion/PluginMain.cs +++ b/External/Plugins/BasicCompletion/PluginMain.cs @@ -130,13 +130,15 @@ public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority prority) Keys keys = (e as KeyEvent).Value; if (this.isSupported && keys == (Keys.Control | Keys.Space)) { - String lang = document.SciControl.ConfigurationLanguage; + var sci = document.SciControl; + if (!sci.ContainsFocus) return; + String lang = sci.ConfigurationLanguage; List items = this.GetCompletionListItems(lang, document.FileName); if (items != null && items.Count > 0) { items.Sort(); - Int32 curPos = document.SciControl.CurrentPos - 1; - String curWord = document.SciControl.GetWordLeft(curPos, false); + Int32 curPos = sci.CurrentPos - 1; + String curWord = sci.GetWordLeft(curPos, false); if (curWord == null) curWord = String.Empty; CompletionList.Show(items, false, curWord); e.Handled = true; diff --git a/External/Plugins/CssCompletion/PluginMain.cs b/External/Plugins/CssCompletion/PluginMain.cs index 445e9f7fa1..3d2ca86e3c 100644 --- a/External/Plugins/CssCompletion/PluginMain.cs +++ b/External/Plugins/CssCompletion/PluginMain.cs @@ -126,11 +126,12 @@ public void HandleEvent(Object sender, NotifyEvent e, HandlingPriority prority) case EventType.Keys: { Keys keys = (e as KeyEvent).Value; - if (this.IsSupported(document) && keys == (Keys.Control | Keys.Space)) + if (this.IsSupported(document) && keys == (Keys.Control | Keys.Space) && completion != null) { - if (completion != null) + var sci = document.SciControl; + if (sci.ContainsFocus) { - completion.OnComplete(document.SciControl, document.SciControl.CurrentPos); + completion.OnComplete(sci, sci.CurrentPos); e.Handled = true; } } diff --git a/External/Plugins/XMLCompletion/XMLComplete.cs b/External/Plugins/XMLCompletion/XMLComplete.cs index 4fba4e3838..e64f8f78d6 100644 --- a/External/Plugins/XMLCompletion/XMLComplete.cs +++ b/External/Plugins/XMLCompletion/XMLComplete.cs @@ -575,6 +575,7 @@ public static Boolean OnShortCut(Keys keys) ITabbedDocument document = PluginBase.MainForm.CurrentDocument; if (!document.IsEditable) return false; ScintillaControl sci = document.SciControl; + if (!sci.ContainsFocus) return false; XMLContextTag ctag = GetXMLContextTag(sci, sci.CurrentPos); // Starting tag if (ctag.Tag == null && (sci.CurrentPos > 0)) From 28df07661070f8eff10fa70c1ae134c7d0e4c0f6 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Tue, 24 Feb 2015 00:08:11 +0100 Subject: [PATCH 14/36] Completion List control improvements Replaced completion list host from Form to ToolStripDropDown: people suggest this one over the other, although both methods are perfectly valid. More Scintilla decoupling (some code commented). Some event handling hookup. Make completion list unfocusable, it improves user experience, some flickering and gives a small performance boost in some cases. --- .../Controls/CompletionListControl.cs | 124 ++++++++++++++---- 1 file changed, 95 insertions(+), 29 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 10d2788902..78dc506b9a 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -21,14 +21,15 @@ public class CompletionListControl : IMessageFilter public event CompletionListInsertedTextHandler OnCancel; public event EventHandler OnShowing; public event EventHandler OnHidden; - + /// /// Properties of the class /// private System.Timers.Timer tempo; private System.Timers.Timer tempoTip; private System.Windows.Forms.ListBox completionList; - private System.Windows.Forms.Form listHost; + private System.Windows.Forms.ToolStripControlHost listContainer; + private System.Windows.Forms.ToolStripDropDown listHost; #region State Properties @@ -74,11 +75,12 @@ public CompletionListControl(ICompletionListTarget target) this.target = target; - listHost = new InactiveForm(); - listHost.StartPosition = FormStartPosition.Manual; - listHost.FormBorderStyle = FormBorderStyle.None; - listHost.ShowIcon = false; - listHost.ShowInTaskbar = false; + listHost = new ToolStripDropDown(); + listHost.Padding = Padding.Empty; + listHost.Margin = Padding.Empty; + listHost.AutoClose = false; + listHost.DropShadowEnabled = false; + listHost.AutoSize = false; listHost.Size = new Size(180, 100); tempo = new System.Timers.Timer(); @@ -91,16 +93,21 @@ public CompletionListControl(ICompletionListTarget target) tempoTip.AutoReset = false; tempoTip.Interval = 800; - completionList = new ListBox(); + completionList = new ListBoxEx(); completionList.Font = new System.Drawing.Font(PluginBase.Settings.DefaultFont, FontStyle.Regular); completionList.ItemHeight = completionList.Font.Height + 2; - completionList.Dock = DockStyle.Fill; completionList.DrawMode = DrawMode.OwnerDrawFixed; completionList.DrawItem += new DrawItemEventHandler(CLDrawListItem); completionList.Click += new EventHandler(CLClick); completionList.DoubleClick += new EventHandler(CLDoubleClick); - listHost.Controls.Add(completionList); + listContainer = new ToolStripControlHost(completionList); + listContainer.AutoToolTip = false; + listContainer.AutoSize = false; + listContainer.Margin = Padding.Empty; + listContainer.Padding = Padding.Empty; + + listHost.Items.Add(listContainer); } #endregion @@ -274,25 +281,29 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) { if (!target.IsEditable) return; ListBox cl = completionList; - Form host = listHost; + ToolStripDropDown host = listHost; if (cl.Items.Count == 0) return; // measure control + var listSize = new Size(); if (needResize && !string.IsNullOrEmpty(widestLabel)) { needResize = false; Graphics g = cl.CreateGraphics(); SizeF size = g.MeasureString(widestLabel, cl.Font); - host.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); + listSize.Width = (int)Math.Min(Math.Max(size.Width + 40, 100), 400) + ScaleHelper.Scale(10); } + else listSize.Width = cl.Width; int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; - if (newHeight != host.Height) host.Height = newHeight; + listSize.Height = newHeight != cl.Height ? newHeight : cl.Height; + cl.Size = listContainer.Size = host.Size = listSize; // place control Point coord = target.GetPositionFromCharIndex(startPos); - listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > target.Owner.Height); coord = target.Owner.PointToScreen(coord); host.Left = coord.X + target.Owner.Left; - var screen = Screen.FromHandle(PluginBase.MainForm.Handle); + var screen = Screen.FromHandle(target.Owner.Handle); + listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > target.Owner.Height && coord.Y - host.Height > screen.WorkingArea.Top) + || coord.Y + target.GetLineHeight() + host.Height > screen.WorkingArea.Bottom; if (listUp) host.Top = coord.Y - host.Height; else host.Top = coord.Y + target.GetLineHeight(); // Keep on screen area @@ -304,9 +315,9 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) { Redraw(); if (OnShowing != null) OnShowing(this, EventArgs.Empty); - host.Show(target.Owner); + host.Show(host.Bounds.Location); if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(((ScintillaControl)target.Owner)); - Application.AddMessageFilter(this); + AddHandlers(); } } @@ -323,12 +334,12 @@ public void Hide() { if (completionList != null && isActive) { - Application.RemoveMessageFilter(this); + RemoveHandlers(); tempo.Enabled = false; isActive = false; fullList = false; faded = false; - listHost.Hide(); + listHost.Close(); if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; allItems = null; @@ -445,11 +456,7 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) private void CLClick(Object sender, System.EventArgs e) { if (!target.IsEditable) - { Hide(); - return; - } - target.Owner.Focus(); } /// @@ -462,7 +469,6 @@ private void CLDoubleClick(Object sender, System.EventArgs e) Hide(); return; } - target.Owner.Focus(); ReplaceText('\0'); } @@ -834,11 +840,11 @@ public bool ReplaceText(string tail, char trigger) replace = replace.Substring(0, replace.IndexOf(tail)); } } - ((ScintillaControl)target.Owner).BeginUndoAction(); - ((ScintillaControl)target.Owner).SetSel(startPos, target.CurrentPos); - ((ScintillaControl)target.Owner).ReplaceSel(replace); + //((ScintillaControl)target.Owner).BeginUndoAction(); + target.SetSelection(startPos, target.CurrentPos); + target.SelectedText = replace; if (OnInsert != null) OnInsert(target.Owner, startPos, replace, trigger, item); - if (tail.Length > 0) ((ScintillaControl)target.Owner).ReplaceSel(tail); + if (tail.Length > 0) target.SelectedText = tail; } return true; } @@ -846,7 +852,7 @@ public bool ReplaceText(string tail, char trigger) } finally { - ((ScintillaControl)target.Owner).EndUndoAction(); + //((ScintillaControl)target.Owner).EndUndoAction(); } } @@ -862,6 +868,39 @@ public IntPtr GetHandle() return completionList.Handle; } + private void AddHandlers() + { + Application.AddMessageFilter(this); + target.LostFocus += Target_LostFocus; + target.MouseDown += Target_LostFocus; + target.KeyDown += Target_KeyDown; + target.Scroll += Target_Scroll; + } + + private void RemoveHandlers() + { + Application.RemoveMessageFilter(this); + target.LostFocus -= Target_LostFocus; + target.MouseDown -= Target_LostFocus; + target.KeyDown -= Target_KeyDown; + target.Scroll -= Target_Scroll; + } + + private void Target_LostFocus(object sender, EventArgs e) + { + if (!listHost.ContainsFocus) + Hide(); + } + + private void Target_KeyDown(object sender, KeyEventArgs e) + { + e.SuppressKeyPress = HandleKeys(e.KeyData); + } + + private void Target_Scroll(object sender, ScrollEventArgs e) { + + } + /// /// /// @@ -1114,6 +1153,33 @@ public bool PreFilterMessage(ref Message m) #endregion + #region Unfocusable List + + // If by any chance this is not compatible with CrossOver, or we want some alternative 100% crossplatform compatible, a custom fully managed control that cannot be focused could be developed + private class ListBoxEx : ListBox + { + protected override void DefWndProc(ref Message m) + { + const int WM_MOUSEACTIVATE = 0x21; + const int WM_LBUTTONDOWN = 0x201; + const int MA_NOACTIVATE = 0x0003; + + switch (m.Msg) + { + case WM_MOUSEACTIVATE: + m.Result = (IntPtr)MA_NOACTIVATE; + return; + case WM_LBUTTONDOWN: + SelectedIndex = IndexFromPoint((short)(m.LParam.ToInt32() & 0xFFFF), (short)((m.LParam.ToInt32() & 0xFFFF0000) >> 16)); + m.Result = IntPtr.Zero; + return; + } + base.DefWndProc(ref m); + } + } + + #endregion + } struct ItemMatch From 162e32f557665627e65d24bba86f4bdd07b78a8d Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Tue, 24 Feb 2015 00:12:33 +0100 Subject: [PATCH 15/36] Better Completion List handling in Immediate Panel and the default control --- .../Controls/ImmediateUI.Designer.cs | 10 +- .../FlashDebugger/Controls/ImmediateUI.cs | 105 +++++++++--------- .../PluginCore/Controls/CompletionList.cs | 8 +- PluginCore/PluginCore/Controls/UITools.cs | 40 +++---- 4 files changed, 76 insertions(+), 87 deletions(-) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs index 258b0e2348..3c9a2e6205 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs @@ -49,7 +49,7 @@ private void InitializeComponent() this.textBox.Size = new System.Drawing.Size(148, 150); this.textBox.TabIndex = 0; this.textBox.WordWrap = false; - this.textBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox_KeyDown); + this.textBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBox_KeyDown); this.textBox.BorderStyle = System.Windows.Forms.BorderStyle.None; // // contextMenuStrip1 @@ -68,21 +68,21 @@ private void InitializeComponent() this.cutToolStripMenuItem.Name = "cutToolStripMenuItem"; this.cutToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.cutToolStripMenuItem.Text = "Cut"; - this.cutToolStripMenuItem.Click += new System.EventHandler(this.cutToolStripMenuItem_Click); + this.cutToolStripMenuItem.Click += new System.EventHandler(this.CutToolStripMenuItem_Click); // // copyToolStripMenuItem // this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; this.copyToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.copyToolStripMenuItem.Text = "Copy"; - this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click); + this.copyToolStripMenuItem.Click += new System.EventHandler(this.CopyToolStripMenuItem_Click); // // pasteToolStripMenuItem // this.pasteToolStripMenuItem.Name = "pasteToolStripMenuItem"; this.pasteToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.pasteToolStripMenuItem.Text = "Paste"; - this.pasteToolStripMenuItem.Click += new System.EventHandler(this.pasteToolStripMenuItem_Click); + this.pasteToolStripMenuItem.Click += new System.EventHandler(this.PasteToolStripMenuItem_Click); // // toolStripSeparator1 // @@ -94,7 +94,7 @@ private void InitializeComponent() this.clearAllToolStripMenuItem.Name = "clearAllToolStripMenuItem"; this.clearAllToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.clearAllToolStripMenuItem.Text = "Clear All"; - this.clearAllToolStripMenuItem.Click += new System.EventHandler(this.clearAllToolStripMenuItem_Click); + this.clearAllToolStripMenuItem.Click += new System.EventHandler(this.ClearAllToolStripMenuItem_Click); // // ImmediateUI // diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index 0187efb3d1..c655552de7 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -22,12 +22,12 @@ public ImmediateUI() this.contextMenuStrip.Renderer = new DockPanelStripRenderer(false); var completionTarget = new TextBoxTarget(textBox); this.completionList = new CompletionListControl(completionTarget); - completionTarget.CompletionList = completionList; this.history = new List(); } - private void textBox_KeyDown(object sender, KeyEventArgs e) + private void TextBox_KeyDown(object sender, KeyEventArgs e) { + if (completionList.Active) return; if (e.KeyCode == Keys.Back && this.textBox.GetFirstCharIndexOfCurrentLine() == this.textBox.SelectionStart) e.SuppressKeyPress = true; if (e.KeyCode == Keys.Up) { @@ -61,14 +61,6 @@ private void textBox_KeyDown(object sender, KeyEventArgs e) { e.SuppressKeyPress = true; int curLine = this.textBox.GetLineFromCharIndex(this.textBox.SelectionStart); - //int curLine = 0; - //int tmp = 0; - //while (true) - //{ - // tmp += this.textBox.Lines[curLine].Length + 2; // newline chars - // if (tmp >= this.textBox.SelectionStart) break; - // curLine++; - //} string line = ""; if (curLine 0 && !this.textBox.Lines[this.textBox.Lines.Length - 1].Trim().Equals("")) this.textBox.AppendText(Environment.NewLine); @@ -78,15 +70,15 @@ private void textBox_KeyDown(object sender, KeyEventArgs e) this.historyPos = this.history.Count; if (line == "swfs") { - this.textBox.AppendText(processSwfs()); + this.textBox.AppendText(ProcessSwfs()); } else if (line.StartsWith("p ")) { - this.textBox.AppendText(processExpr(line.Substring(2))); + this.textBox.AppendText(ProcessExpr(line.Substring(2))); } else if (line.StartsWith("g ")) { - this.textBox.AppendText(processGlobal(line.Substring(2))); + this.textBox.AppendText(ProcessGlobal(line.Substring(2))); } else { @@ -109,7 +101,7 @@ private void textBox_KeyDown(object sender, KeyEventArgs e) { this.textBox.AppendText(!string.IsNullOrEmpty(ex.Message) ? ex.GetType().FullName + ": " + ex.Message : ex.ToString()); } - if (this.textBox.Lines.Length > 0 && !this.textBox.Lines[this.textBox.Lines.Length - 1].Trim().Equals("")) this.textBox.AppendText(Environment.NewLine); + if (this.textBox.Lines.Length > 0) this.textBox.AppendText(Environment.NewLine); this.textBox.Select(this.textBox.Text.Length, 0); this.textBox.ScrollToCaret(); } @@ -120,8 +112,14 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before if ((keyData & Keys.KeyCode) == Keys.Space && (keyData & Keys.Modifiers & Keys.Control) > 0) { + int curLine = this.textBox.GetLineFromCharIndex(this.textBox.SelectionStart); + string line = (curLine < this.textBox.Lines.Length) ? this.textBox.Lines[curLine] : ""; + + if (line == "" || !line.StartsWith("p ")) return true; + var debugger = PluginMain.debugManager.FlashInterface; - if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended) return true; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) + return true; var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); string file = PluginMain.debugManager.GetLocalPath(location.getFile()); if (file == null) return true; @@ -134,7 +132,10 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) sci.Encoding = Encoding.GetEncoding(info.CodePage); sci.ConfigurationLanguage = PluginCore.PluginBase.CurrentProject.Language; - sci.CurrentPos = sci.PositionFromLine(location.getLine()); + sci.CurrentPos = sci.PositionFromLine(location.getLine() - 1); + string expression = line.Substring(2); + sci.SetSel(sci.CurrentPos, sci.CurrentPos); + sci.ReplaceSel(expression); ASCompletion.Completion.ASExpr expr = ASCompletion.Completion.ASComplete.GetExpressionType(sci, sci.CurrentPos).Context; @@ -145,8 +146,7 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) foreach (ASCompletion.Model.MemberModel local in locals) list.Add(new ASCompletion.Completion.MemberItem(local)); } - - completionList.Show(list, false); + completionList.Show(list, true, line.Substring(line.LastIndexOfAny(new[]{' ', '.'}) + 1)); } return true; @@ -154,21 +154,21 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) return base.ProcessCmdKey(ref msg, keyData); } - private string processSwfs() + private string ProcessSwfs() { - StringBuilder ret = new StringBuilder(); + StringBuilder ret = new StringBuilder(); - foreach (SwfInfo info in PluginMain.debugManager.FlashInterface.Session.getSwfs()) - { - if (info == null) continue; - ret.Append(info.getPath()).Append("\tswfsize ").Append(info.getSwfSize()).Append("\tprocesscomplete ").Append(info.isProcessingComplete()) - .Append("\tunloaded ").Append(info.isUnloaded()).Append("\turl ").Append(info.getUrl()).Append("\tsourcecount ") - .Append(info.getSourceCount(PluginMain.debugManager.FlashInterface.Session)).AppendLine(); - } - return ret.ToString(); + foreach (SwfInfo info in PluginMain.debugManager.FlashInterface.Session.getSwfs()) + { + if (info == null) continue; + ret.Append(info.getPath()).Append("\tswfsize ").Append(info.getSwfSize()).Append("\tprocesscomplete ").Append(info.isProcessingComplete()) + .Append("\tunloaded ").Append(info.isUnloaded()).Append("\turl ").Append(info.getUrl()).Append("\tsourcecount ") + .Append(info.getSourceCount(PluginMain.debugManager.FlashInterface.Session)).AppendLine(); + } + return ret.ToString(); } - private string processExpr(string expr) + private string ProcessExpr(string expr) { IASTBuilder builder = new ASTBuilder(true); ValueExp exp = builder.parse(new java.io.StringReader(expr)); @@ -179,7 +179,7 @@ private string processExpr(string expr) return obj.toString(); } - private string processGlobal(string expr) + private string ProcessGlobal(string expr) { var val = PluginMain.debugManager.FlashInterface.Session.getGlobal(expr); //var val = PluginMain.debugManager.FlashInterface.Session.getValue(Convert.ToInt64(expr)); @@ -187,24 +187,24 @@ private string processGlobal(string expr) return ctx.FormatValue(val); } - private void clearAllToolStripMenuItem_Click(object sender, EventArgs e) + private void ClearAllToolStripMenuItem_Click(object sender, EventArgs e) { this.textBox.Clear(); this.history.Clear(); this.historyPos = 0; } - private void cutToolStripMenuItem_Click(object sender, EventArgs e) + private void CutToolStripMenuItem_Click(object sender, EventArgs e) { this.textBox.Cut(); } - private void copyToolStripMenuItem_Click(object sender, EventArgs e) + private void CopyToolStripMenuItem_Click(object sender, EventArgs e) { this.textBox.Copy(); } - private void pasteToolStripMenuItem_Click(object sender, EventArgs e) + private void PasteToolStripMenuItem_Click(object sender, EventArgs e) { this.textBox.Paste(); } @@ -214,13 +214,25 @@ private class TextBoxTarget : ICompletionListTarget #region ICompletionListTarget Members - public event EventHandler LostFocus; + public event EventHandler LostFocus + { + add { _owner.LostFocus += value; } + remove { _owner.LostFocus -= value; } + } public event ScrollEventHandler Scroll; - public event KeyEventHandler KeyDown; + public event KeyEventHandler KeyDown + { + add { _owner.KeyDown += value; } + remove { _owner.KeyDown -= value; } + } - public event MouseEventHandler MouseDown; + public event MouseEventHandler MouseDown + { + add { _owner.MouseDown += value; } + remove { _owner.MouseDown -= value; } + } private TextBox _owner; public Control Owner @@ -279,20 +291,9 @@ public bool IsEditable get { return !_owner.ReadOnly; } } - private CompletionListControl _completionList; - public CompletionListControl CompletionList - { - get { return _completionList; } - set - { - _completionList = value; - } - } - public TextBoxTarget(TextBox owner) { _owner = owner; - _owner.KeyDown += Owner_KeyDown; } public Point GetPositionFromCharIndex(int pos) @@ -311,15 +312,11 @@ public int GetLineHeight() public void SetSelection(int start, int end) { - throw new NotImplementedException(); + _owner.SelectionStart = start; + _owner.SelectionLength = end - start; } #endregion - - private void Owner_KeyDown(object sender, KeyEventArgs e) - { - e.SuppressKeyPress = _completionList.HandleKeys(e.KeyData); - } } diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index cbf5146e1e..d29cfc85dd 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -253,7 +253,11 @@ private class ScintillaTarget : ICompletionListTarget public event EventHandler LostFocus; public event ScrollEventHandler Scroll; - public event KeyEventHandler KeyDown; + public event KeyEventHandler KeyDown + { + add { Owner.KeyDown += value; } + remove { Owner.KeyDown -= value; } + } public event MouseEventHandler MouseDown; public Control Owner @@ -274,7 +278,7 @@ public string SelectedText } set { - throw new NotImplementedException(); + PluginBase.MainForm.CurrentDocument.SciControl.ReplaceSel(value); } } diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 568b899f57..2a618d2709 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -165,7 +165,6 @@ public void ListenTo(ScintillaControl sci) sci.UpdateUI += new UpdateUIHandler(OnUIRefresh); sci.TextInserted += new TextInsertedHandler(OnTextInserted); sci.TextDeleted += new TextDeletedHandler(OnTextDeleted); - sci.KeyDown += OnKeyDown; } /// @@ -246,7 +245,7 @@ public bool PreFilterMessage(ref Message m) { if (Win32.ShouldUseWin32()) { - Win32.SendMessage((IntPtr)CompletionList.GetHandle(), m.Msg, (Int32)m.WParam, (Int32)m.LParam); + Win32.SendMessage(CompletionList.GetHandle(), m.Msg, (Int32)m.WParam, (Int32)m.LParam); return true; } else return false; @@ -342,29 +341,6 @@ private void OnChar(ScintillaControl sci, int value) return; } - private void OnKeyDown(object sender, KeyEventArgs e) - { - if (e.KeyData == (Keys.Control | Keys.Space) || e.KeyData == (Keys.Shift | Keys.Control | Keys.Space)) - { - ignoreKeys = true; - KeyEvent ke = new KeyEvent(EventType.Keys, e.KeyData); - EventManager.DispatchEvent(this, ke); - ignoreKeys = false; - // if not handled - show snippets - if (!ke.Handled && PluginBase.MainForm.CurrentDocument.IsEditable - && !PluginBase.MainForm.CurrentDocument.SciControl.IsSelectionRectangle) - { - PluginBase.MainForm.CallCommand("InsertSnippet", "null"); - } - - e.SuppressKeyPress = true; - } - else if (CompletionList.Active) - { - e.SuppressKeyPress = CompletionList.HandleKeys((ScintillaControl) sender, e.KeyData); - } - } - public void SendChar(ScintillaControl sci, int value) { if (OnCharAdded != null) OnCharAdded(sci, value); @@ -378,7 +354,19 @@ private bool HandleKeys(Keys key) // list/tip shortcut dispatching if ((key == (Keys.Control | Keys.Space)) || (key == (Keys.Shift | Keys.Control | Keys.Space))) { - return false; + ignoreKeys = true; + KeyEvent ke = new KeyEvent(EventType.Keys, key); + EventManager.DispatchEvent(this, ke); + ignoreKeys = false; + // if not handled - show snippets + if (!ke.Handled && PluginBase.MainForm.CurrentDocument.IsEditable && PluginBase.MainForm.CurrentDocument.SciControl.ContainsFocus + && !PluginBase.MainForm.CurrentDocument.SciControl.IsSelectionRectangle) + { + PluginBase.MainForm.CallCommand("InsertSnippet", "null"); + ke.Handled = true; + } + + return ke.Handled; } // toggle "long-description" for the hover tooltip From 7b591cdfc65f266a773a40a0f8faad9a251f82ea Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Tue, 24 Feb 2015 16:42:11 +0100 Subject: [PATCH 16/36] Further work Renamed ICompletionListTarget to ICompletionListHost. Reimplemented Completion List host undo history on text insertion (missing on plain textboxes yet). Restored completion list fading on Ctrl key. Broken after changing the popup to ToolStripDropDown. Improved CallTip and Tip behaviour when selecting and copying the text. Catch KeyPress events to track inserted text when using other hosts than the default ScintillaHost. --- .../FlashDebugger/Controls/ImmediateUI.cs | 55 +++-- PluginCore/PluginCore.csproj | 2 +- .../PluginCore/Controls/CompletionList.cs | 77 +++---- .../Controls/CompletionListControl.cs | 202 +++++++++++------- ...onListTarget.cs => ICompletionListHost.cs} | 11 +- .../PluginCore/Controls/MethodCallTip.cs | 5 - PluginCore/PluginCore/Controls/RichToolTip.cs | 14 +- PluginCore/PluginCore/Controls/UITools.cs | 24 +-- 8 files changed, 217 insertions(+), 173 deletions(-) rename PluginCore/PluginCore/Controls/{ICompletionListTarget.cs => ICompletionListHost.cs} (74%) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index c655552de7..c61a2728ae 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -209,7 +209,7 @@ private void PasteToolStripMenuItem_Click(object sender, EventArgs e) this.textBox.Paste(); } - private class TextBoxTarget : ICompletionListTarget + private class TextBoxTarget : ICompletionListHost { #region ICompletionListTarget Members @@ -220,7 +220,7 @@ public event EventHandler LostFocus remove { _owner.LostFocus -= value; } } - public event ScrollEventHandler Scroll; + public event EventHandler PositionChanged; public event KeyEventHandler KeyDown { @@ -228,6 +228,12 @@ public event KeyEventHandler KeyDown remove { _owner.KeyDown -= value; } } + public event KeyPressEventHandler KeyPress + { + add { _owner.KeyPress += value; } + remove { _owner.KeyPress -= value; } + } + public event MouseEventHandler MouseDown { add { _owner.MouseDown += value; } @@ -240,45 +246,22 @@ public Control Owner get { return _owner; } } - public string Text - { - get { return _owner.Text; } - } - public string SelectedText { - get - { - return _owner.SelectedText; - } - set - { - _owner.SelectedText = value; - } + get { return _owner.SelectedText; } + set { _owner.SelectedText = value; } } public int SelectionEnd { - get - { - return _owner.SelectionStart + _owner.SelectionLength; - } - set - { - _owner.SelectionLength = value - _owner.SelectionStart; - } + get { return _owner.SelectionStart + _owner.SelectionLength; } + set { _owner.SelectionLength = value - _owner.SelectionStart; } } public int SelectionStart { - get - { - return _owner.SelectionStart; - } - set - { - _owner.SelectionStart = value; - } + get { return _owner.SelectionStart; } + set { _owner.SelectionStart = value; } } public int CurrentPos @@ -316,6 +299,16 @@ public void SetSelection(int start, int end) _owner.SelectionLength = end - start; } + public void BeginUndoAction() + { + // TODO + } + + public void EndUndoAction() + { + // TODO + } + #endregion } diff --git a/PluginCore/PluginCore.csproj b/PluginCore/PluginCore.csproj index aa15bc2965..e213f5cec9 100644 --- a/PluginCore/PluginCore.csproj +++ b/PluginCore/PluginCore.csproj @@ -312,7 +312,7 @@ Component - + Form diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index d29cfc85dd..addbe787e2 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -19,7 +19,7 @@ public static class CompletionList /// /// Properties of the class /// - private static CompletionListControl completionList; + internal static CompletionListControl completionList; #region State Properties @@ -48,7 +48,7 @@ public static Int32 MinWordLength /// public static void CreateControl(IMainForm mainForm) { - completionList = new CompletionListControl(new ScintillaTarget()); + completionList = new CompletionListControl(new ScintillaHost()); completionList.OnCancel += OnCancelHandler; completionList.OnInsert += OnInsertHandler; } @@ -211,7 +211,7 @@ static public IntPtr GetHandle() static public void OnChar(ScintillaControl sci, int value) { - if (!completionList.OnChar(value)) + if (!completionList.OnChar((char)value)) UITools.Manager.SendChar(sci, value); } @@ -248,62 +248,55 @@ internal static void FadeIn() #endregion - private class ScintillaTarget : ICompletionListTarget + // TODO: Get hold of current Scintilla control through UITools and don't call CurrentDocument.SciControl everytime + private class ScintillaHost : ICompletionListHost { - public event EventHandler LostFocus; - public event ScrollEventHandler Scroll; + public event EventHandler LostFocus + { + add { Owner.LostFocus += value; } + remove { Owner.LostFocus -= value; } + } + + public event EventHandler PositionChanged; +/* { + add { PluginBase.MainForm.CurrentDocument.SciControl. += value; } + remove { Owner.LostFocus -= value; } + }*/ public event KeyEventHandler KeyDown { add { Owner.KeyDown += value; } remove { Owner.KeyDown -= value; } } - public event MouseEventHandler MouseDown; - public Control Owner + public event KeyPressEventHandler KeyPress; // Unhandled for this one + public event MouseEventHandler MouseDown { - get { return PluginBase.MainForm.CurrentDocument.SciControl; } + add { Owner.MouseDown += value; } + remove { Owner.MouseDown -= value; } } - public string Text + public Control Owner { - get { throw new NotImplementedException(); } + get { return PluginBase.MainForm.CurrentDocument.SciControl; } } public string SelectedText { - get - { - return PluginBase.MainForm.CurrentDocument.SciControl.SelText; - } - set - { - PluginBase.MainForm.CurrentDocument.SciControl.ReplaceSel(value); - } + get { return PluginBase.MainForm.CurrentDocument.SciControl.SelText; } + set { PluginBase.MainForm.CurrentDocument.SciControl.ReplaceSel(value); } } public int SelectionEnd { - get - { - return PluginBase.MainForm.CurrentDocument.SciControl.SelectionEnd; - } - set - { - PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; - } + get { return PluginBase.MainForm.CurrentDocument.SciControl.SelectionEnd; } + set { PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; } } public int SelectionStart { - get - { - return PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart; - } - set - { - PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; - } + get { return PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart; } + set { PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; } } public int CurrentPos @@ -311,6 +304,11 @@ public int CurrentPos get { return PluginBase.MainForm.CurrentDocument.SciControl.CurrentPos; } } + public bool IsEditable + { + get { return PluginBase.MainForm.CurrentDocument.IsEditable && PluginBase.MainForm.CurrentDocument.SciControl != null; } + } + public int GetLineHeight() { var sci = PluginBase.MainForm.CurrentDocument.SciControl; @@ -329,9 +327,14 @@ public void SetSelection(int start, int end) sci.SetSel(start, end); } - public bool IsEditable + public void BeginUndoAction() { - get { return PluginBase.MainForm.CurrentDocument.IsEditable && PluginBase.MainForm.CurrentDocument.SciControl != null; } + PluginBase.MainForm.CurrentDocument.SciControl.BeginUndoAction(); + } + + public void EndUndoAction() + { + PluginBase.MainForm.CurrentDocument.SciControl.EndUndoAction(); } } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 78dc506b9a..bb27129214 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -8,8 +8,6 @@ using ScintillaNet; // TODO: Remove all direct references to ScintillaControl -// TODO: Extract ToolTip reference -// TODO: Extract CallTip reference namespace PluginCore.Controls { @@ -53,7 +51,9 @@ public class CompletionListControl : IMessageFilter private long showTime; private ICompletionListItem defaultItem; - private ICompletionListTarget target; + private ICompletionListHost host; + private RichToolTip tip; + private MethodCallTip callTip; // Used only by the main completion list so far, would it be better to control this case in another way? like the cl, we'd like to show this everywhere possible /// /// Set to 0 after calling .Show to keep the completion list active @@ -68,12 +68,12 @@ public class CompletionListControl : IMessageFilter /// /// Creates the control /// - public CompletionListControl(ICompletionListTarget target) + public CompletionListControl(ICompletionListHost target) { if (target == null) throw new ArgumentNullException("target"); - this.target = target; + this.host = target; listHost = new ToolStripDropDown(); listHost.Padding = Padding.Empty; @@ -150,9 +150,37 @@ public string SelectedLabel /// /// Gets the target of the current completion list control /// - public ICompletionListTarget Target + public ICompletionListHost Host { - get { return target; } + get { return host; } + } + + /// + /// Gets the help tip associated with the completion list + /// + public RichToolTip Tip + { + get + { + if (tip == null) + tip = new RichToolTip(host.Owner); + return tip; + } + internal set { tip = value; } + } + + /// + /// Gets the method call tip associated with the completion list + /// + public MethodCallTip CallTip + { + get + { + if (callTip == null) + callTip = new MethodCallTip(PluginBase.MainForm); + return callTip; + } + internal set { callTip = value; } } #endregion @@ -192,7 +220,7 @@ public void Show(List itemList, bool autoHide) { try { - if (!target.IsEditable) + if (!host.IsEditable) { if (isActive) Hide(); return; @@ -221,11 +249,11 @@ public void Show(List itemList, bool autoHide) fullList = (word.Length == 0) || !autoHide || !PluginBase.MainForm.Settings.AutoFilterList; lastIndex = 0; exactMatchInList = false; - if (target.SelectionStart == target.SelectionEnd) - startPos = target.CurrentPos - word.Length; + if (host.SelectionStart == host.SelectionEnd) + startPos = host.CurrentPos - word.Length; else - startPos = target.SelectionStart; - currentPos = target.SelectionEnd; // sci.CurrentPos; + startPos = host.SelectionStart; + currentPos = host.SelectionEnd; // sci.CurrentPos; defaultItem = null; // populate list needResize = true; @@ -279,9 +307,8 @@ public void DisableAutoInsertion() /// private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) { - if (!target.IsEditable) return; + if (!host.IsEditable) return; ListBox cl = completionList; - ToolStripDropDown host = listHost; if (cl.Items.Count == 0) return; // measure control @@ -296,27 +323,15 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) else listSize.Width = cl.Width; int newHeight = Math.Min(cl.Items.Count, 10) * cl.ItemHeight + 4; listSize.Height = newHeight != cl.Height ? newHeight : cl.Height; - cl.Size = listContainer.Size = host.Size = listSize; + cl.Size = listContainer.Size = listHost.Size = listSize; // place control - Point coord = target.GetPositionFromCharIndex(startPos); - coord = target.Owner.PointToScreen(coord); - host.Left = coord.X + target.Owner.Left; - var screen = Screen.FromHandle(target.Owner.Handle); - listUp = UITools.CallTip.CallTipActive || (coord.Y + host.Height > target.Owner.Height && coord.Y - host.Height > screen.WorkingArea.Top) - || coord.Y + target.GetLineHeight() + host.Height > screen.WorkingArea.Bottom; - if (listUp) host.Top = coord.Y - host.Height; - else host.Top = coord.Y + target.GetLineHeight(); - // Keep on screen area - if (host.Right > screen.WorkingArea.Right) - { - host.Left = screen.WorkingArea.Right - host.Width; - } - if (!host.Visible) + UpdatePosition(); + if (!listHost.Visible) { Redraw(); if (OnShowing != null) OnShowing(this, EventArgs.Empty); - host.Show(host.Bounds.Location); - if (UITools.CallTip.CallTipActive) UITools.CallTip.PositionControl(((ScintillaControl)target.Owner)); + listHost.Show(listHost.Bounds.Location); + if (CallTip.CallTipActive) CallTip.PositionControl(((ScintillaControl)host.Owner)); AddHandlers(); } } @@ -343,7 +358,7 @@ public void Hide() if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; allItems = null; - UITools.Tip.Hide(); + Tip.Hide(); if (OnHidden != null) OnHidden(this, EventArgs.Empty); } } @@ -358,8 +373,8 @@ public void Hide(char trigger) Hide(); if (OnCancel != null) { - if (!target.IsEditable) return; - OnCancel(target.Owner, currentPos, currentWord, trigger, null); + if (!host.IsEditable) return; + OnCancel(host.Owner, currentPos, currentWord, trigger, null); } } } @@ -369,14 +384,14 @@ public void Hide(char trigger) /// public void SelectWordInList(string tail) { - if (!target.IsEditable) + if (!host.IsEditable) { Hide(); return; } currentWord = tail; currentPos += tail.Length; - target.SetSelection(currentPos, currentPos); + host.SetSelection(currentPos, currentPos); } /// @@ -410,7 +425,7 @@ private void CLDrawListItem(Object sender, System.Windows.Forms.DrawItemEventArg e.DrawFocusRectangle(); if ((item != null) && ((e.State & DrawItemState.Selected) > 0)) { - UITools.Tip.Hide(); + Tip.Hide(); currentItem = item; tempoTip.Stop(); tempoTip.Start(); @@ -426,8 +441,8 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) if (currentItem == null || faded) return; - UITools.Tip.SetText(currentItem.Description ?? "", false); - UITools.Tip.Redraw(false); + Tip.SetText(currentItem.Description ?? "", false); + Tip.Redraw(false); var screen = Screen.FromControl(listHost); int rightWidth = screen.WorkingArea.Right - listHost.Right - 10; @@ -441,13 +456,29 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) posTarget.X = 0; } - UITools.Tip.Location = posTarget; - UITools.Tip.AutoSize(widthTarget, 500); + Tip.Location = posTarget; + Tip.AutoSize(widthTarget, 500); if (widthTarget == leftWidth) - UITools.Tip.Location = new Point(listHost.Left - UITools.Tip.Size.Width, posTarget.Y); + Tip.Location = new Point(listHost.Left - Tip.Size.Width, posTarget.Y); - UITools.Tip.Show(); + Tip.Show(); + } + + private void UpdatePosition() + { + Point coord = host.GetPositionFromCharIndex(startPos); + coord = host.Owner.PointToScreen(coord); + listHost.Left = coord.X + host.Owner.Left; + var screen = Screen.FromHandle(host.Owner.Handle); + listUp = CallTip.CallTipActive || (coord.Y + listHost.Height > screen.WorkingArea.Bottom && coord.Y - listHost.Height > screen.WorkingArea.Top); + if (listUp) listHost.Top = coord.Y - listHost.Height; + else listHost.Top = coord.Y + host.GetLineHeight(); + // Keep on screen area + if (listHost.Right > screen.WorkingArea.Right) + { + listHost.Left = screen.WorkingArea.Right - listHost.Width; + } } /// @@ -455,7 +486,7 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) /// private void CLClick(Object sender, System.EventArgs e) { - if (!target.IsEditable) + if (!host.IsEditable) Hide(); } @@ -464,7 +495,7 @@ private void CLClick(Object sender, System.EventArgs e) /// private void CLDoubleClick(Object sender, System.EventArgs e) { - if (!target.IsEditable) + if (!host.IsEditable) { Hide(); return; @@ -840,11 +871,11 @@ public bool ReplaceText(string tail, char trigger) replace = replace.Substring(0, replace.IndexOf(tail)); } } - //((ScintillaControl)target.Owner).BeginUndoAction(); - target.SetSelection(startPos, target.CurrentPos); - target.SelectedText = replace; - if (OnInsert != null) OnInsert(target.Owner, startPos, replace, trigger, item); - if (tail.Length > 0) target.SelectedText = tail; + host.BeginUndoAction(); + host.SetSelection(startPos, host.CurrentPos); + host.SelectedText = replace; + if (OnInsert != null) OnInsert(host.Owner, startPos, replace, trigger, item); + if (tail.Length > 0) host.SelectedText = tail; } return true; } @@ -852,7 +883,7 @@ public bool ReplaceText(string tail, char trigger) } finally { - //((ScintillaControl)target.Owner).EndUndoAction(); + host.EndUndoAction(); } } @@ -871,24 +902,32 @@ public IntPtr GetHandle() private void AddHandlers() { Application.AddMessageFilter(this); - target.LostFocus += Target_LostFocus; - target.MouseDown += Target_LostFocus; - target.KeyDown += Target_KeyDown; - target.Scroll += Target_Scroll; + host.LostFocus += Target_LostFocus; + host.MouseDown += Target_MouseDown; + host.KeyDown += Target_KeyDown; + host.KeyPress += Target_KeyPress; + host.PositionChanged += Target_PositionChanged; } private void RemoveHandlers() { Application.RemoveMessageFilter(this); - target.LostFocus -= Target_LostFocus; - target.MouseDown -= Target_LostFocus; - target.KeyDown -= Target_KeyDown; - target.Scroll -= Target_Scroll; + host.LostFocus -= Target_LostFocus; + host.MouseDown -= Target_MouseDown; + host.KeyDown -= Target_KeyDown; + host.KeyPress -= Target_KeyPress; + host.PositionChanged -= Target_PositionChanged; } private void Target_LostFocus(object sender, EventArgs e) { - if (!listHost.ContainsFocus) + if (!listHost.ContainsFocus && !Tip.Focused && !CallTip.Focused) + Hide(); + } + + private void Target_MouseDown(object sender, MouseEventArgs e) + { + if (host.CurrentPos != currentPos) Hide(); } @@ -897,17 +936,24 @@ private void Target_KeyDown(object sender, KeyEventArgs e) e.SuppressKeyPress = HandleKeys(e.KeyData); } - private void Target_Scroll(object sender, ScrollEventArgs e) { - + private void Target_KeyPress(object sender, KeyPressEventArgs e) + { + if (!char.IsControl(e.KeyChar)) + OnChar(e.KeyChar); + } + + private void Target_PositionChanged(object sender, EventArgs e) + { + UpdatePosition(); + listHost.Show(listHost.Bounds.Location); } /// /// /// - public bool OnChar(int value) + public bool OnChar(char c) { - char c = (char)value; - // TODO: Inject these values + // TODO: Inject these values or get from host string characterClass = ScintillaControl.Configuration.GetLanguage(PluginBase.MainForm.CurrentDocument.SciControl.ConfigurationLanguage).characterclass.Characters; if (characterClass.IndexOf(c) >= 0) { @@ -955,7 +1001,7 @@ public bool HandleKeys(Keys key) if (word.Length > MinWordLength) { word = word.Substring(0, word.Length - 1); - currentPos = target.CurrentPos - 1; + currentPos = host.CurrentPos - 1; lastIndex = 0; FindWordStartingWith(word); } @@ -1082,7 +1128,6 @@ public bool HandleKeys(Keys key) break; default: - //Hide(); return false; } return true; @@ -1090,7 +1135,7 @@ public bool HandleKeys(Keys key) private void RefreshTip() { - UITools.Tip.Hide(); + Tip.Hide(); tempoTip.Enabled = false; } @@ -1104,15 +1149,15 @@ internal void FadeOut() { if (faded) return; faded = true; - UITools.Tip.Hide(); - listHost.Visible = false; + Tip.Hide(); + listHost.Opacity = 0; } internal void FadeIn() { if (!faded) return; faded = false; - listHost.Visible = true; + listHost.Opacity = 1; } #endregion @@ -1121,24 +1166,22 @@ internal void FadeIn() public bool PreFilterMessage(ref Message m) { + if (Tip.Focused || CallTip.Focused) return false; + if (m.Msg == Win32.WM_MOUSEWHEEL) // capture all MouseWheel events { - if (!UITools.CallTip.CallTipActive || !UITools.CallTip.Focused) + if (Win32.ShouldUseWin32()) { - if (Win32.ShouldUseWin32()) - { - Win32.SendMessage(completionList.Handle, m.Msg, (Int32)m.WParam, (Int32)m.LParam); - return true; - } - else return false; + Win32.SendMessage(completionList.Handle, m.Msg, (Int32)m.WParam, (Int32)m.LParam); + return true; } - else return false; } else if (m.Msg == Win32.WM_KEYDOWN) { if ((int)m.WParam == 17) // Ctrl { if (Active) FadeOut(); + if (CallTip.CallTipActive) CallTip.FadeOut(); } } else if (m.Msg == Win32.WM_KEYUP) @@ -1146,6 +1189,7 @@ public bool PreFilterMessage(ref Message m) if ((int)m.WParam == 17 || (int)m.WParam == 18) // Ctrl / AltGr { if (Active) FadeIn(); + if (CallTip.CallTipActive) CallTip.FadeIn(); } } return false; diff --git a/PluginCore/PluginCore/Controls/ICompletionListTarget.cs b/PluginCore/PluginCore/Controls/ICompletionListHost.cs similarity index 74% rename from PluginCore/PluginCore/Controls/ICompletionListTarget.cs rename to PluginCore/PluginCore/Controls/ICompletionListHost.cs index 9829d1492f..31a74256fb 100644 --- a/PluginCore/PluginCore/Controls/ICompletionListTarget.cs +++ b/PluginCore/PluginCore/Controls/ICompletionListHost.cs @@ -4,16 +4,16 @@ namespace PluginCore.Controls { - public interface ICompletionListTarget + public interface ICompletionListHost { event EventHandler LostFocus; - event ScrollEventHandler Scroll; + event EventHandler PositionChanged; event KeyEventHandler KeyDown; + event KeyPressEventHandler KeyPress; event MouseEventHandler MouseDown; - + Control Owner { get; } - string Text { get; } string SelectedText { get; set; } int SelectionEnd { get; set; } int SelectionStart { get; set; } @@ -24,5 +24,8 @@ public interface ICompletionListTarget int GetLineHeight(); void SetSelection(int start, int end); + void BeginUndoAction(); + void EndUndoAction(); + } } diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index b910e5acfe..7209354b95 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -42,11 +42,6 @@ public bool CallTipActive get { return isActive; } } - public bool Focused - { - get { return toolTipRTB.Focused; } - } - public override void Hide() { if (isActive) diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index b1f8a22f77..2df585bac0 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -36,8 +36,13 @@ public class RichToolTip protected IWin32Window owner; #region Public Properties - - public bool Visible + + public bool Focused + { + get { return toolTipRTB.Focused; } + } + + public bool Visible { get { return host.Visible; } } @@ -271,6 +276,11 @@ protected String getRtfFor(String bbcodeText) return rtfCache[bbcodeText]; } + public bool IsMouseInside() + { + return host.Bounds.Contains(Control.MousePosition); + } + #endregion } diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 2a618d2709..a6910246b8 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -99,8 +99,8 @@ private UITools() try { CompletionList.CreateControl(PluginBase.MainForm); - simpleTip = new RichToolTip(PluginBase.MainForm); - callTip = new MethodCallTip(PluginBase.MainForm); + CompletionList.completionList.Tip = simpleTip = new RichToolTip(PluginBase.MainForm); + CompletionList.completionList.CallTip = callTip = new MethodCallTip(PluginBase.MainForm); } catch(Exception ex) { @@ -239,16 +239,14 @@ private void HandleDwellEnd(ScintillaControl sci, int position) public bool PreFilterMessage(ref Message m) { + if (Tip.Focused || CallTip.Focused) return false; + if (m.Msg == Win32.WM_MOUSEWHEEL) // capture all MouseWheel events { - if (!callTip.CallTipActive || !callTip.Focused) + if (Win32.ShouldUseWin32()) { - if (Win32.ShouldUseWin32()) - { - Win32.SendMessage(CompletionList.GetHandle(), m.Msg, (Int32)m.WParam, (Int32)m.LParam); - return true; - } - else return false; + Win32.SendMessage(CompletionList.GetHandle(), m.Msg, (Int32)m.WParam, (Int32)m.LParam); + return true; } else return false; } @@ -257,7 +255,7 @@ public bool PreFilterMessage(ref Message m) if ((int)m.WParam == 17) // Ctrl { if (CompletionList.Active) CompletionList.FadeOut(); - if (callTip.CallTipActive && !callTip.Focused) callTip.FadeOut(); + if (callTip.CallTipActive) callTip.FadeOut(); } } else if (m.Msg == Win32.WM_KEYUP) @@ -299,11 +297,10 @@ private void OnUIRefresh(ScintillaControl sci) if (sci != null && sci.IsFocus) { int position = sci.CurrentPos; - if (CompletionList.Active && CompletionList.CheckPosition(position)) return; + if (CompletionList.Active && CompletionList.CheckPosition(position)) return; if (callTip.CallTipActive && callTip.CheckPosition(position)) return; } callTip.Hide(); - CompletionList.Hide(); simpleTip.Hide(); } @@ -387,7 +384,7 @@ private bool HandleKeys(Keys key) if (key == (Keys.Control | Keys.C) || key == (Keys.Control | Keys.A)) return false; // let text copy in tip UnlockControl(); - CompletionList.Hide((char)27); + //CompletionList.Hide((char)27); callTip.Hide(); return false; } @@ -417,7 +414,6 @@ private bool HandleKeys(Keys key) // handle special keys bool handled = false; if (callTip.CallTipActive) handled |= callTip.HandleKeys(sci, key); - if (CompletionList.Active) handled |= CompletionList.HandleKeys(sci, key); return handled; } From 6afff3d4462fafb4d0ca6b9131ff6c07ede154e5 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Tue, 24 Feb 2015 23:32:53 +0100 Subject: [PATCH 17/36] Some more keys supported by completion list --- .../Controls/CompletionListControl.cs | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index bb27129214..cd3a46025c 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -265,7 +265,6 @@ public void Show(List itemList, bool autoHide) tempoTip.Enabled = false; showTime = DateTime.Now.Ticks; disableSmartMatch = noAutoInsert || PluginBase.MainForm.Settings.DisableSmartMatch; - faded = false; } /// @@ -330,6 +329,7 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) { Redraw(); if (OnShowing != null) OnShowing(this, EventArgs.Empty); + listHost.Opacity = 1; listHost.Show(listHost.Bounds.Location); if (CallTip.CallTipActive) CallTip.PositionControl(((ScintillaControl)host.Owner)); AddHandlers(); @@ -353,7 +353,6 @@ public void Hide() tempo.Enabled = false; isActive = false; fullList = false; - faded = false; listHost.Close(); if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; @@ -438,7 +437,7 @@ private void CLDrawListItem(Object sender, System.Windows.Forms.DrawItemEventArg public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) { tempoTip.Stop(); - if (currentItem == null || faded) + if (currentItem == null || listHost.Opacity != 1) return; Tip.SetText(currentItem.Description ?? "", false); @@ -1077,6 +1076,7 @@ public bool HandleKeys(Keys key) break; case Keys.PageUp: + /*case Keys.PageUp | Keys.Control:*/ // Used to navigate through documents noAutoInsert = false; // the list was hidden and it should not appear if (!listHost.Visible) @@ -1095,6 +1095,7 @@ public bool HandleKeys(Keys key) break; case Keys.PageDown: + /*case Keys.PageDown | Keys.Control:*/ // Used to navigate through documents noAutoInsert = false; // the list was hidden and it should not appear if (!listHost.Visible) @@ -1116,9 +1117,6 @@ public bool HandleKeys(Keys key) break; case Keys.Left: - Hide(); - return false; - case Keys.Right: Hide(); return false; @@ -1128,6 +1126,21 @@ public bool HandleKeys(Keys key) break; default: + Keys modifiers = key & Keys.Modifiers; + if (modifiers == Keys.Control) + { + key = key & Keys.KeyCode; + if (key > 0 && key != Keys.ControlKey && key != Keys.Down && key != Keys.Up) + Hide(); + } + else if (modifiers == Keys.Shift) + { + key = key & Keys.KeyCode; + if (key == Keys.Down || key == Keys.Up || key == Keys.Left || key == Keys.Right || + key == Keys.PageUp || key == Keys.PageDown || key == Keys.Home || key == Keys.End) + Hide(); + } + return false; } return true; @@ -1143,20 +1156,16 @@ private void RefreshTip() #region Controls fading on Control key - private bool faded; - internal void FadeOut() { - if (faded) return; - faded = true; + if (listHost.Opacity != 1) return; Tip.Hide(); listHost.Opacity = 0; } internal void FadeIn() { - if (!faded) return; - faded = false; + if (listHost.Opacity == 1) return; listHost.Opacity = 1; } From 24cf1c4410546040f9defafd97be0368a257ffc9 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Wed, 25 Feb 2015 23:27:40 +0100 Subject: [PATCH 18/36] More list conrol Added Scintilla scroll notification and hooked it to move the completion list accordingly. Update completion list position on scintilla zoom change. Added support for some more keys. --- .../PluginCore/Controls/CompletionList.cs | 35 +- .../Controls/CompletionListControl.cs | 72 +- PluginCore/PluginCore/Controls/UITools.cs | 1 - PluginCore/ScintillaNet/ScintillaControl.cs | 9260 +++++++++-------- 4 files changed, 4752 insertions(+), 4616 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index addbe787e2..e5384e4591 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -258,11 +258,25 @@ public event EventHandler LostFocus remove { Owner.LostFocus -= value; } } - public event EventHandler PositionChanged; -/* { - add { PluginBase.MainForm.CurrentDocument.SciControl. += value; } - remove { Owner.LostFocus -= value; } - }*/ + private EventHandler positionChanged; + public event EventHandler PositionChanged + { + add + { + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + sci.Scroll += Scintilla_Scroll; + sci.Zoom += Scintilla_Zoom; + positionChanged += value; + } + remove + { + var sci = PluginBase.MainForm.CurrentDocument.SciControl; + sci.Scroll -= Scintilla_Scroll; + sci.Zoom -= Scintilla_Zoom; + positionChanged -= value; + } + } + public event KeyEventHandler KeyDown { add { Owner.KeyDown += value; } @@ -337,6 +351,17 @@ public void EndUndoAction() PluginBase.MainForm.CurrentDocument.SciControl.EndUndoAction(); } + private void Scintilla_Scroll(object sender, ScrollEventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Scintilla_Zoom(ScintillaControl sci) + { + if (positionChanged != null) + positionChanged(sci, EventArgs.Empty); + } } } } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index cd3a46025c..7d996a79e6 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -325,15 +325,6 @@ private void DisplayList(Object sender, System.Timers.ElapsedEventArgs e) cl.Size = listContainer.Size = listHost.Size = listSize; // place control UpdatePosition(); - if (!listHost.Visible) - { - Redraw(); - if (OnShowing != null) OnShowing(this, EventArgs.Empty); - listHost.Opacity = 1; - listHost.Show(listHost.Bounds.Location); - if (CallTip.CallTipActive) CallTip.PositionControl(((ScintillaControl)host.Owner)); - AddHandlers(); - } } public void Redraw() @@ -353,12 +344,13 @@ public void Hide() tempo.Enabled = false; isActive = false; fullList = false; + bool visible = listHost.Visible; listHost.Close(); if (completionList.Items.Count > 0) completionList.Items.Clear(); currentItem = null; allItems = null; Tip.Hide(); - if (OnHidden != null) OnHidden(this, EventArgs.Empty); + if (visible && OnHidden != null) OnHidden(this, EventArgs.Empty); } } @@ -467,17 +459,36 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) private void UpdatePosition() { Point coord = host.GetPositionFromCharIndex(startPos); + // Check for completion list outside of control view + if (coord.X < 0 || coord.X > host.Owner.Width || coord.Y < 0 || coord.Y > host.Owner.Height) + { + Hide(); + return; + } coord = host.Owner.PointToScreen(coord); - listHost.Left = coord.X + host.Owner.Left; + coord.X += host.Owner.Left; var screen = Screen.FromHandle(host.Owner.Handle); listUp = CallTip.CallTipActive || (coord.Y + listHost.Height > screen.WorkingArea.Bottom && coord.Y - listHost.Height > screen.WorkingArea.Top); - if (listUp) listHost.Top = coord.Y - listHost.Height; - else listHost.Top = coord.Y + host.GetLineHeight(); + if (listUp) coord.Y -= listHost.Height; + else coord.Y += host.GetLineHeight(); // Keep on screen area - if (listHost.Right > screen.WorkingArea.Right) + if (coord.X + listHost.Width > screen.WorkingArea.Right) + { + coord.X = screen.WorkingArea.Right - listHost.Width; + } + + if (listHost.Visible) + listHost.Show(coord); + else { - listHost.Left = screen.WorkingArea.Right - listHost.Width; + Redraw(); + if (OnShowing != null) OnShowing(this, EventArgs.Empty); + listHost.Opacity = 1; + listHost.Show(coord); + if (CallTip.CallTipActive) CallTip.PositionControl(((ScintillaControl)host.Owner)); + AddHandlers(); } + } /// @@ -944,7 +955,6 @@ private void Target_KeyPress(object sender, KeyPressEventArgs e) private void Target_PositionChanged(object sender, EventArgs e) { UpdatePosition(); - listHost.Show(listHost.Bounds.Location); } /// @@ -1113,6 +1123,30 @@ public bool HandleKeys(Keys key) } break; + case Keys.Home: + noAutoInsert = false; + // go down the list + if (completionList.SelectedIndex > 0) + { + RefreshTip(); + index = 0; + completionList.SelectedIndex = index; + } + + break; + + case Keys.End: + noAutoInsert = false; + // go down the list + if (completionList.SelectedIndex < completionList.Items.Count - 1) + { + RefreshTip(); + index = completionList.Items.Count - 1; + completionList.SelectedIndex = index; + } + + break; + case (Keys.Control | Keys.Space): break; @@ -1140,6 +1174,12 @@ public bool HandleKeys(Keys key) key == Keys.PageUp || key == Keys.PageDown || key == Keys.Home || key == Keys.End) Hide(); } + else if (modifiers == (Keys.Shift | Keys.Control)) + { + key = key & Keys.KeyCode; + if (key == Keys.Left && key == Keys.Right) + Hide(); + } return false; } diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index a6910246b8..d206ac8ac8 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -335,7 +335,6 @@ private void OnChar(ScintillaControl sci, int value) if (callTip.CallTipActive) callTip.OnChar(sci, value); if (CompletionList.Active) CompletionList.OnChar(sci, value); else SendChar(sci, value); - return; } public void SendChar(ScintillaControl sci, int value) diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 6addbe40c7..4334763afd 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -17,31 +17,32 @@ namespace ScintillaNet { - public class ScintillaControl : Control - { + public class ScintillaControl : Control + { private bool saveBOM; private Encoding encoding; - private IntPtr directPointer; + private IntPtr directPointer; private bool hasHighlights = false; - private bool ignoreAllKeys = false; - private bool isBraceMatching = true; + private bool ignoreAllKeys = false; + private bool isBraceMatching = true; private bool isHiliteSelected = true; private bool useHighlightGuides = true; private System.Timers.Timer highlightDelay; - private static Scintilla sciConfiguration = null; + private static Scintilla sciConfiguration = null; private static Dictionary shortcutOverrides = new Dictionary(); private Enums.IndentView indentView = Enums.IndentView.Real; - private Enums.SmartIndent smartIndent = Enums.SmartIndent.CPP; - private HashSet ignoredKeys = new HashSet(); + private Enums.SmartIndent smartIndent = Enums.SmartIndent.CPP; + private HashSet ignoredKeys = new HashSet(); private string configLanguage = String.Empty; private string fileName = String.Empty; private int lastSelectionLength = 0; private int lastSelectionStart = 0; private int lastSelectionEnd = 0; - - #region Scintilla Main - public ScintillaControl() : this("SciLexer.dll") + #region Scintilla Main + + public ScintillaControl() + : this("SciLexer.dll") { if (Win32.ShouldUseWin32()) DragAcceptFiles(this.Handle, 1); } @@ -94,14 +95,14 @@ protected override CreateParams CreateParams } } - #endregion + #endregion + + #region Scintilla Event Members - #region Scintilla Event Members - - public event KeyHandler Key; - public event ZoomHandler Zoom; + public event KeyHandler Key; + public event ZoomHandler Zoom; public event FocusHandler FocusChanged; - public event StyleNeededHandler StyleNeeded; + public event StyleNeededHandler StyleNeeded; public event CharAddedHandler CharAdded; public event SavePointReachedHandler SavePointReached; public event SavePointLeftHandler SavePointLeft; @@ -120,44 +121,45 @@ protected override CreateParams CreateParams public event HotSpotDoubleClickHandler HotSpotDoubleClick; public event CallTipClickHandler CallTipClick; public event AutoCSelectionHandler AutoCSelection; - public event TextInsertedHandler TextInserted; - public event TextDeletedHandler TextDeleted; - public event FoldChangedHandler FoldChanged; - public event UserPerformedHandler UserPerformed; - public event UndoPerformedHandler UndoPerformed; - public event RedoPerformedHandler RedoPerformed; - public event LastStepInUndoRedoHandler LastStepInUndoRedo; - public event MarkerChangedHandler MarkerChanged; - public event BeforeInsertHandler BeforeInsert; - public event BeforeDeleteHandler BeforeDelete; - public event SmartIndentHandler SmartIndent; - public new event StyleChangedHandler StyleChanged; - public new event DoubleClickHandler DoubleClick; + public event TextInsertedHandler TextInserted; + public event TextDeletedHandler TextDeleted; + public event FoldChangedHandler FoldChanged; + public event UserPerformedHandler UserPerformed; + public event UndoPerformedHandler UndoPerformed; + public event RedoPerformedHandler RedoPerformed; + public event LastStepInUndoRedoHandler LastStepInUndoRedo; + public event MarkerChangedHandler MarkerChanged; + public event BeforeInsertHandler BeforeInsert; + public event BeforeDeleteHandler BeforeDelete; + public event SmartIndentHandler SmartIndent; + public new event StyleChangedHandler StyleChanged; + public new event DoubleClickHandler DoubleClick; public event IndicatorClickHandler IndicatorClick; public event IndicatorReleaseHandler IndicatorRelease; public event AutoCCancelledHandler AutoCCancelled; public event AutoCCharDeletedHandler AutoCCharDeleted; public event UpdateSyncHandler UpdateSync; public event SelectionChangedHandler SelectionChanged; - - #endregion + public event ScrollEventHandler Scroll; + + #endregion - #region Scintilla Properties + #region Scintilla Properties /// /// Current used configuration /// static public Scintilla Configuration - { - get - { - return sciConfiguration; + { + get + { + return sciConfiguration; } - set - { - sciConfiguration = value; + set + { + sciConfiguration = value; } - } + } /// /// Indent view type @@ -179,15 +181,15 @@ public Enums.IndentView IndentView /// public string ConfigurationLanguage { - get - { + get + { return this.configLanguage; } set { if (value == null || value.Equals("")) return; this.SetLanguage(value); - + } } @@ -546,13 +548,13 @@ private void SetLanguage(String value) /// public override string Text { - get - { - return GetText(Length); + get + { + return GetText(Length); } - set - { - SetText(value); + set + { + SetText(value); } } @@ -561,12 +563,12 @@ public override string Text /// public string FileName { - get - { - return fileName; + get + { + return fileName; } - set - { + set + { fileName = value; if (UpdateSync != null) this.UpdateSync(this); } @@ -577,9 +579,9 @@ public string FileName /// public override bool Focused { - get - { - return IsFocus; + get + { + return IsFocus; } } @@ -588,12 +590,12 @@ public override bool Focused /// public bool IgnoreAllKeys { - get - { - return ignoreAllKeys; + get + { + return ignoreAllKeys; } - set - { + set + { ignoreAllKeys = value; } } @@ -614,21 +616,21 @@ public bool IsHiliteSelected } } - /// - /// Enables the brace matching from current position. - /// - public bool IsBraceMatching - { - get - { - return isBraceMatching; + /// + /// Enables the brace matching from current position. + /// + public bool IsBraceMatching + { + get + { + return isBraceMatching; } - set - { + set + { isBraceMatching = value; if (UpdateSync != null) this.UpdateSync(this); } - } + } /// /// Enables the highlight guides from current position. @@ -646,45 +648,45 @@ public bool UseHighlightGuides } } - /// - /// Enables the Smart Indenter so that On enter, it indents the next line. - /// - public Enums.SmartIndent SmartIndentType - { - get - { - return smartIndent; + /// + /// Enables the Smart Indenter so that On enter, it indents the next line. + /// + public Enums.SmartIndent SmartIndentType + { + get + { + return smartIndent; } - set - { + set + { smartIndent = value; if (UpdateSync != null) this.UpdateSync(this); } - } - - /// - /// Are white space characters currently visible? + } + + /// + /// Are white space characters currently visible? /// Returns one of Enums.WhiteSpace constants. - /// - public Enums.WhiteSpace ViewWhitespace - { - get - { - return (Enums.WhiteSpace)ViewWS; + /// + public Enums.WhiteSpace ViewWhitespace + { + get + { + return (Enums.WhiteSpace)ViewWS; } - set - { - ViewWS = (int)value; + set + { + ViewWS = (int)value; } - } + } /// /// Get or sets the background alpha of the caret line. /// public int CaretLineBackAlpha { - get - { + get + { return (int)SPerform(2471, 0, 0); } set @@ -753,3893 +755,3907 @@ public int IndicatorValue } } - /// - /// Retrieve the current end of line mode - one of CRLF, CR, or LF. - /// - public Enums.EndOfLine EndOfLineMode - { - get - { - return (Enums.EndOfLine)EOLMode; + /// + /// Retrieve the current end of line mode - one of CRLF, CR, or LF. + /// + public Enums.EndOfLine EndOfLineMode + { + get + { + return (Enums.EndOfLine)EOLMode; } - set - { + set + { EOLMode = (int)value; } - } - - /// - /// Length Method for : Retrieve the text of the line containing the caret. - /// Returns the index of the caret on the line. - /// - public int CurLineSize - { - get - { - return (int)SPerform(2027, 0 , 0); - } - } - - /// - /// Length Method for : Retrieve the contents of a line. - /// Returns the length of the line. - /// - public int LineSize - { - get - { - return (int)SPerform(2153, 0, 0); - } - } - - /// - /// Length Method for : Retrieve the selected text. - /// Return the length of the text. - /// - public int SelTextSize - { - get - { - return (int)SPerform(2161, 0, 0) - 1; - } - } - - /// - /// Length Method for : Retrieve all the text in the document. - /// Returns number of characters retrieved. - /// - public int TextSize - { - get - { - return (int)SPerform(2182, 0, 0); - } - } - - /// - /// Are there any redoable actions in the undo history? - /// - public bool CanRedo - { - get - { - return SPerform(2016, 0, 0) != 0; - } - } - - /// - /// Is there an auto-completion list visible? - /// - public bool IsAutoCActive - { - get - { - return SPerform(2102, 0, 0) != 0; - } - } - - /// - /// Retrieve the position of the caret when the auto-completion list was displayed. - /// - public int AutoCPosStart - { - get - { - return (int)SPerform(2103, 0, 0); - } - } - - /// - /// Will a paste succeed? - /// - public bool CanPaste - { - get - { - return SPerform(2173, 0, 0) != 0; - } - } - - /// - /// Are there any undoable actions in the undo history? - /// - public bool CanUndo - { - get - { - return SPerform(2174, 0, 0) != 0; - } - } - - /// - /// Is there an active call tip? - /// - public bool IsCallTipActive - { - get - { - return SPerform(2202, 0, 0) != 0; - } - } - - /// - /// Retrieve the position where the caret was before displaying the call tip. - /// - public int CallTipPosStart - { - get - { - return (int)SPerform(2203, 0, 0); - } - } - - /// - /// Create a new document object. - /// Starts with reference count of 1 and not selected into editor. - /// - public int CreateDocument - { - get - { - return (int)SPerform(2375, 0, 0); - } - } - - /// - /// Get currently selected item position in the auto-completion list - /// - public int AutoCGetCurrent - { - get - { - return (int)SPerform(2445, 0, 0); - } - } - - /// - /// Returns the number of characters in the document. - /// - public int Length - { - get - { - return (int)SPerform(2006, 0, 0); - } - } - - /// - /// Enable/Disable convert-on-paste for line endings - /// - public bool PasteConvertEndings - { - get - { - return SPerform(2468, 0, 0) != 0; - } - set - { - SPerform(2467, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Returns the position of the caret. - /// - public int CurrentPos - { - get - { - return (int)SPerform(2008, 0, 0); - } - set - { - SPerform(2141, (uint)value , 0); - } - } + } /// - /// Returns the chracter at the caret posiion. + /// Length Method for : Retrieve the text of the line containing the caret. + /// Returns the index of the caret on the line. /// - public char CurrentChar + public int CurLineSize { get { - return (char)CharAt(CurrentPos); + return (int)SPerform(2027, 0, 0); } } /// - /// Returns the line containing the current position. + /// Length Method for : Retrieve the contents of a line. + /// Returns the length of the line. /// - public int CurrentLine + public int LineSize { get { - return LineFromPosition(CurrentPos); + return (int)SPerform(2153, 0, 0); } } - - /// - /// Returns the position of the opposite end of the selection to the caret. - /// - public int AnchorPosition - { - get - { - return (int)SPerform(2009, 0, 0); - } - set - { - SPerform(2026, (uint)value , 0); - } - } - - /// - /// Is undo history being collected? - /// - public bool IsUndoCollection - { - get - { - return SPerform(2019, 0, 0)!=0; - } - set - { - SPerform(2012 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Are white space characters currently visible? - /// Returns one of SCWS_/// constants. - /// - public int ViewWS - { - get - { - return (int)SPerform(2020, 0, 0); - } - set - { - SPerform(2021, (uint)value , 0); - } - } - - /// - /// Retrieve the position of the last correctly styled character. - /// - public int EndStyled - { - get - { - return (int)SPerform(2028, 0, 0); - } - } - - /// - /// Retrieve the current end of line mode - one of CRLF, CR, or LF. - /// - public int EOLMode - { - get - { - return (int)SPerform(2030, 0, 0); - } - set - { - SPerform(2031, (uint)value , 0); - } - } - - /// - /// Is drawing done first into a buffer or direct to the screen? - /// - public bool IsBufferedDraw - { - get - { - return SPerform(2034, 0, 0)!=0; - } - set - { - SPerform(2035 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve the visible size of a tab. - /// - public int TabWidth - { - get - { - return (int)SPerform(2121, 0, 0); - } - set - { - SPerform(2036, (uint)value, 0); - } - } - - /// - /// Get the time in milliseconds that the caret is on and off. - /// - public int CaretPeriod - { - get - { - return (int)SPerform(2075, 0, 0); - } - set - { - SPerform(2076, (uint)value, 0); - } - } - - /// - /// Retrieve number of bits in style bytes used to hold the lexical state. - /// - public int StyleBits - { - get - { - return (int)SPerform(2091, 0, 0); - } - set - { - SPerform(2090, (uint)value, 0); - } - } - - /// - /// Retrieve the last line number that has line state. - /// - public int MaxLineState - { - get - { - return (int)SPerform(2094, 0, 0); - } - } - - /// - /// Is the background of the line containing the caret in a different colour? - /// - public bool IsCaretLineVisible - { - get - { - return SPerform(2095, 0, 0) != 0; - } - set - { - SPerform(2096, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Get the colour of the background of the line containing the caret. - /// - public int CaretLineBack - { - get - { - return (int)SPerform(2097, 0, 0); - } - set - { - SPerform(2098, (uint)value, 0); - } - } - - /// - /// Retrieve the auto-completion list separator character. - /// - public int AutoCSeparator - { - get - { - return (int)SPerform(2107, 0, 0); - } - set - { - SPerform(2106, (uint)value, 0); - } - } - - /// - /// Retrieve whether auto-completion cancelled by backspacing before start. - /// - public bool IsAutoCGetCancelAtStart - { - get - { - return SPerform(2111, 0, 0) != 0; - } - set - { - SPerform(2110 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve whether a single item auto-completion list automatically choose the item. - /// - public bool IsAutoCGetChooseSingle - { - get - { - return SPerform(2114, 0, 0) != 0; - } - set - { - SPerform(2113, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve state of ignore case flag. - /// - public bool IsAutoCGetIgnoreCase - { - get - { - return SPerform(2116, 0, 0) != 0; - } - set - { - SPerform(2115, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve whether or not autocompletion is hidden automatically when nothing matches. - /// - public bool IsAutoCGetAutoHide - { - get - { - return SPerform(2119, 0, 0) != 0; - } - set - { - SPerform(2118, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve whether or not autocompletion deletes any word characters - /// after the inserted text upon completion. - /// - public bool IsAutoCGetDropRestOfWord - { - get - { - return SPerform(2271, 0, 0) != 0; - } - set - { - SPerform(2270, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve the auto-completion list type-separator character. - /// - public int AutoCTypeSeparator - { - get - { - return (int)SPerform(2285, 0, 0); - } - set - { - SPerform(2286, (uint)value, 0); - } - } - - /// - /// Retrieve indentation size. - /// - public int Indent - { - get - { - return (int)SPerform(2123, 0, 0); - } - set - { - SPerform(2122, (uint)value, 0); - } - } - - /// - /// Retrieve whether tabs will be used in indentation. - /// - public bool IsUseTabs - { - get - { - return SPerform(2125, 0, 0) != 0; - } - set - { - SPerform(2124 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Is the horizontal scroll bar visible? - /// - public bool IsHScrollBar - { - get - { - return SPerform(2131, 0, 0) != 0; - } - set - { - SPerform(2130, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Are the indentation guides visible? - /// - public bool IsIndentationGuides - { - get - { - return SPerform(2133, 0, 0) != 0; - } - set - { - SPerform(2132, (uint)(value ? (int)this.indentView : 0), 0); - } - } - - /// - /// Get the highlighted indentation guide column. - /// - public int HighlightGuide - { - get - { - return (int)SPerform(2135, 0, 0); - } - set - { - SPerform(2134, (uint)value, 0); - } - } - - /// - /// Get the code page used to interpret the bytes of the document as characters. - /// - public int CodePage - { - get - { - return (int)SPerform(2137, 0, 0); - } - set - { - SPerform(2037, (uint)value, 0); - } - } - - /// - /// Get the foreground colour of the caret. - /// - public int CaretFore - { - get - { - return (int)SPerform(2138, 0, 0); - } - set - { - SPerform(2069, (uint)value, 0); - } - } - - /// - /// In palette mode? - /// - public bool IsUsePalette - { - get - { - return SPerform(2139, 0, 0) != 0; - } - set - { - SPerform(2039, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// In read-only mode? - /// - public bool IsReadOnly - { - get - { - return SPerform(2140, 0, 0) != 0; - } - set - { - SPerform(2171, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Returns the position at the start of the selection. - /// - public int SelectionStart - { - get - { - return (int)SPerform(2143, 0, 0); - } - set - { - SPerform(2142, (uint)value, 0); - } - } - - /// - /// Returns the position at the end of the selection. - /// - public int SelectionEnd - { - get - { - return (int)SPerform(2145, 0, 0); - } - set - { - SPerform(2144, (uint)value, 0); - } - } /// - /// Returns true if the selection extends over more than one line. + /// Length Method for : Retrieve the selected text. + /// Return the length of the text. /// - public bool IsSelectionMultiline + public int SelTextSize { get { - return LineFromPosition(SelectionStart) != LineFromPosition(SelectionEnd); + return (int)SPerform(2161, 0, 0) - 1; } } - /// - /// Returns the print magnification. - /// - public int PrintMagnification - { - get - { - return (int)SPerform(2147, 0, 0); - } - set - { - SPerform(2146, (uint)value, 0); - } - } - - /// - /// Returns the print colour mode. - /// - public int PrintColourMode - { - get - { - return (int)SPerform(2149, 0, 0); - } - set - { - SPerform(2148, (uint)value, 0); - } - } - - /// - /// Retrieve the display line at the top of the display. - /// - public int FirstVisibleLine - { - get - { - return (int)SPerform(2152, 0, 0); - } - } - - /// - /// Returns the number of lines in the document. There is always at least one. - /// - public int LineCount - { - get - { - return (int)SPerform(2154, 0, 0); - } - } - - /// - /// Returns the size in pixels of the left margin. - /// - public int MarginLeft - { - get - { - return (int)SPerform(2156, 0, 0); - } - set - { - SPerform(2155, 0, (uint)value); - } - } - - /// - /// Returns the size in pixels of the right margin. - /// - public int MarginRight - { - get - { - return (int)SPerform(2158, 0, 0); - } - set - { - SPerform(2157, 0, (uint)value); - } - } - - /// - /// Is the document different from when it was last saved? - /// - public bool IsModify - { - get - { - return SPerform(2159, 0, 0) != 0; - } - } - - /// - /// Retrieve the number of characters in the document. - /// - public int TextLength - { - get - { - return (int)SPerform(2183, 0, 0); - } - } - - /// - /// Retrieve a pointer to a function that processes messages for this Scintilla. - /// - public int DirectFunction - { - get - { - return (int)SPerform(2184, 0, 0); - } - } - - /// - /// Retrieve a pointer value to use as the first argument when calling - /// the function returned by GetDirectFunction. - /// - public IntPtr DirectPointer - { - get - { - if (directPointer == IntPtr.Zero) - directPointer = SendMessage(Handle, 2185, 0, 0); - return directPointer; - } - } - - /// - /// Returns true if overtype mode is active otherwise false is returned. - /// - public bool IsOvertype - { - get - { - return SPerform(2187, 0, 0) != 0; - } - set - { - SPerform(2186 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Returns the width of the insert mode caret. - /// - public int CaretWidth - { - get - { - return (int)SPerform(2189, 0, 0); - } - set - { - SPerform(2188, (uint)value, 0); - } - } - - /// - /// Get the position that starts the target. - /// - public int TargetStart - { - get - { - return (int)SPerform(2191, 0, 0); - } - set - { - SPerform(2190, (uint)value , 0); - } - } - - /// - /// Get the position that ends the target. - /// - public int TargetEnd - { - get - { - return (int)SPerform(2193, 0, 0); - } - set - { - SPerform(2192, (uint)value , 0); - } - } - - /// - /// Get the search flags used by SearchInTarget. - /// - public int SearchFlags - { - get - { - return (int)SPerform(2199, 0, 0); - } - set - { - SPerform(2198, (uint)value, 0); - } - } - - /// - /// Is a line visible? - /// - public bool IsLineVisible - { - get - { - return SPerform(2228, 0, 0) != 0; - } - } - - /// - /// Does a tab pressed when caret is within indentation indent? - /// - public bool IsTabIndents - { - get - { - return SPerform(2261, 0, 0) != 0; - } - set - { - SPerform(2260, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Does a backspace pressed when caret is within indentation unindent? - /// - public bool IsBackSpaceUnIndents - { - get - { - return SPerform(2263, 0, 0) != 0; - } - set - { - SPerform(2262, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve the time the mouse must sit still to generate a mouse dwell event. - /// - public int MouseDwellTime - { - get - { - return (int)SPerform(2265, 0, 0); - } - set - { - SPerform(2264, (uint)value, 0); - } - } - - /// - /// Retrieve whether text is word wrapped. - /// - public int WrapMode - { - get - { - return (int)SPerform(2269, 0, 0); - } - set - { - SPerform(2268, (uint)value, 0); - } - } - - /// - /// Retrive the display mode of visual flags for wrapped lines. - /// - public int WrapVisualFlags - { - get - { - return (int)SPerform(2461, 0, 0); - } - set - { - SPerform(2460, (uint)value , 0); - } - } - - /// - /// Retrive the location of visual flags for wrapped lines. - /// - public int WrapVisualFlagsLocation - { - get - { - return (int)SPerform(2463, 0, 0); - } - set - { - SPerform(2462, (uint)value, 0); - } - } - - /// - /// Retrive the start indent for wrapped lines. - /// - public int WrapStartIndent - { - get - { - return (int)SPerform(2465, 0, 0); - } - set - { - SPerform(2464, (uint)value, 0); - } - } - - /// - /// Retrieve the degree of caching of layout information. - /// - public int LayoutCache - { - get - { - return (int)SPerform(2273, 0, 0); - } - set - { - SPerform(2272, (uint)value, 0); - } - } - - /// - /// Retrieve the document width assumed for scrolling. - /// - public int ScrollWidth - { - get - { - return (int)SPerform(2275, 0, 0); - } - set - { - SPerform(2274, (uint)value, 0); - } - } - - /// - /// Retrieve whether the maximum scroll position has the last - /// line at the bottom of the view. - /// - public int EndAtLastLine - { - get - { - return (int)SPerform(2278, 0, 0); - } - set - { - SPerform(2277, (uint)value , 0); - } - } - - /// - /// Is the vertical scroll bar visible? - /// - public bool IsVScrollBar - { - get - { - return SPerform(2281, 0, 0) != 0; - } - set - { - SPerform(2280, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Is drawing done in two phases with backgrounds drawn before faoregrounds? - /// - public bool IsTwoPhaseDraw - { - get - { - return SPerform(2283, 0, 0)!=0; - } - set - { - SPerform(2284, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Are the end of line characters visible? - /// - public bool IsViewEOL - { - get - { - return SPerform(2355, 0, 0) != 0; - } - set - { - SPerform(2356, (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Retrieve a pointer to the document object. - /// - public int DocPointer - { - get - { - return (int)SPerform(2357, 0, 0); - } - set - { - SPerform(2358, 0, (uint)value); - } - } - - /// - /// Retrieve the column number which text should be kept within. - /// - public int EdgeColumn - { - get - { - return (int)SPerform(2360, 0, 0); - } - set - { - SPerform(2361, (uint)value, 0); - } - } - - /// - /// Retrieve the edge highlight mode. - /// - public int EdgeMode - { - get - { - return (int)SPerform(2362, 0, 0); - } - set - { - SPerform(2363, (uint)value, 0); - } - } - - /// - /// Retrieve the colour used in edge indication. - /// - public int EdgeColour - { - get - { - return (int)SPerform(2364, 0, 0); - } - set - { - SPerform(2365, (uint)value, 0); - } - } - - /// - /// Retrieves the number of lines completely visible. - /// - public int LinesOnScreen - { - get - { - return (int)SPerform(2370, 0, 0); - } - } - - /// - /// Is the selection rectangular? The alternative is the more common stream selection. - /// - public bool IsSelectionRectangle - { - get - { - return SPerform(2372, 0, 0) != 0; - } - } - - /// - /// Set the zoom level. This number of points is added to the size of all fonts. - /// It may be positive to magnify or negative to reduce. Retrieve the zoom level. - /// - public int ZoomLevel - { - get - { - return (int)SPerform(2374, 0, 0); - } - set - { - SPerform(2373, (uint)value, 0); - } - } - - /// - /// Get which document modification events are sent to the container. - /// - public int ModEventMask - { - get - { - return (int)SPerform(2378, 0, 0); - } - set - { - SPerform(2359, (uint)value, 0); - } - } - - /// - /// Change internal focus flag. Get internal focus flag. - /// - public bool IsFocus - { - get - { - return SPerform(2381, 0, 0) != 0; - } - set - { - SPerform(2380 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Change error status - 0 = OK. Get error status. - /// - public int Status - { - get - { - return (int)SPerform(2383, 0, 0); - } - set - { - SPerform(2382, (uint)value, 0); - } - } - - /// - /// Set whether the mouse is captured when its button is pressed. Get whether mouse gets captured. - /// - public bool IsMouseDownCaptures - { - get - { - return SPerform(2385, 0, 0) != 0; - } - set - { - SPerform(2384 , (uint)(value ? 1 : 0), 0); - } - } - - /// - /// Sets the cursor to one of the SC_CURSOR/// values. Get cursor type. - /// - public int CursorType - { - get - { - return (int)SPerform(2387, 0, 0); - } - set - { - SPerform(2386, (uint)value, 0); - } - } - - /// - /// Change the way control characters are displayed: - /// If symbol is < 32, keep the drawn way, else, use the given character. - /// Get the way control characters are displayed. - /// - public int ControlCharSymbol - { - get - { - return (int)SPerform(2389, 0, 0); - } - set - { - SPerform(2388, (uint)value, 0); - } - } - - /// - /// Get and Set the xOffset (ie, horizonal scroll position). - /// - public int XOffset - { - get - { - return (int)SPerform(2398, 0, 0); - } - set - { - SPerform(2397, (uint)value, 0); - } - } - - /// - /// Is printing line wrapped? - /// - public int PrintWrapMode - { - get - { - return (int)SPerform(2407, 0, 0); - } - set - { - SPerform(2406, (uint)value, 0); - } - } - - /// - /// Get the mode of the current selection. - /// - public int SelectionMode - { - get - { - return (int)SPerform(2423, 0, 0); - } - set - { - SPerform(2422, (uint)value, 0); - } - } - - /// - /// Retrieve the lexing language of the document. - /// - public int Lexer - { - get - { - return (int)SPerform(4002, 0, 0); - } - set - { - SPerform(4001, (uint)value, 0); - } - } - /// - /// Gets the EOL marker + /// Length Method for : Retrieve all the text in the document. + /// Returns number of characters retrieved. /// - public string NewLineMarker + public int TextSize { get { - if (EOLMode == 1) return "\r"; - else if (EOLMode == 2) return "\n"; - else return "\r\n"; + return (int)SPerform(2182, 0, 0); } } /// - /// Compact the document buffer and return a read-only pointer to the characters in the document. + /// Are there any redoable actions in the undo history? /// - public int CharacterPointer + public bool CanRedo { get { - return (int)SPerform(2520, 0, 0); + return SPerform(2016, 0, 0) != 0; } } /// - /// Always interpret keyboard input as Unicode + /// Is there an auto-completion list visible? /// - public bool UnicodeKeys + public bool IsAutoCActive { get { - return SPerform(2522, 0, 0) != 0; - } - set - { - SPerform(2521, (uint)(value ? 1 : 0), 0); + return SPerform(2102, 0, 0) != 0; } } /// - /// Set extra ascent for each line + /// Retrieve the position of the caret when the auto-completion list was displayed. /// - public int ExtraAscent + public int AutoCPosStart { get { - return (int)SPerform(2526, 0, 0); + return (int)SPerform(2103, 0, 0); } - set + } + + /// + /// Will a paste succeed? + /// + public bool CanPaste + { + get { - SPerform(2525, (uint)value, 0); + return SPerform(2173, 0, 0) != 0; } } /// - /// Set extra descent for each line + /// Are there any undoable actions in the undo history? /// - public int ExtraDescent + public bool CanUndo { get { - return (int)SPerform(2528, 0, 0); + return SPerform(2174, 0, 0) != 0; } - set + } + + /// + /// Is there an active call tip? + /// + public bool IsCallTipActive + { + get { - SPerform(2527, (uint)value, 0); + return SPerform(2202, 0, 0) != 0; } } /// - /// Get the start of the range of style numbers used for margin text + /// Retrieve the position where the caret was before displaying the call tip. /// - public int MarginStyleOffset + public int CallTipPosStart { get { - return (int)SPerform(2538, 0, 0); + return (int)SPerform(2203, 0, 0); } - set + } + + /// + /// Create a new document object. + /// Starts with reference count of 1 and not selected into editor. + /// + public int CreateDocument + { + get { - SPerform(2537, (uint)value, 0); + return (int)SPerform(2375, 0, 0); } } /// - /// Get the start of the range of style numbers used for annotations + /// Get currently selected item position in the auto-completion list /// - public int AnnotationStyleOffset + public int AutoCGetCurrent { get { - return (int)SPerform(2551, 0, 0); + return (int)SPerform(2445, 0, 0); } - set + } + + /// + /// Returns the number of characters in the document. + /// + public int Length + { + get { - SPerform(2550, (uint)value, 0); + return (int)SPerform(2006, 0, 0); } } /// - /// Get the start of the range of style numbers used for annotations + /// Enable/Disable convert-on-paste for line endings /// - public bool AnnotationVisible + public bool PasteConvertEndings { get { - return SPerform(2549, 0, 0) != 0; + return SPerform(2468, 0, 0) != 0; } set { - SPerform(2548, (uint)(value ? 1 : 0), 0); + SPerform(2467, (uint)(value ? 1 : 0), 0); } } /// - /// Sets whether the maximum width line displayed is used to set scroll width. + /// Returns the position of the caret. /// - public bool ScrollWidthTracking + public int CurrentPos { get { - return SPerform(2517, 0, 0) != 0; + return (int)SPerform(2008, 0, 0); } set { - SPerform(2516, (uint)(value ? 1 : 0), 0); + SPerform(2141, (uint)value, 0); } } - #endregion - - #region Scintilla Methods - /// - /// Adds a new keys to ignore - /// - public virtual void AddIgnoredKeys(Keys keys) + /// Returns the chracter at the caret posiion. + /// + public char CurrentChar { - ignoredKeys.Add((int)keys); + get + { + return (char)CharAt(CurrentPos); + } } /// - /// Removes the ignored keys - /// - public virtual void RemoveIgnoredKeys(Keys keys) + /// Returns the line containing the current position. + /// + public int CurrentLine { - ignoredKeys.Remove((int)keys); + get + { + return LineFromPosition(CurrentPos); + } } /// - /// Clears the ignored keys container - /// - public virtual void ClearIgnoredKeys() + /// Returns the position of the opposite end of the selection to the caret. + /// + public int AnchorPosition { - ignoredKeys.Clear(); + get + { + return (int)SPerform(2009, 0, 0); + } + set + { + SPerform(2026, (uint)value, 0); + } } /// - /// Does the container have keys? - /// - public virtual bool ContainsIgnoredKeys(Keys keys) + /// Is undo history being collected? + /// + public bool IsUndoCollection { - return ignoredKeys.Contains((int)keys); + get + { + return SPerform(2019, 0, 0) != 0; + } + set + { + SPerform(2012, (uint)(value ? 1 : 0), 0); + } } - /// - /// Duplicate the selection. - /// If selection empty duplicate the line containing the caret. - /// - public void SelectionDuplicate() - { - SPerform(2469, 0, 0); - } - - /// - /// Can the caret preferred x position only be changed by explicit movement commands? - /// - public bool GetCaretSticky() - { - return SPerform(2457, 0, 0) != 0; - } - - /// - /// Stop the caret preferred x position changing when the user types. - /// - public void SetCaretSticky(bool useSetting) - { - SPerform(2458, (uint)(useSetting ? 1 : 0), 0); - } - - /// - /// Switch between sticky and non-sticky: meant to be bound to a key. - /// - public void ToggleCaretSticky() - { - SPerform(2459, 0, 0); - } - - - /// - /// Retrieve the fold level of a line. - /// - public int GetFoldLevel(int line) - { - return (int)SPerform(2223, (uint)line, 0); - } - - /// - /// Set the fold level of a line. - /// This encodes an integer level along with flags indicating whether the - /// line is a header and whether it is effectively white space. - /// - public void SetFoldLevel(int line, int level) - { - SPerform(2222, (uint)line, (uint)level); - } - - /// - /// Find the last child line of a header line. - /// - public int LastChild(int line, int level) - { - return (int)SPerform(2224, (uint)line, (uint)level); - } - - /// - /// Find the last child line of a header line. - /// - public int LastChild(int line) - { - return (int)SPerform(2224, (uint)line, 0); - } - - /// - /// Find the parent line of a child line. - /// - public int FoldParent(int line) - { - return (int)SPerform(2225, (uint)line, 0); - } - - /// - /// Is a header line expanded? - /// - public bool FoldExpanded(int line) - { - return SPerform(2230, (uint)line, 0) != 0; - } - - /// - /// Show the children of a header line. - /// - public void FoldExpanded(int line, bool expanded) - { - SPerform(2229, (uint)line, (uint)(expanded ? 1 : 0)); - } - - /// - /// Clear all the styles and make equivalent to the global default style. - /// - public void StyleClearAll() - { - SPerform(2050, 0, 0); - } - - /// - /// Set the foreground colour of a style. - /// - public void StyleSetFore(int style, int fore) - { - SPerform(2051, (uint)style, (uint)fore); - } - - /// - /// Set the background colour of a style. - /// - public void StyleSetBack(int style, int back) - { - SPerform(2052, (uint)style, (uint)back); - } - - /// - /// Set a style to be bold or not. - /// - public void StyleSetBold(int style, bool bold) - { - SPerform(2053, (uint)style, (uint)(bold ? 1 : 0)); - } - - /// - /// Set a style to be italic or not. - /// - public void StyleSetItalic(int style, bool italic) - { - SPerform(2054, (uint)style, (uint)(italic ? 1 : 0)); - } - - /// - /// Set the size of characters of a style. - /// - public void StyleSetSize(int style, int sizePoints) - { - SPerform(2055, (uint)style, (uint)sizePoints); - } - - /// - /// Set the font of a style. - /// - unsafe public void StyleSetFont(int style, string fontName) - { - if (fontName == null || fontName.Equals("")) fontName = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(fontName)) - { - SPerform(2056,(uint)style, (uint)b ); - } - } - - /// - /// Set a style to have its end of line filled or not. - /// - public void StyleSetEOLFilled(int style, bool filled) - { - SPerform(2057, (uint)style, (uint)(filled ? 1 : 0)); - } - - /// - /// Set a style to be underlined or not. - /// - public void StyleSetUnderline(int style, bool underline ) - { - SPerform(2059, (uint)style, (uint)(underline?1:0) ); - } - - /// - /// Set a style to be mixed case, or to force upper or lower case. - /// - public void StyleSetCase(int style, int caseForce) - { - SPerform(2060, (uint)style, (uint)caseForce); - } - - /// - /// Set the character set of the font in a style. - /// - public void StyleSetCharacterSet(int style, int characterSet ) - { - SPerform(2066, (uint)style, (uint)characterSet); - } - - /// - /// Set a style to be a hotspot or not. - /// - public void StyleSetHotSpot(int style, bool hotspot) - { - SPerform(2409, (uint)style, (uint)(hotspot ? 1 : 0)); - } - - /// - /// Set a style to be visible or not. - /// - public void StyleSetVisible(int style, bool visible) - { - SPerform(2074, (uint)style, (uint)(visible ? 1 : 0)); - } - - /// - /// Set the set of characters making up words for when moving or selecting by word. - /// First sets deaults like SetCharsDefault. - /// - unsafe public void WordChars(string characters) - { - if (characters == null || characters.Equals("")) characters = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characters)) - { - SPerform(2077, 0, (uint)b); - } - } - - /// - /// Set a style to be changeable or not (read only). - /// Experimental feature, currently buggy. - /// - public void StyleSetChangeable(int style, bool changeable ) - { - SPerform(2099, (uint)style, (uint)(changeable?1:0) ); - } - - /// - /// Define a set of characters that when typed will cause the autocompletion to - /// choose the selected item. - /// - unsafe public void AutoCSetFillUps(string characterSet ) - { - if (characterSet == null || characterSet.Equals("")) characterSet = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characterSet)) - { - SPerform(2112, 0, (uint)b); - } - } - - /// - /// Enable / Disable underlining active hotspots. - /// - public void HotspotActiveUnderline(bool useSetting) - { - SPerform(2412, (uint)(useSetting ? 1 : 0), 0); - } - - /// - /// Limit hotspots to single line so hotspots on two lines don't merge. - /// - public void HotspotSingleLine(bool useSetting) - { - SPerform(2421, (uint)(useSetting ? 1 : 0), 0); - } - - /// - /// Set a fore colour for active hotspots. - /// - public void HotspotActiveFore(bool useSetting, int fore) - { - SPerform(2410, (uint)(useSetting ? 1 : 0), (uint)fore); - } - - /// - /// Set a back colour for active hotspots. - /// - public void HotspotActiveBack(bool useSetting, int back) - { - SPerform(2411, (uint)(useSetting ? 1 : 0), (uint)back); - } - - /// - /// Retrieve the number of bits the current lexer needs for styling. - /// - public int GetStyleBitsNeeded() - { - return (int)SPerform(4011, 0, 0); - } - - /// - /// Set up a value that may be used by a lexer for some optional feature. - /// - unsafe public void SetProperty(string key, string val) - { - if (key == null || key.Equals("")) key = "\0\0"; - if (val == null || val.Equals("")) val = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(val)) - { - fixed (byte* b2 = Encoding.GetEncoding(this.CodePage).GetBytes(key)) - { - SPerform(4004, (uint)b2, (uint)b); - } - } - } - - /// - /// Retrieve a "property" value previously set with SetProperty, - /// interpreted as an int AFTER any "$()" variable replacement. - /// - unsafe public int GetPropertyInt(string key) - { - if (key == null || key.Equals("")) key = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(key)) - { - return (int)SPerform(4010, (uint)b, 0); - } - } - - /// - /// Set up the key words used by the lexer. - /// - unsafe public void KeyWords(int keywordSet, string keyWords) - { - if (keyWords == null || keyWords.Equals("")) keyWords = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(keyWords)) - { - SPerform(4005, (uint)keywordSet, (uint)b); - } - } - - /// - /// Set the lexing language of the document based on string name. - /// - unsafe public void LexerLanguage(string language) - { - if (language == null || language.Equals("")) language = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(language)) - { - SPerform(4006, 0, (uint)b); - } - } - - /// - /// Retrieve the extra styling information for a line. - /// - public int GetLineState(int line) - { - return (int)SPerform(2093,(uint)line, 0); - } - - /// - /// Used to hold extra styling information for each line. - /// - public void SetLineState(int line, int state) - { - SPerform(2092, (uint)line, (uint)state); - } - - /// - /// Retrieve the number of columns that a line is indented. - /// - public int GetLineIndentation(int line) - { - return (int)SPerform(2127, (uint)line, 0); - } - - /// - /// Change the indentation of a line to a number of columns. - /// - public void SetLineIndentation(int line, int indentSize) - { - SPerform(2126, (uint)line, (uint)indentSize); - } - - /// - /// Retrieve the position before the first non indentation character on a line. - /// - public int LineIndentPosition(int line) - { - return (int)SPerform(2128, (uint)line, 0); - } - - /// - /// Retrieve the column number of a position, taking tab width into account. - /// - public int Column(int pos) - { - return (int)SPerform(2129, (uint)pos, 0); - } - - /// - /// Get the position after the last visible characters on a line. - /// - public int LineEndPosition(int line) - { - return (int)SPerform(2136, (uint)line, 0); - } - - /// - /// Returns the character byte at the position. - /// - public int CharAt(int pos) - { - return (int)SPerform(2007, (uint)pos, 0); - } - - /// - /// Returns the style byte at the position. - /// - public int StyleAt(int pos) - { - return (int)SPerform(2010, (uint)pos, 0); - } - - /// - /// Retrieve the type of a margin. - /// - public int GetMarginTypeN(int margin) - { - return (int)SPerform(2241, (uint)margin, 0); - } - - /// - /// Set a margin to be either numeric or symbolic. - /// - public void SetMarginTypeN(int margin, int marginType) - { - SPerform(2240, (uint)margin, (uint)marginType); - } - - /// - /// Retrieve the width of a margin in pixels. - /// - public int GetMarginWidthN(int margin) - { - return (int)SPerform(2243,(uint)margin, 0); - } - - /// - /// Set the width of a margin to a width expressed in pixels. - /// - public void SetMarginWidthN(int margin, int pixelWidth) - { - SPerform(2242, (uint)margin, (uint)pixelWidth); - } - - /// - /// Retrieve the marker mask of a margin. - /// - public int GetMarginMaskN(int margin) - { - return (int)SPerform(2245, (uint)margin, 0); - } - - /// - /// Set a mask that determines which markers are displayed in a margin. - /// - public void SetMarginMaskN(int margin, int mask) - { - SPerform(2244, (uint)margin, (uint)mask); - } - - /// - /// Retrieve the mouse click sensitivity of a margin. - /// - public bool MarginSensitiveN(int margin) - { - return SPerform(2247, (uint)margin, 0) != 0; - } - - /// - /// Make a margin sensitive or insensitive to mouse clicks. - /// - public void MarginSensitiveN(int margin, bool sensitive) - { - SPerform(2246, (uint)margin, (uint)(sensitive ? 1 : 0)); - } - - /// - /// Retrieve the style of an indicator. - /// - public int GetIndicStyle(int indic) - { - return (int)SPerform(2081, (uint)indic, 0); - } - - /// - /// Set an indicator to plain, squiggle or TT. - /// - public void SetIndicStyle(int indic, int style) - { - SPerform(2080, (uint)indic , (uint)style); - } - - /// - /// Retrieve the foreground colour of an indicator. - /// - public int GetIndicFore(int indic) - { - return (int)SPerform(2083,(uint)indic, 0); - } - - /// - /// Set the foreground colour of an indicator. - /// - public void SetIndicFore(int indic, int fore) - { - SPerform(2082, (uint)indic, (uint)fore); - } - - /// - /// Add text to the document at current position. - /// - unsafe public void AddText(int length, string text ) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2001,(uint)length, (uint)b); - } - } - - /// - /// Insert string at a position. - /// - unsafe public void InsertText(int pos, string text ) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2003, (uint)pos, (uint)b); - } - } - - /// - /// Convert all line endings in the document to one mode. - /// - public void ConvertEOLs(Enums.EndOfLine eolMode) - { - ConvertEOLs((int)eolMode); - } - - /// - /// Set the symbol used for a particular marker number. - /// - public void MarkerDefine(int markerNumber, Enums.MarkerSymbol markerSymbol) - { - MarkerDefine(markerNumber, (int)markerSymbol); - } - - /// - /// Set the character set of the font in a style. - /// - public void StyleSetCharacterSet(int style, Enums.CharacterSet characterSet) - { - StyleSetCharacterSet(style, (int)characterSet); - } - - /// - /// Set a style to be mixed case, or to force upper or lower case. - /// - public void StyleSetCase(int style, Enums.CaseVisible caseForce) - { - StyleSetCase(style, (int)caseForce); - } - - /// - /// Delete all text in the document. - /// - public void ClearAll() - { - SPerform(2004, 0, 0); - } - - /// - /// Set all style bytes to 0, remove all folding information. - /// - public void ClearDocumentStyle() - { - SPerform(2005, 0, 0); - } - - /// - /// Redoes the next action on the undo history. - /// - public void Redo() - { - SPerform(2011, 0, 0); - } - - /// - /// Select all the text in the document. - /// - public void SelectAll() - { - SPerform(2013, 0, 0); - } - - /// - /// Remember the current position in the undo history as the position - /// at which the document was saved. - /// - public void SetSavePoint() - { - SPerform(2014, 0, 0); - } - - /// - /// Retrieve the line number at which a particular marker is located. - /// - public int MarkerLineFromHandle(int handle) - { - return (int)SPerform(2017, (uint)handle, 0); - } - - /// - /// Delete a marker. - /// - public void MarkerDeleteHandle(int handle) - { - SPerform(2018, (uint)handle, 0); - } - - /// - /// Find the position from a point within the window. - /// - public int PositionFromPoint(int x, int y) - { - return (int)SPerform(2022, (uint)x, (uint)y); - } - - /// - /// Find the position from a point within the window but return - /// INVALID_POSITION if not close to text. - /// - public int PositionFromPointClose(int x, int y) - { - return (int)SPerform(2023, (uint)x, (uint)y); - } - - /// - /// Set caret to start of a line and ensure it is visible. - /// - public void GotoLine(int line) - { - SPerform(2024, (uint)line, 0); - } - - /// - /// Set caret to a position and ensure it is visible. - /// - public void GotoPos(int pos) - { - SPerform(2025, (uint)pos, 0); - } - - /// - /// Retrieve the text of the line containing the caret. - /// Returns the index of the caret on the line. - /// - unsafe public string GetCurLine(int length) - { - int sz = (int)SPerform(2027, (uint)length, 0); - byte[] buffer = new byte[sz+1]; - fixed (byte* b = buffer) SPerform(2027, (uint)length+1, (uint)b); - return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz-1); - } - - /// - /// Convert all line endings in the document to one mode. - /// - public void ConvertEOLs(int eolMode) - { - SPerform(2029, (uint)eolMode, 0); - } - - /// - /// Set the current styling position to pos and the styling mask to mask. - /// The styling mask can be used to protect some bits in each styling byte from modification. - /// - public void StartStyling(int pos, int mask) - { - SPerform(2032, (uint)pos, (uint)mask); - } - - /// - /// Change style from current styling position for length characters to a style - /// and move the current styling position to after this newly styled segment. - /// - public void SetStyling(int length, int style) - { - SPerform(2033, (uint)length, (uint)style); - } - - /// - /// Set the symbol used for a particular marker number. - /// - public void MarkerDefine(int markerNumber, int markerSymbol) - { - SPerform(2040, (uint)markerNumber, (uint)markerSymbol); - } - - /// - /// Set the foreground colour used for a particular marker number. - /// - public void MarkerSetFore(int markerNumber, int fore) - { - SPerform(2041, (uint)markerNumber, (uint)fore); - } - - /// - /// Set the background colour used for a particular marker number. - /// - public void MarkerSetBack(int markerNumber, int back) - { - SPerform(2042, (uint)markerNumber, (uint)back); - } - - /// - /// Add a marker to a line, returning an ID which can be used to find or delete the marker. - /// - public int MarkerAdd(int line, int markerNumber) - { - return (int)SPerform(2043, (uint)line, (uint)markerNumber); - } - - /// - /// Delete a marker from a line. - /// - public void MarkerDelete(int line, int markerNumber) - { - SPerform(2044, (uint)line, (uint)markerNumber); - } - - /// - /// Delete all markers with a particular number from all lines. - /// - public void MarkerDeleteAll(int markerNumber) - { - SPerform(2045, (uint)markerNumber, 0); - } - - /// - /// Get a bit mask of all the markers set on a line. - /// - public int MarkerGet(int line) - { - return (int)SPerform(2046, (uint)line, 0); - } - - /// - /// Find the next line after lineStart that includes a marker in mask. - /// - public int MarkerNext(int lineStart, int markerMask) - { - return (int)SPerform(2047, (uint)lineStart, (uint)markerMask); - } - - /// - /// Find the previous line before lineStart that includes a marker in mask. - /// - public int MarkerPrevious(int lineStart, int markerMask) - { - return (int)SPerform(2048, (uint)lineStart, (uint)markerMask); - } - - /// - /// Define a marker from a pixmap. - /// - unsafe public void MarkerDefinePixmap(int markerNumber, string pixmap ) - { - if (pixmap == null || pixmap.Equals("")) pixmap = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(pixmap)) - { - SPerform(2049, (uint)markerNumber, (uint)b); - } - } - - /// - /// Reset the default style to its state at startup - /// - public void StyleResetDefault() - { - SPerform(2058, 0, 0); - } - - /// - /// Set the foreground colour of the selection and whether to use this setting. - /// - public void SetSelFore(bool useSetting, int fore) - { - SPerform(2067,(uint)(useSetting ? 1 : 0), (uint)fore); - } - - /// - /// Set the background colour of the selection and whether to use this setting. - /// - public void SetSelBack(bool useSetting, int back) - { - SPerform(2068, (uint)(useSetting ? 1 : 0), (uint)back); - } - - /// - /// When key+modifier combination km is pressed perform msg. - /// - public void AssignCmdKey(int km, int msg) - { - SPerform(2070, (uint)km, (uint)msg); - } - - /// - /// When key+modifier combination km is pressed do nothing. - /// - public void ClearCmdKey(int km) - { - SPerform(2071, (uint)km, 0); - } - - /// - /// Drop all key mappings. - /// - public void ClearAllCmdKeys() - { - SPerform(2072, 0, 0); - } - - /// - /// Set the styles for a segment of the document. - /// - unsafe public void SetStylingEx(int length, string styles) - { - if (styles == null || styles.Equals("")) styles = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(styles)) - { - SPerform(2073,(uint)length, (uint)b); - } - } - - /// - /// Start a sequence of actions that is undone and redone as a unit. - /// May be nested. - /// - public void BeginUndoAction() - { - SPerform(2078, 0, 0); - } - - /// - /// End a sequence of actions that is undone and redone as a unit. - /// - public void EndUndoAction() - { - SPerform(2079, 0, 0); - } - - /// - /// Set the foreground colour of all whitespace and whether to use this setting. - /// - public void SetWhitespaceFore(bool useSetting, int fore) - { - SPerform(2084, (uint)(useSetting ? 1 : 0), (uint)fore); - } - - /// - /// Set the background colour of all whitespace and whether to use this setting. - /// - public void SetWhitespaceBack(bool useSetting, int back) - { - SPerform(2085, (uint)(useSetting ? 1 : 0), (uint)back); - } - - /// - /// Display a auto-completion list. - /// The lenEntered parameter indicates how many characters before - /// the caret should be used to provide context. - /// - unsafe public void AutoCShow(int lenEntered, string itemList) - { - if (itemList == null || itemList.Equals("")) itemList = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(itemList)) - { - SPerform(2100, (uint)lenEntered, (uint)b); - } - } - - /// - /// Remove the auto-completion list from the screen. - /// - public void AutoCCancel() - { - SPerform(2101, 0, 0); - } - - /// - /// User has selected an item so remove the list and insert the selection. - /// - public void AutoCComplete() - { - SPerform(2104, 0, 0); - } - - /// - /// Define a set of character that when typed cancel the auto-completion list. - /// - unsafe public void AutoCStops(string characterSet) - { - if (characterSet == null || characterSet.Equals("")) characterSet = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characterSet)) - { - SPerform(2105, 0, (uint)b); - } - } - - /// - /// Select the item in the auto-completion list that starts with a string. - /// - unsafe public void AutoCSelect(string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2108, 0, (uint)b); - } - } - - /// - /// Display a list of strings and send notification when user chooses one. - /// - unsafe public void UserListShow(int listType, string itemList) - { - if (itemList == null || itemList.Equals("")) itemList = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(itemList)) - { - SPerform(2117, (uint)listType, (uint)b); - } - } - - /// - /// Register an XPM image for use in autocompletion lists. - /// - unsafe public void RegisterImage(int type, string xpmData) - { - if (xpmData == null || xpmData.Equals("")) xpmData = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(xpmData)) - { - SPerform(2405,(uint)type, (uint)b); - } - } - - /// - /// Clear all the registered XPM images. - /// - public void ClearRegisteredImages() - { - SPerform(2408, 0, 0); - } - - /// - /// Retrieve the contents of a line. - /// - unsafe public string GetLine(int line) - { - try - { - int sz = (int)SPerform(2153, (uint)line, 0); - byte[] buffer = new byte[sz + 1]; - fixed (byte* b = buffer) SPerform(2153, (uint)line, (uint)b); - if (buffer[sz - 1] == 10) sz--; - return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz); - } - catch - { - return ""; - } - } - - /// - /// Select a range of text. - /// - public void SetSel(int start, int end) - { - SPerform(2160, (uint)start, (uint)end); - } - - /// - /// Retrieve the selected text. - /// Return the length of the text. - /// - unsafe public string SelText - { - get - { - int sz = (int)SPerform(2161,0 ,0); - byte[] buffer = new byte[sz+1]; - fixed (byte* b = buffer) - { - SPerform(2161, (UInt32)sz + 1, (uint)b); - } - return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz-1); - } - } - - /// - /// Draw the selection in normal style or with selection highlighted. - /// - public void HideSelection(bool normal) - { - SPerform(2163, (uint)(normal ? 1 : 0), 0); - } - - /// - /// Retrieve the x value of the point in the window where a position is displayed. - /// - public int PointXFromPosition(int pos) - { - return (int) SPerform(2164, 0, (uint)pos); - } - - /// - /// Retrieve the y value of the point in the window where a position is displayed. - /// - public int PointYFromPosition(int pos) - { - return (int) SPerform(2165, 0, (uint)pos); - } - - /// - /// Retrieve the line containing a position. - /// - public int LineFromPosition(int pos) - { - return (int) SPerform(2166, (uint)pos, 0); - } - - /// - /// Retrieve the position at the start of a line. - /// - public int PositionFromLine(int line) - { - return (int) SPerform(2167, (uint)line, 0); - } - - /// - /// Retrieve the text from line before position - /// - public String GetLineUntilPosition(int pos) + /// + /// Are white space characters currently visible? + /// Returns one of SCWS_/// constants. + /// + public int ViewWS { - int curLine = LineFromPosition(pos); - int curPosInLine = pos - PositionFromLine(curLine); - String line = GetLine(curLine); - int length = MBSafeLengthFromBytes(line, curPosInLine); - String lineUntilPos = line.Substring(0, length); - return lineUntilPos; + get + { + return (int)SPerform(2020, 0, 0); + } + set + { + SPerform(2021, (uint)value, 0); + } } - - /// - /// Scroll horizontally and vertically. - /// - public void LineScroll(int columns, int lines) - { - SPerform(2168, (uint)columns, (uint)lines); - } - - /// - /// Ensure the caret is visible. - /// - public void ScrollCaret() - { - SPerform(2169, 0, 0); - } - - /// - /// Replace the selected text with the argument text. - /// - unsafe public void ReplaceSel(string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2170,0 , (uint)b); - } - } - - /// - /// Null operation. - /// - public void Null() - { - SPerform(2172, 0, 0); - } - - /// - /// Delete the undo history. - /// - public void EmptyUndoBuffer() - { - SPerform(2175, 0, 0); - } - - /// - /// Undo one action in the undo history. - /// - public void Undo() - { - SPerform(2176, 0, 0); - } - - /// - /// Cut the selection to the clipboard. - /// - public void Cut() - { - SPerform(2177, 0, 0); - } - - /// - /// Copy the selection to the clipboard. - /// - public void Copy() - { - SPerform(2178, 0, 0); - // Invoke UI update after copy... - if (UpdateUI != null) UpdateUI(this); - } /// - /// Copy the selection to the clipboard as RTF. + /// Retrieve the position of the last correctly styled character. /// - public void CopyRTF() + public int EndStyled { - Language language = ScintillaControl.Configuration.GetLanguage(this.configLanguage); - String conversion = RTF.GetConversion(language, this, this.SelectionStart, this.SelectionEnd); - Clipboard.SetText(conversion, TextDataFormat.Rtf); + get + { + return (int)SPerform(2028, 0, 0); + } } - - /// - /// Paste the contents of the clipboard into the document replacing the selection. - /// - public void Paste() - { - SPerform(2179, 0, 0); - } - - /// - /// Clear the selection. - /// - public void Clear() - { - SPerform(2180, 0, 0); - } - - /// - /// Replace the contents of the document with the argument text. - /// - unsafe public void SetText(string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2181, 0, (uint)b); - } - } - - /// - /// Retrieve all the text in the document. Returns number of characters retrieved. - /// - unsafe public string GetText(int length) - { - int sz = (int)SPerform(2182, (uint)length, 0); - byte[] buffer = new byte[sz+1]; - fixed (byte* b = buffer)SPerform(2182, (uint)length+1, (uint)b); - return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz-1); - } - - /// - /// Replace the target text with the argument text. - /// Text is counted so it can contain NULs. - /// Returns the length of the replacement text. - /// - unsafe public int ReplaceTarget(int length, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int)SPerform(2194, (uint)length, (uint)b); - } - } - - /// - /// Replace the target text with the argument text after \d processing. - /// Text is counted so it can contain NULs. - /// Looks for \d where d is between 1 and 9 and replaces these with the strings - /// matched in the last search operation which were surrounded by \( and \). - /// Returns the length of the replacement text including any change - /// caused by processing the \d patterns. - /// - unsafe public int ReplaceTargetRE(int length, string text ) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int) SPerform(2195, (uint)length, (uint)b); - } - } - - /// - /// Search for a counted string in the target and set the target to the found - /// range. Text is counted so it can contain NULs. - /// Returns length of range or -1 for failure in which case target is not moved. - /// - unsafe public int SearchInTarget(int length, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int) SPerform(2197, (uint)length, (uint)b); - } - } - - /// - /// Show a call tip containing a definition near position pos. - /// - unsafe public void CallTipShow(int pos, string definition) - { - if (definition == null || definition.Equals("")) definition = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(definition)) - { - SPerform(2200, (uint)pos, (uint)b); - } - } - - /// - /// Remove the call tip from the screen. - /// - public void CallTipCancel() - { - SPerform(2201, 0, 0); - } - - /// - /// Highlight a segment of the definition. - /// - public void CallTipSetHlt(int start, int end) - { - SPerform(2204, (uint)start, (uint)end); - } - - /// - /// Set the background colour for the call tip. - /// - public void CallTipSetBack(int color) - { - SPerform(2205, (uint)color, 0); - } - - /// - /// Set the foreground colour for the call tip. - /// - public void CallTipSetFore(int color) - { - SPerform(2206, (uint)color, 0); - } - - /// - /// Set the foreground colour for the highlighted part of the call tip. - /// - public void CallTipSetForeHlt(int color) - { - SPerform(2207, (uint)color, 0); - } - - /// - /// Find the display line of a document line taking hidden lines into account. - /// - public int VisibleFromDocLine(int line) - { - return (int)SPerform(2220, (uint)line, 0); - } - - /// - /// Find the document line of a display line taking hidden lines into account. - /// - public int DocLineFromVisible(int lineDisplay) - { - return (int)SPerform(2221, (uint)lineDisplay, 0); - } - - /// - /// Make a range of lines visible. - /// - public void ShowLines(int lineStart, int lineEnd) - { - SPerform(2226, (uint)lineStart, (uint)lineEnd); - } - - /// - /// Make a range of lines invisible. - /// - public void HideLines(int lineStart, int lineEnd) - { - SPerform(2227, (uint)lineStart, (uint)lineEnd); - } - - /// - /// Switch a header line between expanded and contracted. - /// - public void ToggleFold(int line) - { - SPerform(2231, (uint)line, 0); - } - - /// - /// Ensure a particular line is visible by expanding any header line hiding it. - /// - public void EnsureVisible(int line) - { - SPerform(2232, (uint)line, 0); - } - - /// - /// Set some style options for folding. - /// - public void SetFoldFlags(int flags) - { - SPerform(2233, (uint)flags, 0); - } - - /// - /// Ensure a particular line is visible by expanding any header line hiding it. - /// Use the currently set visibility policy to determine which range to display. - /// - public void EnsureVisibleEnforcePolicy(int line) - { - SPerform(2234, (uint)line, 0); - } - - /// - /// Get position of start of word. - /// - public int WordStartPosition(int pos, bool onlyWordCharacters) - { - return (int)SPerform(2266, (uint)pos, (uint)(onlyWordCharacters ? 1 : 0)); - } - - /// - /// Get position of end of word. - /// - public int WordEndPosition(int pos, bool onlyWordCharacters) - { - return (int)SPerform(2267, (uint)pos, (uint)(onlyWordCharacters ? 1 : 0)); - } - - /// - /// Measure the pixel width of some text in a particular style. - /// NUL terminated text argument. - /// Does not handle tab or control characters. - /// - unsafe public int TextWidth(int style, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int)SPerform(2276, (uint)style, (uint)b); - } - } - - /// - /// Retrieve the height of a particular line of text in pixels. - /// - public int TextHeight(int line) - { - return (int) SPerform(2279, (uint)line, 0); - } - - /// - /// Append a string to the end of the document without changing the selection. - /// - unsafe public void AppendText(int length, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2282, (uint)length, (uint)b); - } - } - - /// - /// Make the target range start and end be the same as the selection range start and end. - /// - public void TargetFromSelection() - { - SPerform(2287, 0, 0); - } - - /// - /// Join the lines in the target. - /// - public void LinesJoin() - { - SPerform(2288, 0, 0); - } - - /// - /// Split the lines in the target into lines that are less wide than pixelWidth - /// where possible. - /// - public void LinesSplit(int pixelWidth) - { - SPerform(2289, (uint)pixelWidth, 0); - } - - /// - /// Set the colours used as a chequerboard pattern in the fold margin - /// - public void SetFoldMarginColour(bool useSetting, int back) - { - SPerform(2290,(uint)(useSetting ? 1 : 0), (uint)back); - } - - /// - /// Set the colours used as a chequerboard pattern in the fold margin - /// - public void SetFoldMarginHiColour(bool useSetting, int fore) - { - SPerform(2291,(uint)(useSetting ? 1 : 0), (uint)fore); - } - - /// - /// Move caret down one line. - /// - public void LineDown() - { - SPerform(2300, 0, 0); - } - - /// - /// Move caret down one line extending selection to new caret position. - /// - public void LineDownExtend() - { - SPerform(2301, 0, 0); - } - - /// - /// Move caret up one line. - /// - public void LineUp() - { - SPerform(2302, 0, 0); - } - - /// - /// Move caret up one line extending selection to new caret position. - /// - public void LineUpExtend() - { - SPerform(2303, 0, 0); - } - - /// - /// Move caret left one character. - /// - public void CharLeft() - { - SPerform(2304, 0, 0); - } - - /// - /// Move caret left one character extending selection to new caret position. - /// - public void CharLeftExtend() - { - SPerform(2305, 0, 0); - } - - /// - /// Move caret right one character. - /// - public void CharRight() - { - SPerform(2306, 0, 0); - } - - /// - /// Move caret right one character extending selection to new caret position. - /// - public void CharRightExtend() - { - SPerform(2307, 0, 0); - } - - /// - /// Move caret left one word. - /// - public void WordLeft() - { - SPerform(2308, 0, 0); - } - - /// - /// Move caret left one word extending selection to new caret position. - /// - public void WordLeftExtend() - { - SPerform(2309, 0, 0); - } - - /// - /// Move caret right one word. - /// - public void WordRight() - { - SPerform(2310, 0, 0); - } - - /// - /// Move caret right one word extending selection to new caret position. - /// - public void WordRightExtend() - { - SPerform(2311, 0, 0); - } - - /// - /// Move caret to first position on line. - /// - public void Home() - { - SPerform(2312, 0, 0); - } - - /// - /// Move caret to first position on line extending selection to new caret position. - /// - public void HomeExtend() - { - SPerform(2313, 0, 0); - } - - /// - /// Move caret to last position on line. - /// - public void LineEnd() - { - SPerform(2314, 0, 0); - } - - /// - /// Move caret to last position on line extending selection to new caret position. - /// - public void LineEndExtend() - { - SPerform(2315, 0, 0); - } - - /// - /// Move caret to first position in document. - /// - public void DocumentStart() - { - SPerform(2316, 0, 0); - } - - /// - /// Move caret to first position in document extending selection to new caret position. - /// - public void DocumentStartExtend() - { - SPerform(2317, 0, 0); - } - - /// - /// Move caret to last position in document. - /// - public void DocumentEnd() - { - SPerform(2318, 0, 0); - } - - /// - /// Move caret to last position in document extending selection to new caret position. - /// - public void DocumentEndExtend() - { - SPerform(2319, 0, 0); - } - - /// - /// Move caret one page up. - /// - public void PageUp() - { - SPerform(2320, 0, 0); - } - - /// - /// Move caret one page up extending selection to new caret position. - /// - public void PageUpExtend() - { - SPerform(2321, 0, 0); - } - - /// - /// Move caret one page down. - /// - public void PageDown() - { - SPerform(2322, 0, 0); - } - - /// - /// Move caret one page down extending selection to new caret position. - /// - public void PageDownExtend() - { - SPerform(2323, 0, 0); - } - - /// - /// Switch from insert to overtype mode or the reverse. - /// - public void EditToggleOvertype() - { - SPerform(2324, 0, 0); - } - - /// - /// Cancel any modes such as call tip or auto-completion list display. - /// - public void Cancel() - { - SPerform(2325, 0, 0); - } - - /// - /// Delete the selection or if no selection, the character before the caret. - /// - public void DeleteBack() - { - SPerform(2326, 0, 0); - } /// - /// Delete the character after the caret. + /// Retrieve the current end of line mode - one of CRLF, CR, or LF. /// - public void DeleteForward() + public int EOLMode { - SetSel(CurrentPos + 1, CurrentPos + 1); - DeleteBack(); + get + { + return (int)SPerform(2030, 0, 0); + } + set + { + SPerform(2031, (uint)value, 0); + } } - - /// - /// If selection is empty or all on one line replace the selection with a tab character. - /// If more than one line selected, indent the lines. - /// - public void Tab() - { - SPerform(2327, 0, 0); - } - - /// - /// Dedent the selected lines. - /// - public void BackTab() - { - SPerform(2328, 0, 0); - } - - /// - /// Insert a new line, may use a CRLF, CR or LF depending on EOL mode. - /// - public void NewLine() - { - SPerform(2329, 0, 0); - } - - /// - /// Insert a Form Feed character. - /// - public void FormFeed() - { - SPerform(2330, 0, 0); - } - - /// - /// Move caret to before first visible character on line. - /// If already there move to first character on line. - /// - public void VCHome() - { - SPerform(2331, 0, 0); - } - - /// - /// Like VCHome but extending selection to new caret position. - /// - public void VCHomeExtend() - { - SPerform(2332, 0, 0); - } - - /// - /// Magnify the displayed text by increasing the sizes by 1 point. - /// - public void ZoomIn() - { - SPerform(2333, 0, 0); - } - - /// - /// Make the displayed text smaller by decreasing the sizes by 1 point. - /// - public void ZoomOut() - { - SPerform(2334, 0, 0); - } - + /// - /// Reset the text zooming by setting zoom level to 0. + /// Is drawing done first into a buffer or direct to the screen? /// - public void ResetZoom() + public bool IsBufferedDraw { - SPerform(2373, 0, 0); + get + { + return SPerform(2034, 0, 0) != 0; + } + set + { + SPerform(2035, (uint)(value ? 1 : 0), 0); + } } - /// - /// Delete the word to the left of the caret. - /// - public void DelWordLeft() - { - SPerform(2335, 0, 0); - } - - /// - /// Delete the word to the right of the caret. - /// - public void DelWordRight() - { - SPerform(2336, 0, 0); - } - - /// - /// Cut the line containing the caret. - /// - public void LineCut() - { - SPerform(2337, 0, 0); - } - - /// - /// Delete the line containing the caret. - /// - public void LineDelete() - { - SPerform(2338, 0, 0); - } - - /// - /// Switch the current line with the previous. - /// - public void LineTranspose() - { - SPerform(2339, 0, 0); - } - - /// - /// Duplicate the current line. - /// - public void LineDuplicate() - { - SPerform(2404, 0, 0); - } - - /// - /// Transform the selection to lower case. - /// - public void LowerCase() - { - SPerform(2340, 0, 0); - } - - /// - /// Transform the selection to upper case. - /// - public void UpperCase() - { - SPerform(2341, 0, 0); - } - - /// - /// Scroll the document down, keeping the caret visible. - /// - public void LineScrollDown() - { - SPerform(2342, 0, 0); - } - - /// - /// Scroll the document up, keeping the caret visible. - /// - public void LineScrollUp() - { - SPerform(2343, 0, 0); - } - - /// - /// Delete the selection or if no selection, the character before the caret. - /// Will not delete the character before at the start of a line. - /// - public void DeleteBackNotLine() - { - SPerform(2344, 0, 0); - } - - /// - /// Move caret to first position on display line. - /// - public void HomeDisplay() - { - SPerform(2345, 0, 0); - } - - /// - /// Move caret to first position on display line extending selection to - /// new caret position. - /// - public void HomeDisplayExtend() - { - SPerform(2346, 0, 0); - } - - /// - /// Move caret to last position on display line. - /// - public void LineEndDisplay() - { - SPerform(2347, 0, 0); - } - - /// - /// Move caret to last position on display line extending selection to new - /// caret position. - /// - public void LineEndDisplayExtend() - { - SPerform(2348, 0, 0); - } - - /// - /// - public void HomeWrap() - { - SPerform(2349, 0, 0); - } - - /// - /// - public void HomeWrapExtend() - { - SPerform(2450, 0, 0); - } - - /// - /// - public void LineEndWrap() - { - SPerform(2451, 0, 0); - } - - /// - /// - public void LineEndWrapExtend() - { - SPerform(2452, 0, 0); - } - - /// - /// - public void VCHomeWrap() - { - SPerform(2453, 0, 0); - } - - /// - /// - public void VCHomeWrapExtend() - { - SPerform(2454, 0, 0); - } - - /// - /// Copy the line containing the caret. - /// - public void LineCopy() - { - SPerform(2455, 0, 0); - } - - /// - /// Move the caret inside current view if it's not there already. - /// - public void MoveCaretInsideView() - { - SPerform(2401, 0, 0); - } - - /// - /// How many characters are on a line, not including end of line characters? - /// - public int LineLength(int line) - { - return (int)SPerform(2350, (uint)line, 0); - } - - /// - /// Highlight the characters at two positions. - /// - public void BraceHighlight(int pos1, int pos2) - { - SPerform(2351, (uint)pos1, (uint)pos2); - } - - /// - /// Highlight the character at a position indicating there is no matching brace. - /// - public void BraceBadLight(int pos) - { - SPerform(2352, (uint)pos, 0); - } - - /// - /// Find the position of a matching brace or INVALID_POSITION if no match. - /// - public int BraceMatch(int pos) - { - return (int)SPerform(2353, (uint)pos, 0); - } - - /// - /// Sets the current caret position to be the search anchor. - /// - public void SearchAnchor() - { - SPerform(2366, 0, 0); - } - - /// - /// Find some text starting at the search anchor. - /// Does not ensure the selection is visible. - /// - unsafe public int SearchNext(int flags, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int)SPerform(2367, (uint)flags, (uint)b); - } - } - - /// - /// Find some text starting at the search anchor and moving backwards. - /// Does not ensure the selection is visible. - /// - unsafe public int SearchPrev(int flags, string text) - { - if (text == null || text.Equals("")) text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - return (int)SPerform(2368,(uint)flags, (uint)b); - } - } - - /// - /// Set whether a pop up menu is displayed automatically when the user presses - /// the wrong mouse button. - /// - public void UsePopUp(bool allowPopUp) - { - SPerform(2371, (uint)(allowPopUp ? 1 : 0), 0); - } - - /// - /// Create a new document object. - /// Starts with reference count of 1 and not selected into editor. - /// Extend life of document. - /// - public void AddRefDocument(int doc) - { - SPerform(2376, 0, (uint)doc ); - } - - /// - /// Release a reference to the document, deleting document if it fades to black. - /// - public void ReleaseDocument(int doc) - { - SPerform(2377, 0, (uint)doc ); - } - - /// - /// Move to the previous change in capitalisation. - /// - public void WordPartLeft() - { - SPerform(2390, 0, 0); - } - - /// - /// Move to the previous change in capitalisation extending selection - /// to new caret position. - /// - public void WordPartLeftExtend() - { - SPerform(2391, 0, 0); - } - - /// - /// Move to the change next in capitalisation. - /// - public void WordPartRight() - { - SPerform(2392, 0, 0); - } - - /// - /// Move to the next change in capitalisation extending selection - /// to new caret position. - /// - public void WordPartRightExtend() - { - SPerform(2393, 0, 0); - } - - /// - /// Constants for use with SetVisiblePolicy, similar to SetCaretPolicy. - /// Set the way the display area is determined when a particular line - /// is to be moved to by Find, FindNext, GotoLine, etc. - /// - public void SetVisiblePolicy(int visiblePolicy, int visibleSlop) - { - SPerform(2394, (uint)visiblePolicy, (uint)visibleSlop); - } - - /// - /// Delete back from the current position to the start of the line. - /// - public void DelLineLeft() - { - SPerform(2395, 0, 0); - } - - /// - /// Delete forwards from the current position to the end of the line. - /// - public void DelLineRight() - { - SPerform(2396, 0, 0); - } - - /// - /// Set the last x chosen value to be the caret x position. - /// - public void ChooseCaretX() - { - SPerform(2399, 0, 0); - } - - /// - /// Set the focus to this Scintilla widget. - /// GTK+ Specific. - /// - public void GrabFocus() - { - SPerform(2400, 0, 0); - } - - /// - /// Set the way the caret is kept visible when going sideway. - /// The exclusion zone is given in pixels. - /// - public void SetXCaretPolicy(int caretPolicy, int caretSlop) - { - SPerform(2402, (uint)caretPolicy, (uint)caretSlop); - } - - /// - /// Set the way the line the caret is on is kept visible. - /// The exclusion zone is given in lines. - /// - public void SetYCaretPolicy(int caretPolicy, int caretSlop) - { - SPerform(2403, (uint)caretPolicy, (uint)caretSlop); - } - - /// - /// Move caret between paragraphs (delimited by empty lines). - /// - public void ParaDown() - { - SPerform(2413, 0, 0); - } - - /// - /// Move caret between paragraphs (delimited by empty lines). - /// - public void ParaDownExtend() - { - SPerform(2414, 0, 0); - } - - /// - /// Move caret between paragraphs (delimited by empty lines). - /// - public void ParaUp() - { - SPerform(2415, 0, 0); - } - - /// - /// Move caret between paragraphs (delimited by empty lines). - /// - public void ParaUpExtend() - { - SPerform(2416, 0, 0); - } - - /// - /// Given a valid document position, return the previous position taking code - /// page into account. Returns 0 if passed 0. - /// - public int PositionBefore(int pos) - { - return (int)SPerform(2417, (uint)pos, 0); - } - - /// - /// Given a valid document position, return the next position taking code - /// page into account. Maximum value returned is the last position in the document. - /// - public int PositionAfter(int pos) - { - return (int)SPerform(2418, (uint)pos, 0); - } - - /// - /// Copy a range of text to the clipboard. Positions are clipped into the document. - /// - public void CopyRange(int start, int end) - { - SPerform(2419, (uint)start, (uint)end); - } - - /// - /// Copy argument text to the clipboard. - /// - unsafe public void CopyText(int length, string text) - { - if (text == null || text.Equals(""))text = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) - { - SPerform(2420,(uint)length, (uint)b); - } - } - - /// - /// Retrieve the position of the start of the selection at the given line (INVALID_POSITION if no selection on this line). - /// - public int GetLineSelStartPosition(int line) - { - return (int)SPerform(2424, (uint)line, 0); - } - - /// - /// Retrieve the position of the end of the selection at the given line (INVALID_POSITION if no selection on this line). - /// - public int GetLineSelEndPosition(int line) - { - return (int)SPerform(2425, (uint)line, 0); - } - - /// - /// Move caret down one line, extending rectangular selection to new caret position. - /// - public void LineDownRectExtend() - { - SPerform(2426, 0, 0); - } - - /// - /// Move caret up one line, extending rectangular selection to new caret position. - /// - public void LineUpRectExtend() - { - SPerform(2427, 0, 0); - } - - /// - /// Move caret left one character, extending rectangular selection to new caret position. - /// - public void CharLeftRectExtend() - { - SPerform(2428, 0, 0); - } - - /// - /// Move caret right one character, extending rectangular selection to new caret position. - /// - public void CharRightRectExtend() - { - SPerform(2429, 0, 0); - } - - /// - /// Move caret to first position on line, extending rectangular selection to new caret position. - /// - public void HomeRectExtend() - { - SPerform(2430, 0, 0); - } - - /// - /// Move caret to before first visible character on line. - /// If already there move to first character on line. - /// In either case, extend rectangular selection to new caret position. - /// - public void VCHomeRectExtend() - { - SPerform(2431, 0, 0); - } - - /// - /// Move caret to last position on line, extending rectangular selection to new caret position. - /// - public void LineEndRectExtend() - { - SPerform(2432, 0, 0); - } - - /// - /// Move caret one page up, extending rectangular selection to new caret position. - /// - public void PageUpRectExtend() - { - SPerform(2433, 0, 0); - } - - /// - /// Move caret one page down, extending rectangular selection to new caret position. - /// - public void PageDownRectExtend() - { - SPerform(2434, 0, 0); - } - - /// - /// Move caret to top of page, or one page up if already at top of page. - /// - public void StutteredPageUp() - { - SPerform(2435, 0, 0); - } - - /// - /// Move caret to top of page, or one page up if already at top of page, extending selection to new caret position. - /// - public void StutteredPageUpExtend() - { - SPerform(2436, 0, 0); - } - - /// - /// Move caret to bottom of page, or one page down if already at bottom of page. - /// - public void StutteredPageDown() - { - SPerform(2437, 0, 0); - } - - /// - /// Move caret to bottom of page, or one page down if already at bottom of page, extending selection to new caret position. - /// - public void StutteredPageDownExtend() - { - SPerform(2438, 0, 0); - } - - /// - /// Move caret left one word, position cursor at end of word. - /// - public void WordLeftEnd() - { - SPerform(2439, 0, 0); - } - - /// - /// Move caret left one word, position cursor at end of word, extending selection to new caret position. - /// - public void WordLeftEndExtend() - { - SPerform(2440, 0, 0); - } - - /// - /// Move caret right one word, position cursor at end of word. - /// - public void WordRightEnd() - { - SPerform(2441, 0, 0); - } - - /// - /// Move caret right one word, position cursor at end of word, extending selection to new caret position. - /// - public void WordRightEndExtend() - { - SPerform(2442, 0, 0); - } - /// - /// Set the set of characters making up whitespace for when moving or selecting by word. Should be called after WordChars. + /// Retrieve the visible size of a tab. /// - unsafe public void WhitespaceChars(string characters) + public int TabWidth { - if (characters == null || characters.Equals("")) characters = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characters)) + get { - SPerform(2443, 0, (uint)b); + return (int)SPerform(2121, 0, 0); + } + set + { + SPerform(2036, (uint)value, 0); } } - - /// - /// Reset the set of characters for whitespace and word characters to the defaults. - /// - public void SetCharsDefault() - { - SPerform(2444, 0, 0); - } - - /// - /// Enlarge the document to a particular size of text bytes. - /// - public void Allocate(int bytes) - { - SPerform(2446, (uint)bytes, 0); - } - - /// - /// Start notifying the container of all key presses and commands. - /// - public void StartRecord() - { - SPerform(3001, 0, 0); - } - - /// - /// Stop notifying the container of all key presses and commands. - /// - public void StopRecord() - { - SPerform(3002, 0, 0); - } - - /// - /// Colourise a segment of the document using the current lexing language. - /// - public void Colourise(int start, int end) - { - SPerform(4003, (uint)start, (uint)end); - } - - /// - /// Load a lexer library (dll / so). - /// - unsafe public void LoadLexerLibrary(string path) - { - if (path == null || path.Equals("")) path = "\0\0"; - fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(path)) - { - SPerform(4007, 0, (uint)b); - } - } /// - /// Find the position of a column on a line taking into account tabs and - /// multi-byte characters. If beyond end of line, return line end position. + /// Get the time in milliseconds that the caret is on and off. /// - public int FindColumn(int line, int column) + public int CaretPeriod { - return (int)SPerform(2456, (uint)line, (uint)column); + get + { + return (int)SPerform(2075, 0, 0); + } + set + { + SPerform(2076, (uint)value, 0); + } } /// - /// Turn a indicator on over a range. + /// Retrieve number of bits in style bytes used to hold the lexical state. + /// + public int StyleBits + { + get + { + return (int)SPerform(2091, 0, 0); + } + set + { + SPerform(2090, (uint)value, 0); + } + } + + /// + /// Retrieve the last line number that has line state. + /// + public int MaxLineState + { + get + { + return (int)SPerform(2094, 0, 0); + } + } + + /// + /// Is the background of the line containing the caret in a different colour? + /// + public bool IsCaretLineVisible + { + get + { + return SPerform(2095, 0, 0) != 0; + } + set + { + SPerform(2096, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Get the colour of the background of the line containing the caret. + /// + public int CaretLineBack + { + get + { + return (int)SPerform(2097, 0, 0); + } + set + { + SPerform(2098, (uint)value, 0); + } + } + + /// + /// Retrieve the auto-completion list separator character. + /// + public int AutoCSeparator + { + get + { + return (int)SPerform(2107, 0, 0); + } + set + { + SPerform(2106, (uint)value, 0); + } + } + + /// + /// Retrieve whether auto-completion cancelled by backspacing before start. + /// + public bool IsAutoCGetCancelAtStart + { + get + { + return SPerform(2111, 0, 0) != 0; + } + set + { + SPerform(2110, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve whether a single item auto-completion list automatically choose the item. + /// + public bool IsAutoCGetChooseSingle + { + get + { + return SPerform(2114, 0, 0) != 0; + } + set + { + SPerform(2113, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve state of ignore case flag. + /// + public bool IsAutoCGetIgnoreCase + { + get + { + return SPerform(2116, 0, 0) != 0; + } + set + { + SPerform(2115, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve whether or not autocompletion is hidden automatically when nothing matches. + /// + public bool IsAutoCGetAutoHide + { + get + { + return SPerform(2119, 0, 0) != 0; + } + set + { + SPerform(2118, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve whether or not autocompletion deletes any word characters + /// after the inserted text upon completion. + /// + public bool IsAutoCGetDropRestOfWord + { + get + { + return SPerform(2271, 0, 0) != 0; + } + set + { + SPerform(2270, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve the auto-completion list type-separator character. + /// + public int AutoCTypeSeparator + { + get + { + return (int)SPerform(2285, 0, 0); + } + set + { + SPerform(2286, (uint)value, 0); + } + } + + /// + /// Retrieve indentation size. + /// + public int Indent + { + get + { + return (int)SPerform(2123, 0, 0); + } + set + { + SPerform(2122, (uint)value, 0); + } + } + + /// + /// Retrieve whether tabs will be used in indentation. + /// + public bool IsUseTabs + { + get + { + return SPerform(2125, 0, 0) != 0; + } + set + { + SPerform(2124, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Is the horizontal scroll bar visible? + /// + public bool IsHScrollBar + { + get + { + return SPerform(2131, 0, 0) != 0; + } + set + { + SPerform(2130, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Are the indentation guides visible? + /// + public bool IsIndentationGuides + { + get + { + return SPerform(2133, 0, 0) != 0; + } + set + { + SPerform(2132, (uint)(value ? (int)this.indentView : 0), 0); + } + } + + /// + /// Get the highlighted indentation guide column. + /// + public int HighlightGuide + { + get + { + return (int)SPerform(2135, 0, 0); + } + set + { + SPerform(2134, (uint)value, 0); + } + } + + /// + /// Get the code page used to interpret the bytes of the document as characters. + /// + public int CodePage + { + get + { + return (int)SPerform(2137, 0, 0); + } + set + { + SPerform(2037, (uint)value, 0); + } + } + + /// + /// Get the foreground colour of the caret. + /// + public int CaretFore + { + get + { + return (int)SPerform(2138, 0, 0); + } + set + { + SPerform(2069, (uint)value, 0); + } + } + + /// + /// In palette mode? + /// + public bool IsUsePalette + { + get + { + return SPerform(2139, 0, 0) != 0; + } + set + { + SPerform(2039, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// In read-only mode? + /// + public bool IsReadOnly + { + get + { + return SPerform(2140, 0, 0) != 0; + } + set + { + SPerform(2171, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Returns the position at the start of the selection. + /// + public int SelectionStart + { + get + { + return (int)SPerform(2143, 0, 0); + } + set + { + SPerform(2142, (uint)value, 0); + } + } + + /// + /// Returns the position at the end of the selection. + /// + public int SelectionEnd + { + get + { + return (int)SPerform(2145, 0, 0); + } + set + { + SPerform(2144, (uint)value, 0); + } + } + + /// + /// Returns true if the selection extends over more than one line. + /// + public bool IsSelectionMultiline + { + get + { + return LineFromPosition(SelectionStart) != LineFromPosition(SelectionEnd); + } + } + + /// + /// Returns the print magnification. + /// + public int PrintMagnification + { + get + { + return (int)SPerform(2147, 0, 0); + } + set + { + SPerform(2146, (uint)value, 0); + } + } + + /// + /// Returns the print colour mode. + /// + public int PrintColourMode + { + get + { + return (int)SPerform(2149, 0, 0); + } + set + { + SPerform(2148, (uint)value, 0); + } + } + + /// + /// Retrieve the display line at the top of the display. + /// + public int FirstVisibleLine + { + get + { + return (int)SPerform(2152, 0, 0); + } + } + + /// + /// Returns the number of lines in the document. There is always at least one. + /// + public int LineCount + { + get + { + return (int)SPerform(2154, 0, 0); + } + } + + /// + /// Returns the size in pixels of the left margin. + /// + public int MarginLeft + { + get + { + return (int)SPerform(2156, 0, 0); + } + set + { + SPerform(2155, 0, (uint)value); + } + } + + /// + /// Returns the size in pixels of the right margin. + /// + public int MarginRight + { + get + { + return (int)SPerform(2158, 0, 0); + } + set + { + SPerform(2157, 0, (uint)value); + } + } + + /// + /// Is the document different from when it was last saved? + /// + public bool IsModify + { + get + { + return SPerform(2159, 0, 0) != 0; + } + } + + /// + /// Retrieve the number of characters in the document. + /// + public int TextLength + { + get + { + return (int)SPerform(2183, 0, 0); + } + } + + /// + /// Retrieve a pointer to a function that processes messages for this Scintilla. + /// + public int DirectFunction + { + get + { + return (int)SPerform(2184, 0, 0); + } + } + + /// + /// Retrieve a pointer value to use as the first argument when calling + /// the function returned by GetDirectFunction. + /// + public IntPtr DirectPointer + { + get + { + if (directPointer == IntPtr.Zero) + directPointer = SendMessage(Handle, 2185, 0, 0); + return directPointer; + } + } + + /// + /// Returns true if overtype mode is active otherwise false is returned. + /// + public bool IsOvertype + { + get + { + return SPerform(2187, 0, 0) != 0; + } + set + { + SPerform(2186, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Returns the width of the insert mode caret. + /// + public int CaretWidth + { + get + { + return (int)SPerform(2189, 0, 0); + } + set + { + SPerform(2188, (uint)value, 0); + } + } + + /// + /// Get the position that starts the target. + /// + public int TargetStart + { + get + { + return (int)SPerform(2191, 0, 0); + } + set + { + SPerform(2190, (uint)value, 0); + } + } + + /// + /// Get the position that ends the target. + /// + public int TargetEnd + { + get + { + return (int)SPerform(2193, 0, 0); + } + set + { + SPerform(2192, (uint)value, 0); + } + } + + /// + /// Get the search flags used by SearchInTarget. + /// + public int SearchFlags + { + get + { + return (int)SPerform(2199, 0, 0); + } + set + { + SPerform(2198, (uint)value, 0); + } + } + + /// + /// Is a line visible? + /// + public bool IsLineVisible + { + get + { + return SPerform(2228, 0, 0) != 0; + } + } + + /// + /// Does a tab pressed when caret is within indentation indent? + /// + public bool IsTabIndents + { + get + { + return SPerform(2261, 0, 0) != 0; + } + set + { + SPerform(2260, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Does a backspace pressed when caret is within indentation unindent? + /// + public bool IsBackSpaceUnIndents + { + get + { + return SPerform(2263, 0, 0) != 0; + } + set + { + SPerform(2262, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve the time the mouse must sit still to generate a mouse dwell event. + /// + public int MouseDwellTime + { + get + { + return (int)SPerform(2265, 0, 0); + } + set + { + SPerform(2264, (uint)value, 0); + } + } + + /// + /// Retrieve whether text is word wrapped. + /// + public int WrapMode + { + get + { + return (int)SPerform(2269, 0, 0); + } + set + { + SPerform(2268, (uint)value, 0); + } + } + + /// + /// Retrive the display mode of visual flags for wrapped lines. + /// + public int WrapVisualFlags + { + get + { + return (int)SPerform(2461, 0, 0); + } + set + { + SPerform(2460, (uint)value, 0); + } + } + + /// + /// Retrive the location of visual flags for wrapped lines. + /// + public int WrapVisualFlagsLocation + { + get + { + return (int)SPerform(2463, 0, 0); + } + set + { + SPerform(2462, (uint)value, 0); + } + } + + /// + /// Retrive the start indent for wrapped lines. + /// + public int WrapStartIndent + { + get + { + return (int)SPerform(2465, 0, 0); + } + set + { + SPerform(2464, (uint)value, 0); + } + } + + /// + /// Retrieve the degree of caching of layout information. + /// + public int LayoutCache + { + get + { + return (int)SPerform(2273, 0, 0); + } + set + { + SPerform(2272, (uint)value, 0); + } + } + + /// + /// Retrieve the document width assumed for scrolling. + /// + public int ScrollWidth + { + get + { + return (int)SPerform(2275, 0, 0); + } + set + { + SPerform(2274, (uint)value, 0); + } + } + + /// + /// Retrieve whether the maximum scroll position has the last + /// line at the bottom of the view. + /// + public int EndAtLastLine + { + get + { + return (int)SPerform(2278, 0, 0); + } + set + { + SPerform(2277, (uint)value, 0); + } + } + + /// + /// Is the vertical scroll bar visible? + /// + public bool IsVScrollBar + { + get + { + return SPerform(2281, 0, 0) != 0; + } + set + { + SPerform(2280, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Is drawing done in two phases with backgrounds drawn before faoregrounds? + /// + public bool IsTwoPhaseDraw + { + get + { + return SPerform(2283, 0, 0) != 0; + } + set + { + SPerform(2284, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Are the end of line characters visible? + /// + public bool IsViewEOL + { + get + { + return SPerform(2355, 0, 0) != 0; + } + set + { + SPerform(2356, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Retrieve a pointer to the document object. + /// + public int DocPointer + { + get + { + return (int)SPerform(2357, 0, 0); + } + set + { + SPerform(2358, 0, (uint)value); + } + } + + /// + /// Retrieve the column number which text should be kept within. + /// + public int EdgeColumn + { + get + { + return (int)SPerform(2360, 0, 0); + } + set + { + SPerform(2361, (uint)value, 0); + } + } + + /// + /// Retrieve the edge highlight mode. + /// + public int EdgeMode + { + get + { + return (int)SPerform(2362, 0, 0); + } + set + { + SPerform(2363, (uint)value, 0); + } + } + + /// + /// Retrieve the colour used in edge indication. + /// + public int EdgeColour + { + get + { + return (int)SPerform(2364, 0, 0); + } + set + { + SPerform(2365, (uint)value, 0); + } + } + + /// + /// Retrieves the number of lines completely visible. + /// + public int LinesOnScreen + { + get + { + return (int)SPerform(2370, 0, 0); + } + } + + /// + /// Is the selection rectangular? The alternative is the more common stream selection. + /// + public bool IsSelectionRectangle + { + get + { + return SPerform(2372, 0, 0) != 0; + } + } + + /// + /// Set the zoom level. This number of points is added to the size of all fonts. + /// It may be positive to magnify or negative to reduce. Retrieve the zoom level. + /// + public int ZoomLevel + { + get + { + return (int)SPerform(2374, 0, 0); + } + set + { + SPerform(2373, (uint)value, 0); + } + } + + /// + /// Get which document modification events are sent to the container. + /// + public int ModEventMask + { + get + { + return (int)SPerform(2378, 0, 0); + } + set + { + SPerform(2359, (uint)value, 0); + } + } + + /// + /// Change internal focus flag. Get internal focus flag. + /// + public bool IsFocus + { + get + { + return SPerform(2381, 0, 0) != 0; + } + set + { + SPerform(2380, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Change error status - 0 = OK. Get error status. + /// + public int Status + { + get + { + return (int)SPerform(2383, 0, 0); + } + set + { + SPerform(2382, (uint)value, 0); + } + } + + /// + /// Set whether the mouse is captured when its button is pressed. Get whether mouse gets captured. + /// + public bool IsMouseDownCaptures + { + get + { + return SPerform(2385, 0, 0) != 0; + } + set + { + SPerform(2384, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Sets the cursor to one of the SC_CURSOR/// values. Get cursor type. + /// + public int CursorType + { + get + { + return (int)SPerform(2387, 0, 0); + } + set + { + SPerform(2386, (uint)value, 0); + } + } + + /// + /// Change the way control characters are displayed: + /// If symbol is < 32, keep the drawn way, else, use the given character. + /// Get the way control characters are displayed. + /// + public int ControlCharSymbol + { + get + { + return (int)SPerform(2389, 0, 0); + } + set + { + SPerform(2388, (uint)value, 0); + } + } + + /// + /// Get and Set the xOffset (ie, horizonal scroll position). + /// + public int XOffset + { + get + { + return (int)SPerform(2398, 0, 0); + } + set + { + SPerform(2397, (uint)value, 0); + } + } + + /// + /// Is printing line wrapped? + /// + public int PrintWrapMode + { + get + { + return (int)SPerform(2407, 0, 0); + } + set + { + SPerform(2406, (uint)value, 0); + } + } + + /// + /// Get the mode of the current selection. + /// + public int SelectionMode + { + get + { + return (int)SPerform(2423, 0, 0); + } + set + { + SPerform(2422, (uint)value, 0); + } + } + + /// + /// Retrieve the lexing language of the document. + /// + public int Lexer + { + get + { + return (int)SPerform(4002, 0, 0); + } + set + { + SPerform(4001, (uint)value, 0); + } + } + + /// + /// Gets the EOL marker + /// + public string NewLineMarker + { + get + { + if (EOLMode == 1) return "\r"; + else if (EOLMode == 2) return "\n"; + else return "\r\n"; + } + } + + /// + /// Compact the document buffer and return a read-only pointer to the characters in the document. + /// + public int CharacterPointer + { + get + { + return (int)SPerform(2520, 0, 0); + } + } + + /// + /// Always interpret keyboard input as Unicode + /// + public bool UnicodeKeys + { + get + { + return SPerform(2522, 0, 0) != 0; + } + set + { + SPerform(2521, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Set extra ascent for each line + /// + public int ExtraAscent + { + get + { + return (int)SPerform(2526, 0, 0); + } + set + { + SPerform(2525, (uint)value, 0); + } + } + + /// + /// Set extra descent for each line + /// + public int ExtraDescent + { + get + { + return (int)SPerform(2528, 0, 0); + } + set + { + SPerform(2527, (uint)value, 0); + } + } + + /// + /// Get the start of the range of style numbers used for margin text + /// + public int MarginStyleOffset + { + get + { + return (int)SPerform(2538, 0, 0); + } + set + { + SPerform(2537, (uint)value, 0); + } + } + + /// + /// Get the start of the range of style numbers used for annotations + /// + public int AnnotationStyleOffset + { + get + { + return (int)SPerform(2551, 0, 0); + } + set + { + SPerform(2550, (uint)value, 0); + } + } + + /// + /// Get the start of the range of style numbers used for annotations + /// + public bool AnnotationVisible + { + get + { + return SPerform(2549, 0, 0) != 0; + } + set + { + SPerform(2548, (uint)(value ? 1 : 0), 0); + } + } + + /// + /// Sets whether the maximum width line displayed is used to set scroll width. + /// + public bool ScrollWidthTracking + { + get + { + return SPerform(2517, 0, 0) != 0; + } + set + { + SPerform(2516, (uint)(value ? 1 : 0), 0); + } + } + + #endregion + + #region Scintilla Methods + + /// + /// Adds a new keys to ignore + /// + public virtual void AddIgnoredKeys(Keys keys) + { + ignoredKeys.Add((int)keys); + } + + /// + /// Removes the ignored keys + /// + public virtual void RemoveIgnoredKeys(Keys keys) + { + ignoredKeys.Remove((int)keys); + } + + /// + /// Clears the ignored keys container + /// + public virtual void ClearIgnoredKeys() + { + ignoredKeys.Clear(); + } + + /// + /// Does the container have keys? + /// + public virtual bool ContainsIgnoredKeys(Keys keys) + { + return ignoredKeys.Contains((int)keys); + } + + /// + /// Duplicate the selection. + /// If selection empty duplicate the line containing the caret. + /// + public void SelectionDuplicate() + { + SPerform(2469, 0, 0); + } + + /// + /// Can the caret preferred x position only be changed by explicit movement commands? + /// + public bool GetCaretSticky() + { + return SPerform(2457, 0, 0) != 0; + } + + /// + /// Stop the caret preferred x position changing when the user types. + /// + public void SetCaretSticky(bool useSetting) + { + SPerform(2458, (uint)(useSetting ? 1 : 0), 0); + } + + /// + /// Switch between sticky and non-sticky: meant to be bound to a key. + /// + public void ToggleCaretSticky() + { + SPerform(2459, 0, 0); + } + + + /// + /// Retrieve the fold level of a line. + /// + public int GetFoldLevel(int line) + { + return (int)SPerform(2223, (uint)line, 0); + } + + /// + /// Set the fold level of a line. + /// This encodes an integer level along with flags indicating whether the + /// line is a header and whether it is effectively white space. + /// + public void SetFoldLevel(int line, int level) + { + SPerform(2222, (uint)line, (uint)level); + } + + /// + /// Find the last child line of a header line. + /// + public int LastChild(int line, int level) + { + return (int)SPerform(2224, (uint)line, (uint)level); + } + + /// + /// Find the last child line of a header line. + /// + public int LastChild(int line) + { + return (int)SPerform(2224, (uint)line, 0); + } + + /// + /// Find the parent line of a child line. + /// + public int FoldParent(int line) + { + return (int)SPerform(2225, (uint)line, 0); + } + + /// + /// Is a header line expanded? + /// + public bool FoldExpanded(int line) + { + return SPerform(2230, (uint)line, 0) != 0; + } + + /// + /// Show the children of a header line. + /// + public void FoldExpanded(int line, bool expanded) + { + SPerform(2229, (uint)line, (uint)(expanded ? 1 : 0)); + } + + /// + /// Clear all the styles and make equivalent to the global default style. + /// + public void StyleClearAll() + { + SPerform(2050, 0, 0); + } + + /// + /// Set the foreground colour of a style. + /// + public void StyleSetFore(int style, int fore) + { + SPerform(2051, (uint)style, (uint)fore); + } + + /// + /// Set the background colour of a style. + /// + public void StyleSetBack(int style, int back) + { + SPerform(2052, (uint)style, (uint)back); + } + + /// + /// Set a style to be bold or not. + /// + public void StyleSetBold(int style, bool bold) + { + SPerform(2053, (uint)style, (uint)(bold ? 1 : 0)); + } + + /// + /// Set a style to be italic or not. + /// + public void StyleSetItalic(int style, bool italic) + { + SPerform(2054, (uint)style, (uint)(italic ? 1 : 0)); + } + + /// + /// Set the size of characters of a style. + /// + public void StyleSetSize(int style, int sizePoints) + { + SPerform(2055, (uint)style, (uint)sizePoints); + } + + /// + /// Set the font of a style. + /// + unsafe public void StyleSetFont(int style, string fontName) + { + if (fontName == null || fontName.Equals("")) fontName = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(fontName)) + { + SPerform(2056, (uint)style, (uint)b); + } + } + + /// + /// Set a style to have its end of line filled or not. + /// + public void StyleSetEOLFilled(int style, bool filled) + { + SPerform(2057, (uint)style, (uint)(filled ? 1 : 0)); + } + + /// + /// Set a style to be underlined or not. + /// + public void StyleSetUnderline(int style, bool underline) + { + SPerform(2059, (uint)style, (uint)(underline ? 1 : 0)); + } + + /// + /// Set a style to be mixed case, or to force upper or lower case. + /// + public void StyleSetCase(int style, int caseForce) + { + SPerform(2060, (uint)style, (uint)caseForce); + } + + /// + /// Set the character set of the font in a style. + /// + public void StyleSetCharacterSet(int style, int characterSet) + { + SPerform(2066, (uint)style, (uint)characterSet); + } + + /// + /// Set a style to be a hotspot or not. + /// + public void StyleSetHotSpot(int style, bool hotspot) + { + SPerform(2409, (uint)style, (uint)(hotspot ? 1 : 0)); + } + + /// + /// Set a style to be visible or not. + /// + public void StyleSetVisible(int style, bool visible) + { + SPerform(2074, (uint)style, (uint)(visible ? 1 : 0)); + } + + /// + /// Set the set of characters making up words for when moving or selecting by word. + /// First sets deaults like SetCharsDefault. + /// + unsafe public void WordChars(string characters) + { + if (characters == null || characters.Equals("")) characters = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characters)) + { + SPerform(2077, 0, (uint)b); + } + } + + /// + /// Set a style to be changeable or not (read only). + /// Experimental feature, currently buggy. + /// + public void StyleSetChangeable(int style, bool changeable) + { + SPerform(2099, (uint)style, (uint)(changeable ? 1 : 0)); + } + + /// + /// Define a set of characters that when typed will cause the autocompletion to + /// choose the selected item. + /// + unsafe public void AutoCSetFillUps(string characterSet) + { + if (characterSet == null || characterSet.Equals("")) characterSet = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characterSet)) + { + SPerform(2112, 0, (uint)b); + } + } + + /// + /// Enable / Disable underlining active hotspots. + /// + public void HotspotActiveUnderline(bool useSetting) + { + SPerform(2412, (uint)(useSetting ? 1 : 0), 0); + } + + /// + /// Limit hotspots to single line so hotspots on two lines don't merge. + /// + public void HotspotSingleLine(bool useSetting) + { + SPerform(2421, (uint)(useSetting ? 1 : 0), 0); + } + + /// + /// Set a fore colour for active hotspots. + /// + public void HotspotActiveFore(bool useSetting, int fore) + { + SPerform(2410, (uint)(useSetting ? 1 : 0), (uint)fore); + } + + /// + /// Set a back colour for active hotspots. + /// + public void HotspotActiveBack(bool useSetting, int back) + { + SPerform(2411, (uint)(useSetting ? 1 : 0), (uint)back); + } + + /// + /// Retrieve the number of bits the current lexer needs for styling. + /// + public int GetStyleBitsNeeded() + { + return (int)SPerform(4011, 0, 0); + } + + /// + /// Set up a value that may be used by a lexer for some optional feature. + /// + unsafe public void SetProperty(string key, string val) + { + if (key == null || key.Equals("")) key = "\0\0"; + if (val == null || val.Equals("")) val = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(val)) + { + fixed (byte* b2 = Encoding.GetEncoding(this.CodePage).GetBytes(key)) + { + SPerform(4004, (uint)b2, (uint)b); + } + } + } + + /// + /// Retrieve a "property" value previously set with SetProperty, + /// interpreted as an int AFTER any "$()" variable replacement. + /// + unsafe public int GetPropertyInt(string key) + { + if (key == null || key.Equals("")) key = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(key)) + { + return (int)SPerform(4010, (uint)b, 0); + } + } + + /// + /// Set up the key words used by the lexer. + /// + unsafe public void KeyWords(int keywordSet, string keyWords) + { + if (keyWords == null || keyWords.Equals("")) keyWords = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(keyWords)) + { + SPerform(4005, (uint)keywordSet, (uint)b); + } + } + + /// + /// Set the lexing language of the document based on string name. + /// + unsafe public void LexerLanguage(string language) + { + if (language == null || language.Equals("")) language = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(language)) + { + SPerform(4006, 0, (uint)b); + } + } + + /// + /// Retrieve the extra styling information for a line. + /// + public int GetLineState(int line) + { + return (int)SPerform(2093, (uint)line, 0); + } + + /// + /// Used to hold extra styling information for each line. + /// + public void SetLineState(int line, int state) + { + SPerform(2092, (uint)line, (uint)state); + } + + /// + /// Retrieve the number of columns that a line is indented. + /// + public int GetLineIndentation(int line) + { + return (int)SPerform(2127, (uint)line, 0); + } + + /// + /// Change the indentation of a line to a number of columns. + /// + public void SetLineIndentation(int line, int indentSize) + { + SPerform(2126, (uint)line, (uint)indentSize); + } + + /// + /// Retrieve the position before the first non indentation character on a line. + /// + public int LineIndentPosition(int line) + { + return (int)SPerform(2128, (uint)line, 0); + } + + /// + /// Retrieve the column number of a position, taking tab width into account. + /// + public int Column(int pos) + { + return (int)SPerform(2129, (uint)pos, 0); + } + + /// + /// Get the position after the last visible characters on a line. + /// + public int LineEndPosition(int line) + { + return (int)SPerform(2136, (uint)line, 0); + } + + /// + /// Returns the character byte at the position. + /// + public int CharAt(int pos) + { + return (int)SPerform(2007, (uint)pos, 0); + } + + /// + /// Returns the style byte at the position. + /// + public int StyleAt(int pos) + { + return (int)SPerform(2010, (uint)pos, 0); + } + + /// + /// Retrieve the type of a margin. + /// + public int GetMarginTypeN(int margin) + { + return (int)SPerform(2241, (uint)margin, 0); + } + + /// + /// Set a margin to be either numeric or symbolic. + /// + public void SetMarginTypeN(int margin, int marginType) + { + SPerform(2240, (uint)margin, (uint)marginType); + } + + /// + /// Retrieve the width of a margin in pixels. + /// + public int GetMarginWidthN(int margin) + { + return (int)SPerform(2243, (uint)margin, 0); + } + + /// + /// Set the width of a margin to a width expressed in pixels. + /// + public void SetMarginWidthN(int margin, int pixelWidth) + { + SPerform(2242, (uint)margin, (uint)pixelWidth); + } + + /// + /// Retrieve the marker mask of a margin. + /// + public int GetMarginMaskN(int margin) + { + return (int)SPerform(2245, (uint)margin, 0); + } + + /// + /// Set a mask that determines which markers are displayed in a margin. + /// + public void SetMarginMaskN(int margin, int mask) + { + SPerform(2244, (uint)margin, (uint)mask); + } + + /// + /// Retrieve the mouse click sensitivity of a margin. + /// + public bool MarginSensitiveN(int margin) + { + return SPerform(2247, (uint)margin, 0) != 0; + } + + /// + /// Make a margin sensitive or insensitive to mouse clicks. + /// + public void MarginSensitiveN(int margin, bool sensitive) + { + SPerform(2246, (uint)margin, (uint)(sensitive ? 1 : 0)); + } + + /// + /// Retrieve the style of an indicator. + /// + public int GetIndicStyle(int indic) + { + return (int)SPerform(2081, (uint)indic, 0); + } + + /// + /// Set an indicator to plain, squiggle or TT. + /// + public void SetIndicStyle(int indic, int style) + { + SPerform(2080, (uint)indic, (uint)style); + } + + /// + /// Retrieve the foreground colour of an indicator. + /// + public int GetIndicFore(int indic) + { + return (int)SPerform(2083, (uint)indic, 0); + } + + /// + /// Set the foreground colour of an indicator. + /// + public void SetIndicFore(int indic, int fore) + { + SPerform(2082, (uint)indic, (uint)fore); + } + + /// + /// Add text to the document at current position. + /// + unsafe public void AddText(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2001, (uint)length, (uint)b); + } + } + + /// + /// Insert string at a position. + /// + unsafe public void InsertText(int pos, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2003, (uint)pos, (uint)b); + } + } + + /// + /// Convert all line endings in the document to one mode. + /// + public void ConvertEOLs(Enums.EndOfLine eolMode) + { + ConvertEOLs((int)eolMode); + } + + /// + /// Set the symbol used for a particular marker number. + /// + public void MarkerDefine(int markerNumber, Enums.MarkerSymbol markerSymbol) + { + MarkerDefine(markerNumber, (int)markerSymbol); + } + + /// + /// Set the character set of the font in a style. + /// + public void StyleSetCharacterSet(int style, Enums.CharacterSet characterSet) + { + StyleSetCharacterSet(style, (int)characterSet); + } + + /// + /// Set a style to be mixed case, or to force upper or lower case. + /// + public void StyleSetCase(int style, Enums.CaseVisible caseForce) + { + StyleSetCase(style, (int)caseForce); + } + + /// + /// Delete all text in the document. + /// + public void ClearAll() + { + SPerform(2004, 0, 0); + } + + /// + /// Set all style bytes to 0, remove all folding information. + /// + public void ClearDocumentStyle() + { + SPerform(2005, 0, 0); + } + + /// + /// Redoes the next action on the undo history. + /// + public void Redo() + { + SPerform(2011, 0, 0); + } + + /// + /// Select all the text in the document. + /// + public void SelectAll() + { + SPerform(2013, 0, 0); + } + + /// + /// Remember the current position in the undo history as the position + /// at which the document was saved. + /// + public void SetSavePoint() + { + SPerform(2014, 0, 0); + } + + /// + /// Retrieve the line number at which a particular marker is located. + /// + public int MarkerLineFromHandle(int handle) + { + return (int)SPerform(2017, (uint)handle, 0); + } + + /// + /// Delete a marker. + /// + public void MarkerDeleteHandle(int handle) + { + SPerform(2018, (uint)handle, 0); + } + + /// + /// Find the position from a point within the window. + /// + public int PositionFromPoint(int x, int y) + { + return (int)SPerform(2022, (uint)x, (uint)y); + } + + /// + /// Find the position from a point within the window but return + /// INVALID_POSITION if not close to text. + /// + public int PositionFromPointClose(int x, int y) + { + return (int)SPerform(2023, (uint)x, (uint)y); + } + + /// + /// Set caret to start of a line and ensure it is visible. + /// + public void GotoLine(int line) + { + SPerform(2024, (uint)line, 0); + } + + /// + /// Set caret to a position and ensure it is visible. + /// + public void GotoPos(int pos) + { + SPerform(2025, (uint)pos, 0); + } + + /// + /// Retrieve the text of the line containing the caret. + /// Returns the index of the caret on the line. + /// + unsafe public string GetCurLine(int length) + { + int sz = (int)SPerform(2027, (uint)length, 0); + byte[] buffer = new byte[sz + 1]; + fixed (byte* b = buffer) SPerform(2027, (uint)length + 1, (uint)b); + return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz - 1); + } + + /// + /// Convert all line endings in the document to one mode. + /// + public void ConvertEOLs(int eolMode) + { + SPerform(2029, (uint)eolMode, 0); + } + + /// + /// Set the current styling position to pos and the styling mask to mask. + /// The styling mask can be used to protect some bits in each styling byte from modification. + /// + public void StartStyling(int pos, int mask) + { + SPerform(2032, (uint)pos, (uint)mask); + } + + /// + /// Change style from current styling position for length characters to a style + /// and move the current styling position to after this newly styled segment. + /// + public void SetStyling(int length, int style) + { + SPerform(2033, (uint)length, (uint)style); + } + + /// + /// Set the symbol used for a particular marker number. + /// + public void MarkerDefine(int markerNumber, int markerSymbol) + { + SPerform(2040, (uint)markerNumber, (uint)markerSymbol); + } + + /// + /// Set the foreground colour used for a particular marker number. + /// + public void MarkerSetFore(int markerNumber, int fore) + { + SPerform(2041, (uint)markerNumber, (uint)fore); + } + + /// + /// Set the background colour used for a particular marker number. + /// + public void MarkerSetBack(int markerNumber, int back) + { + SPerform(2042, (uint)markerNumber, (uint)back); + } + + /// + /// Add a marker to a line, returning an ID which can be used to find or delete the marker. + /// + public int MarkerAdd(int line, int markerNumber) + { + return (int)SPerform(2043, (uint)line, (uint)markerNumber); + } + + /// + /// Delete a marker from a line. + /// + public void MarkerDelete(int line, int markerNumber) + { + SPerform(2044, (uint)line, (uint)markerNumber); + } + + /// + /// Delete all markers with a particular number from all lines. + /// + public void MarkerDeleteAll(int markerNumber) + { + SPerform(2045, (uint)markerNumber, 0); + } + + /// + /// Get a bit mask of all the markers set on a line. + /// + public int MarkerGet(int line) + { + return (int)SPerform(2046, (uint)line, 0); + } + + /// + /// Find the next line after lineStart that includes a marker in mask. + /// + public int MarkerNext(int lineStart, int markerMask) + { + return (int)SPerform(2047, (uint)lineStart, (uint)markerMask); + } + + /// + /// Find the previous line before lineStart that includes a marker in mask. + /// + public int MarkerPrevious(int lineStart, int markerMask) + { + return (int)SPerform(2048, (uint)lineStart, (uint)markerMask); + } + + /// + /// Define a marker from a pixmap. + /// + unsafe public void MarkerDefinePixmap(int markerNumber, string pixmap) + { + if (pixmap == null || pixmap.Equals("")) pixmap = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(pixmap)) + { + SPerform(2049, (uint)markerNumber, (uint)b); + } + } + + /// + /// Reset the default style to its state at startup + /// + public void StyleResetDefault() + { + SPerform(2058, 0, 0); + } + + /// + /// Set the foreground colour of the selection and whether to use this setting. + /// + public void SetSelFore(bool useSetting, int fore) + { + SPerform(2067, (uint)(useSetting ? 1 : 0), (uint)fore); + } + + /// + /// Set the background colour of the selection and whether to use this setting. + /// + public void SetSelBack(bool useSetting, int back) + { + SPerform(2068, (uint)(useSetting ? 1 : 0), (uint)back); + } + + /// + /// When key+modifier combination km is pressed perform msg. + /// + public void AssignCmdKey(int km, int msg) + { + SPerform(2070, (uint)km, (uint)msg); + } + + /// + /// When key+modifier combination km is pressed do nothing. + /// + public void ClearCmdKey(int km) + { + SPerform(2071, (uint)km, 0); + } + + /// + /// Drop all key mappings. + /// + public void ClearAllCmdKeys() + { + SPerform(2072, 0, 0); + } + + /// + /// Set the styles for a segment of the document. + /// + unsafe public void SetStylingEx(int length, string styles) + { + if (styles == null || styles.Equals("")) styles = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(styles)) + { + SPerform(2073, (uint)length, (uint)b); + } + } + + /// + /// Start a sequence of actions that is undone and redone as a unit. + /// May be nested. + /// + public void BeginUndoAction() + { + SPerform(2078, 0, 0); + } + + /// + /// End a sequence of actions that is undone and redone as a unit. + /// + public void EndUndoAction() + { + SPerform(2079, 0, 0); + } + + /// + /// Set the foreground colour of all whitespace and whether to use this setting. + /// + public void SetWhitespaceFore(bool useSetting, int fore) + { + SPerform(2084, (uint)(useSetting ? 1 : 0), (uint)fore); + } + + /// + /// Set the background colour of all whitespace and whether to use this setting. + /// + public void SetWhitespaceBack(bool useSetting, int back) + { + SPerform(2085, (uint)(useSetting ? 1 : 0), (uint)back); + } + + /// + /// Display a auto-completion list. + /// The lenEntered parameter indicates how many characters before + /// the caret should be used to provide context. + /// + unsafe public void AutoCShow(int lenEntered, string itemList) + { + if (itemList == null || itemList.Equals("")) itemList = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(itemList)) + { + SPerform(2100, (uint)lenEntered, (uint)b); + } + } + + /// + /// Remove the auto-completion list from the screen. + /// + public void AutoCCancel() + { + SPerform(2101, 0, 0); + } + + /// + /// User has selected an item so remove the list and insert the selection. + /// + public void AutoCComplete() + { + SPerform(2104, 0, 0); + } + + /// + /// Define a set of character that when typed cancel the auto-completion list. + /// + unsafe public void AutoCStops(string characterSet) + { + if (characterSet == null || characterSet.Equals("")) characterSet = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characterSet)) + { + SPerform(2105, 0, (uint)b); + } + } + + /// + /// Select the item in the auto-completion list that starts with a string. + /// + unsafe public void AutoCSelect(string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2108, 0, (uint)b); + } + } + + /// + /// Display a list of strings and send notification when user chooses one. + /// + unsafe public void UserListShow(int listType, string itemList) + { + if (itemList == null || itemList.Equals("")) itemList = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(itemList)) + { + SPerform(2117, (uint)listType, (uint)b); + } + } + + /// + /// Register an XPM image for use in autocompletion lists. + /// + unsafe public void RegisterImage(int type, string xpmData) + { + if (xpmData == null || xpmData.Equals("")) xpmData = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(xpmData)) + { + SPerform(2405, (uint)type, (uint)b); + } + } + + /// + /// Clear all the registered XPM images. + /// + public void ClearRegisteredImages() + { + SPerform(2408, 0, 0); + } + + /// + /// Retrieve the contents of a line. + /// + unsafe public string GetLine(int line) + { + try + { + int sz = (int)SPerform(2153, (uint)line, 0); + byte[] buffer = new byte[sz + 1]; + fixed (byte* b = buffer) SPerform(2153, (uint)line, (uint)b); + if (buffer[sz - 1] == 10) sz--; + return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz); + } + catch + { + return ""; + } + } + + /// + /// Select a range of text. + /// + public void SetSel(int start, int end) + { + SPerform(2160, (uint)start, (uint)end); + } + + /// + /// Retrieve the selected text. + /// Return the length of the text. + /// + unsafe public string SelText + { + get + { + int sz = (int)SPerform(2161, 0, 0); + byte[] buffer = new byte[sz + 1]; + fixed (byte* b = buffer) + { + SPerform(2161, (UInt32)sz + 1, (uint)b); + } + return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz - 1); + } + } + + /// + /// Draw the selection in normal style or with selection highlighted. + /// + public void HideSelection(bool normal) + { + SPerform(2163, (uint)(normal ? 1 : 0), 0); + } + + /// + /// Retrieve the x value of the point in the window where a position is displayed. + /// + public int PointXFromPosition(int pos) + { + return (int)SPerform(2164, 0, (uint)pos); + } + + /// + /// Retrieve the y value of the point in the window where a position is displayed. + /// + public int PointYFromPosition(int pos) + { + return (int)SPerform(2165, 0, (uint)pos); + } + + /// + /// Retrieve the line containing a position. + /// + public int LineFromPosition(int pos) + { + return (int)SPerform(2166, (uint)pos, 0); + } + + /// + /// Retrieve the position at the start of a line. + /// + public int PositionFromLine(int line) + { + return (int)SPerform(2167, (uint)line, 0); + } + + /// + /// Retrieve the text from line before position + /// + public String GetLineUntilPosition(int pos) + { + int curLine = LineFromPosition(pos); + int curPosInLine = pos - PositionFromLine(curLine); + String line = GetLine(curLine); + int length = MBSafeLengthFromBytes(line, curPosInLine); + String lineUntilPos = line.Substring(0, length); + return lineUntilPos; + } + + /// + /// Scroll horizontally and vertically. + /// + public void LineScroll(int columns, int lines) + { + SPerform(2168, (uint)columns, (uint)lines); + } + + /// + /// Ensure the caret is visible. + /// + public void ScrollCaret() + { + SPerform(2169, 0, 0); + } + + /// + /// Replace the selected text with the argument text. + /// + unsafe public void ReplaceSel(string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2170, 0, (uint)b); + } + } + + /// + /// Null operation. + /// + public void Null() + { + SPerform(2172, 0, 0); + } + + /// + /// Delete the undo history. + /// + public void EmptyUndoBuffer() + { + SPerform(2175, 0, 0); + } + + /// + /// Undo one action in the undo history. + /// + public void Undo() + { + SPerform(2176, 0, 0); + } + + /// + /// Cut the selection to the clipboard. + /// + public void Cut() + { + SPerform(2177, 0, 0); + } + + /// + /// Copy the selection to the clipboard. + /// + public void Copy() + { + SPerform(2178, 0, 0); + // Invoke UI update after copy... + if (UpdateUI != null) UpdateUI(this); + } + + /// + /// Copy the selection to the clipboard as RTF. + /// + public void CopyRTF() + { + Language language = ScintillaControl.Configuration.GetLanguage(this.configLanguage); + String conversion = RTF.GetConversion(language, this, this.SelectionStart, this.SelectionEnd); + Clipboard.SetText(conversion, TextDataFormat.Rtf); + } + + /// + /// Paste the contents of the clipboard into the document replacing the selection. + /// + public void Paste() + { + SPerform(2179, 0, 0); + } + + /// + /// Clear the selection. + /// + public void Clear() + { + SPerform(2180, 0, 0); + } + + /// + /// Replace the contents of the document with the argument text. + /// + unsafe public void SetText(string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2181, 0, (uint)b); + } + } + + /// + /// Retrieve all the text in the document. Returns number of characters retrieved. + /// + unsafe public string GetText(int length) + { + int sz = (int)SPerform(2182, (uint)length, 0); + byte[] buffer = new byte[sz + 1]; + fixed (byte* b = buffer) SPerform(2182, (uint)length + 1, (uint)b); + return Encoding.GetEncoding(this.CodePage).GetString(buffer, 0, sz - 1); + } + + /// + /// Replace the target text with the argument text. + /// Text is counted so it can contain NULs. + /// Returns the length of the replacement text. + /// + unsafe public int ReplaceTarget(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2194, (uint)length, (uint)b); + } + } + + /// + /// Replace the target text with the argument text after \d processing. + /// Text is counted so it can contain NULs. + /// Looks for \d where d is between 1 and 9 and replaces these with the strings + /// matched in the last search operation which were surrounded by \( and \). + /// Returns the length of the replacement text including any change + /// caused by processing the \d patterns. + /// + unsafe public int ReplaceTargetRE(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2195, (uint)length, (uint)b); + } + } + + /// + /// Search for a counted string in the target and set the target to the found + /// range. Text is counted so it can contain NULs. + /// Returns length of range or -1 for failure in which case target is not moved. + /// + unsafe public int SearchInTarget(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2197, (uint)length, (uint)b); + } + } + + /// + /// Show a call tip containing a definition near position pos. + /// + unsafe public void CallTipShow(int pos, string definition) + { + if (definition == null || definition.Equals("")) definition = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(definition)) + { + SPerform(2200, (uint)pos, (uint)b); + } + } + + /// + /// Remove the call tip from the screen. + /// + public void CallTipCancel() + { + SPerform(2201, 0, 0); + } + + /// + /// Highlight a segment of the definition. + /// + public void CallTipSetHlt(int start, int end) + { + SPerform(2204, (uint)start, (uint)end); + } + + /// + /// Set the background colour for the call tip. + /// + public void CallTipSetBack(int color) + { + SPerform(2205, (uint)color, 0); + } + + /// + /// Set the foreground colour for the call tip. + /// + public void CallTipSetFore(int color) + { + SPerform(2206, (uint)color, 0); + } + + /// + /// Set the foreground colour for the highlighted part of the call tip. + /// + public void CallTipSetForeHlt(int color) + { + SPerform(2207, (uint)color, 0); + } + + /// + /// Find the display line of a document line taking hidden lines into account. + /// + public int VisibleFromDocLine(int line) + { + return (int)SPerform(2220, (uint)line, 0); + } + + /// + /// Find the document line of a display line taking hidden lines into account. + /// + public int DocLineFromVisible(int lineDisplay) + { + return (int)SPerform(2221, (uint)lineDisplay, 0); + } + + /// + /// Make a range of lines visible. + /// + public void ShowLines(int lineStart, int lineEnd) + { + SPerform(2226, (uint)lineStart, (uint)lineEnd); + } + + /// + /// Make a range of lines invisible. + /// + public void HideLines(int lineStart, int lineEnd) + { + SPerform(2227, (uint)lineStart, (uint)lineEnd); + } + + /// + /// Switch a header line between expanded and contracted. + /// + public void ToggleFold(int line) + { + SPerform(2231, (uint)line, 0); + } + + /// + /// Ensure a particular line is visible by expanding any header line hiding it. + /// + public void EnsureVisible(int line) + { + SPerform(2232, (uint)line, 0); + } + + /// + /// Set some style options for folding. + /// + public void SetFoldFlags(int flags) + { + SPerform(2233, (uint)flags, 0); + } + + /// + /// Ensure a particular line is visible by expanding any header line hiding it. + /// Use the currently set visibility policy to determine which range to display. + /// + public void EnsureVisibleEnforcePolicy(int line) + { + SPerform(2234, (uint)line, 0); + } + + /// + /// Get position of start of word. + /// + public int WordStartPosition(int pos, bool onlyWordCharacters) + { + return (int)SPerform(2266, (uint)pos, (uint)(onlyWordCharacters ? 1 : 0)); + } + + /// + /// Get position of end of word. + /// + public int WordEndPosition(int pos, bool onlyWordCharacters) + { + return (int)SPerform(2267, (uint)pos, (uint)(onlyWordCharacters ? 1 : 0)); + } + + /// + /// Measure the pixel width of some text in a particular style. + /// NUL terminated text argument. + /// Does not handle tab or control characters. + /// + unsafe public int TextWidth(int style, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2276, (uint)style, (uint)b); + } + } + + /// + /// Retrieve the height of a particular line of text in pixels. + /// + public int TextHeight(int line) + { + return (int)SPerform(2279, (uint)line, 0); + } + + /// + /// Append a string to the end of the document without changing the selection. + /// + unsafe public void AppendText(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2282, (uint)length, (uint)b); + } + } + + /// + /// Make the target range start and end be the same as the selection range start and end. + /// + public void TargetFromSelection() + { + SPerform(2287, 0, 0); + } + + /// + /// Join the lines in the target. + /// + public void LinesJoin() + { + SPerform(2288, 0, 0); + } + + /// + /// Split the lines in the target into lines that are less wide than pixelWidth + /// where possible. + /// + public void LinesSplit(int pixelWidth) + { + SPerform(2289, (uint)pixelWidth, 0); + } + + /// + /// Set the colours used as a chequerboard pattern in the fold margin + /// + public void SetFoldMarginColour(bool useSetting, int back) + { + SPerform(2290, (uint)(useSetting ? 1 : 0), (uint)back); + } + + /// + /// Set the colours used as a chequerboard pattern in the fold margin + /// + public void SetFoldMarginHiColour(bool useSetting, int fore) + { + SPerform(2291, (uint)(useSetting ? 1 : 0), (uint)fore); + } + + /// + /// Move caret down one line. + /// + public void LineDown() + { + SPerform(2300, 0, 0); + } + + /// + /// Move caret down one line extending selection to new caret position. + /// + public void LineDownExtend() + { + SPerform(2301, 0, 0); + } + + /// + /// Move caret up one line. + /// + public void LineUp() + { + SPerform(2302, 0, 0); + } + + /// + /// Move caret up one line extending selection to new caret position. + /// + public void LineUpExtend() + { + SPerform(2303, 0, 0); + } + + /// + /// Move caret left one character. + /// + public void CharLeft() + { + SPerform(2304, 0, 0); + } + + /// + /// Move caret left one character extending selection to new caret position. + /// + public void CharLeftExtend() + { + SPerform(2305, 0, 0); + } + + /// + /// Move caret right one character. + /// + public void CharRight() + { + SPerform(2306, 0, 0); + } + + /// + /// Move caret right one character extending selection to new caret position. + /// + public void CharRightExtend() + { + SPerform(2307, 0, 0); + } + + /// + /// Move caret left one word. + /// + public void WordLeft() + { + SPerform(2308, 0, 0); + } + + /// + /// Move caret left one word extending selection to new caret position. + /// + public void WordLeftExtend() + { + SPerform(2309, 0, 0); + } + + /// + /// Move caret right one word. + /// + public void WordRight() + { + SPerform(2310, 0, 0); + } + + /// + /// Move caret right one word extending selection to new caret position. + /// + public void WordRightExtend() + { + SPerform(2311, 0, 0); + } + + /// + /// Move caret to first position on line. + /// + public void Home() + { + SPerform(2312, 0, 0); + } + + /// + /// Move caret to first position on line extending selection to new caret position. + /// + public void HomeExtend() + { + SPerform(2313, 0, 0); + } + + /// + /// Move caret to last position on line. + /// + public void LineEnd() + { + SPerform(2314, 0, 0); + } + + /// + /// Move caret to last position on line extending selection to new caret position. + /// + public void LineEndExtend() + { + SPerform(2315, 0, 0); + } + + /// + /// Move caret to first position in document. + /// + public void DocumentStart() + { + SPerform(2316, 0, 0); + } + + /// + /// Move caret to first position in document extending selection to new caret position. + /// + public void DocumentStartExtend() + { + SPerform(2317, 0, 0); + } + + /// + /// Move caret to last position in document. + /// + public void DocumentEnd() + { + SPerform(2318, 0, 0); + } + + /// + /// Move caret to last position in document extending selection to new caret position. + /// + public void DocumentEndExtend() + { + SPerform(2319, 0, 0); + } + + /// + /// Move caret one page up. + /// + public void PageUp() + { + SPerform(2320, 0, 0); + } + + /// + /// Move caret one page up extending selection to new caret position. + /// + public void PageUpExtend() + { + SPerform(2321, 0, 0); + } + + /// + /// Move caret one page down. + /// + public void PageDown() + { + SPerform(2322, 0, 0); + } + + /// + /// Move caret one page down extending selection to new caret position. + /// + public void PageDownExtend() + { + SPerform(2323, 0, 0); + } + + /// + /// Switch from insert to overtype mode or the reverse. + /// + public void EditToggleOvertype() + { + SPerform(2324, 0, 0); + } + + /// + /// Cancel any modes such as call tip or auto-completion list display. + /// + public void Cancel() + { + SPerform(2325, 0, 0); + } + + /// + /// Delete the selection or if no selection, the character before the caret. + /// + public void DeleteBack() + { + SPerform(2326, 0, 0); + } + + /// + /// Delete the character after the caret. + /// + public void DeleteForward() + { + SetSel(CurrentPos + 1, CurrentPos + 1); + DeleteBack(); + } + + /// + /// If selection is empty or all on one line replace the selection with a tab character. + /// If more than one line selected, indent the lines. + /// + public void Tab() + { + SPerform(2327, 0, 0); + } + + /// + /// Dedent the selected lines. + /// + public void BackTab() + { + SPerform(2328, 0, 0); + } + + /// + /// Insert a new line, may use a CRLF, CR or LF depending on EOL mode. + /// + public void NewLine() + { + SPerform(2329, 0, 0); + } + + /// + /// Insert a Form Feed character. + /// + public void FormFeed() + { + SPerform(2330, 0, 0); + } + + /// + /// Move caret to before first visible character on line. + /// If already there move to first character on line. + /// + public void VCHome() + { + SPerform(2331, 0, 0); + } + + /// + /// Like VCHome but extending selection to new caret position. + /// + public void VCHomeExtend() + { + SPerform(2332, 0, 0); + } + + /// + /// Magnify the displayed text by increasing the sizes by 1 point. + /// + public void ZoomIn() + { + SPerform(2333, 0, 0); + } + + /// + /// Make the displayed text smaller by decreasing the sizes by 1 point. + /// + public void ZoomOut() + { + SPerform(2334, 0, 0); + } + + /// + /// Reset the text zooming by setting zoom level to 0. + /// + public void ResetZoom() + { + SPerform(2373, 0, 0); + } + + /// + /// Delete the word to the left of the caret. + /// + public void DelWordLeft() + { + SPerform(2335, 0, 0); + } + + /// + /// Delete the word to the right of the caret. + /// + public void DelWordRight() + { + SPerform(2336, 0, 0); + } + + /// + /// Cut the line containing the caret. + /// + public void LineCut() + { + SPerform(2337, 0, 0); + } + + /// + /// Delete the line containing the caret. + /// + public void LineDelete() + { + SPerform(2338, 0, 0); + } + + /// + /// Switch the current line with the previous. + /// + public void LineTranspose() + { + SPerform(2339, 0, 0); + } + + /// + /// Duplicate the current line. + /// + public void LineDuplicate() + { + SPerform(2404, 0, 0); + } + + /// + /// Transform the selection to lower case. + /// + public void LowerCase() + { + SPerform(2340, 0, 0); + } + + /// + /// Transform the selection to upper case. + /// + public void UpperCase() + { + SPerform(2341, 0, 0); + } + + /// + /// Scroll the document down, keeping the caret visible. + /// + public void LineScrollDown() + { + int oldScroll = FirstVisibleLine; + + SPerform(2342, 0, 0); + + int newScroll = FirstVisibleLine; + + // Decrement? + OnScroll(new ScrollEventArgs(ScrollEventType.SmallIncrement, oldScroll, newScroll, ScrollOrientation.VerticalScroll)); + } + + /// + /// Scroll the document up, keeping the caret visible. + /// + public void LineScrollUp() + { + int oldScroll = FirstVisibleLine; + + SPerform(2343, 0, 0); + + int newScroll = FirstVisibleLine; + + // Decrement? + OnScroll(new ScrollEventArgs(ScrollEventType.SmallIncrement, oldScroll, newScroll, ScrollOrientation.VerticalScroll)); + } + + /// + /// Delete the selection or if no selection, the character before the caret. + /// Will not delete the character before at the start of a line. + /// + public void DeleteBackNotLine() + { + SPerform(2344, 0, 0); + } + + /// + /// Move caret to first position on display line. + /// + public void HomeDisplay() + { + SPerform(2345, 0, 0); + } + + /// + /// Move caret to first position on display line extending selection to + /// new caret position. + /// + public void HomeDisplayExtend() + { + SPerform(2346, 0, 0); + } + + /// + /// Move caret to last position on display line. + /// + public void LineEndDisplay() + { + SPerform(2347, 0, 0); + } + + /// + /// Move caret to last position on display line extending selection to new + /// caret position. + /// + public void LineEndDisplayExtend() + { + SPerform(2348, 0, 0); + } + + /// + /// + public void HomeWrap() + { + SPerform(2349, 0, 0); + } + + /// + /// + public void HomeWrapExtend() + { + SPerform(2450, 0, 0); + } + + /// + /// + public void LineEndWrap() + { + SPerform(2451, 0, 0); + } + + /// + /// + public void LineEndWrapExtend() + { + SPerform(2452, 0, 0); + } + + /// + /// + public void VCHomeWrap() + { + SPerform(2453, 0, 0); + } + + /// + /// + public void VCHomeWrapExtend() + { + SPerform(2454, 0, 0); + } + + /// + /// Copy the line containing the caret. + /// + public void LineCopy() + { + SPerform(2455, 0, 0); + } + + /// + /// Move the caret inside current view if it's not there already. + /// + public void MoveCaretInsideView() + { + SPerform(2401, 0, 0); + } + + /// + /// How many characters are on a line, not including end of line characters? + /// + public int LineLength(int line) + { + return (int)SPerform(2350, (uint)line, 0); + } + + /// + /// Highlight the characters at two positions. + /// + public void BraceHighlight(int pos1, int pos2) + { + SPerform(2351, (uint)pos1, (uint)pos2); + } + + /// + /// Highlight the character at a position indicating there is no matching brace. + /// + public void BraceBadLight(int pos) + { + SPerform(2352, (uint)pos, 0); + } + + /// + /// Find the position of a matching brace or INVALID_POSITION if no match. + /// + public int BraceMatch(int pos) + { + return (int)SPerform(2353, (uint)pos, 0); + } + + /// + /// Sets the current caret position to be the search anchor. + /// + public void SearchAnchor() + { + SPerform(2366, 0, 0); + } + + /// + /// Find some text starting at the search anchor. + /// Does not ensure the selection is visible. + /// + unsafe public int SearchNext(int flags, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2367, (uint)flags, (uint)b); + } + } + + /// + /// Find some text starting at the search anchor and moving backwards. + /// Does not ensure the selection is visible. + /// + unsafe public int SearchPrev(int flags, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + return (int)SPerform(2368, (uint)flags, (uint)b); + } + } + + /// + /// Set whether a pop up menu is displayed automatically when the user presses + /// the wrong mouse button. + /// + public void UsePopUp(bool allowPopUp) + { + SPerform(2371, (uint)(allowPopUp ? 1 : 0), 0); + } + + /// + /// Create a new document object. + /// Starts with reference count of 1 and not selected into editor. + /// Extend life of document. + /// + public void AddRefDocument(int doc) + { + SPerform(2376, 0, (uint)doc); + } + + /// + /// Release a reference to the document, deleting document if it fades to black. + /// + public void ReleaseDocument(int doc) + { + SPerform(2377, 0, (uint)doc); + } + + /// + /// Move to the previous change in capitalisation. + /// + public void WordPartLeft() + { + SPerform(2390, 0, 0); + } + + /// + /// Move to the previous change in capitalisation extending selection + /// to new caret position. + /// + public void WordPartLeftExtend() + { + SPerform(2391, 0, 0); + } + + /// + /// Move to the change next in capitalisation. + /// + public void WordPartRight() + { + SPerform(2392, 0, 0); + } + + /// + /// Move to the next change in capitalisation extending selection + /// to new caret position. + /// + public void WordPartRightExtend() + { + SPerform(2393, 0, 0); + } + + /// + /// Constants for use with SetVisiblePolicy, similar to SetCaretPolicy. + /// Set the way the display area is determined when a particular line + /// is to be moved to by Find, FindNext, GotoLine, etc. + /// + public void SetVisiblePolicy(int visiblePolicy, int visibleSlop) + { + SPerform(2394, (uint)visiblePolicy, (uint)visibleSlop); + } + + /// + /// Delete back from the current position to the start of the line. + /// + public void DelLineLeft() + { + SPerform(2395, 0, 0); + } + + /// + /// Delete forwards from the current position to the end of the line. + /// + public void DelLineRight() + { + SPerform(2396, 0, 0); + } + + /// + /// Set the last x chosen value to be the caret x position. + /// + public void ChooseCaretX() + { + SPerform(2399, 0, 0); + } + + /// + /// Set the focus to this Scintilla widget. + /// GTK+ Specific. + /// + public void GrabFocus() + { + SPerform(2400, 0, 0); + } + + /// + /// Set the way the caret is kept visible when going sideway. + /// The exclusion zone is given in pixels. + /// + public void SetXCaretPolicy(int caretPolicy, int caretSlop) + { + SPerform(2402, (uint)caretPolicy, (uint)caretSlop); + } + + /// + /// Set the way the line the caret is on is kept visible. + /// The exclusion zone is given in lines. + /// + public void SetYCaretPolicy(int caretPolicy, int caretSlop) + { + SPerform(2403, (uint)caretPolicy, (uint)caretSlop); + } + + /// + /// Move caret between paragraphs (delimited by empty lines). + /// + public void ParaDown() + { + SPerform(2413, 0, 0); + } + + /// + /// Move caret between paragraphs (delimited by empty lines). + /// + public void ParaDownExtend() + { + SPerform(2414, 0, 0); + } + + /// + /// Move caret between paragraphs (delimited by empty lines). + /// + public void ParaUp() + { + SPerform(2415, 0, 0); + } + + /// + /// Move caret between paragraphs (delimited by empty lines). + /// + public void ParaUpExtend() + { + SPerform(2416, 0, 0); + } + + /// + /// Given a valid document position, return the previous position taking code + /// page into account. Returns 0 if passed 0. + /// + public int PositionBefore(int pos) + { + return (int)SPerform(2417, (uint)pos, 0); + } + + /// + /// Given a valid document position, return the next position taking code + /// page into account. Maximum value returned is the last position in the document. + /// + public int PositionAfter(int pos) + { + return (int)SPerform(2418, (uint)pos, 0); + } + + /// + /// Copy a range of text to the clipboard. Positions are clipped into the document. + /// + public void CopyRange(int start, int end) + { + SPerform(2419, (uint)start, (uint)end); + } + + /// + /// Copy argument text to the clipboard. + /// + unsafe public void CopyText(int length, string text) + { + if (text == null || text.Equals("")) text = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(text)) + { + SPerform(2420, (uint)length, (uint)b); + } + } + + /// + /// Retrieve the position of the start of the selection at the given line (INVALID_POSITION if no selection on this line). + /// + public int GetLineSelStartPosition(int line) + { + return (int)SPerform(2424, (uint)line, 0); + } + + /// + /// Retrieve the position of the end of the selection at the given line (INVALID_POSITION if no selection on this line). + /// + public int GetLineSelEndPosition(int line) + { + return (int)SPerform(2425, (uint)line, 0); + } + + /// + /// Move caret down one line, extending rectangular selection to new caret position. + /// + public void LineDownRectExtend() + { + SPerform(2426, 0, 0); + } + + /// + /// Move caret up one line, extending rectangular selection to new caret position. + /// + public void LineUpRectExtend() + { + SPerform(2427, 0, 0); + } + + /// + /// Move caret left one character, extending rectangular selection to new caret position. + /// + public void CharLeftRectExtend() + { + SPerform(2428, 0, 0); + } + + /// + /// Move caret right one character, extending rectangular selection to new caret position. + /// + public void CharRightRectExtend() + { + SPerform(2429, 0, 0); + } + + /// + /// Move caret to first position on line, extending rectangular selection to new caret position. + /// + public void HomeRectExtend() + { + SPerform(2430, 0, 0); + } + + /// + /// Move caret to before first visible character on line. + /// If already there move to first character on line. + /// In either case, extend rectangular selection to new caret position. + /// + public void VCHomeRectExtend() + { + SPerform(2431, 0, 0); + } + + /// + /// Move caret to last position on line, extending rectangular selection to new caret position. + /// + public void LineEndRectExtend() + { + SPerform(2432, 0, 0); + } + + /// + /// Move caret one page up, extending rectangular selection to new caret position. + /// + public void PageUpRectExtend() + { + SPerform(2433, 0, 0); + } + + /// + /// Move caret one page down, extending rectangular selection to new caret position. + /// + public void PageDownRectExtend() + { + SPerform(2434, 0, 0); + } + + /// + /// Move caret to top of page, or one page up if already at top of page. + /// + public void StutteredPageUp() + { + SPerform(2435, 0, 0); + } + + /// + /// Move caret to top of page, or one page up if already at top of page, extending selection to new caret position. + /// + public void StutteredPageUpExtend() + { + SPerform(2436, 0, 0); + } + + /// + /// Move caret to bottom of page, or one page down if already at bottom of page. + /// + public void StutteredPageDown() + { + SPerform(2437, 0, 0); + } + + /// + /// Move caret to bottom of page, or one page down if already at bottom of page, extending selection to new caret position. + /// + public void StutteredPageDownExtend() + { + SPerform(2438, 0, 0); + } + + /// + /// Move caret left one word, position cursor at end of word. + /// + public void WordLeftEnd() + { + SPerform(2439, 0, 0); + } + + /// + /// Move caret left one word, position cursor at end of word, extending selection to new caret position. + /// + public void WordLeftEndExtend() + { + SPerform(2440, 0, 0); + } + + /// + /// Move caret right one word, position cursor at end of word. + /// + public void WordRightEnd() + { + SPerform(2441, 0, 0); + } + + /// + /// Move caret right one word, position cursor at end of word, extending selection to new caret position. + /// + public void WordRightEndExtend() + { + SPerform(2442, 0, 0); + } + + /// + /// Set the set of characters making up whitespace for when moving or selecting by word. Should be called after WordChars. + /// + unsafe public void WhitespaceChars(string characters) + { + if (characters == null || characters.Equals("")) characters = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(characters)) + { + SPerform(2443, 0, (uint)b); + } + } + + /// + /// Reset the set of characters for whitespace and word characters to the defaults. + /// + public void SetCharsDefault() + { + SPerform(2444, 0, 0); + } + + /// + /// Enlarge the document to a particular size of text bytes. + /// + public void Allocate(int bytes) + { + SPerform(2446, (uint)bytes, 0); + } + + /// + /// Start notifying the container of all key presses and commands. + /// + public void StartRecord() + { + SPerform(3001, 0, 0); + } + + /// + /// Stop notifying the container of all key presses and commands. + /// + public void StopRecord() + { + SPerform(3002, 0, 0); + } + + /// + /// Colourise a segment of the document using the current lexing language. + /// + public void Colourise(int start, int end) + { + SPerform(4003, (uint)start, (uint)end); + } + + /// + /// Load a lexer library (dll / so). + /// + unsafe public void LoadLexerLibrary(string path) + { + if (path == null || path.Equals("")) path = "\0\0"; + fixed (byte* b = Encoding.GetEncoding(this.CodePage).GetBytes(path)) + { + SPerform(4007, 0, (uint)b); + } + } + + /// + /// Find the position of a column on a line taking into account tabs and + /// multi-byte characters. If beyond end of line, return line end position. + /// + public int FindColumn(int line, int column) + { + return (int)SPerform(2456, (uint)line, (uint)column); + } + + /// + /// Turn a indicator on over a range. /// public void IndicatorFillRange(int position, int fillLength) { @@ -4935,27 +4951,31 @@ public int ContractedFoldNext(int lineStart) return (int)SPerform(2618, (uint)lineStart, 0); } - #endregion - - #region Scintilla Constants + #endregion + + #region Scintilla Constants private const int WM_NOTIFY = 0x004e; - private const int WM_USER = 0x0400; + private const int WM_USER = 0x0400; private const int WM_REFLECT = WM_USER + 0x1C00; private const int WM_SYSCHAR = 0x106; private const int WM_COMMAND = 0x0111; private const int WM_KEYDOWN = 0x0100; + private const int WM_SETCURSOR = 0x0020; + private const int WM_MOUSEWHEEL = 0x20A; private const int WM_SYSKEYDOWN = 0x0104; + private const int WM_HSCROLL = 0x114; + private const int WM_VSCROLL = 0x115; private const int WM_DROPFILES = 0x0233; - private const uint WS_CHILD = (uint)0x40000000L; - private const uint WS_VISIBLE = (uint)0x10000000L; - private const uint WS_TABSTOP = (uint)0x00010000L; - private const uint WS_CHILD_VISIBLE_TABSTOP = WS_CHILD|WS_VISIBLE|WS_TABSTOP; + private const uint WS_CHILD = (uint)0x40000000L; + private const uint WS_VISIBLE = (uint)0x10000000L; + private const uint WS_TABSTOP = (uint)0x00010000L; + private const uint WS_CHILD_VISIBLE_TABSTOP = WS_CHILD | WS_VISIBLE | WS_TABSTOP; public const int MAXDWELLTIME = 10000000; - private const int PATH_LEN = 1024; - - #endregion - + private const int PATH_LEN = 1024; + + #endregion + #region Scintilla Shortcuts /// @@ -5037,268 +5057,320 @@ public ShortcutOverride(Keys keys, Action action) [DllImport("user32.dll")] public static extern IntPtr SetFocus(IntPtr hwnd); - [DllImport("gdi32.dll")] - public static extern int GetDeviceCaps(IntPtr hdc, Int32 capindex); - - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); + [DllImport("gdi32.dll")] + public static extern int GetDeviceCaps(IntPtr hdc, Int32 capindex); + + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); + + [DllImport("user32.dll")] + public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); - [DllImport("user32.dll")] - public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); - - [DllImport("shell32.dll")] + [DllImport("shell32.dll")] public static extern int DragQueryFileA(IntPtr hDrop, uint idx, IntPtr buff, int sz); - + [DllImport("shell32.dll")] public static extern int DragFinish(IntPtr hDrop); - + [DllImport("shell32.dll")] public static extern void DragAcceptFiles(IntPtr hwnd, int accept); - - [DllImport("scilexer.dll", EntryPoint = "Scintilla_DirectFunction")] - public static extern int Perform(IntPtr directPointer, UInt32 message, UInt32 wParam, UInt32 lParam); - public UInt32 SPerform(UInt32 message, UInt32 wParam, UInt32 lParam) - { + [DllImport("scilexer.dll", EntryPoint = "Scintilla_DirectFunction")] + public static extern int Perform(IntPtr directPointer, UInt32 message, UInt32 wParam, UInt32 lParam); + + public UInt32 SPerform(UInt32 message, UInt32 wParam, UInt32 lParam) + { if (Win32.ShouldUseWin32()) return (UInt32)Perform(DirectPointer, message, wParam, lParam); else return (UInt32)Encoding.ASCII.CodePage; - } + } public override bool PreProcessMessage(ref Message m) { switch (m.Msg) { case WM_KEYDOWN: - { - Int32 keys = (Int32)Control.ModifierKeys + (Int32)m.WParam; - if (!IsFocus || ignoreAllKeys || ignoredKeys.Contains(keys)) { - if (this.ExecuteShortcut(keys) || base.PreProcessMessage(ref m)) return true; + Int32 keys = (Int32)Control.ModifierKeys + (Int32)m.WParam; + if (!IsFocus || ignoreAllKeys || ignoredKeys.Contains(keys)) + { + if (this.ExecuteShortcut(keys) || base.PreProcessMessage(ref m)) return true; + } + if (((Control.ModifierKeys & Keys.Control) != 0) && ((Control.ModifierKeys & Keys.Alt) == 0)) + { + Int32 code = (Int32)m.WParam; + if ((code >= 65) && (code <= 90)) return true; // Eat non-writable characters + else if ((code == 9) || (code == 33) || (code == 34)) // Transmit Ctrl with Tab, PageUp/PageDown + { + return base.PreProcessMessage(ref m); + } + } + break; + } + case WM_SYSKEYDOWN: + { + return base.PreProcessMessage(ref m); } - if (((Control.ModifierKeys & Keys.Control) != 0) && ((Control.ModifierKeys & Keys.Alt) == 0)) + case WM_SYSCHAR: + { + return base.PreProcessMessage(ref m); + } + } + return false; + } + + private void WmScroll(ref Message m) + { + ScrollOrientation so = ScrollOrientation.VerticalScroll; + int oldScroll = 0, newScroll = 0; + ScrollEventType set; + if (m.Msg == WM_HSCROLL) + { + so = ScrollOrientation.HorizontalScroll; + oldScroll = XOffset; + + // Let Scintilla Handle the scroll Message to actually perform scrolling + base.WndProc(ref m); + newScroll = XOffset; + } + else + { + so = ScrollOrientation.VerticalScroll; + oldScroll = FirstVisibleLine; + base.WndProc(ref m); + newScroll = FirstVisibleLine; + } + + if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) + set = (ScrollEventType) ((short) ((int) (long) m.WParam & 0xffff)); + else + set = oldScroll > newScroll ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement; + + OnScroll(new ScrollEventArgs(set, oldScroll, newScroll, so)); + } + + protected override void WndProc(ref System.Windows.Forms.Message m) + { + switch (m.Msg) + { + case WM_SETCURSOR: + base.DefWndProc(ref m); + break; + + case WM_NOTIFY + WM_REFLECT: + SCNotification scn = (SCNotification)Marshal.PtrToStructure(m.LParam, typeof(SCNotification)); + if (!this.DisableAllSciEvents) { - Int32 code = (Int32)m.WParam; - if ((code >= 65) && (code <= 90)) return true; // Eat non-writable characters - else if ((code == 9) || (code == 33) || (code == 34)) // Transmit Ctrl with Tab, PageUp/PageDown + switch (scn.nmhdr.code) { - return base.PreProcessMessage(ref m); + case (uint)Enums.ScintillaEvents.StyleNeeded: + if (StyleNeeded != null) StyleNeeded(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.CharAdded: + if (CharAdded != null) CharAdded(this, scn.ch); + break; + + case (uint)Enums.ScintillaEvents.SavePointReached: + if (SavePointReached != null) SavePointReached(this); + break; + + case (uint)Enums.ScintillaEvents.SavePointLeft: + if (SavePointLeft != null) SavePointLeft(this); + break; + + case (uint)Enums.ScintillaEvents.ModifyAttemptRO: + if (ModifyAttemptRO != null) ModifyAttemptRO(this); + break; + + case (uint)Enums.ScintillaEvents.Key: + if (Key != null) Key(this, scn.ch, scn.modifiers); + break; + + case (uint)Enums.ScintillaEvents.DoubleClick: + if (DoubleClick != null) DoubleClick(this); + break; + + case (uint)Enums.ScintillaEvents.UpdateUI: + if (UpdateUI != null) UpdateUI(this); + break; + + case (uint)Enums.ScintillaEvents.MacroRecord: + if (MacroRecord != null) MacroRecord(this, scn.message, scn.wParam, scn.lParam); + break; + + case (uint)Enums.ScintillaEvents.MarginClick: + if (MarginClick != null) MarginClick(this, scn.modifiers, scn.position, scn.margin); + break; + + case (uint)Enums.ScintillaEvents.NeedShown: + if (NeedShown != null) NeedShown(this, scn.position, scn.length); + break; + + case (uint)Enums.ScintillaEvents.Painted: + if (Painted != null) Painted(this); + break; + + case (uint)Enums.ScintillaEvents.UserListSelection: + if (UserListSelection != null) UserListSelection(this, scn.listType, MarshalStr(scn.text)); + break; + + case (uint)Enums.ScintillaEvents.URIDropped: + if (URIDropped != null) URIDropped(this, MarshalStr(scn.text)); + break; + + case (uint)Enums.ScintillaEvents.DwellStart: + if (DwellStart != null) DwellStart(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.DwellEnd: + if (DwellEnd != null) DwellEnd(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.Zoom: + if (Zoom != null) Zoom(this); + break; + + case (uint)Enums.ScintillaEvents.HotspotClick: + if (HotSpotClick != null) HotSpotClick(this, scn.modifiers, scn.position); + break; + + case (uint)Enums.ScintillaEvents.HotspotDoubleClick: + if (HotSpotDoubleClick != null) HotSpotDoubleClick(this, scn.modifiers, scn.position); + break; + + case (uint)Enums.ScintillaEvents.CalltipClick: + if (CallTipClick != null) CallTipClick(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.AutoCSelection: + if (AutoCSelection != null) AutoCSelection(this, MarshalStr(scn.text)); + break; + + case (uint)Enums.ScintillaEvents.IndicatorClick: + if (IndicatorClick != null) IndicatorClick(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.IndicatorRelease: + if (IndicatorRelease != null) IndicatorRelease(this, scn.position); + break; + + case (uint)Enums.ScintillaEvents.AutoCCharDeleted: + if (AutoCCharDeleted != null) AutoCCharDeleted(this); + break; + + case (uint)Enums.ScintillaEvents.AutoCCancelled: + if (AutoCCancelled != null) AutoCCancelled(this); + break; + + case (uint)Enums.ScintillaEvents.Modified: + bool notify = false; + if ((scn.modificationType & (uint)Enums.ModificationFlags.InsertText) > 0) + { + if (TextInserted != null) TextInserted(this, scn.position, scn.length, scn.linesAdded); + notify = true; + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.DeleteText) > 0) + { + if (TextDeleted != null) TextDeleted(this, scn.position, scn.length, scn.linesAdded); + notify = true; + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeStyle) > 0) + { + if (StyleChanged != null) StyleChanged(this, scn.position, scn.length); + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeFold) > 0) + { + if (FoldChanged != null) FoldChanged(this, scn.line, scn.foldLevelNow, scn.foldLevelPrev); + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.UserPerformed) > 0) + { + if (UserPerformed != null) UserPerformed(this); + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.UndoPerformed) > 0) + { + if (UndoPerformed != null) UndoPerformed(this); + notify = true; + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.RedoPerformed) > 0) + { + if (RedoPerformed != null) RedoPerformed(this); + notify = true; + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.LastStepInUndoRedo) > 0) + { + if (LastStepInUndoRedo != null) LastStepInUndoRedo(this); + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeMarker) > 0) + { + if (MarkerChanged != null) MarkerChanged(this, scn.line); + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.BeforeInsert) > 0) + { + if (BeforeInsert != null) BeforeInsert(this, scn.position, scn.length); + notify = false; + } + if ((scn.modificationType & (uint)Enums.ModificationFlags.BeforeDelete) > 0) + { + if (BeforeDelete != null) BeforeDelete(this, scn.position, scn.length); + notify = false; + } + if (notify && Modified != null && scn.text != null) + { + try + { + string text = MarshalStr(scn.text, scn.length); + Modified(this, scn.position, scn.modificationType, text, scn.length, scn.linesAdded, scn.line, scn.foldLevelNow, scn.foldLevelPrev); + } + catch { } + } + break; } } break; - } - case WM_SYSKEYDOWN: - { - return base.PreProcessMessage(ref m); - } - case WM_SYSCHAR: - { - return base.PreProcessMessage(ref m); - } + + case WM_DROPFILES: + if (Win32.ShouldUseWin32()) HandleFileDrop(m.WParam); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + case WM_MOUSEWHEEL: + WmScroll(ref m); + break; + + default: + base.WndProc(ref m); + break; } - return false; } - protected override void WndProc(ref System.Windows.Forms.Message m) - { - if (m.Msg == WM_NOTIFY + WM_REFLECT) - { - SCNotification scn = (SCNotification)Marshal.PtrToStructure(m.LParam, typeof(SCNotification)); - if (!this.DisableAllSciEvents) - { - switch (scn.nmhdr.code) - { - case (uint)Enums.ScintillaEvents.StyleNeeded: - if (StyleNeeded != null) StyleNeeded(this, scn.position); - break; - - case (uint)Enums.ScintillaEvents.CharAdded: - if (CharAdded != null) CharAdded(this, scn.ch); - break; - - case (uint)Enums.ScintillaEvents.SavePointReached: - if (SavePointReached != null) SavePointReached(this); - break; - - case (uint)Enums.ScintillaEvents.SavePointLeft: - if (SavePointLeft != null) SavePointLeft(this); - break; - - case (uint)Enums.ScintillaEvents.ModifyAttemptRO: - if (ModifyAttemptRO != null) ModifyAttemptRO(this); - break; - - case (uint)Enums.ScintillaEvents.Key: - if (Key != null) Key(this, scn.ch, scn.modifiers); - break; - - case (uint)Enums.ScintillaEvents.DoubleClick: - if (DoubleClick != null) DoubleClick(this); - break; - - case (uint)Enums.ScintillaEvents.UpdateUI: - if (UpdateUI != null) UpdateUI(this); - break; - - case (uint)Enums.ScintillaEvents.MacroRecord: - if (MacroRecord != null) MacroRecord(this, scn.message, scn.wParam, scn.lParam); - break; - - case (uint)Enums.ScintillaEvents.MarginClick: - if (MarginClick != null) MarginClick(this, scn.modifiers, scn.position, scn.margin); - break; - - case (uint)Enums.ScintillaEvents.NeedShown: - if (NeedShown != null) NeedShown(this, scn.position, scn.length); - break; - - case (uint)Enums.ScintillaEvents.Painted: - if (Painted != null) Painted(this); - break; - - case (uint)Enums.ScintillaEvents.UserListSelection: - if (UserListSelection != null) UserListSelection(this, scn.listType, MarshalStr(scn.text)); - break; - - case (uint)Enums.ScintillaEvents.URIDropped: - if (URIDropped != null) URIDropped(this, MarshalStr(scn.text)); - break; - - case (uint)Enums.ScintillaEvents.DwellStart: - if (DwellStart != null) DwellStart(this, scn.position); - break; - - case (uint)Enums.ScintillaEvents.DwellEnd: - if (DwellEnd != null) DwellEnd(this, scn.position); - break; - - case (uint)Enums.ScintillaEvents.Zoom: - if (Zoom != null) Zoom(this); - break; - - case (uint)Enums.ScintillaEvents.HotspotClick: - if (HotSpotClick != null) HotSpotClick(this, scn.modifiers, scn.position); - break; - - case (uint)Enums.ScintillaEvents.HotspotDoubleClick: - if (HotSpotDoubleClick != null) HotSpotDoubleClick(this, scn.modifiers, scn.position); - break; - - case (uint)Enums.ScintillaEvents.CalltipClick: - if (CallTipClick != null) CallTipClick(this, scn.position); - break; - - case (uint)Enums.ScintillaEvents.AutoCSelection: - if (AutoCSelection != null) AutoCSelection(this, MarshalStr(scn.text)); - break; - - case (uint)Enums.ScintillaEvents.IndicatorClick: - if (IndicatorClick != null) IndicatorClick(this, scn.position); - break; + unsafe string MarshalStr(IntPtr p) + { + sbyte* b = (sbyte*)p; + int len = 0; + while (b[len] != 0) ++len; + return new string(b, 0, len); + } - case (uint)Enums.ScintillaEvents.IndicatorRelease: - if (IndicatorRelease != null) IndicatorRelease(this, scn.position); - break; + unsafe string MarshalStr(IntPtr p, int len) + { + sbyte* b = (sbyte*)p; + return new string(b, 0, len); + } - case (uint)Enums.ScintillaEvents.AutoCCharDeleted: - if (AutoCCharDeleted != null) AutoCCharDeleted(this); - break; + #endregion - case (uint)Enums.ScintillaEvents.AutoCCancelled: - if (AutoCCancelled != null) AutoCCancelled(this); - break; + #region Automated Features - case (uint)Enums.ScintillaEvents.Modified: - bool notify = false; - if ((scn.modificationType & (uint)Enums.ModificationFlags.InsertText)>0) - { - if (TextInserted != null) TextInserted(this, scn.position, scn.length, scn.linesAdded); - notify = true; - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.DeleteText)>0) - { - if (TextDeleted != null) TextDeleted(this, scn.position, scn.length, scn.linesAdded); - notify = true; - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeStyle)>0) - { - if (StyleChanged != null) StyleChanged(this, scn.position, scn.length); - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeFold)>0) - { - if (FoldChanged != null ) FoldChanged(this, scn.line, scn.foldLevelNow, scn.foldLevelPrev); - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.UserPerformed)>0) - { - if (UserPerformed != null ) UserPerformed(this); - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.UndoPerformed)>0) - { - if (UndoPerformed != null ) UndoPerformed(this); - notify = true; - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.RedoPerformed)>0) - { - if (RedoPerformed != null ) RedoPerformed(this); - notify = true; - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.LastStepInUndoRedo)>0) - { - if (LastStepInUndoRedo != null ) LastStepInUndoRedo(this); - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.ChangeMarker)>0) - { - if (MarkerChanged != null ) MarkerChanged(this, scn.line); - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.BeforeInsert)>0) - { - if (BeforeInsert != null ) BeforeInsert(this, scn.position, scn.length); - notify = false; - } - if ((scn.modificationType & (uint)Enums.ModificationFlags.BeforeDelete)>0) - { - if (BeforeDelete != null ) BeforeDelete(this, scn.position, scn.length); - notify = false; - } - if (notify && Modified != null && scn.text != null) - { - try - { - string text = MarshalStr(scn.text, scn.length); - Modified(this, scn.position, scn.modificationType, text, scn.length, scn.linesAdded, scn.line, scn.foldLevelNow, scn.foldLevelPrev); - } - catch {} - } - break; - } - } - } - else if (m.Msg == WM_DROPFILES) - { - if (Win32.ShouldUseWin32()) HandleFileDrop(m.WParam); - } - else - { - base.WndProc(ref m); - } - } - - unsafe string MarshalStr(IntPtr p) - { - sbyte* b = (sbyte*)p; - int len = 0; - while (b[len] != 0) ++len; - return new string(b,0,len); - } - - unsafe string MarshalStr(IntPtr p, int len) - { - sbyte* b = (sbyte*)p; - return new string(b,0,len); - } - - #endregion - - #region Automated Features + /// + /// Raises the event. + /// + /// An that contains the event data. + protected virtual void OnScroll(ScrollEventArgs e) + { + if (Scroll != null) + Scroll(this, e); + } /// /// Support for selection highlighting and selection changed event @@ -5311,18 +5383,18 @@ private void OnUpdateUI(ScintillaControl sci) switch (PluginBase.MainForm.Settings.HighlightMatchingWordsMode) // Handle selection highlighting { case Enums.HighlightMatchingWordsMode.SelectionOrPosition: - { - StartHighlightSelectionTimer(sci); - break; - } - case Enums.HighlightMatchingWordsMode.SelectedWord: - { - if (sci.SelText == sci.GetWordFromPosition(sci.CurrentPos)) { StartHighlightSelectionTimer(sci); + break; + } + case Enums.HighlightMatchingWordsMode.SelectedWord: + { + if (sci.SelText == sci.GetWordFromPosition(sci.CurrentPos)) + { + StartHighlightSelectionTimer(sci); + } + break; } - break; - } } } lastSelectionStart = sci.SelectionStart; @@ -5363,7 +5435,7 @@ private void HighlightWordsMatchingSelected() if (String.IsNullOrEmpty(word)) return; String pattern = word.Trim(); FRSearch search = new FRSearch(pattern); - search.WholeWord = true; + search.WholeWord = true; search.NoCase = false; search.Filter = SearchFilter.OutsideCodeComments | SearchFilter.OutsideStringLiterals; RemoveHighlights(); @@ -5395,7 +5467,7 @@ private void OnBlockSelect(ScintillaControl sci) /// private void OnCancelHighlight(ScintillaControl sci) { - if (sci.isHiliteSelected && sci.hasHighlights && sci.SelText.Length == 0 + if (sci.isHiliteSelected && sci.hasHighlights && sci.SelText.Length == 0 && PluginBase.MainForm.Settings.HighlightMatchingWordsMode != Enums.HighlightMatchingWordsMode.SelectionOrPosition) { sci.RemoveHighlights(); @@ -5403,20 +5475,20 @@ private void OnCancelHighlight(ScintillaControl sci) } } - /// - /// Provides the support for brace matching - /// - private void OnBraceMatch(ScintillaControl sci) - { - if (isBraceMatching && sci.SelText.Length == 0) - { - int position = CurrentPos-1; - char character = (char)CharAt(position); - if (character != '{' && character != '}' && character != '(' && character != ')' && character != '[' && character != ']') - { - position = CurrentPos; - character = (char)CharAt(position); - } + /// + /// Provides the support for brace matching + /// + private void OnBraceMatch(ScintillaControl sci) + { + if (isBraceMatching && sci.SelText.Length == 0) + { + int position = CurrentPos - 1; + char character = (char)CharAt(position); + if (character != '{' && character != '}' && character != '(' && character != ')' && character != '[' && character != ']') + { + position = CurrentPos; + character = (char)CharAt(position); + } if (character == '{' || character == '}' || character == '(' || character == ')' || character == '[' || character == ']') { if (!this.PositionIsOnComment(position)) @@ -5441,23 +5513,23 @@ private void OnBraceMatch(ScintillaControl sci) BraceHighlight(-1, -1); HighlightGuide = 0; } - } - } - - /// - /// Provides support for smart indenting - /// + } + } + + /// + /// Provides support for smart indenting + /// /// private void OnSmartIndent(ScintillaControl ctrl, int ch) - { + { char newline = (EOLMode == 1) ? '\r' : '\n'; - switch (SmartIndentType) - { - case Enums.SmartIndent.None: - return; - case Enums.SmartIndent.Simple: - if (ch == newline) - { + switch (SmartIndentType) + { + case Enums.SmartIndent.None: + return; + case Enums.SmartIndent.Simple: + if (ch == newline) + { this.BeginUndoAction(); try { @@ -5471,11 +5543,11 @@ private void OnSmartIndent(ScintillaControl ctrl, int ch) { this.EndUndoAction(); } - } - break; - case Enums.SmartIndent.CPP: - if (ch == newline) - { + } + break; + case Enums.SmartIndent.CPP: + if (ch == newline) + { this.BeginUndoAction(); try { @@ -5502,7 +5574,7 @@ private void OnSmartIndent(ScintillaControl ctrl, int ch) int bracePos = CurrentPos - 1; while (bracePos > 0 && CharAt(bracePos) != '{') bracePos--; int style = BaseStyleAt(bracePos); - if (bracePos >= 0 && CharAt(bracePos) == '{' && (style == 10/*CPP*/ || style == 5/*CSS*/)) + if (bracePos >= 0 && CharAt(bracePos) == '{' && (style == 10/*CPP*/ || style == 5/*CSS*/)) previousIndent += TabWidth; } // TODO: Should this test a config variable for indenting after case : statements? @@ -5540,7 +5612,7 @@ private void OnSmartIndent(ScintillaControl ctrl, int ch) InsertText(position + 1, "+ " + quote); GotoPos(position + 4); //if (Regex.IsMatch(GetLine(curLine - 1), "=[\\s]*" + quote)) - SetLineIndentation(curLine, GetLineIndentation(curLine - 1) + TabWidth); + SetLineIndentation(curLine, GetLineIndentation(curLine - 1) + TabWidth); } } } @@ -5548,9 +5620,9 @@ private void OnSmartIndent(ScintillaControl ctrl, int ch) { this.EndUndoAction(); } - } - else if (ch == '}') - { + } + else if (ch == '}') + { this.BeginUndoAction(); try { @@ -5568,16 +5640,16 @@ private void OnSmartIndent(ScintillaControl ctrl, int ch) { this.EndUndoAction(); } - } - break; - case Enums.SmartIndent.Custom: - if (ch == newline) - { - if (SmartIndent != null) SmartIndent(this); - } - break; - } - } + } + break; + case Enums.SmartIndent.Custom: + if (ch == newline) + { + if (SmartIndent != null) SmartIndent(this); + } + break; + } + } /// /// Detects the string-literal quote style @@ -5591,7 +5663,7 @@ public char GetStringType(int position) for (int i = position; i > 0; i--) { c = next; - next = (char)CharAt(i-1); + next = (char)CharAt(i - 1); if (next == '\\' && (c == '\'' || c == '"')) i--; if (c == '\'') return '\''; @@ -5599,64 +5671,64 @@ public char GetStringType(int position) } return ' '; } - - #endregion + + #endregion #region Misc Custom Stuff - /// - /// Render the contents for printing - /// - public int FormatRange(bool measureOnly, PrintPageEventArgs e, int charFrom, int charTo) - { - IntPtr hdc = e.Graphics.GetHdc(); - int wParam = (measureOnly ? 0 : 1); - RangeToFormat frPrint = this.GetRangeToFormat(hdc, charFrom, charTo); - IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(frPrint)); - Marshal.StructureToPtr(frPrint, lParam, false); - int res = (int)this.SPerform(2151, (uint)wParam, (uint)lParam); - Marshal.FreeCoTaskMem(lParam); - e.Graphics.ReleaseHdc(hdc); - return res; - } - - /// - /// Populates the RangeToFormat struct - /// - private RangeToFormat GetRangeToFormat(IntPtr hdc, int charFrom, int charTo) - { - RangeToFormat frPrint; - int pageWidth = (int)GetDeviceCaps(hdc, 110); - int pageHeight = (int)GetDeviceCaps(hdc, 111); - frPrint.hdcTarget = hdc; - frPrint.hdc = hdc; - frPrint.rcPage.Left = 0; - frPrint.rcPage.Top = 0; - frPrint.rcPage.Right = pageWidth; - frPrint.rcPage.Bottom = pageHeight; - frPrint.rc.Left = Convert.ToInt32(pageWidth*0.02); - frPrint.rc.Top = Convert.ToInt32(pageHeight*0.03); - frPrint.rc.Right = Convert.ToInt32(pageWidth*0.975); - frPrint.rc.Bottom = Convert.ToInt32(pageHeight*0.95); - frPrint.chrg.cpMin = charFrom; - frPrint.chrg.cpMax = charTo; - return frPrint; - } - - /// - /// Free cached data from the control after printing - /// - public void FormatRangeDone() - { - this.SPerform(2151, 0, 0); - } - - /// - /// This holds the actual encoding of the document - /// - public Encoding Encoding - { - get { return this.encoding; } + /// + /// Render the contents for printing + /// + public int FormatRange(bool measureOnly, PrintPageEventArgs e, int charFrom, int charTo) + { + IntPtr hdc = e.Graphics.GetHdc(); + int wParam = (measureOnly ? 0 : 1); + RangeToFormat frPrint = this.GetRangeToFormat(hdc, charFrom, charTo); + IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(frPrint)); + Marshal.StructureToPtr(frPrint, lParam, false); + int res = (int)this.SPerform(2151, (uint)wParam, (uint)lParam); + Marshal.FreeCoTaskMem(lParam); + e.Graphics.ReleaseHdc(hdc); + return res; + } + + /// + /// Populates the RangeToFormat struct + /// + private RangeToFormat GetRangeToFormat(IntPtr hdc, int charFrom, int charTo) + { + RangeToFormat frPrint; + int pageWidth = (int)GetDeviceCaps(hdc, 110); + int pageHeight = (int)GetDeviceCaps(hdc, 111); + frPrint.hdcTarget = hdc; + frPrint.hdc = hdc; + frPrint.rcPage.Left = 0; + frPrint.rcPage.Top = 0; + frPrint.rcPage.Right = pageWidth; + frPrint.rcPage.Bottom = pageHeight; + frPrint.rc.Left = Convert.ToInt32(pageWidth * 0.02); + frPrint.rc.Top = Convert.ToInt32(pageHeight * 0.03); + frPrint.rc.Right = Convert.ToInt32(pageWidth * 0.975); + frPrint.rc.Bottom = Convert.ToInt32(pageHeight * 0.95); + frPrint.chrg.cpMin = charFrom; + frPrint.chrg.cpMax = charTo; + return frPrint; + } + + /// + /// Free cached data from the control after printing + /// + public void FormatRangeDone() + { + this.SPerform(2151, 0, 0); + } + + /// + /// This holds the actual encoding of the document + /// + public Encoding Encoding + { + get { return this.encoding; } set { this.encoding = value; @@ -5670,37 +5742,37 @@ public Encoding Encoding public bool SaveBOM { get { return this.saveBOM; } - set - { + set + { this.saveBOM = value; if (UpdateSync != null) this.UpdateSync(this); } } - - /// - /// Adds a line end marker to the end of the document - /// - public void AddLastLineEnd() - { - string eolMarker = "\r\n"; - if (this.EOLMode == 1) eolMarker = "\r"; - else if (this.EOLMode == 2) eolMarker = "\n"; - if (!this.Text.EndsWith(eolMarker)) - { - this.TargetStart = this.TargetEnd = this.TextLength; - this.ReplaceTarget(eolMarker.Length, eolMarker); - } - } - - /// - /// Removes trailing spaces from each line - /// + + /// + /// Adds a line end marker to the end of the document + /// + public void AddLastLineEnd() + { + string eolMarker = "\r\n"; + if (this.EOLMode == 1) eolMarker = "\r"; + else if (this.EOLMode == 2) eolMarker = "\n"; + if (!this.Text.EndsWith(eolMarker)) + { + this.TargetStart = this.TargetEnd = this.TextLength; + this.ReplaceTarget(eolMarker.Length, eolMarker); + } + } + + /// + /// Removes trailing spaces from each line + /// public void StripTrailingSpaces() { this.StripTrailingSpaces(false); } - public void StripTrailingSpaces(Boolean keepIndentTabs) - { + public void StripTrailingSpaces(Boolean keepIndentTabs) + { this.BeginUndoAction(); try { @@ -5737,7 +5809,7 @@ public void StripTrailingSpaces(Boolean keepIndentTabs) { this.EndUndoAction(); } - } + } /// /// Checks if a line is in preprocessor block @@ -5775,222 +5847,222 @@ public bool LineIsInPreprocessor(ScintillaControl sci, int lexerPpStyle, int lin else return false; } - /// - /// Checks that if the specified position is on comment. + /// + /// Checks that if the specified position is on comment. /// NOTE: You may need to manually update coloring: "sci.Colourise(0, -1);" - /// - public bool PositionIsOnComment(int position) - { - return PositionIsOnComment(position, this.Lexer); - } - public bool PositionIsOnComment(int position, int lexer) - { - int style = BaseStyleAt(position); - if (lexer == 3 || lexer == 18 || lexer == 25 || lexer == 27) + /// + public bool PositionIsOnComment(int position) + { + return PositionIsOnComment(position, this.Lexer); + } + public bool PositionIsOnComment(int position, int lexer) + { + int style = BaseStyleAt(position); + if (lexer == 3 || lexer == 18 || lexer == 25 || lexer == 27) { return ( // cpp, tcl, bullant or pascal - style == 1 - || style == 2 - || style == 3 - || style == 15 - || style == 17 - || style == 18); - } - else if (lexer == 4 || lexer == 5) + style == 1 + || style == 2 + || style == 3 + || style == 15 + || style == 17 + || style == 18); + } + else if (lexer == 4 || lexer == 5) { return ( // html or xml - style == 9 - || style == 20 - || style == 29 - || style == 30 - || style == 42 - || style == 43 - || style == 44 - || style == 57 - || style == 58 - || style == 59 - || style == 72 - || style == 82 - || style == 92 - || style == 107 - || style == 124 - || style == 125); - } - else if (lexer == 2 || lexer == 21) + style == 9 + || style == 20 + || style == 29 + || style == 30 + || style == 42 + || style == 43 + || style == 44 + || style == 57 + || style == 58 + || style == 59 + || style == 72 + || style == 82 + || style == 92 + || style == 107 + || style == 124 + || style == 125); + } + else if (lexer == 2 || lexer == 21) { return ( // python or lisp - style == 1 - || style == 12); - } - else if (lexer == 6 || lexer == 22 || lexer == 45 || lexer == 62) + style == 1 + || style == 12); + } + else if (lexer == 6 || lexer == 22 || lexer == 45 || lexer == 62) { return ( // perl, bash, clarion/clw or ruby - style == 2); - } - else if (lexer == 7) + style == 2); + } + else if (lexer == 7) { return ( // sql - style == 1 - || style == 2 - || style == 3 - || style == 13 - || style == 15 - || style == 17 - || style == 18); - } - else if (lexer == 8 || lexer == 9 || lexer == 11 || lexer == 12 || lexer == 16 || lexer == 17 || lexer == 19 || lexer == 23 || lexer == 24 || lexer == 26 || lexer == 28 || lexer == 32 || lexer == 36 || lexer == 37 || lexer == 40 || lexer == 44 || lexer == 48 || lexer == 51 || lexer == 53 || lexer == 54 || lexer == 57 || lexer == 63) + style == 1 + || style == 2 + || style == 3 + || style == 13 + || style == 15 + || style == 17 + || style == 18); + } + else if (lexer == 8 || lexer == 9 || lexer == 11 || lexer == 12 || lexer == 16 || lexer == 17 || lexer == 19 || lexer == 23 || lexer == 24 || lexer == 26 || lexer == 28 || lexer == 32 || lexer == 36 || lexer == 37 || lexer == 40 || lexer == 44 || lexer == 48 || lexer == 51 || lexer == 53 || lexer == 54 || lexer == 57 || lexer == 63) { return ( // asn1, vb, diff, batch, makefile, avenue, eiffel, eiffelkw, vbscript, matlab, crontab, fortran, f77, lout, mmixal, yaml, powerbasic, erlang, octave, kix or properties - style == 1); - } - else if (lexer == 14) + style == 1); + } + else if (lexer == 14) { return ( // latex - style == 4); - } - else if (lexer == 15 || lexer == 41 || lexer == 56) + style == 4); + } + else if (lexer == 15 || lexer == 41 || lexer == 56) { return ( // lua, verilog or escript - style == 1 - || style == 2 - || style == 3); - } - else if (lexer == 20) + style == 1 + || style == 2 + || style == 3); + } + else if (lexer == 20) { return ( // ada - style == 10); - } - else if (lexer == 31 || lexer == 39 || lexer == 42 || lexer == 52 || lexer == 55 || lexer == 58 || lexer == 60 || lexer == 61 || lexer == 64 || lexer == 71) + style == 10); + } + else if (lexer == 31 || lexer == 39 || lexer == 42 || lexer == 52 || lexer == 55 || lexer == 58 || lexer == 60 || lexer == 61 || lexer == 64 || lexer == 71) { return ( // au3, apdl, baan, ps, mssql, rebol, forth, gui4cli, vhdl or pov - style == 1 - || style == 2); - } - else if (lexer == 34) + style == 1 + || style == 2); + } + else if (lexer == 34) { return ( // asm - style == 1 - || style == 11); - } - else if (lexer == 43) + style == 1 + || style == 11); + } + else if (lexer == 43) { return ( // nsis - style == 1 - || style == 18); - } - else if (lexer == 59) + style == 1 + || style == 18); + } + else if (lexer == 59) { return ( // specman - style == 2 - || style == 3); - } - else if (lexer == 70) + style == 2 + || style == 3); + } + else if (lexer == 70) { return ( // tads3 style == 3 || style == 4); - } - else if (lexer == 74) + } + else if (lexer == 74) { return ( // csound - style == 1 - || style == 9); - } - else if (lexer == 65) + style == 1 + || style == 9); + } + else if (lexer == 65) { return ( // caml - style == 12 - || style == 13 - || style == 14 - || style == 15); - } - else if (lexer == 68) + style == 12 + || style == 13 + || style == 14 + || style == 15); + } + else if (lexer == 68) { return ( // haskell - style == 13 - || style == 14 - || style == 15 - || style == 16); - } - else if (lexer == 73) + style == 13 + || style == 14 + || style == 15 + || style == 16); + } + else if (lexer == 73) { return ( // flagship - style == 1 - || style == 2 - || style == 3 - || style == 4 - || style == 5 - || style == 6); - } - else if (lexer == 72) + style == 1 + || style == 2 + || style == 3 + || style == 4 + || style == 5 + || style == 6); + } + else if (lexer == 72) { return ( // smalltalk - style == 3); - } - else if (lexer == 38) + style == 3); + } + else if (lexer == 38) { return ( // css - style == 9); - } - return false; - } - - /// - /// Indents the specified line - /// - protected void IndentLine(int line, int indent) - { - if (indent < 0) return; - int selStart = SelectionStart; - int selEnd = SelectionEnd; - int posBefore = LineIndentPosition(line); - SetLineIndentation(line, indent); - int posAfter = LineIndentPosition(line); - int posDifference = posAfter - posBefore; - if (posAfter > posBefore) - { - if (selStart >= posBefore) selStart += posDifference; - if (selEnd >= posBefore) selEnd += posDifference; - } - else if (posAfter < posBefore) - { - if (selStart >= posAfter) - { - if (selStart >= posBefore) selStart += posDifference; - else selStart = posAfter; - } - if (selEnd >= posAfter) - { - if (selEnd >= posBefore) selEnd += posDifference; - else selEnd = posAfter; - } - } - SetSel(selStart, selEnd); - } - - /// - /// Expands all folds - /// - public void ExpandAllFolds() - { - for (int i = 0; i - /// Collapses all folds - /// - public void CollapseAllFolds() - { - for (int i = 0; i + /// Indents the specified line + /// + protected void IndentLine(int line, int indent) + { + if (indent < 0) return; + int selStart = SelectionStart; + int selEnd = SelectionEnd; + int posBefore = LineIndentPosition(line); + SetLineIndentation(line, indent); + int posAfter = LineIndentPosition(line); + int posDifference = posAfter - posBefore; + if (posAfter > posBefore) + { + if (selStart >= posBefore) selStart += posDifference; + if (selEnd >= posBefore) selEnd += posDifference; + } + else if (posAfter < posBefore) + { + if (selStart >= posAfter) + { + if (selStart >= posBefore) selStart += posDifference; + else selStart = posAfter; + } + if (selEnd >= posAfter) + { + if (selEnd >= posBefore) selEnd += posDifference; + else selEnd = posAfter; + } + } + SetSel(selStart, selEnd); + } + + /// + /// Expands all folds + /// + public void ExpandAllFolds() + { + for (int i = 0; i < LineCount; i++) + { + FoldExpanded(i, true); + ShowLines(i + 1, i + 1); + } + } + + /// + /// Collapses all folds + /// + public void CollapseAllFolds() + { + for (int i = 0; i < LineCount; i++) + { + int maxSubOrd = LastChild(i, -1); + FoldExpanded(i, false); + HideLines(i + 1, maxSubOrd); + } } /// @@ -6089,15 +6161,15 @@ public void CollapseRegions() } } - /// - /// Selects the specified text, starting from the caret position - /// - public int SelectText(string text) - { + /// + /// Selects the specified text, starting from the caret position + /// + public int SelectText(string text) + { int pos = this.Text.IndexOf(text, MBSafeCharPosition(this.CurrentPos)); if (pos >= 0) this.MBSafeSetSel(pos, text); return pos; - } + } /// /// Selects the specified text, starting from the given position @@ -6109,141 +6181,141 @@ public int SelectText(string text, int startPos) return pos; } - /// - /// Gets a word from the specified position - /// - public string GetWordFromPosition(int position) - { - try - { - int startPosition = this.MBSafeCharPosition(this.WordStartPosition(position, true)); - int endPosition = this.MBSafeCharPosition(this.WordEndPosition(position, true)); - string keyword = this.Text.Substring(startPosition, endPosition - startPosition); - if (keyword == "" || keyword == " ") return null; - return keyword.Trim(); - } - catch - { - return null; - } - } - + /// + /// Gets a word from the specified position + /// + public string GetWordFromPosition(int position) + { + try + { + int startPosition = this.MBSafeCharPosition(this.WordStartPosition(position, true)); + int endPosition = this.MBSafeCharPosition(this.WordEndPosition(position, true)); + string keyword = this.Text.Substring(startPosition, endPosition - startPosition); + if (keyword == "" || keyword == " ") return null; + return keyword.Trim(); + } + catch + { + return null; + } + } + /// /// Insert text with wide-char to byte position conversion /// - public void MBSafeInsertText(int position, string text) - { - if (this.CodePage != 65001) - { - this.InsertText(position, text); - } - else - { - int mbpos = this.MBSafePosition(position); - this.InsertText(mbpos, text); - } - } + public void MBSafeInsertText(int position, string text) + { + if (this.CodePage != 65001) + { + this.InsertText(position, text); + } + else + { + int mbpos = this.MBSafePosition(position); + this.InsertText(mbpos, text); + } + } /// /// Set cursor position with wide-char to byte position conversion /// - public void MBSafeGotoPos(int position) - { - if (this.CodePage != 65001) - { - this.GotoPos(position); - } - else - { - int mbpos = this.MBSafePosition(position); - this.GotoPos(mbpos); - } - } + public void MBSafeGotoPos(int position) + { + if (this.CodePage != 65001) + { + this.GotoPos(position); + } + else + { + int mbpos = this.MBSafePosition(position); + this.GotoPos(mbpos); + } + } /// /// Select text using wide-char to byte indexes conversion /// - public void MBSafeSetSel(int start, int end) - { - if (this.CodePage != 65001) - { - this.SetSel(start, end); - } - else - { - string count = this.Text.Substring(start, end-start); - start = this.MBSafePosition(start); - end = start+this.MBSafeTextLength(count); - this.SetSel(start, end); - } - } + public void MBSafeSetSel(int start, int end) + { + if (this.CodePage != 65001) + { + this.SetSel(start, end); + } + else + { + string count = this.Text.Substring(start, end - start); + start = this.MBSafePosition(start); + end = start + this.MBSafeTextLength(count); + this.SetSel(start, end); + } + } /// /// Select text using wide-char to byte index & text conversion /// - public void MBSafeSetSel(int start, string text) - { - if (this.CodePage != 65001) - { - this.SetSel(start, start+text.Length); - } - else - { - int mbpos = this.MBSafePosition(start); - this.SetSel(mbpos, mbpos+this.MBSafeTextLength(text)); - } - } + public void MBSafeSetSel(int start, string text) + { + if (this.CodePage != 65001) + { + this.SetSel(start, start + text.Length); + } + else + { + int mbpos = this.MBSafePosition(start); + this.SetSel(mbpos, mbpos + this.MBSafeTextLength(text)); + } + } /// /// Wide-char to byte position in the editor text /// - public int MBSafePosition(int position) - { + public int MBSafePosition(int position) + { if (this.CodePage != 65001) { return position; } else if (position < 0) return position; else - { - string count = this.Text.Substring(0, position); - int mbpos = Encoding.UTF8.GetByteCount(count); - return mbpos; - } - } + { + string count = this.Text.Substring(0, position); + int mbpos = Encoding.UTF8.GetByteCount(count); + return mbpos; + } + } /// /// Byte to wide-char position in the editor text /// - public int MBSafeCharPosition(int bytePosition) - { - if (this.CodePage != 65001) - { - return bytePosition; - } + public int MBSafeCharPosition(int bytePosition) + { + if (this.CodePage != 65001) + { + return bytePosition; + } else if (bytePosition < 0) return bytePosition; else - { - byte[] bytes = Encoding.UTF8.GetBytes(this.Text); - int chrpos = Encoding.UTF8.GetCharCount(bytes, 0, bytePosition); - return chrpos; - } - } + { + byte[] bytes = Encoding.UTF8.GetBytes(this.Text); + int chrpos = Encoding.UTF8.GetCharCount(bytes, 0, bytePosition); + return chrpos; + } + } /// /// Counts byte length of wide-char text /// - public int MBSafeTextLength(string text) - { - if (this.CodePage != 65001) - { - return text.Length; - } - else - { - int mblength = Encoding.UTF8.GetByteCount(text); + public int MBSafeTextLength(string text) + { + if (this.CodePage != 65001) + { + return text.Length; + } + else + { + int mblength = Encoding.UTF8.GetByteCount(text); return mblength; - } + } } /// @@ -6258,107 +6330,107 @@ public int MBSafeLengthFromBytes(string txt, int bytes) byte[] raw = Encoding.UTF8.GetBytes(txt); return Encoding.UTF8.GetString(raw, 0, Math.Min(raw.Length, bytes)).Length; } - - /// - /// Custom way to find the matching brace when BraceMatch() does not work - /// - public int SafeBraceMatch(int position) - { - int match = this.CharAt(position); - int toMatch = 0; - int length = TextLength; - int ch; - int sub = 0; - int lexer = Lexer; - Colourise(0, -1); - bool comment = PositionIsOnComment(position, lexer); - switch (match) - { - case '{': - toMatch = '}'; - goto down; - case '(': - toMatch = ')'; - goto down; - case '[': - toMatch = ']'; - goto down; - case '}': - toMatch = '{'; - goto up; - case ')': - toMatch = '('; - goto up; - case ']': - toMatch = '['; - goto up; - } - return -1; - // search up - up: - while (position >= 0) - { - position--; - ch = CharAt(position); - if (ch == match) - { - if (comment == PositionIsOnComment(position, lexer)) sub++; - } - else if (ch == toMatch && comment == PositionIsOnComment(position, lexer)) - { - sub--; - if (sub < 0) return position; - } - } - return -1; - // search down - down: - while (position < length) - { - position++; - ch = CharAt(position); - if (ch == match) - { - if (comment == PositionIsOnComment(position, lexer)) sub++; - } - else if (ch == toMatch && comment == PositionIsOnComment(position, lexer)) - { - sub--; - if (sub < 0) return position; - } - } - return -1; - } - - /// - /// File dropped on the control, fire URIDropped event - /// - unsafe void HandleFileDrop(IntPtr hDrop) - { - int nfiles = DragQueryFileA(hDrop, 0xffffffff, (IntPtr)null, 0); - string files = ""; - byte[] buffer = new byte[PATH_LEN]; - for (uint i = 0; i 0) files += ' '; - files += '"'+MarshalStr((IntPtr)b) + '"'; - } - } - DragFinish(hDrop); - if (URIDropped != null) URIDropped(this, files); - } - - - /// - /// Returns the base style (without indicators) byte at the position. - /// - public int BaseStyleAt(int pos) - { - return (int)(SPerform(2010, (uint)pos, 0) & ((1 << this.StyleBits) - 1)); - } + + /// + /// Custom way to find the matching brace when BraceMatch() does not work + /// + public int SafeBraceMatch(int position) + { + int match = this.CharAt(position); + int toMatch = 0; + int length = TextLength; + int ch; + int sub = 0; + int lexer = Lexer; + Colourise(0, -1); + bool comment = PositionIsOnComment(position, lexer); + switch (match) + { + case '{': + toMatch = '}'; + goto down; + case '(': + toMatch = ')'; + goto down; + case '[': + toMatch = ']'; + goto down; + case '}': + toMatch = '{'; + goto up; + case ')': + toMatch = '('; + goto up; + case ']': + toMatch = '['; + goto up; + } + return -1; + // search up + up: + while (position >= 0) + { + position--; + ch = CharAt(position); + if (ch == match) + { + if (comment == PositionIsOnComment(position, lexer)) sub++; + } + else if (ch == toMatch && comment == PositionIsOnComment(position, lexer)) + { + sub--; + if (sub < 0) return position; + } + } + return -1; + // search down + down: + while (position < length) + { + position++; + ch = CharAt(position); + if (ch == match) + { + if (comment == PositionIsOnComment(position, lexer)) sub++; + } + else if (ch == toMatch && comment == PositionIsOnComment(position, lexer)) + { + sub--; + if (sub < 0) return position; + } + } + return -1; + } + + /// + /// File dropped on the control, fire URIDropped event + /// + unsafe void HandleFileDrop(IntPtr hDrop) + { + int nfiles = DragQueryFileA(hDrop, 0xffffffff, (IntPtr)null, 0); + string files = ""; + byte[] buffer = new byte[PATH_LEN]; + for (uint i = 0; i < nfiles; i++) + { + fixed (byte* b = buffer) + { + DragQueryFileA(hDrop, i, (IntPtr)b, PATH_LEN); + if (files.Length > 0) files += ' '; + files += '"' + MarshalStr((IntPtr)b) + '"'; + } + } + DragFinish(hDrop); + if (URIDropped != null) URIDropped(this, files); + } + + + /// + /// Returns the base style (without indicators) byte at the position. + /// + public int BaseStyleAt(int pos) + { + return (int)(SPerform(2010, (uint)pos, 0) & ((1 << this.StyleBits) - 1)); + } /// /// Adds the specified highlights to the control @@ -6481,7 +6553,7 @@ public void MoveLine(int dir) int line = startLine; if (dir > 0) --line; int indent = dir * this.Indent; - if (ctrlBlock < 0)indent = -indent; + if (ctrlBlock < 0) indent = -indent; this.SetLineIndentation(line, this.GetLineIndentation(line) + indent); } } @@ -6631,7 +6703,7 @@ public bool IsComment(string str) ret = ((!String.IsNullOrEmpty(lineComment) && str.StartsWith(lineComment)) || (!String.IsNullOrEmpty(blockComment) && str.StartsWith(blockComment))); return ret; } - + /// /// Determines whether the input string is a start/end of a control block /// Returns -1:start, 1:end, 0:neither @@ -6777,8 +6849,8 @@ public string GetWordLeft(int position, bool skipWS) return word; } - #endregion + #endregion } - + } From 9a8db43de8b1fb8cefd89179cccb06a94715c86a Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Thu, 26 Feb 2015 23:42:27 +0100 Subject: [PATCH 19/36] Scintilla commands replacement Managed Ctrl + Up/Down command to get notified of scroll changes. New setting to control word-related actions behaviour. --- FlashDevelop/Managers/ScintillaManager.cs | 1 + FlashDevelop/Settings/Accessors.cs | 6 ++ .../PluginCore/Controls/CompletionList.cs | 3 +- .../Controls/CompletionListControl.cs | 2 +- PluginCore/PluginCore/Interfaces.cs | 31 +++---- PluginCore/PluginCore/Resources/de_DE.resX | 4 + PluginCore/PluginCore/Resources/en_US.resX | 4 + PluginCore/PluginCore/Resources/eu_ES.resX | 4 + PluginCore/PluginCore/Resources/ja_JP.resX | 4 + PluginCore/PluginCore/Resources/zh_CN.resx | 4 + PluginCore/ScintillaNet/ScintillaControl.cs | 89 ++++++++++++++++++- 11 files changed, 134 insertions(+), 18 deletions(-) diff --git a/FlashDevelop/Managers/ScintillaManager.cs b/FlashDevelop/Managers/ScintillaManager.cs index fa25a099b0..574b4af519 100644 --- a/FlashDevelop/Managers/ScintillaManager.cs +++ b/FlashDevelop/Managers/ScintillaManager.cs @@ -211,6 +211,7 @@ public static void ApplySciSettings(ScintillaControl sci, Boolean hardUpdate) sci.TabWidth = Globals.Settings.TabWidth; sci.ViewWS = Convert.ToInt32(Globals.Settings.ViewWhitespace); sci.WrapMode = Convert.ToInt32(Globals.Settings.WrapText); + sci.CamelHumps = Globals.Settings.UseCamelHumps; sci.SetProperty("fold", Convert.ToInt32(Globals.Settings.UseFolding).ToString()); sci.SetProperty("fold.comment", Convert.ToInt32(Globals.Settings.FoldComment).ToString()); sci.SetProperty("fold.compact", Convert.ToInt32(Globals.Settings.FoldCompact).ToString()); diff --git a/FlashDevelop/Settings/Accessors.cs b/FlashDevelop/Settings/Accessors.cs index 6dcf563e5e..976938fdaf 100644 --- a/FlashDevelop/Settings/Accessors.cs +++ b/FlashDevelop/Settings/Accessors.cs @@ -370,6 +370,12 @@ public ScintillaNet.Enums.HighlightMatchingWordsMode HighlightMatchingWordsMode set { this.highlightMatchingWordsMode = value; } } + [DefaultValue(false)] + [DisplayName("Use Camel Humps")] + [LocalizedCategory("FlashDevelop.Category.Editor")] + [LocalizedDescription("FlashDevelop.Description.UseCamelHumps")] + public Boolean UseCamelHumps { get; set; } + #endregion #region Locale diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index e5384e4591..a06fe2c8c6 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -282,8 +282,9 @@ public event KeyEventHandler KeyDown add { Owner.KeyDown += value; } remove { Owner.KeyDown -= value; } } - + #pragma warning disable 0067 public event KeyPressEventHandler KeyPress; // Unhandled for this one + #pragma warning restore 0067 public event MouseEventHandler MouseDown { add { Owner.MouseDown += value; } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 7d996a79e6..8b1dda791a 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -943,7 +943,7 @@ private void Target_MouseDown(object sender, MouseEventArgs e) private void Target_KeyDown(object sender, KeyEventArgs e) { - e.SuppressKeyPress = HandleKeys(e.KeyData); + e.SuppressKeyPress = e.Handled = HandleKeys(e.KeyData); } private void Target_KeyPress(object sender, KeyPressEventArgs e) diff --git a/PluginCore/PluginCore/Interfaces.cs b/PluginCore/PluginCore/Interfaces.cs index 4549491da1..e605fb7ccd 100644 --- a/PluginCore/PluginCore/Interfaces.cs +++ b/PluginCore/PluginCore/Interfaces.cs @@ -15,14 +15,14 @@ namespace PluginCore { public interface IPlugin : IEventHandler { - #region IPlugin Methods - - void Dispose(); - void Initialize(); - - #endregion - - #region IPlugin Properties + #region IPlugin Methods + + void Dispose(); + void Initialize(); + + #endregion + + #region IPlugin Properties Int32 Api { get; } String Name { get; } @@ -34,18 +34,18 @@ public interface IPlugin : IEventHandler // List of valid API levels: // FlashDevelop 4.0 = 1 - - #endregion + + #endregion } public interface IEventHandler - { + { #region IEventHandler Methods void HandleEvent(Object sender, NotifyEvent e, HandlingPriority priority); #endregion - } + } public interface ITabbedDocument { @@ -116,7 +116,7 @@ public interface IMainForm : IWin32Window DockContent OpenEditableDocument(String file); DockContent CreateCustomDocument(Control ctrl); DockContent CreateEditableDocument(String file, String text, Int32 codepage); - DockContent CreateDockablePanel(Control form, String guid, Image image, DockState defaultDockState); + DockContent CreateDockablePanel(Control form, String guid, Image image, DockState defaultDockState); Boolean CallCommand(String command, String arguments); List FindMenuItems(String name); ToolStripItem FindMenuItem(String name); @@ -272,7 +272,7 @@ public interface ISettings Int32 CaretPeriod { get; set; } Int32 CaretWidth { get; set; } Int32 ScrollWidth { get; set; } - Int32 PrintMarginColumn { get; set; } + Int32 PrintMarginColumn { get; set; } Size WindowSize { get; set; } FormWindowState WindowState { get; set; } Point WindowPosition { get; set; } @@ -285,7 +285,8 @@ public interface ISettings Boolean DisableSmartMatch { get; set; } Boolean SaveUnicodeWithBOM { get; set; } String InsertionTriggers { get; set; } - + Boolean UseCamelHumps { get; set; } + #endregion } diff --git a/PluginCore/PluginCore/Resources/de_DE.resX b/PluginCore/PluginCore/Resources/de_DE.resX index 7b8fa75386..5f24adab97 100644 --- a/PluginCore/PluginCore/Resources/de_DE.resX +++ b/PluginCore/PluginCore/Resources/de_DE.resX @@ -3155,6 +3155,10 @@ Bitte bedenken Sie, dass Sie viele Projektoptionen nicht mehr nutzen können, so Wann Wörter die der momentanen Auswahl entsprechen hervorgehoben werden sollen. Added after 4.7.0 + + If true, Next/Previous Word related actions work on word segments delimited by capitalisation changes or underscores. + Added after 4.7.1 + Aufgaben in ausgeschlossenen Pfaden werden nicht angezeigt. diff --git a/PluginCore/PluginCore/Resources/en_US.resX b/PluginCore/PluginCore/Resources/en_US.resX index bac5dc6545..b2e1b011ee 100644 --- a/PluginCore/PluginCore/Resources/en_US.resX +++ b/PluginCore/PluginCore/Resources/en_US.resX @@ -3160,6 +3160,10 @@ Please note that with injection enabled, you will not be able to use many projec When words matching the current selection should be highlighted. Added after 4.7.0 + + If true, Next/Previous Word related actions work on word segments delimited by capitalisation changes or underscores. + Added after 4.7.1 + Tasks under the excluded paths are not shown in the task list. diff --git a/PluginCore/PluginCore/Resources/eu_ES.resX b/PluginCore/PluginCore/Resources/eu_ES.resX index a0dbb2629b..60b482a730 100644 --- a/PluginCore/PluginCore/Resources/eu_ES.resX +++ b/PluginCore/PluginCore/Resources/eu_ES.resX @@ -3148,6 +3148,10 @@ Kontutan izan injekzioa gaituz gero, ezin izanen diren proiektuaren hainbat auke When words matching the current selection should be highlighted. Added after 4.7.0 + + If true, Next/Previous Word related actions work on word segments delimited by capitalisation changes or underscores. + Added after 4.7.1 + Baztertutako bideetako zereginak ez dira zereginen zerrendan erakutisko. diff --git a/PluginCore/PluginCore/Resources/ja_JP.resX b/PluginCore/PluginCore/Resources/ja_JP.resX index 353592dc20..caecc1089f 100644 --- a/PluginCore/PluginCore/Resources/ja_JP.resX +++ b/PluginCore/PluginCore/Resources/ja_JP.resX @@ -3150,6 +3150,10 @@ AfterSimilarAccessorMethod: 同様のアクセサメソッドの後に配置。" When words matching the current selection should be highlighted. Added after 4.7.0 + + If true, Next/Previous Word related actions work on word segments delimited by capitalisation changes or underscores. + Added after 4.7.1 + FlashDevelop のウインドウにシステムカラーを適応します。 diff --git a/PluginCore/PluginCore/Resources/zh_CN.resx b/PluginCore/PluginCore/Resources/zh_CN.resx index d924f0ad61..28878201d1 100644 --- a/PluginCore/PluginCore/Resources/zh_CN.resx +++ b/PluginCore/PluginCore/Resources/zh_CN.resx @@ -3155,6 +3155,10 @@ When words matching the current selection should be highlighted. Added after 4.7.0 + + If true, Next/Previous Word related actions work on word segments delimited by capitalisation changes or underscores. + Added after 4.7.1 + 排除路径下的任务不显示在任务列表中。 diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 4334763afd..00f8ab36d2 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -20,6 +20,7 @@ namespace ScintillaNet public class ScintillaControl : Control { private bool saveBOM; + private bool camelHumps; private Encoding encoding; private IntPtr directPointer; private bool hasHighlights = false; @@ -33,6 +34,7 @@ public class ScintillaControl : Control private Enums.IndentView indentView = Enums.IndentView.Real; private Enums.SmartIndent smartIndent = Enums.SmartIndent.CPP; private HashSet ignoredKeys = new HashSet(); + private Dictionary keyCommands = new Dictionary(); private string configLanguage = String.Empty; private string fileName = String.Empty; private int lastSelectionLength = 0; @@ -65,6 +67,25 @@ public ScintillaControl(string fullpath) { IntPtr lib = LoadLibrary(fullpath); } + + // Most Windows Forms controls delay-load everything until a handle is created. + // That's a major pain so we just explicity create a handle right away. + CreateControl(); + + // Clear some default shortcuts, we are interested in managing them ourselves + // IMHO a better approach would be to call ClearAllCmdKeys and set managed replacements, like current ScintillaNet + ClearCmdKey(SCK_DOWN + (SCMOD_CTRL << 16)); + ClearCmdKey(SCK_UP + (SCMOD_CTRL << 16)); + ClearCmdKey(SCK_LEFT + (SCMOD_CTRL << 16)); + ClearCmdKey(SCK_RIGHT + (SCMOD_CTRL << 16)); + ClearCmdKey(SCK_LEFT + (SCMOD_CTRL << 16) + (SCMOD_SHIFT << 16)); + ClearCmdKey(SCK_RIGHT + (SCMOD_CTRL << 16) + (SCMOD_SHIFT << 16)); + ClearCmdKey(SCK_DELETE + (SCMOD_CTRL << 16)); + + keyCommands[Keys.Control | Keys.Down] = LineScrollDown; + keyCommands[Keys.Control | Keys.Up] = LineScrollUp; + CamelHumps = false; + UpdateUI += new UpdateUIHandler(OnUpdateUI); UpdateUI += new UpdateUIHandler(OnBraceMatch); UpdateUI += new UpdateUIHandler(OnCancelHighlight); @@ -3990,6 +4011,16 @@ public void DelWordRight() SPerform(2336, 0, 0); } + /// + /// Delete the word part to the right of the caret. + /// + public void DelWordPartRight() + { + SetSel(CurrentPos, CurrentPos); + WordPartRightExtend(); + Clear(); + } + /// /// Cut the line containing the caret. /// @@ -4049,6 +4080,8 @@ public void LineScrollDown() int newScroll = FirstVisibleLine; + if (newScroll == oldScroll) return; + // Decrement? OnScroll(new ScrollEventArgs(ScrollEventType.SmallIncrement, oldScroll, newScroll, ScrollOrientation.VerticalScroll)); } @@ -4064,6 +4097,8 @@ public void LineScrollUp() int newScroll = FirstVisibleLine; + if (newScroll == oldScroll) return; + // Decrement? OnScroll(new ScrollEventArgs(ScrollEventType.SmallIncrement, oldScroll, newScroll, ScrollOrientation.VerticalScroll)); } @@ -4974,6 +5009,15 @@ public int ContractedFoldNext(int lineStart) public const int MAXDWELLTIME = 10000000; private const int PATH_LEN = 1024; + private const int SCK_DOWN = 300; + private const int SCK_UP = 301; + private const int SCK_LEFT = 302; + private const int SCK_RIGHT = 303; + private const int SCK_DELETE = 308; + private const int SCMOD_SHIFT = 1; + private const int SCMOD_CTRL = 2; + private const int SCMOD_ALT = 4; + #endregion #region Scintilla Shortcuts @@ -5141,9 +5185,12 @@ private void WmScroll(ref Message m) } if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) - set = (ScrollEventType) ((short) ((int) (long) m.WParam & 0xffff)); + set = (ScrollEventType)((short)((int)(long)m.WParam & 0xffff)); else + { + if (oldScroll == newScroll) return; set = oldScroll > newScroll ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement; + } OnScroll(new ScrollEventArgs(set, oldScroll, newScroll, so)); } @@ -5362,6 +5409,18 @@ unsafe string MarshalStr(IntPtr p, int len) #region Automated Features + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + Action keyCommand; + if (!e.Handled && keyCommands.TryGetValue(e.KeyData, out keyCommand)) + { + keyCommand(); + e.SuppressKeyPress = true; + } + } + /// /// Raises the event. /// @@ -5749,6 +5808,34 @@ public bool SaveBOM } } + /// + /// Defines the current behaviour for next/previous word-related actions + /// + public bool CamelHumps + { + get { return camelHumps; } + set + { + camelHumps = value; + if (!value) + { + keyCommands[Keys.Control | Keys.Left] = WordLeft; + keyCommands[Keys.Control | Keys.Right] = WordRight; + keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordLeftExtend; + keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordRightExtend; + keyCommands[Keys.Control | Keys.Delete] = DelWordRight; + } + else + { + keyCommands[Keys.Control | Keys.Left] = WordPartLeft; + keyCommands[Keys.Control | Keys.Right] = WordPartRight; + keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordPartLeftExtend; + keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordPartRightExtend; + keyCommands[Keys.Control | Keys.Delete] = DelWordPartRight; + } + } + } + /// /// Adds a line end marker to the end of the document /// From e0b9eb4020e267a553d9b9a38f5c318c19350261 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 00:11:33 +0100 Subject: [PATCH 20/36] Scintilla focus event change Removed custom focus event not needed anymore and got TabbedDocument.EditorFocusChanged working again. --- FlashDevelop/Docking/TabbedDocument.cs | 16 +++++++--------- PluginCore/ScintillaNet/Events.cs | 1 - PluginCore/ScintillaNet/ScintillaControl.cs | 1 - 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/FlashDevelop/Docking/TabbedDocument.cs b/FlashDevelop/Docking/TabbedDocument.cs index 57fd87ec1f..e895d02314 100644 --- a/FlashDevelop/Docking/TabbedDocument.cs +++ b/FlashDevelop/Docking/TabbedDocument.cs @@ -293,8 +293,8 @@ public void AddEditorControls(String file, String text, Int32 codepage) this.editor.MarkerDeleteAll(2); this.IsModified = false; }; - this.editor.FocusChanged += new FocusHandler(this.EditorFocusChanged); - this.editor2.FocusChanged += new FocusHandler(this.EditorFocusChanged); + editor.GotFocus += EditorFocusChanged; + editor2.GotFocus += EditorFocusChanged; this.editor.UpdateSync += new UpdateSyncHandler(this.EditorUpdateSync); this.editor2.UpdateSync += new UpdateSyncHandler(this.EditorUpdateSync); this.Controls.Add(this.splitContainer); @@ -323,14 +323,12 @@ private void EditorUpdateSync(ScintillaControl sender) /// /// When the user changes to sci, block events from inactive sci /// - private void EditorFocusChanged(ScintillaControl sender) + private void EditorFocusChanged(object sender, EventArgs e) { - if (sender.IsFocus) - { - this.lastEditor = sender; - this.editor.DisableAllSciEvents = (sender == editor2); - this.editor2.DisableAllSciEvents = (sender == editor); - } + var sci = (ScintillaControl)sender; + this.lastEditor = sci; + this.editor.DisableAllSciEvents = (sender == editor2); + this.editor2.DisableAllSciEvents = (sender == editor); } /// diff --git a/PluginCore/ScintillaNet/Events.cs b/PluginCore/ScintillaNet/Events.cs index c57a93c246..4952554ce5 100644 --- a/PluginCore/ScintillaNet/Events.cs +++ b/PluginCore/ScintillaNet/Events.cs @@ -3,7 +3,6 @@ namespace ScintillaNet { - public delegate void FocusHandler(ScintillaControl sender); public delegate void ZoomHandler(ScintillaControl sender); public delegate void PaintedHandler(ScintillaControl sender); public delegate void UpdateUIHandler(ScintillaControl sender); diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 00f8ab36d2..ba2e04a7ac 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -122,7 +122,6 @@ protected override CreateParams CreateParams public event KeyHandler Key; public event ZoomHandler Zoom; - public event FocusHandler FocusChanged; public event StyleNeededHandler StyleNeeded; public event CharAddedHandler CharAdded; public event SavePointReachedHandler SavePointReached; From c69726233d9e15f9ca53bab7accd77999968bbfa Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 11:42:00 +0100 Subject: [PATCH 21/36] Only handle back key in ASComplete if the editor has the focus --- External/Plugins/ASCompletion/Completion/ASComplete.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/Plugins/ASCompletion/Completion/ASComplete.cs b/External/Plugins/ASCompletion/Completion/ASComplete.cs index 0cb71043bd..6d76a845d8 100644 --- a/External/Plugins/ASCompletion/Completion/ASComplete.cs +++ b/External/Plugins/ASCompletion/Completion/ASComplete.cs @@ -258,7 +258,7 @@ static public bool OnShortcut(Keys keys, ScintillaControl Sci) } else if (keys == Keys.Back) { - HandleAddClosingBraces(Sci, Sci.CurrentChar, false); + if (Sci.ContainsFocus) HandleAddClosingBraces(Sci, Sci.CurrentChar, false); return false; } // show calltip From 1080373e85e882959d5762ac1631553f2adb96ef Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 11:44:31 +0100 Subject: [PATCH 22/36] Restore back key notification on ASComplete Also, cleaned up a bit "Scintilla focus event change" commit --- FlashDevelop/Docking/TabbedDocument.cs | 7 +++---- PluginCore/ScintillaNet/ScintillaControl.cs | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/FlashDevelop/Docking/TabbedDocument.cs b/FlashDevelop/Docking/TabbedDocument.cs index e895d02314..4e0bab7526 100644 --- a/FlashDevelop/Docking/TabbedDocument.cs +++ b/FlashDevelop/Docking/TabbedDocument.cs @@ -293,8 +293,8 @@ public void AddEditorControls(String file, String text, Int32 codepage) this.editor.MarkerDeleteAll(2); this.IsModified = false; }; - editor.GotFocus += EditorFocusChanged; - editor2.GotFocus += EditorFocusChanged; + this.editor.GotFocus += EditorFocusChanged; + this.editor2.GotFocus += EditorFocusChanged; this.editor.UpdateSync += new UpdateSyncHandler(this.EditorUpdateSync); this.editor2.UpdateSync += new UpdateSyncHandler(this.EditorUpdateSync); this.Controls.Add(this.splitContainer); @@ -325,8 +325,7 @@ private void EditorUpdateSync(ScintillaControl sender) /// private void EditorFocusChanged(object sender, EventArgs e) { - var sci = (ScintillaControl)sender; - this.lastEditor = sci; + this.lastEditor = (ScintillaControl)sender; this.editor.DisableAllSciEvents = (sender == editor2); this.editor2.DisableAllSciEvents = (sender == editor); } diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index ba2e04a7ac..f6a2798f9a 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -4015,7 +4015,8 @@ public void DelWordRight() /// public void DelWordPartRight() { - SetSel(CurrentPos, CurrentPos); + int currPos = CurrentPos; + SetSel(currPos, currPos); WordPartRightExtend(); Clear(); } @@ -5138,6 +5139,9 @@ public override bool PreProcessMessage(ref Message m) { if (this.ExecuteShortcut(keys) || base.PreProcessMessage(ref m)) return true; } + if (keys == 8) + // Hacky... Back key, it's handled by ASCompletion, before it was set as a shortcut so it was present in the ignoredKeys collection, that was in several ways hackier + return base.PreProcessMessage(ref m); if (((Control.ModifierKeys & Keys.Control) != 0) && ((Control.ModifierKeys & Keys.Alt) == 0)) { Int32 code = (Int32)m.WParam; From c24b0bd83edbcdf484e0e459be8ddb6379c02f49 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 12:22:16 +0100 Subject: [PATCH 23/36] Don't hide simple tip in DwellEnd if the completion list is active It fixes when the user wants to select something, but when the user moves the mouse the tip suddenly disappears. --- PluginCore/PluginCore/Controls/UITools.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index d206ac8ac8..57d6ef66e3 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -191,6 +191,7 @@ private void HandleDwellStart(ScintillaControl sci, int position) if (!bounds.Contains(mousePos)) return; // check no panel is over the editor + // 2015/02 CompletionList changes: Is this check currently needed? If a panel is over the editor HandleDwellStart doesn't seem to fire DockPanel panel = PluginBase.MainForm.DockPanel; DockContentCollection panels = panel.Contents; foreach (DockContent content in panels) @@ -229,7 +230,10 @@ private Point GetMousePosIn(Control ctrl) private void HandleDwellEnd(ScintillaControl sci, int position) { - simpleTip.Hide(); + // NOTE: simpleTip should only be hidden if a certain movement threshold is exceeded (x <> current word, y <> word + tip pos & height) or HandleDwellStart is fired again + // This would allow the user to select the tip text + if (!CompletionList.Active) + simpleTip.Hide(); if (OnMouseHoverEnd != null) OnMouseHoverEnd(sci, position); } From c102b25a77cd3257a1246a531eb74536ecce9a76 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 13:26:44 +0100 Subject: [PATCH 24/36] Some default ScintilaHost improvements Optimized the implementation so the current Scintilla control doesn't need to be constantly resolved. Hooked up the Scintilla UpdateUI even to hide the completion list after some events. --- .../PluginCore/Controls/CompletionList.cs | 77 ++++++++++++++----- PluginCore/PluginCore/Controls/UITools.cs | 6 ++ 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index a06fe2c8c6..dd20e72344 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -1,4 +1,4 @@ -// NOTE: We may well dump this static class, or mark it as deprecated, and create UITools.CompletionList, it would make the code look bit more organized and in line with some other controls +// NOTE: We may well dump this static class, or mark it as deprecated, and create UITools.CompletionList, it would make the code look bit more organized and in line with other code in there using System; using System.Drawing; @@ -51,6 +51,8 @@ public static void CreateControl(IMainForm mainForm) completionList = new CompletionListControl(new ScintillaHost()); completionList.OnCancel += OnCancelHandler; completionList.OnInsert += OnInsertHandler; + completionList.OnShowing += OnShowingHandler; + completionList.OnHidden += OnHiddenHandler; } #endregion @@ -211,6 +213,7 @@ static public IntPtr GetHandle() static public void OnChar(ScintillaControl sci, int value) { + // Note: If we refactor/remove this class, this could be called directly from UITools if (!completionList.OnChar((char)value)) UITools.Manager.SendChar(sci, value); } @@ -232,6 +235,21 @@ private static void OnInsertHandler(Control sender, Int32 position, String text, OnInsert((ScintillaControl)sender, position, text, trigger, item); } + private static void OnShowingHandler(object sender, EventArgs e) + { + ((ScintillaControl)completionList.Host.Owner).UpdateUI += OnUIRefresh; + } + + private static void OnHiddenHandler(object sender, EventArgs e) + { + ((ScintillaControl)completionList.Host.Owner).UpdateUI -= OnUIRefresh; + } + + private static void OnUIRefresh(ScintillaControl sci) + { + if (Active && !CheckPosition(sci.CurrentPos)) Hide(); + } + #endregion #region Controls fading on Control key @@ -248,10 +266,28 @@ internal static void FadeIn() #endregion - // TODO: Get hold of current Scintilla control through UITools and don't call CurrentDocument.SciControl everytime - private class ScintillaHost : ICompletionListHost + internal class ScintillaHost : ICompletionListHost { + private WeakReference sci = new WeakReference(null); + internal ScintillaControl SciControl + { + get + { + if (sci.Target == null) + return null; + + if (!sci.IsAlive) + return PluginBase.MainForm.CurrentDocument.SciControl; + + return (ScintillaControl)sci.Target; + } + set + { + sci.Target = value; + } + } + public event EventHandler LostFocus { add { Owner.LostFocus += value; } @@ -263,14 +299,14 @@ public event EventHandler PositionChanged { add { - var sci = PluginBase.MainForm.CurrentDocument.SciControl; + var sci = SciControl; sci.Scroll += Scintilla_Scroll; sci.Zoom += Scintilla_Zoom; positionChanged += value; } remove { - var sci = PluginBase.MainForm.CurrentDocument.SciControl; + var sci = SciControl; sci.Scroll -= Scintilla_Scroll; sci.Zoom -= Scintilla_Zoom; positionChanged -= value; @@ -293,63 +329,61 @@ public event MouseEventHandler MouseDown public Control Owner { - get { return PluginBase.MainForm.CurrentDocument.SciControl; } + get { return SciControl; } } public string SelectedText { - get { return PluginBase.MainForm.CurrentDocument.SciControl.SelText; } - set { PluginBase.MainForm.CurrentDocument.SciControl.ReplaceSel(value); } + get { return SciControl.SelText; } + set { SciControl.ReplaceSel(value); } } public int SelectionEnd { - get { return PluginBase.MainForm.CurrentDocument.SciControl.SelectionEnd; } - set { PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; } + get { return SciControl.SelectionEnd; } + set { SciControl.SelectionStart = value; } } public int SelectionStart { - get { return PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart; } - set { PluginBase.MainForm.CurrentDocument.SciControl.SelectionStart = value; } + get { return SciControl.SelectionStart; } + set { SciControl.SelectionStart = value; } } public int CurrentPos { - get { return PluginBase.MainForm.CurrentDocument.SciControl.CurrentPos; } + get { return SciControl.CurrentPos; } } public bool IsEditable { - get { return PluginBase.MainForm.CurrentDocument.IsEditable && PluginBase.MainForm.CurrentDocument.SciControl != null; } + get { return PluginBase.MainForm.CurrentDocument.IsEditable && SciControl != null; } } public int GetLineHeight() { - var sci = PluginBase.MainForm.CurrentDocument.SciControl; - return UITools.Manager.LineHeight(sci); + return UITools.Manager.LineHeight(SciControl); } public Point GetPositionFromCharIndex(int pos) { - var sci = PluginBase.MainForm.CurrentDocument.SciControl; + var sci = SciControl; return new Point(sci.PointXFromPosition(pos), sci.PointYFromPosition(pos)); } public void SetSelection(int start, int end) { - var sci = PluginBase.MainForm.CurrentDocument.SciControl; - sci.SetSel(start, end); + SciControl.SetSel(start, end); } public void BeginUndoAction() { - PluginBase.MainForm.CurrentDocument.SciControl.BeginUndoAction(); + SciControl.BeginUndoAction(); } public void EndUndoAction() { - PluginBase.MainForm.CurrentDocument.SciControl.EndUndoAction(); + SciControl.EndUndoAction(); } private void Scintilla_Scroll(object sender, ScrollEventArgs e) @@ -363,6 +397,7 @@ private void Scintilla_Zoom(ScintillaControl sci) if (positionChanged != null) positionChanged(sci, EventArgs.Empty); } + } } } diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 57d6ef66e3..1779432298 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -165,6 +165,7 @@ public void ListenTo(ScintillaControl sci) sci.UpdateUI += new UpdateUIHandler(OnUIRefresh); sci.TextInserted += new TextInsertedHandler(OnTextInserted); sci.TextDeleted += new TextDeletedHandler(OnTextDeleted); + sci.GotFocus += OnGotFocus; } /// @@ -319,6 +320,11 @@ private void OnTextDeleted(ScintillaControl sci, int position, int length, int l OnTextChanged(sci, position, -length, linesAdded); } + private void OnGotFocus(object sender, EventArgs e) + { + ((CompletionList.ScintillaHost)CompletionList.completionList.Host).SciControl = (ScintillaControl)sender; + } + private void OnChar(ScintillaControl sci, int value) { if (sci == null || DisableEvents) return; From 15befec13d35bcc05d7062ba81dfbe1a3d3d3277 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 13:27:39 +0100 Subject: [PATCH 25/36] F1 key support Hooked up the F1 key in a way that's contained in the CompletionList control itself. Added some notes. --- .../Controls/CompletionListControl.cs | 18 ++++++++++++++++-- .../PluginCore/Controls/ICompletionListHost.cs | 5 +++++ PluginCore/PluginCore/Controls/UITools.cs | 11 +---------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 8b1dda791a..f412199d87 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1215,10 +1215,9 @@ internal void FadeIn() public bool PreFilterMessage(ref Message m) { - if (Tip.Focused || CallTip.Focused) return false; - if (m.Msg == Win32.WM_MOUSEWHEEL) // capture all MouseWheel events { + if (Tip.Focused || CallTip.Focused) return false; if (Win32.ShouldUseWin32()) { Win32.SendMessage(completionList.Handle, m.Msg, (Int32)m.WParam, (Int32)m.LParam); @@ -1227,14 +1226,29 @@ public bool PreFilterMessage(ref Message m) } else if (m.Msg == Win32.WM_KEYDOWN) { + if (Tip.Focused || CallTip.Focused) return false; if ((int)m.WParam == 17) // Ctrl { if (Active) FadeOut(); if (CallTip.CallTipActive) CallTip.FadeOut(); } + else if ((int) m.WParam == 112) // F1 - since it's by default set as a shortcut we are required to handle it at a lower level + { + UITools.Manager.ShowDetails = !UITools.Manager.ShowDetails; + if (Active) + UpdateTip(null, null); + else + { + if (Tip.Visible) + Tip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); + if (CallTip.Visible) + callTip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); + } + } } else if (m.Msg == Win32.WM_KEYUP) { + if (Tip.Focused || CallTip.Focused) return false; if ((int)m.WParam == 17 || (int)m.WParam == 18) // Ctrl / AltGr { if (Active) FadeIn(); diff --git a/PluginCore/PluginCore/Controls/ICompletionListHost.cs b/PluginCore/PluginCore/Controls/ICompletionListHost.cs index 31a74256fb..2d89aae388 100644 --- a/PluginCore/PluginCore/Controls/ICompletionListHost.cs +++ b/PluginCore/PluginCore/Controls/ICompletionListHost.cs @@ -4,6 +4,11 @@ namespace PluginCore.Controls { + /* Possible properties/methods of interest: + * - suppressedKeys: collection of extra key combinations that would be consumed by the completionList + * - OnListShowing/OnListHidden: method to know when the list is going to show or is hidden, better to get a reference to the list and listen for events + * - AfterCompletionCommit/BeforeCompletionCommit + */ public interface ICompletionListHost { diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 1779432298..742fdefc6a 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -405,17 +405,8 @@ private bool HandleKeys(Keys key) return false; } - // toggle "long-description" - if (key == Keys.F1) - { - showDetails = !showDetails; - if (callTip.CallTipActive) callTip.UpdateTip(sci); - else CompletionList.UpdateTip(null, null); - return true; - } - // switches - else if ((key & Keys.ShiftKey) == Keys.ShiftKey || (key & Keys.ControlKey) == Keys.ControlKey || (key & Keys.Menu) == Keys.Menu) + if ((key & Keys.ShiftKey) == Keys.ShiftKey || (key & Keys.ControlKey) == Keys.ControlKey || (key & Keys.Menu) == Keys.Menu) { return false; } From 6343665bccfdd7a4f6b77f78f1f49604a92cf682 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 13:52:11 +0100 Subject: [PATCH 26/36] Do not always propagate F1 key --- .../PluginCore/Controls/CompletionListControl.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index f412199d87..4cf120e355 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1235,15 +1235,27 @@ public bool PreFilterMessage(ref Message m) else if ((int) m.WParam == 112) // F1 - since it's by default set as a shortcut we are required to handle it at a lower level { UITools.Manager.ShowDetails = !UITools.Manager.ShowDetails; + bool retVal = false; if (Active) + { UpdateTip(null, null); + retVal = true; + } else { if (Tip.Visible) + { Tip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); + retVal = true; + } if (CallTip.Visible) + { callTip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); + retVal = true; + } } + + return retVal; } } else if (m.Msg == Win32.WM_KEYUP) From e7ca7c32f99fd7c381b35ffd6a53f699e235e91b Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 27 Feb 2015 13:56:38 +0100 Subject: [PATCH 27/36] Key detection fix Ctrl + Shift + Left or Ctrl + Shift + Right --- PluginCore/PluginCore/Controls/CompletionListControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 4cf120e355..3c613389a2 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1177,7 +1177,7 @@ public bool HandleKeys(Keys key) else if (modifiers == (Keys.Shift | Keys.Control)) { key = key & Keys.KeyCode; - if (key == Keys.Left && key == Keys.Right) + if (key == Keys.Left || key == Keys.Right) Hide(); } From 762aa04a58f7a6861d43a1dc6ae46a7eb26e0cfa Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 2 Mar 2015 15:25:27 +0100 Subject: [PATCH 28/36] Ctrl + Backspace when CamelHumps = true --- PluginCore/ScintillaNet/ScintillaControl.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index f6a2798f9a..c324b03a4b 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -80,6 +80,7 @@ public ScintillaControl(string fullpath) ClearCmdKey(SCK_RIGHT + (SCMOD_CTRL << 16)); ClearCmdKey(SCK_LEFT + (SCMOD_CTRL << 16) + (SCMOD_SHIFT << 16)); ClearCmdKey(SCK_RIGHT + (SCMOD_CTRL << 16) + (SCMOD_SHIFT << 16)); + ClearCmdKey(SCK_BACK + (SCMOD_CTRL << 16)); ClearCmdKey(SCK_DELETE + (SCMOD_CTRL << 16)); keyCommands[Keys.Control | Keys.Down] = LineScrollDown; @@ -4010,6 +4011,17 @@ public void DelWordRight() SPerform(2336, 0, 0); } + /// + /// Delete the word part to the left of the caret. + /// + public void DelWordPartLeft() + { + int currPos = CurrentPos; + SetSel(currPos, currPos); + WordPartLeftExtend(); + Clear(); + } + /// /// Delete the word part to the right of the caret. /// @@ -5009,6 +5021,7 @@ public int ContractedFoldNext(int lineStart) public const int MAXDWELLTIME = 10000000; private const int PATH_LEN = 1024; + private const int SCK_BACK = 8; private const int SCK_DOWN = 300; private const int SCK_UP = 301; private const int SCK_LEFT = 302; @@ -5826,6 +5839,7 @@ public bool CamelHumps keyCommands[Keys.Control | Keys.Right] = WordRight; keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordLeftExtend; keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordRightExtend; + keyCommands[Keys.Control | Keys.Back] = DelWordLeft; keyCommands[Keys.Control | Keys.Delete] = DelWordRight; } else @@ -5834,6 +5848,7 @@ public bool CamelHumps keyCommands[Keys.Control | Keys.Right] = WordPartRight; keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordPartLeftExtend; keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordPartRightExtend; + keyCommands[Keys.Control | Keys.Back] = DelWordPartLeft; keyCommands[Keys.Control | Keys.Delete] = DelWordPartRight; } } From 601a917ca9b2dfe0cc88d57400f984a00824346b Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Thu, 5 Mar 2015 10:15:58 +0100 Subject: [PATCH 29/36] Finished with the refactoring - Completely decoupled RichToolTip and MethodCallTip, there is room for improvement, but the effort and time may not be worth it at this moment. I consider user experience has improved considerably, although the changes may not be apparent at first sight: the call tip continues on other lines if needed, doesn't disappear when moving left to a parent call, like the completion list is less intrusive with the key handling, etc. Continuing the call tip through other members has the problem that if jumping to the first argument of *eventListener methods it displays the completion list with possible event types, should we ignore this case or take it into account to show the call tip? Feed would be welcome and then act accordingly. - The default implementation for Scintilla now only gets the current Scintilla control for the first time and tracks window movements and resizing. - CharacterClass is now a property of CompletionListControl, it completely removes the need for a ScintillaControl reference, optimizes inputting characters and is more logical. - Improved F1 key handling for tips. - Cleaned UITools a bit. We could remove the code related to locking Scintilla Control, but may be desired by some bizarre plugin? - Some other minimal implementation changes. --- .../ASCompletion/Completion/ASComplete.cs | 2 +- External/Plugins/ASCompletion/PluginMain.cs | 12 +- .../FlashDebugger/Controls/ImmediateUI.cs | 7 + .../PluginCore/Controls/CompletionList.cs | 101 +++++-- .../Controls/CompletionListControl.cs | 70 ++--- .../Controls/ICompletionListHost.cs | 7 +- .../PluginCore/Controls/MethodCallTip.cs | 273 ++++++++++++------ PluginCore/PluginCore/Controls/RichToolTip.cs | 34 ++- PluginCore/PluginCore/Controls/UITools.cs | 62 +--- PluginCore/ScintillaNet/ScintillaControl.cs | 16 + 10 files changed, 361 insertions(+), 223 deletions(-) diff --git a/External/Plugins/ASCompletion/Completion/ASComplete.cs b/External/Plugins/ASCompletion/Completion/ASComplete.cs index 6d76a845d8..fa4782e3ac 100644 --- a/External/Plugins/ASCompletion/Completion/ASComplete.cs +++ b/External/Plugins/ASCompletion/Completion/ASComplete.cs @@ -1332,7 +1332,7 @@ static private void ShowCalltip(ScintillaControl Sci, int paramIndex, bool force prevParam = paramName; calltipDetails = UITools.Manager.ShowDetails; string text = calltipDef + ASDocumentation.GetTipDetails(calltipMember, paramName); - UITools.CallTip.CallTipShow(Sci, calltipPos - calltipOffset, text, forceRedraw); + UITools.CallTip.CallTipShow(calltipPos - calltipOffset, text, forceRedraw); } // highlight diff --git a/External/Plugins/ASCompletion/PluginMain.cs b/External/Plugins/ASCompletion/PluginMain.cs index 7e7adf3e2f..90b0b945e5 100644 --- a/External/Plugins/ASCompletion/PluginMain.cs +++ b/External/Plugins/ASCompletion/PluginMain.cs @@ -900,16 +900,16 @@ private void OnTextChanged(ScintillaNet.ScintillaControl sender, int position, i ASContext.OnTextChanged(sender, position, length, linesAdded); } - private void OnUpdateCallTip(ScintillaNet.ScintillaControl sci, int position) + private void OnUpdateCallTip(Control sci, int position) { - if (ASComplete.HasCalltip()) - ASComplete.HandleFunctionCompletion(sci, false, true); - } + if (!ASComplete.HandleFunctionCompletion((ScintillaNet.ScintillaControl) sci, false, true)) + UITools.CallTip.Hide(); + } - private void OnUpdateSimpleTip(ScintillaNet.ScintillaControl sci, Point mousePosition) + private void OnUpdateSimpleTip(Control sci, Point mousePosition) { if (UITools.Tip.Visible) - OnMouseHover(sci, lastHoverPosition); + OnMouseHover((ScintillaNet.ScintillaControl)sci, lastHoverPosition); } void timerPosition_Elapsed(object sender, System.Timers.ElapsedEventArgs e) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index c61a2728ae..6ac98d1acb 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -228,6 +228,8 @@ public event KeyEventHandler KeyDown remove { _owner.KeyDown -= value; } } + public event KeyEventHandler KeyPosted; + public event KeyPressEventHandler KeyPress { add { _owner.KeyPress += value; } @@ -279,6 +281,11 @@ public TextBoxTarget(TextBox owner) _owner = owner; } + public int GetLineFromCharIndex(int pos) + { + return _owner.GetLineFromCharIndex(pos); + } + public Point GetPositionFromCharIndex(int pos) { return _owner.GetPositionFromCharIndex(pos == _owner.TextLength ? pos - 1 : pos); diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index dd20e72344..5066f267ec 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -51,8 +51,6 @@ public static void CreateControl(IMainForm mainForm) completionList = new CompletionListControl(new ScintillaHost()); completionList.OnCancel += OnCancelHandler; completionList.OnInsert += OnInsertHandler; - completionList.OnShowing += OnShowingHandler; - completionList.OnHidden += OnHiddenHandler; } #endregion @@ -235,21 +233,6 @@ private static void OnInsertHandler(Control sender, Int32 position, String text, OnInsert((ScintillaControl)sender, position, text, trigger, item); } - private static void OnShowingHandler(object sender, EventArgs e) - { - ((ScintillaControl)completionList.Host.Owner).UpdateUI += OnUIRefresh; - } - - private static void OnHiddenHandler(object sender, EventArgs e) - { - ((ScintillaControl)completionList.Host.Owner).UpdateUI -= OnUIRefresh; - } - - private static void OnUIRefresh(ScintillaControl sci) - { - if (Active && !CheckPosition(sci.CurrentPos)) Hide(); - } - #endregion #region Controls fading on Control key @@ -266,9 +249,13 @@ internal static void FadeIn() #endregion + #region Default Completion List Host + internal class ScintillaHost : ICompletionListHost { + private List controlHierarchy = new List(); + private WeakReference sci = new WeakReference(null); internal ScintillaControl SciControl { @@ -276,7 +263,7 @@ internal ScintillaControl SciControl { if (sci.Target == null) return null; - + if (!sci.IsAlive) return PluginBase.MainForm.CurrentDocument.SciControl; @@ -284,7 +271,10 @@ internal ScintillaControl SciControl } set { + if (sci.Target == value) return; + sci.Target = value; + ClearControlHierarchy(); } } @@ -299,17 +289,26 @@ public event EventHandler PositionChanged { add { - var sci = SciControl; - sci.Scroll += Scintilla_Scroll; - sci.Zoom += Scintilla_Zoom; + if (positionChanged == null || positionChanged.GetInvocationList().Length == 0) + { + var sci = SciControl; + sci.Scroll += Scintilla_Scroll; + sci.Zoom += Scintilla_Zoom; + + BuildControlHierarchy(sci); + } positionChanged += value; } remove { - var sci = SciControl; - sci.Scroll -= Scintilla_Scroll; - sci.Zoom -= Scintilla_Zoom; positionChanged -= value; + if (positionChanged == null || positionChanged.GetInvocationList().Length < 1) + { + var sci = SciControl; + sci.Scroll -= Scintilla_Scroll; + sci.Zoom -= Scintilla_Zoom; + ClearControlHierarchy(); + } } } @@ -318,9 +317,17 @@ public event KeyEventHandler KeyDown add { Owner.KeyDown += value; } remove { Owner.KeyDown -= value; } } + + public event KeyEventHandler KeyPosted + { + add { SciControl.KeyPosted += value; } + remove { SciControl.KeyPosted -= value; } + } + #pragma warning disable 0067 - public event KeyPressEventHandler KeyPress; // Unhandled for this one + public event KeyPressEventHandler KeyPress; // Unhandled for this one, although we could #pragma warning restore 0067 + public event MouseEventHandler MouseDown { add { Owner.MouseDown += value; } @@ -365,6 +372,11 @@ public int GetLineHeight() return UITools.Manager.LineHeight(SciControl); } + public int GetLineFromCharIndex(int pos) + { + return SciControl.LineFromPosition(pos); + } + public Point GetPositionFromCharIndex(int pos) { var sci = SciControl; @@ -386,6 +398,41 @@ public void EndUndoAction() SciControl.EndUndoAction(); } + private void BuildControlHierarchy(Control current) + { + while (current != null) + { + current.LocationChanged += Control_LocationChanged; + current.ParentChanged += Control_ParentChanged; + controlHierarchy.Add(current); + current = current.Parent; + } + } + + private void ClearControlHierarchy() + { + foreach (var control in controlHierarchy) + { + control.LocationChanged -= Control_LocationChanged; + control.ParentChanged -= Control_ParentChanged; + } + controlHierarchy.Clear(); + } + + private void Control_LocationChanged(object sender, EventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Control_ParentChanged(object sender, EventArgs e) + { + ClearControlHierarchy(); + BuildControlHierarchy(SciControl); + if (positionChanged != null) + positionChanged(sender, e); + } + private void Scintilla_Scroll(object sender, ScrollEventArgs e) { if (positionChanged != null) @@ -399,5 +446,7 @@ private void Scintilla_Zoom(ScintillaControl sci) } } - } + + #endregion + } } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 3c613389a2..48042e9432 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -5,9 +5,6 @@ using System.Windows.Forms; using PluginCore.Managers; using PluginCore.Helpers; -using ScintillaNet; - -// TODO: Remove all direct references to ScintillaControl namespace PluginCore.Controls { @@ -55,12 +52,6 @@ public class CompletionListControl : IMessageFilter private RichToolTip tip; private MethodCallTip callTip; // Used only by the main completion list so far, would it be better to control this case in another way? like the cl, we'd like to show this everywhere possible - /// - /// Set to 0 after calling .Show to keep the completion list active - /// when the text was erased completely (using backspace) - /// - public int MinWordLength; - #endregion #region Control Creation @@ -108,6 +99,8 @@ public CompletionListControl(ICompletionListHost target) listContainer.Padding = Padding.Empty; listHost.Items.Add(listContainer); + + CharacterClass = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; } #endregion @@ -147,6 +140,17 @@ public string SelectedLabel } } + /// + /// Set to 0 after calling .Show to keep the completion list active + /// when the text was erased completely (using backspace) + /// + public int MinWordLength { get; set; } + + /// + /// Defines the characters allowed as part of a variable name + /// + public string CharacterClass { get; set; } + /// /// Gets the target of the current completion list control /// @@ -163,10 +167,11 @@ public RichToolTip Tip get { if (tip == null) - tip = new RichToolTip(host.Owner); + tip = new RichToolTip(host); return tip; } - internal set { tip = value; } + // Allow injection of our own implementations + set { tip = value; } } /// @@ -177,10 +182,11 @@ public MethodCallTip CallTip get { if (callTip == null) - callTip = new MethodCallTip(PluginBase.MainForm); + callTip = new MethodCallTip(this); return callTip; } - internal set { callTip = value; } + // Allow injection of our own implementations + set { callTip = value; } } #endregion @@ -468,7 +474,7 @@ private void UpdatePosition() coord = host.Owner.PointToScreen(coord); coord.X += host.Owner.Left; var screen = Screen.FromHandle(host.Owner.Handle); - listUp = CallTip.CallTipActive || (coord.Y + listHost.Height > screen.WorkingArea.Bottom && coord.Y - listHost.Height > screen.WorkingArea.Top); + listUp = CallTip.CallTipActive || (coord.Y - listHost.Height > screen.WorkingArea.Top && coord.Y + host.GetLineHeight() + listHost.Height > screen.WorkingArea.Bottom); if (listUp) coord.Y -= listHost.Height; else coord.Y += host.GetLineHeight(); // Keep on screen area @@ -485,7 +491,7 @@ private void UpdatePosition() if (OnShowing != null) OnShowing(this, EventArgs.Empty); listHost.Opacity = 1; listHost.Show(coord); - if (CallTip.CallTipActive) CallTip.PositionControl(((ScintillaControl)host.Owner)); + if (CallTip.CallTipActive) CallTip.PositionControl(); AddHandlers(); } @@ -911,7 +917,8 @@ public IntPtr GetHandle() private void AddHandlers() { - Application.AddMessageFilter(this); + if (!CallTip.CallTipActive) + Application.AddMessageFilter(this); host.LostFocus += Target_LostFocus; host.MouseDown += Target_MouseDown; host.KeyDown += Target_KeyDown; @@ -921,7 +928,8 @@ private void AddHandlers() private void RemoveHandlers() { - Application.RemoveMessageFilter(this); + if (!CallTip.CallTipActive) + Application.RemoveMessageFilter(this); host.LostFocus -= Target_LostFocus; host.MouseDown -= Target_MouseDown; host.KeyDown -= Target_KeyDown; @@ -943,7 +951,8 @@ private void Target_MouseDown(object sender, MouseEventArgs e) private void Target_KeyDown(object sender, KeyEventArgs e) { - e.SuppressKeyPress = e.Handled = HandleKeys(e.KeyData); + if (!e.Handled) + e.SuppressKeyPress = e.Handled = HandleKeys(e.KeyData); } private void Target_KeyPress(object sender, KeyPressEventArgs e) @@ -962,9 +971,7 @@ private void Target_PositionChanged(object sender, EventArgs e) /// public bool OnChar(char c) { - // TODO: Inject these values or get from host - string characterClass = ScintillaControl.Configuration.GetLanguage(PluginBase.MainForm.CurrentDocument.SciControl.ConfigurationLanguage).characterclass.Characters; - if (characterClass.IndexOf(c) >= 0) + if (CharacterClass.IndexOf(c) >= 0) { word += c; currentPos++; @@ -1226,9 +1233,9 @@ public bool PreFilterMessage(ref Message m) } else if (m.Msg == Win32.WM_KEYDOWN) { - if (Tip.Focused || CallTip.Focused) return false; if ((int)m.WParam == 17) // Ctrl { + if (Tip.Focused || CallTip.Focused) return false; if (Active) FadeOut(); if (CallTip.CallTipActive) CallTip.FadeOut(); } @@ -1236,23 +1243,20 @@ public bool PreFilterMessage(ref Message m) { UITools.Manager.ShowDetails = !UITools.Manager.ShowDetails; bool retVal = false; + if (CallTip.Visible) + { + callTip.UpdateTip(); + retVal = true; + } if (Active) { UpdateTip(null, null); retVal = true; } - else + else if (Tip.Visible) { - if (Tip.Visible) - { - Tip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); - retVal = true; - } - if (CallTip.Visible) - { - callTip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); - retVal = true; - } + Tip.UpdateTip(); + retVal = true; } return retVal; diff --git a/PluginCore/PluginCore/Controls/ICompletionListHost.cs b/PluginCore/PluginCore/Controls/ICompletionListHost.cs index 2d89aae388..f5e53c6ce6 100644 --- a/PluginCore/PluginCore/Controls/ICompletionListHost.cs +++ b/PluginCore/PluginCore/Controls/ICompletionListHost.cs @@ -6,7 +6,7 @@ namespace PluginCore.Controls { /* Possible properties/methods of interest: * - suppressedKeys: collection of extra key combinations that would be consumed by the completionList - * - OnListShowing/OnListHidden: method to know when the list is going to show or is hidden, better to get a reference to the list and listen for events + * - OnListShowing/OnListHidden: method to know when the list is going to show or is hidden, better than getting a reference to the list and listen for events * - AfterCompletionCommit/BeforeCompletionCommit */ public interface ICompletionListHost @@ -15,6 +15,9 @@ public interface ICompletionListHost event EventHandler LostFocus; event EventHandler PositionChanged; event KeyEventHandler KeyDown; + // Hacky event... needed for MethodCallTip where we need to get the new state after the key has been sent + // A better approach, and the way some IDEs work, would require MethodCallTip to be more "active" having more knowledge about the written function data, as well as a timer for some operations + event KeyEventHandler KeyPosted; event KeyPressEventHandler KeyPress; event MouseEventHandler MouseDown; @@ -25,6 +28,7 @@ public interface ICompletionListHost int CurrentPos { get; } bool IsEditable { get; } + int GetLineFromCharIndex(int pos); Point GetPositionFromCharIndex(int pos); int GetLineHeight(); void SetSelection(int start, int end); @@ -33,4 +37,5 @@ public interface ICompletionListHost void EndUndoAction(); } + } diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index 7209354b95..b75a2fb5bb 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -3,14 +3,13 @@ using System.Drawing; using System.Text; using System.Windows.Forms; -using ScintillaNet; namespace PluginCore.Controls { public class MethodCallTip: RichToolTip { - public delegate void UpdateCallTipHandler(ScintillaControl sender, int position); + public delegate void UpdateCallTipHandler(Control sender, int position); // events public event UpdateCallTipHandler OnUpdateCallTip; @@ -30,11 +29,14 @@ public class MethodCallTip: RichToolTip protected int memberPos; protected int startPos; protected int currentPos; - protected int deltaPos; protected int currentLine; - public MethodCallTip(IMainForm mainForm): base(mainForm) + protected CompletionListControl completionList; + + public MethodCallTip(CompletionListControl owner): base(owner.Host) { + completionList = owner; + host.VisibleChanged += Host_VisibleChanged; } public bool CallTipActive @@ -47,9 +49,7 @@ public override void Hide() if (isActive) { isActive = false; - UITools.Manager.UnlockControl(); // unlock keys } - faded = false; currentText = null; currentHLStart = -1; currentHLEnd = -1; @@ -61,14 +61,19 @@ public bool CheckPosition(int position) return position == currentPos; } - public void CallTipShow(ScintillaControl sci, int position, string text) + public void CallTipShow(int position, string text) { - CallTipShow(sci, position, text, true); + CallTipShow(position, text, true); } - public void CallTipShow(ScintillaControl sci, int position, string text, bool redraw) + public void CallTipShow(int position, string text, bool redraw) { if (host.Visible && position == memberPos && text == currentText) + { + if (owner.GetLineFromCharIndex(owner.CurrentPos) != currentLine) + PositionControl(); + return; + } host.Visible = false; currentText = text; @@ -76,32 +81,39 @@ public void CallTipShow(ScintillaControl sci, int position, string text, bool re memberPos = position; startPos = memberPos + toolTipRTB.Text.IndexOf('('); - currentPos = sci.CurrentPos; - deltaPos = startPos - currentPos + 1; - currentLine = sci.CurrentLine; - PositionControl(sci); + PositionControl(); + Show(); // state isActive = true; - faded = false; - UITools.Manager.LockControl(sci); } - public void PositionControl(ScintillaControl sci) + public void PositionControl() { + currentPos = owner.CurrentPos; + currentLine = owner.GetLineFromCharIndex(currentPos); // compute control location - Point p = new Point(sci.PointXFromPosition(memberPos), sci.PointYFromPosition(memberPos)); - p = sci.PointToScreen(p); + Point p = owner.GetPositionFromCharIndex(memberPos); + p.Y = owner.GetPositionFromCharIndex(currentPos).Y; + if (p.Y < 0 || p.Y > owner.Owner.Height || p.X < 0 || p.X > owner.Owner.Width) + { + Hide(); + return; + } + p = owner.Owner.PointToScreen(p); host.Left = p.X /*+ sci.Left*/; - bool hasListUp = !CompletionList.Active || CompletionList.listUp; - if (currentLine > sci.LineFromPosition(memberPos) || !hasListUp) host.Top = p.Y - host.Height /*+ sci.Top*/; - else host.Top = p.Y + UITools.Manager.LineHeight(sci) /*+ sci.Top*/; - // Keep on control area - if (host.Right > ((Form)PluginBase.MainForm).ClientRectangle.Right) + bool hasListUp = !completionList.Active || completionList.listUp; + if (!hasListUp) host.Top = p.Y - host.Height /*+ sci.Top*/; + else host.Top = p.Y + owner.GetLineHeight(); + // Keep on screen area + var screen = Screen.FromControl(owner.Owner); + if (host.Right > screen.WorkingArea.Right) + { + host.Left = screen.WorkingArea.Right - host.Width; + } + if (host.Left < 0) { - host.Left = ((Form)PluginBase.MainForm).ClientRectangle.Right - host.Width; + host.Left = 0; } - if (!host.Visible) - host.Show(owner); } public void CallTipSetHlt(int start, int end) @@ -110,8 +122,12 @@ public void CallTipSetHlt(int start, int end) } public void CallTipSetHlt(int start, int end, bool forceRedraw) { - if (currentHLStart == start && currentHLEnd == end) - return; + if (currentHLStart == start && currentHLEnd == end) + { + if (owner.GetLineFromCharIndex(owner.CurrentPos) != currentLine) + PositionControl(); + return; + } currentHLStart = start; currentHLEnd = end; @@ -139,109 +155,174 @@ public void CallTipSetHlt(int start, int end, bool forceRedraw) } } + private void Host_VisibleChanged(object sender, EventArgs e) + { + if (host.Visible) + { + owner.KeyDown += Target_KeyDown; + owner.KeyPosted += Target_KeyPosted; + owner.KeyPress += Target_KeyPress; + owner.PositionChanged += Target_PositionChanged; + owner.LostFocus += Target_LostFocus; + owner.MouseDown += Target_MouseDown; + + if (!completionList.Active) + Application.AddMessageFilter(completionList); + } + else + { + owner.KeyDown -= Target_KeyDown; + owner.KeyPosted -= Target_KeyPosted; + owner.KeyPress -= Target_KeyPress; + owner.PositionChanged -= Target_PositionChanged; + owner.LostFocus -= Target_LostFocus; + owner.MouseDown -= Target_MouseDown; + + if (!completionList.Active) + Application.RemoveMessageFilter(completionList); + } + } + + private void Target_KeyDown(object sender, KeyEventArgs e) + { + if (!e.Handled) + e.SuppressKeyPress = e.Handled = HandleKeys(e.KeyData); + } + + private void Target_KeyPosted(object sender, KeyEventArgs e) + { + HandlePostedKeys(e.KeyData); + } + + private void Target_KeyPress(object sender, KeyPressEventArgs e) + { + if (!char.IsControl(e.KeyChar)) + OnChar(e.KeyChar); + } + + private void Target_PositionChanged(object sender, EventArgs e) + { + PositionControl(); + } + + private void Target_LostFocus(object sender, EventArgs e) + { + if (!Focused && !completionList.Tip.Focused) + Hide(); + } + + private void Target_MouseDown(object sender, MouseEventArgs e) + { + if (owner.CurrentPos != currentPos) + Hide(); + } + #region Keys handling - public void OnChar(ScintillaControl sci, int value) + public void OnChar(int value) { currentPos++; - UpdateTip(sci); + UpdateTip(); } - public new void UpdateTip(ScintillaControl sci) + public override void UpdateTip() { - if (OnUpdateCallTip != null) OnUpdateCallTip(sci, currentPos); + if (CallTipActive && OnUpdateCallTip != null) OnUpdateCallTip(owner.Owner, currentPos); } - public bool HandleKeys(ScintillaControl sci, Keys key) + public bool HandleKeys(Keys key) { switch (key) { - case Keys.Multiply: - case Keys.Subtract: - case Keys.Divide: - case Keys.Decimal: - case Keys.Add: - return false; + case Keys.PageDown: + case Keys.PageUp: + if (!completionList.Active) + Hide(); + break; - case Keys.Up: - if (!CompletionList.Active) sci.LineUp(); - return false; - case Keys.Down: - if (!CompletionList.Active) sci.LineDown(); - return false; case Keys.Up | Keys.Shift: - sci.LineUpExtend(); - return false; case Keys.Down | Keys.Shift: - sci.LineDownExtend(); - return false; - case Keys.Left | Keys.Shift: - sci.CharLeftExtend(); - return false; - case Keys.Right | Keys.Shift: - sci.CharRightExtend(); - return false; + case Keys.PageDown | Keys.Shift: + case Keys.PageUp | Keys.Shift: + Hide(); + break; - case Keys.Right: - if (!CompletionList.Active) - { - sci.CharRight(); - currentPos = sci.CurrentPos; - if (sci.CurrentLine != currentLine) Hide(); - else if (OnUpdateCallTip != null) OnUpdateCallTip(sci, currentPos); - } + case Keys.Escape: + Hide(); return true; + } + + return false; + } + + private void HandlePostedKeys(Keys key) + { + switch (key) + { + case Keys.Right: + case Keys.Right | Keys.Shift: + case Keys.Right | Keys.Control: + currentPos = owner.CurrentPos; + if (OnUpdateCallTip != null) OnUpdateCallTip(owner.Owner, currentPos); + break; case Keys.Left: - if (!CompletionList.Active) - { - sci.CharLeft(); - currentPos = sci.CurrentPos; - if (currentPos < startPos) Hide(); - else - { - if (sci.CurrentLine != currentLine) Hide(); - else if (OnUpdateCallTip != null) OnUpdateCallTip(sci, currentPos); - } - } - return true; + case Keys.Left | Keys.Shift: + case Keys.Left | Keys.Control: + currentPos = owner.CurrentPos; + if (currentPos < startPos) Hide(); + if (OnUpdateCallTip != null) OnUpdateCallTip(owner.Owner, currentPos); + break; - case Keys.Back: - sci.DeleteBack(); - currentPos = sci.CurrentPos; - if (currentPos + deltaPos < startPos) Hide(); - else if (OnUpdateCallTip != null) OnUpdateCallTip(sci, currentPos); - return true; + case Keys.Up: + case Keys.Down: + currentPos = owner.CurrentPos; + if (!completionList.Active) + if (OnUpdateCallTip != null) OnUpdateCallTip(owner.Owner, currentPos); + break; - case Keys.Tab: - case Keys.Space: - return false; + case Keys.PageDown: + case Keys.PageUp: + if (!completionList.Active) + Hide(); + break; - default: - if (!CompletionList.Active) Hide(); - return false; + case Keys.Up | Keys.Shift: + case Keys.Down | Keys.Shift: + case Keys.PageDown | Keys.Shift: + case Keys.PageUp | Keys.Shift: + Hide(); + break; + + case Keys.Back: + case Keys.Back | Keys.Control: + case Keys.Delete: + case Keys.Delete | Keys.Control: + currentPos = owner.CurrentPos; + if (currentPos < startPos) Hide(); + if (OnUpdateCallTip != null) OnUpdateCallTip.BeginInvoke(owner.Owner, currentPos, null, null); + break; + + case Keys.Escape: + Hide(); + break; } } #endregion #region Controls fading on Control key - private static bool faded; internal void FadeOut() { - if (faded) return; - faded = true; - //base.Hide(); - host.Visible = false; + if (host.Opacity != 1) return; + host.Opacity = 0; } internal void FadeIn() { - if (!faded) return; - faded = false; - //base.Show(); - host.Visible = true; + if (host.Opacity == 1) return; + host.Opacity = 1; } #endregion } diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index 2df585bac0..ba68df2dff 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -17,7 +17,7 @@ namespace PluginCore.Controls /// public class RichToolTip { - public delegate void UpdateTipHandler(ScintillaControl sender, Point mousePosition); + public delegate void UpdateTipHandler(Control sender, Point mousePosition); // events public event UpdateTipHandler OnUpdateSimpleTip; @@ -33,7 +33,7 @@ public class RichToolTip protected List rtfCacheList; protected Point mousePos; - protected IWin32Window owner; + protected ICompletionListHost owner; // We could just use Control here, or pass a reference on each related call, as Control may be a problem with default implementation #region Public Properties @@ -72,13 +72,15 @@ public string Text #region Control creation - public RichToolTip(IWin32Window owner) + public RichToolTip(ICompletionListHost owner) { // host host = new InactiveForm(); host.FormBorderStyle = FormBorderStyle.None; host.ShowInTaskbar = false; host.StartPosition = FormStartPosition.Manual; + host.KeyPreview = true; + host.KeyDown += Host_KeyDown; this.owner = owner; @@ -110,10 +112,20 @@ public RichToolTip(IWin32Window owner) } #endregion - - #region Tip Methods - public bool AutoSize() + #region Event Handlers + + protected virtual void Host_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyData == Keys.Escape) + Hide(); + } + + #endregion + + #region Tip Methods + + public bool AutoSize() { return AutoSize(0); } @@ -128,7 +140,7 @@ public bool AutoSize(int availableWidth, int maxWidth) Size txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, toolTipRTB.Width, toolTipRTB.Height, false); // tooltip larger than the window: wrap - var screenArea = Screen.FromHandle(owner.Handle).WorkingArea; + var screenArea = Screen.FromControl(owner.Owner).WorkingArea; int limitLeft = screenArea.Left + 10; int limitRight = screenArea.Right - 10; int limitBottom = screenArea.Bottom - 26; @@ -203,12 +215,12 @@ public void ShowAtMouseLocation() host.Top = mousePos.Y - host.Height - 10;// +sci.Top; if (host.Top < 5) host.Top = mousePos.Y + 10; - host.Show(owner); + Show(); } - public void UpdateTip(ScintillaControl sci) + public virtual void UpdateTip() { - if (OnUpdateSimpleTip != null) OnUpdateSimpleTip(sci, mousePos); + if (OnUpdateSimpleTip != null) OnUpdateSimpleTip(owner.Owner, mousePos); } public virtual void Hide() @@ -223,7 +235,7 @@ public virtual void Hide() public virtual void Show() { if (!host.Visible) - host.Show(owner); + host.Show(owner.Owner); } public void SetText(String rawText, bool redraw) diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 742fdefc6a..20cbea18ef 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -99,9 +99,9 @@ private UITools() try { CompletionList.CreateControl(PluginBase.MainForm); - CompletionList.completionList.Tip = simpleTip = new RichToolTip(PluginBase.MainForm); - CompletionList.completionList.CallTip = callTip = new MethodCallTip(PluginBase.MainForm); - } + simpleTip = CompletionList.completionList.Tip; + callTip = CompletionList.completionList.CallTip; + } catch(Exception ex) { ErrorManager.ShowError(/*"Error while creating editor controls.",*/ ex); @@ -111,7 +111,6 @@ private UITools() // PluginBase.MainForm.IgnoredKeys.Add(Keys.Space | Keys.Control); // complete member PluginBase.MainForm.IgnoredKeys.Add(Keys.Space | Keys.Control | Keys.Shift); // complete method - PluginBase.MainForm.DockPanel.ActivePaneChanged += new EventHandler(DockPanel_ActivePaneChanged); EventManager.AddEventHandler(this, eventMask); } #endregion @@ -121,15 +120,6 @@ private UITools() #region SciControls & MainForm Events - private void DockPanel_ActivePaneChanged(object sender, EventArgs e) - { - if (PluginBase.MainForm.DockPanel.ActivePane != null - && PluginBase.MainForm.DockPanel.ActivePane != PluginBase.MainForm.DockPanel.ActiveDocumentPane) - { - OnUIRefresh(null); - } - } - public void HandleEvent(object sender, NotifyEvent e, HandlingPriority priority) { switch (e.Type) @@ -305,6 +295,7 @@ private void OnUIRefresh(ScintillaControl sci) if (CompletionList.Active && CompletionList.CheckPosition(position)) return; if (callTip.CallTipActive && callTip.CheckPosition(position)) return; } + CompletionList.Hide(); callTip.Hide(); simpleTip.Hide(); } @@ -322,7 +313,11 @@ private void OnTextDeleted(ScintillaControl sci, int position, int length, int l private void OnGotFocus(object sender, EventArgs e) { - ((CompletionList.ScintillaHost)CompletionList.completionList.Host).SciControl = (ScintillaControl)sender; + var sci = (ScintillaControl)sender; + ((CompletionList.ScintillaHost)CompletionList.completionList.Host).SciControl = sci; + var language = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage); + if (language != null) // Should we provide some custom string otherwise? + CompletionList.completionList.CharacterClass = language.characterclass.Characters; } private void OnChar(ScintillaControl sci, int value) @@ -342,7 +337,7 @@ private void OnChar(ScintillaControl sci, int value) // return; //} - if (callTip.CallTipActive) callTip.OnChar(sci, value); + if (callTip.CallTipActive) callTip.OnChar(value); if (CompletionList.Active) CompletionList.OnChar(sci, value); else SendChar(sci, value); } @@ -376,45 +371,14 @@ private bool HandleKeys(Keys key) } // toggle "long-description" for the hover tooltip - if (key == Keys.F1 && Tip.Visible && !CompletionList.Active) + if (key == Keys.F1 && Tip.Visible && !CompletionList.Active && !CallTip.Visible) { showDetails = !showDetails; - simpleTip.UpdateTip(PluginBase.MainForm.CurrentDocument.SciControl); + simpleTip.UpdateTip(); return true; } - // are we currently displaying something? - if (!CompletionList.Active && !callTip.CallTipActive) return false; - - // hide if pressing Esc or Ctrl+Key combination - if (lockedSciControl == null || !lockedSciControl.IsAlive || key == Keys.Escape - || ((Control.ModifierKeys & Keys.Control) != 0 && Control.ModifierKeys != (Keys.Control|Keys.Alt)) ) - { - if (key == (Keys.Control | Keys.C) || key == (Keys.Control | Keys.A)) - return false; // let text copy in tip - UnlockControl(); - //CompletionList.Hide((char)27); - callTip.Hide(); - return false; - } - ScintillaControl sci = (ScintillaControl)lockedSciControl.Target; - // chars - string ks = key.ToString(); - if (ks.Length == 1 || (ks.EndsWith(", Shift") && ks.IndexOf(',') == 1) || ks.StartsWith("NumPad")) - { - return false; - } - - // switches - if ((key & Keys.ShiftKey) == Keys.ShiftKey || (key & Keys.ControlKey) == Keys.ControlKey || (key & Keys.Menu) == Keys.Menu) - { - return false; - } - - // handle special keys - bool handled = false; - if (callTip.CallTipActive) handled |= callTip.HandleKeys(sci, key); - return handled; + return false; } diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index c324b03a4b..83f8b8a02c 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -162,6 +162,7 @@ protected override CreateParams CreateParams public event UpdateSyncHandler UpdateSync; public event SelectionChangedHandler SelectionChanged; public event ScrollEventHandler Scroll; + public event KeyEventHandler KeyPosted; //Hacky event for MethodCallTip, although with some rather valid use cases #endregion @@ -5211,6 +5212,14 @@ private void WmScroll(ref Message m) OnScroll(new ScrollEventArgs(set, oldScroll, newScroll, so)); } + protected override void DefWndProc(ref Message m) + { + base.DefWndProc(ref m); + + if (m.Msg == WM_KEYDOWN || m.Msg == WM_SYSKEYDOWN) // If we're worried about performance/GC, we can store latest OnKeyDown e + OnKeyPosted(new KeyEventArgs((Keys)((int)m.WParam) | ModifierKeys)); + } + protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) @@ -5433,10 +5442,17 @@ protected override void OnKeyDown(KeyEventArgs e) if (!e.Handled && keyCommands.TryGetValue(e.KeyData, out keyCommand)) { keyCommand(); + OnKeyPosted(e); e.SuppressKeyPress = true; } } + protected virtual void OnKeyPosted(KeyEventArgs e) + { + if (KeyPosted != null) + KeyPosted(this, e); + } + /// /// Raises the event. /// From 939f88e5dc941fd51a7f7f4e8166973091a11f56 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Thu, 5 Mar 2015 15:43:17 +0100 Subject: [PATCH 30/36] Added SizeChanged event to ICompletionListHost. This event could be dispatched by the PositionChanged event, but this gives more fine-grained control. Maybe some of the common Control events like this one could be directly attached to the Owner control itself. --- External/Plugins/FlashDebugger/Controls/ImmediateUI.cs | 6 ++++++ PluginCore/PluginCore/Controls/CompletionList.cs | 6 ++++++ .../PluginCore/Controls/CompletionListControl.cs | 10 ++++++++++ PluginCore/PluginCore/Controls/ICompletionListHost.cs | 1 + PluginCore/PluginCore/Controls/MethodCallTip.cs | 10 ++++++++++ 5 files changed, 33 insertions(+) diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index 6ac98d1acb..4c2e435878 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -222,6 +222,12 @@ public event EventHandler LostFocus public event EventHandler PositionChanged; + public event EventHandler SizeChanged + { + add { Owner.SizeChanged += value; } + remove { Owner.SizeChanged -= value; } + } + public event KeyEventHandler KeyDown { add { _owner.KeyDown += value; } diff --git a/PluginCore/PluginCore/Controls/CompletionList.cs b/PluginCore/PluginCore/Controls/CompletionList.cs index 5066f267ec..9876eb4e0c 100644 --- a/PluginCore/PluginCore/Controls/CompletionList.cs +++ b/PluginCore/PluginCore/Controls/CompletionList.cs @@ -312,6 +312,12 @@ public event EventHandler PositionChanged } } + public event EventHandler SizeChanged + { + add { Owner.SizeChanged += value; } + remove { Owner.SizeChanged -= value; } + } + public event KeyEventHandler KeyDown { add { Owner.KeyDown += value; } diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 48042e9432..6f061adf15 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -924,6 +924,7 @@ private void AddHandlers() host.KeyDown += Target_KeyDown; host.KeyPress += Target_KeyPress; host.PositionChanged += Target_PositionChanged; + host.SizeChanged += Target_SizeChanged; } private void RemoveHandlers() @@ -935,6 +936,7 @@ private void RemoveHandlers() host.KeyDown -= Target_KeyDown; host.KeyPress -= Target_KeyPress; host.PositionChanged -= Target_PositionChanged; + host.SizeChanged -= Target_SizeChanged; } private void Target_LostFocus(object sender, EventArgs e) @@ -966,6 +968,14 @@ private void Target_PositionChanged(object sender, EventArgs e) UpdatePosition(); } + private void Target_SizeChanged(object sender, EventArgs e) + { + Point coord = host.GetPositionFromCharIndex(startPos); + // Check for completion list outside of control view + if (coord.X < 0 || coord.X > host.Owner.Width || coord.Y < 0 || coord.Y > host.Owner.Height) + Hide(); + } + /// /// /// diff --git a/PluginCore/PluginCore/Controls/ICompletionListHost.cs b/PluginCore/PluginCore/Controls/ICompletionListHost.cs index f5e53c6ce6..db315c045c 100644 --- a/PluginCore/PluginCore/Controls/ICompletionListHost.cs +++ b/PluginCore/PluginCore/Controls/ICompletionListHost.cs @@ -14,6 +14,7 @@ public interface ICompletionListHost event EventHandler LostFocus; event EventHandler PositionChanged; + event EventHandler SizeChanged; event KeyEventHandler KeyDown; // Hacky event... needed for MethodCallTip where we need to get the new state after the key has been sent // A better approach, and the way some IDEs work, would require MethodCallTip to be more "active" having more knowledge about the written function data, as well as a timer for some operations diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index b75a2fb5bb..2807c525cf 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -163,6 +163,7 @@ private void Host_VisibleChanged(object sender, EventArgs e) owner.KeyPosted += Target_KeyPosted; owner.KeyPress += Target_KeyPress; owner.PositionChanged += Target_PositionChanged; + owner.SizeChanged += Target_SizeChanged; owner.LostFocus += Target_LostFocus; owner.MouseDown += Target_MouseDown; @@ -175,6 +176,7 @@ private void Host_VisibleChanged(object sender, EventArgs e) owner.KeyPosted -= Target_KeyPosted; owner.KeyPress -= Target_KeyPress; owner.PositionChanged -= Target_PositionChanged; + owner.SizeChanged -= Target_SizeChanged; owner.LostFocus -= Target_LostFocus; owner.MouseDown -= Target_MouseDown; @@ -205,6 +207,14 @@ private void Target_PositionChanged(object sender, EventArgs e) PositionControl(); } + private void Target_SizeChanged(object sender, EventArgs e) + { + Point p = owner.GetPositionFromCharIndex(memberPos); + p.Y = owner.GetPositionFromCharIndex(currentPos).Y; + if (p.Y < 0 || p.Y > owner.Owner.Height || p.X < 0 || p.X > owner.Owner.Width) + Hide(); + } + private void Target_LostFocus(object sender, EventArgs e) { if (!Focused && !completionList.Tip.Focused) From 6e2775912f108b5714902674b5d4ebe27d61dce7 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 9 Mar 2015 10:38:15 +0100 Subject: [PATCH 31/36] Custom word part functions It solves and improves some cases. Organized code a bit, there were more logical regions to place some of the new code. --- PluginCore/ScintillaNet/ScintillaControl.cs | 382 ++++++++++++++++++-- 1 file changed, 347 insertions(+), 35 deletions(-) diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 83f8b8a02c..0f3fc16f91 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -5142,6 +5142,35 @@ public UInt32 SPerform(UInt32 message, UInt32 wParam, UInt32 lParam) else return (UInt32)Encoding.ASCII.CodePage; } + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + Action keyCommand; + if (!e.Handled && keyCommands.TryGetValue(e.KeyData, out keyCommand)) + { + keyCommand(); + OnKeyPosted(e); + e.SuppressKeyPress = true; + } + } + + protected virtual void OnKeyPosted(KeyEventArgs e) + { + if (KeyPosted != null) + KeyPosted(this, e); + } + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected virtual void OnScroll(ScrollEventArgs e) + { + if (Scroll != null) + Scroll(this, e); + } + public override bool PreProcessMessage(ref Message m) { switch (m.Msg) @@ -5434,35 +5463,6 @@ unsafe string MarshalStr(IntPtr p, int len) #region Automated Features - protected override void OnKeyDown(KeyEventArgs e) - { - base.OnKeyDown(e); - - Action keyCommand; - if (!e.Handled && keyCommands.TryGetValue(e.KeyData, out keyCommand)) - { - keyCommand(); - OnKeyPosted(e); - e.SuppressKeyPress = true; - } - } - - protected virtual void OnKeyPosted(KeyEventArgs e) - { - if (KeyPosted != null) - KeyPosted(this, e); - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected virtual void OnScroll(ScrollEventArgs e) - { - if (Scroll != null) - Scroll(this, e); - } - /// /// Support for selection highlighting and selection changed event /// @@ -5860,12 +5860,12 @@ public bool CamelHumps } else { - keyCommands[Keys.Control | Keys.Left] = WordPartLeft; - keyCommands[Keys.Control | Keys.Right] = WordPartRight; - keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordPartLeftExtend; - keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordPartRightExtend; - keyCommands[Keys.Control | Keys.Back] = DelWordPartLeft; - keyCommands[Keys.Control | Keys.Delete] = DelWordPartRight; + keyCommands[Keys.Control | Keys.Left] = WordPartLeftEx; + keyCommands[Keys.Control | Keys.Right] = WordPartRightEx; + keyCommands[Keys.Control | Keys.Shift | Keys.Left] = WordPartLeftExtendEx; + keyCommands[Keys.Control | Keys.Shift | Keys.Right] = WordPartRightExtendEx; + keyCommands[Keys.Control | Keys.Back] = DelWordPartLeftEx; + keyCommands[Keys.Control | Keys.Delete] = DelWordPartRightEx; } } } @@ -6970,6 +6970,318 @@ public string GetWordLeft(int position, bool skipWS) return word; } + /// + /// Delete the word part to the left of the caret. Supports Unicode and uses a slightly different ruleset + /// + public void DelWordPartLeftEx() + { + int currPos = CurrentPos; + SetSel(currPos, currPos); + WordPartLeftExtendEx(); + Clear(); + } + + /// + /// Delete the word part to the right of the caret. Supports Unicode and uses a slightly different ruleset + /// + public void DelWordPartRightEx() + { + int currPos = CurrentPos; + SetSel(currPos, currPos); + WordPartRightExtendEx(); + Clear(); + } + + /// + /// Move to the previous change in capitalisation. Supports Unicode and uses a slightly different ruleset + /// + public void WordPartLeftEx() + { + int pos = GetCustomWordPartLeft() + 1; + SetSel(pos, pos); + CharLeft(); // Hack to force caret visible, is there a better way for this? + } + + /// + /// Move to the change next in capitalisation. Supports Unicode and uses a slightly different ruleset + /// + public void WordPartRightEx() + { + int pos = GetCustomWordPartRight() - 1; + SetSel(pos, pos); + CharRight(); // Hack to force caret visible, is there a better way for this? + } + + /// + /// Move to the previous change in capitalisation extending selection + /// to new caret position. Supports Unicode and uses a slightly different ruleset + /// + public void WordPartLeftExtendEx() + { + int pos = GetCustomWordPartLeft(); + int selStart = SelectionStart; + int selEnd = SelectionEnd; + if (CurrentPos > selStart) selEnd = selStart; + SetSel(selEnd, pos); + } + + /// + /// Move to the next change in capitalisation extending selection + /// to new caret position. Supports Unicode and uses a slightly different ruleset + /// + public void WordPartRightExtendEx() + { + int pos = GetCustomWordPartRight(); + int selStart = SelectionStart; + int selEnd = SelectionEnd; + if (CurrentPos < selEnd) selStart = selEnd; + SetSel(selStart, pos); + } + + private int GetCustomWordPartLeft() + { + /* This is a more or less direct translation of default Scintilla implementation with the following differences: + * - Sadly, Scintilla doesn't support multi byte characters in the WORDPART* function, this solves it. + * - This implementation is a bit more complex, as checks for some more types of characters, making browsing a bit more fluent. + * - Line jumps are treated differently, the default implementation just skips all lines, this one behaves like normal WORD* functions, with stops in between if there are whitespaces. + * - Since we cannot use the CharAt function we have to get the properly encoded text, but since getting the whole text may use way more resources than needed, we go line per line, and + * this makes code a bit more difficult to read. + */ + int pos = CurrentPos; + if (pos == 0) return 0; + + int line = LineFromPosition(pos - 1); + int linePos = pos - PositionFromLine(line); + int i, count = 0; + char startChar = '\0'; + + do + { + int sz = (int) SPerform(2153, (uint) line, 0); + byte[] buffer = new byte[sz + 1]; + unsafe + { + fixed (byte* b = buffer) SPerform(2153, (uint) line, (uint) b); + } + string lineText = Encoding.GetEncoding(CodePage).GetString(buffer, 0, linePos == 0 ? sz : linePos); + + i = lineText.Length - 1; + if (count == 0) + startChar = lineText[i]; + if (count == 0 && char.GetUnicodeCategory(startChar) == System.Globalization.UnicodeCategory.ConnectorPunctuation) + { + while (i > 0 && char.GetUnicodeCategory(lineText[i]) == System.Globalization.UnicodeCategory.ConnectorPunctuation) + { + --i; + } + } + if (i > 0) + { + if (count == 0) + { + startChar = lineText[i]; + --i; + } + if (char.IsLower(startChar)) + { + while (i > 0 && char.IsLower(lineText[i])) + --i; + if (!char.IsUpper(lineText[i]) && !char.IsLower(lineText[i])) + ++i; + } + else if (char.IsUpper(startChar)) + { + while (i > 0 && char.IsUpper(lineText[i])) + --i; + if (!char.IsUpper(lineText[i])) + ++i; + } + else if (char.IsLetter(startChar)) + { + while (i > 0 && char.IsLetter(lineText[i])) + --i; + if (!char.IsLetter(lineText[i])) + ++i; + } + else if (char.IsDigit(startChar)) + { + while (i > 0 && char.IsDigit(lineText[i])) + --i; + if (!char.IsDigit(lineText[i])) + ++i; + } + else if (char.IsPunctuation(startChar) || char.IsSymbol(startChar)) + { + char c; + while (i > 0 && (char.IsPunctuation((c = lineText[i])) || char.IsSymbol(c))) + --i; + c = lineText[i]; + if (!char.IsPunctuation(c) && !char.IsSymbol(c)) + ++i; + } + else if (startChar == '\n' || startChar == '\r') + { + char c; + while (i > 0 && ((c = lineText[i]) == '\n' || c == '\r')) + --i; + c = lineText[i]; + if (c != '\n' && c != '\r') + ++i; + } + else if (char.IsWhiteSpace(startChar)) + { + char c; + while (i > 0 && (c = lineText[i]) != '\n' && c != '\r' && + char.GetUnicodeCategory(c) != System.Globalization.UnicodeCategory.ConnectorPunctuation && + (char.IsPunctuation(c) || char.IsWhiteSpace(c))) + --i; + + if (i == 0) + startChar = '\n'; + else if (!char.IsWhiteSpace(lineText[i])) + ++i; + } + else if (!IsAscii(startChar)) + { + while (i > 0 && !IsAscii(lineText[i])) + --i; + if (IsAscii(lineText[i])) + ++i; + } + else + { + ++i; + } + } + else if (line > 0 && char.IsWhiteSpace(startChar)) + startChar = '\n'; + + count += Encoding.GetEncoding(CodePage).GetByteCount(lineText.ToCharArray(), i, lineText.Length - i); + linePos = 0; + line--; + } while (i == 0 && line >= 0); + + return pos - count; + } + + private int GetCustomWordPartRight() + { + /* This is a more or less direct translation of default Scintilla implementation with the following differences: + * - Sadly, Scintilla doesn't support multi byte characters in the WORDPART* function, this solves it. + * - This implementation is a bit more complex, as checks for some more types of characters, making browsing a bit more fluent. + * - Line jumps are treated differently, the default implementation just skips all lines, this one behaves like normal WORD* functions, with stops in between if there are whitespaces. + * - Since we cannot use the CharAt function we have to get the properly encoded text, but since getting the whole text may use way more resources than needed, we go line per line, and + * this makes code a bit more difficult to read. + */ + int pos = CurrentPos; + if (pos == TextLength) return pos; + int lineCount = LineCount; + int line = LineFromPosition(pos); + int linePos = pos - PositionFromLine(line); + int length, i, count = 0; + char startChar = '\0'; + + do + { + int sz = (int) SPerform(2153, (uint) line, 0); + byte[] buffer = new byte[sz + 1]; + unsafe + { + fixed (byte* b = buffer) SPerform(2153, (uint) line, (uint) b); + } + string lineText = Encoding.GetEncoding(CodePage).GetString(buffer, linePos, sz - linePos); + + length = lineText.Length; + i = 0; + + if (count == 0) + { + startChar = lineText[i]; + if (char.GetUnicodeCategory(startChar) == System.Globalization.UnicodeCategory.ConnectorPunctuation) + { + while (i < length && char.GetUnicodeCategory(lineText[i]) == System.Globalization.UnicodeCategory.ConnectorPunctuation) + ++i; + startChar = lineText[i]; + } + } + if (char.IsLower(startChar)) + { + while (i < length && char.IsLower(lineText[i])) + ++i; + // We may be interested in not running this loop if startChar was the same + while (i < length && char.GetUnicodeCategory(lineText[i]) == System.Globalization.UnicodeCategory.ConnectorPunctuation) + ++i; + } + else if (char.IsUpper(startChar)) + { + if (i < length - 1 && char.IsLower(lineText[i + 1])) + { + ++i; + while (i < length && char.IsLower(lineText[i])) + ++i; + } + else + { + while (i < length && char.IsUpper(lineText[i])) + ++i; + } + if (i < length && char.IsLower(lineText[i]) && char.IsUpper(lineText[i - 1])) + --i; + } + else if (char.IsLetter(startChar)) + { + while (i < length && char.IsLetter(lineText[i])) + ++i; + } + else if (char.IsDigit(startChar)) + { + while (i < length && char.IsDigit(lineText[i])) + ++i; + } + else if (char.IsPunctuation(startChar) || char.IsSymbol(startChar)) + { + char c; + while (i < length && (char.IsPunctuation((c = lineText[i])) || char.IsSymbol(c))) + ++i; + } + else if (startChar == '\n' || startChar == '\r') + { + char c; + while (i < length && ((c = lineText[i]) == '\r' || c == '\n')) + ++i; + while (i < length && char.IsWhiteSpace((c = lineText[i])) && c != '\r' && c != '\n') + ++i; + } + else if (char.IsWhiteSpace(startChar)) + { + if (count == 0) ++i; + char c; + while (i < length && (c = lineText[i]) != '\r' && c != '\n' && char.IsWhiteSpace(c)) + ++i; + } + else if (!IsAscii(startChar)) + { + while (i < length && !IsAscii(lineText[i])) + ++i; + } + else + { + ++i; + count += Encoding.GetEncoding(CodePage).GetByteCount(lineText.ToCharArray(), 0, i); + break; + } + count += Encoding.GetEncoding(CodePage).GetByteCount(lineText.ToCharArray(), 0, i); + line++; + linePos = 0; + } while (i == length && line < lineCount); + return pos + count; + } + + private static bool IsAscii(char c) + { + return c < 0x80; + } + #endregion } From bbc35b5b265e7764598a6d0522c075924754aed9 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 20 Apr 2015 00:32:06 +0200 Subject: [PATCH 32/36] Fixed completion list location on control hosts with Y or X != 0. Added events to notify when the Tip and CallTip are going to show or are hidden. Adjusted completion list and tips limits to remove some white space. Don't focus completion list on double click. Change Tip display order, because it sometimes was giving erratic behavior. Made Tip and CallTip TopMost like the original ToolTip, and because the floating panels give some problems because their use of BringToFront(). Global completion in Immediate panel. Created a helper class to allow the use of ASComplete with custom completion lists. It adds proper completion support to expressions in the Immediate panel, and used it to add Watch BreakPoint expressions. Some other refactorings and minor improvements. --- .../Plugins/ASCompletion/ASCompletion.csproj | 1 + .../ASCompletion/Completion/ASComplete.cs | 39 +- .../FlashDebugger/Controls/BreakPointUI.cs | 418 ++++++++++++++- .../Controls/DataTreeControl.Designer.cs | 5 +- .../FlashDebugger/Controls/DataTreeControl.cs | 119 +++- .../Controls/ImmediateUI.Designer.cs | 5 +- .../FlashDebugger/Controls/ImmediateUI.cs | 345 ++++++++++-- .../FlashDebugger/FlashDebugger.csproj | 3 + .../Controls/CompletionListControl.cs | 90 +++- .../PluginCore/Controls/InactiveForm.cs | 38 +- .../PluginCore/Controls/MethodCallTip.cs | 100 ++-- PluginCore/PluginCore/Controls/RichToolTip.cs | 506 +++++++++++------- PluginCore/PluginCore/Controls/UITools.cs | 17 +- 13 files changed, 1341 insertions(+), 345 deletions(-) diff --git a/External/Plugins/ASCompletion/ASCompletion.csproj b/External/Plugins/ASCompletion/ASCompletion.csproj index 0de86e3561..7e7a007075 100644 --- a/External/Plugins/ASCompletion/ASCompletion.csproj +++ b/External/Plugins/ASCompletion/ASCompletion.csproj @@ -92,6 +92,7 @@ ModelsExplorer.cs + diff --git a/External/Plugins/ASCompletion/Completion/ASComplete.cs b/External/Plugins/ASCompletion/Completion/ASComplete.cs index fa4782e3ac..54c2b10014 100644 --- a/External/Plugins/ASCompletion/Completion/ASComplete.cs +++ b/External/Plugins/ASCompletion/Completion/ASComplete.cs @@ -178,18 +178,17 @@ static public bool OnChar(ScintillaControl Sci, int Value, bool autoHide) { return HandleColonCompletion(Sci, "", autoHide); } - else break; + break; case '<': if (features.hasGenerics && position > 2) { char c0 = (char)Sci.CharAt(position - 2); - bool result = false; if (c0 == '.' /*|| Char.IsLetterOrDigit(c0)*/) return HandleColonCompletion(Sci, "", autoHide); - return result; + return false; } - else break; + break; case '(': case ',': @@ -198,7 +197,7 @@ static public bool OnChar(ScintillaControl Sci, int Value, bool autoHide) else return false; case ')': - if (UITools.CallTip.CallTipActive) UITools.CallTip.Hide(); + if (CompletionList.CallTip.CallTipActive) CompletionList.CallTip.Hide(); return false; case '*': @@ -1273,9 +1272,27 @@ private static bool IsDeclaration(string line, ContextFeatures features) static private string prevParam = ""; static private string paramInfo = ""; + static private CompletionListControl completionList; + /// + /// Target Completion List to use + /// + static public CompletionListControl CompletionList + { + get + { + if (completionList == null) + completionList = UITools.CompletionList; + return completionList; + } + set + { + completionList = value; + } + } + static public bool HasCalltip() { - return UITools.CallTip.CallTipActive && (calltipDef != null); + return CompletionList.CallTip.CallTipActive && (calltipDef != null); } /// @@ -1327,17 +1344,17 @@ static private void ShowCalltip(ScintillaControl Sci, int paramIndex, bool force } // show calltip - if (!UITools.CallTip.CallTipActive || UITools.Manager.ShowDetails != calltipDetails || paramName != prevParam) + if (!CompletionList.CallTip.CallTipActive || UITools.Manager.ShowDetails != calltipDetails || paramName != prevParam) { prevParam = paramName; calltipDetails = UITools.Manager.ShowDetails; string text = calltipDef + ASDocumentation.GetTipDetails(calltipMember, paramName); - UITools.CallTip.CallTipShow(calltipPos - calltipOffset, text, forceRedraw); + CompletionList.CallTip.CallTipShow(calltipPos - calltipOffset, text, forceRedraw); } // highlight - if ((start < 0) || (end < 0)) UITools.CallTip.CallTipSetHlt(0, 0, true); - else UITools.CallTip.CallTipSetHlt(start + 1, end, true); + if ((start < 0) || (end < 0)) CompletionList.CallTip.CallTipSetHlt(0, 0, true); + else CompletionList.CallTip.CallTipSetHlt(start + 1, end, true); } static string[] featStart = new string[] { "/*", "{", "<", "[", "(" }; @@ -1395,7 +1412,7 @@ static public bool HandleFunctionCompletion(ScintillaControl Sci, bool autoHide, ShowCalltip(Sci, paramIndex, forceRedraw); return true; } - else UITools.CallTip.Hide(); + else CompletionList.CallTip.Hide(); } if (!ResolveFunction(Sci, position, autoHide)) diff --git a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs index c01e3fbb0a..591ce2929e 100644 --- a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs +++ b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs @@ -5,16 +5,17 @@ using System.Drawing; using System.Text.RegularExpressions; using System.Windows.Forms; +using ASCompletion.Helpers; using FlashDebugger.Properties; using PluginCore.Localization; using PluginCore; using PluginCore.Helpers; -using System.Linq; using PluginCore.Managers; +using System.Linq; namespace FlashDebugger { - class BreakPointUI : DockPanelControl + class BreakPointUI : DockPanelControl, ASCompletionListBackend.IBackendFileGetter { private static ImageList imageList; @@ -25,7 +26,7 @@ class BreakPointUI : DockPanelControl private DataGridViewTextBoxColumn ColumnBreakPointFilePath; private DataGridViewTextBoxColumn ColumnBreakPointFileName; private DataGridViewTextBoxColumn ColumnBreakPointLine; - private DataGridViewTextBoxColumn ColumnBreakPointExp; + private DataGridViewTextBoxExColumn ColumnBreakPointExp; private ToolStrip tsActions; private ToolStripButton tsbRemoveSelected; private ToolStripButton tsbRemoveFiltered; @@ -37,6 +38,10 @@ class BreakPointUI : DockPanelControl private ToolStripComboBox tscbFilterColumns; private Color defaultColor; + // Auto Completion + private PluginCore.Controls.CompletionListControl completionList; + private ASCompletionListBackend completionBackend; + public BreakPointUI(PluginMain pluginMain, BreakPointManager breakPointManager) { init(); @@ -101,7 +106,7 @@ private void init() this.ColumnBreakPointFilePath = new DataGridViewTextBoxColumn(); this.ColumnBreakPointFileName = new DataGridViewTextBoxColumn(); this.ColumnBreakPointLine = new DataGridViewTextBoxColumn(); - this.ColumnBreakPointExp = new DataGridViewTextBoxColumn(); + this.ColumnBreakPointExp = new DataGridViewTextBoxExColumn(); this.ColumnBreakPointEnable.HeaderText = TextHelper.GetString("Label.Enable"); this.ColumnBreakPointEnable.Name = "Enable"; @@ -137,9 +142,10 @@ private void init() defaultColor = dgv.Rows[dgv.Rows.Add()].DefaultCellStyle.BackColor; dgv.Rows.Clear(); - this.dgv.CellEndEdit += new DataGridViewCellEventHandler(dgv_CellEndEdit); - this.dgv.CellMouseUp += new DataGridViewCellMouseEventHandler(dgv_CellMouseUp); - this.dgv.CellDoubleClick += new DataGridViewCellEventHandler(dgv_CellDoubleClick); + this.dgv.EditingControlShowing += dgv_EditingControlShowing; + this.dgv.CellEndEdit += dgv_CellEndEdit; + this.dgv.CellMouseUp += dgv_CellMouseUp; + this.dgv.CellDoubleClick += dgv_CellDoubleClick; this.Controls.Add(this.dgv); @@ -200,6 +206,20 @@ void dgv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) } } + void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) + { + if (ColumnBreakPointExp == dgv.CurrentCell.OwningColumn) + { + var listHost = + new Controls.ImmediateUI.TextBoxTarget((FlashDebugger.Controls.ImmediateUI.TextBoxEx) e.Control); + completionList = new PluginCore.Controls.CompletionListControl(listHost); + // We need this because MainForm.Activated event handler gives some conflicts + completionList.Tip.Selectable = completionList.CallTip.Selectable = false; + completionBackend = new ASCompletionListBackend(completionList, this); + e.Control.PreviewKeyDown += EditingControl_PreviewKeyDown; + } + } + void dgv_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex < 0) return; @@ -210,6 +230,31 @@ void dgv_CellEndEdit(object sender, DataGridViewCellEventArgs e) int line = int.Parse((string)dgv.Rows[e.RowIndex].Cells["Line"].Value); string exp = (string)dgv.Rows[e.RowIndex].Cells["Exp"].Value; breakPointManager.SetBreakPointCondition(filename, line - 1, exp); + + if (completionBackend != null) + { + completionList.Host.Owner.PreviewKeyDown -= EditingControl_PreviewKeyDown; + completionBackend.Dispose(); + completionBackend = null; + completionList = null; + } + } + } + + void EditingControl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + if (completionList != null && completionList.Active) + { + switch (e.KeyData) + { + case Keys.Enter: + case Keys.Escape: + case Keys.Down: + case Keys.Up: + case Keys.Tab: + e.IsInputKey = true; + break; + } } } @@ -559,6 +604,365 @@ private void TstxtFilter_KeyDown(object sender, KeyEventArgs e) } } + #region Auto Completion + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before + if (keyData == (Keys.Control | Keys.Space) || keyData == (Keys.Control | Keys.Shift | Keys.Space)) + { + var box = dgv.EditingControl as DataGridViewTextBoxExEditingControl; + if (box != null && completionBackend != null) + { + if (keyData == (Keys.Control | Keys.Space)) + completionBackend.ShowAutoCompletioList(); + else + completionBackend.ShowFunctionDetails(); + + return true; + } + } + return base.ProcessCmdKey(ref msg, keyData); + } + + string ASCompletionListBackend.IBackendFileGetter.GetExpression() + { + var box = (TextBox) dgv.EditingControl; + return box.Text.Substring(0, box.SelectionStart); + } + + bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionListBackend.BackendFileInfo fileInfo) + { + fileInfo = default(ASCompletionListBackend.BackendFileInfo); + string filePath = (string) dgv.CurrentRow.Cells[ColumnBreakPointFilePath.Name].Value; + + if (!File.Exists(filePath)) return false; + + fileInfo.Line = int.Parse((string)dgv.CurrentRow.Cells[ColumnBreakPointLine.Name].Value) - 1; + fileInfo.File = filePath; + fileInfo.LastUpdate = File.GetLastWriteTime(filePath); + + return true; + } + + EncodingFileInfo ASCompletionListBackend.IBackendFileGetter.GetFileContent(ASCompletionListBackend.BackendFileInfo file) + { + return FileHelper.GetEncodingFileInfo(file.File); + } + + #endregion + + } + + public class DataGridViewTextBoxExColumn : DataGridViewColumn + { + + public override DataGridViewCell CellTemplate + { + get { return base.CellTemplate; } + set + { + if (value != null && !(value is DataGridViewTextBoxExCell)) + { + throw new InvalidCastException("Cell type is not based upon the DataGridViewTextBoxExCell"); + } + base.CellTemplate = value; + } + } + + [System.ComponentModel.DefaultValue(32767)] + public int MaxInputLength + { + get + { + return ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength; + } + set + { + if (MaxInputLength != value) + { + ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength = value; + if (DataGridView != null) + { + DataGridViewRowCollection rows = DataGridView.Rows; + int count = rows.Count; + for (int i = 0; i < count; i++) + { + DataGridViewRow dataGridViewRow = rows.SharedRow(i); + var item = dataGridViewRow.Cells[Index] as DataGridViewTextBoxExCell; + if (item != null) + { + item.MaxInputLength = value; + } + } + } + } + } + } + + public DataGridViewTextBoxExColumn() + : base(new DataGridViewTextBoxExCell()) + { + SortMode = DataGridViewColumnSortMode.Automatic; + } + } + + public class DataGridViewTextBoxExCell : DataGridViewTextBoxCell + { + + private TextBox editingControl; + + public override Type EditType + { + get { return typeof(DataGridViewTextBoxExEditingControl); } + } + + private int maxInputLength = 32767; + public override int MaxInputLength + { + get { return maxInputLength; } + set + { + if (maxInputLength == value) return; + + maxInputLength = value; + if (editingControl != null && RowIndex == ((IDataGridViewEditingControl)editingControl).EditingControlRowIndex) + editingControl.MaxLength = value; + } + } + + public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) + { + base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); + + var ctl = DataGridView.EditingControl as TextBox; + if (ctl != null) + { + ctl.MaxLength = maxInputLength; + ctl.AcceptsReturn = ctl.Multiline = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True; + ctl.BorderStyle = BorderStyle.None; + if (initialFormattedValue != null) ctl.Text = (string) initialFormattedValue; + editingControl = ctl; + } + } + + public override void DetachEditingControl() + { + base.DetachEditingControl(); + editingControl = null; + } + + protected override void OnKeyDown(KeyEventArgs e, int rowIndex) + { + base.OnKeyDown(e, rowIndex); + } + + } + + public class DataGridViewTextBoxExEditingControl : Controls.ImmediateUI.TextBoxEx, IDataGridViewEditingControl + { + + private static readonly DataGridViewContentAlignment anyRight = DataGridViewContentAlignment.BottomRight | + DataGridViewContentAlignment.MiddleRight | + DataGridViewContentAlignment.TopRight; + + private static readonly DataGridViewContentAlignment anyCenter = DataGridViewContentAlignment.BottomCenter | + DataGridViewContentAlignment.MiddleCenter | + DataGridViewContentAlignment.TopCenter; + + private static readonly DataGridViewContentAlignment anyTop = DataGridViewContentAlignment.TopCenter | + DataGridViewContentAlignment.TopLeft | + DataGridViewContentAlignment.TopRight; + + private Keys lastInputKey; + private bool repositionOnValueChange; + + public DataGridViewTextBoxExEditingControl() + { + TabStop = false; + } + + #region IDataGridViewEditingControl Members + + public bool RepositionEditingControlOnValueChange + { + get { return repositionOnValueChange; } + } + + public DataGridView EditingControlDataGridView { get; set; } + + public object EditingControlFormattedValue + { + get { return Text; } + set { Text = (string)value; } + } + + public int EditingControlRowIndex { get; set; } + + public bool EditingControlValueChanged { get; set; } + + public Cursor EditingPanelCursor + { + get { return Cursors.Default; } + } + + public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) + { + Font = dataGridViewCellStyle.Font; + if (dataGridViewCellStyle.BackColor.A < 255) + { + Color color = Color.FromArgb(255, dataGridViewCellStyle.BackColor); + BackColor = color; + EditingControlDataGridView.EditingPanel.BackColor = color; + } + else + { + BackColor = dataGridViewCellStyle.BackColor; + } + ForeColor = dataGridViewCellStyle.ForeColor; + if (dataGridViewCellStyle.WrapMode == DataGridViewTriState.True) + { + WordWrap = true; + } + TextAlign = TranslateAlignment(dataGridViewCellStyle.Alignment); + repositionOnValueChange = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True && + (dataGridViewCellStyle.Alignment & anyTop) == 0; + } + + public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) + { + if (keyData == lastInputKey) return true; + Keys key = keyData & Keys.KeyCode; + if (key != Keys.Return) + { + switch (key) + { + case Keys.Prior: + case Keys.Next: + if (!EditingControlValueChanged) + { + break; + } + return true; + case Keys.End: + case Keys.Home: + if (this.SelectionLength == this.Text.Length) + { + break; + } + return true; + case Keys.Left: + if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == 0) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length)) + { + break; + } + return true; + case Keys.Up: + if (this.Text.IndexOf("\r\n") < 0 || base.SelectionStart + this.SelectionLength < this.Text.IndexOf("\r\n")) + { + break; + } + return true; + case Keys.Right: + if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == 0)) + { + break; + } + return true; + case Keys.Down: + int selectionStart = base.SelectionStart + this.SelectionLength; + if (this.Text.IndexOf("\r\n", selectionStart) == -1) + { + break; + } + return true; + case Keys.Delete: + if (this.SelectionLength <= 0 && base.SelectionStart >= this.Text.Length) + { + break; + } + return true; + } + } + else if ((keyData & (Keys.Shift | Keys.Control | Keys.Alt)) == Keys.Shift && this.Multiline && base.AcceptsReturn) + { + return true; + } + return !dataGridViewWantsInputKey; + } + + public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) + { + return Text; + } + + public void PrepareEditingControlForEdit(bool selectAll) + { + if (selectAll) + SelectAll(); + else + SelectionStart = Text.Length; + } + + #endregion + + private void NotifyDataGridViewOfValueChange() + { + EditingControlValueChanged = true; + EditingControlDataGridView.NotifyCurrentCellDirty(true); + } + + private static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align) + { + if ((align & anyRight) != 0) + return HorizontalAlignment.Right; + + if ((align & anyCenter) != 0) + return HorizontalAlignment.Center; + + return HorizontalAlignment.Left; + } + + protected override void OnTextChanged(EventArgs e) + { + base.OnTextChanged(e); + NotifyDataGridViewOfValueChange(); + } + + protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) + { + base.OnPreviewKeyDown(e); + + lastInputKey = e.IsInputKey ? e.KeyData : Keys.None; + } + + protected override bool ProcessKeyEventArgs(ref Message m) + { + Keys wParam = (Keys)((int)m.WParam); + if (wParam == Keys.LineFeed) + { + if (m.Msg == 258 && Control.ModifierKeys == Keys.Control && this.Multiline && base.AcceptsReturn) + { + return true; + } + } + else if (wParam != Keys.Return) + { + if (wParam == Keys.A) + { + if (m.Msg == 256 && Control.ModifierKeys == Keys.Control) + { + base.SelectAll(); + return true; + } + } + } + else if (m.Msg == 258 && (Control.ModifierKeys != Keys.Shift || !this.Multiline || !base.AcceptsReturn)) + { + return true; + } + return base.ProcessKeyEventArgs(ref m); + } } } diff --git a/External/Plugins/FlashDebugger/Controls/DataTreeControl.Designer.cs b/External/Plugins/FlashDebugger/Controls/DataTreeControl.Designer.cs index dfcf985b3d..798fdda37c 100644 --- a/External/Plugins/FlashDebugger/Controls/DataTreeControl.Designer.cs +++ b/External/Plugins/FlashDebugger/Controls/DataTreeControl.Designer.cs @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License using Aga.Controls.Tree; using Aga.Controls.Tree.NodeControls; +using FlashDebugger.Controls.DataTree.NodeControls; namespace FlashDebugger.Controls { @@ -50,7 +51,7 @@ private void InitializeComponent() this._tree = new TreeViewAdv(); this.NameTreeColumn = new TreeColumn(); this.ValueTreeColumn = new Aga.Controls.Tree.TreeColumn(); - this.NameNodeTextBox = new NodeTextBox(); + this.NameNodeTextBox = new NodeTextBoxEx(); this.ValueNodeTextBox = new Aga.Controls.Tree.NodeControls.NodeTextBox(); this.SuspendLayout(); // @@ -122,7 +123,7 @@ private void InitializeComponent() private Aga.Controls.Tree.TreeViewAdv _tree; private Aga.Controls.Tree.TreeColumn NameTreeColumn; private Aga.Controls.Tree.TreeColumn ValueTreeColumn; - private Aga.Controls.Tree.NodeControls.NodeTextBox NameNodeTextBox; + private FlashDebugger.Controls.DataTree.NodeControls.NodeTextBoxEx NameNodeTextBox; private Aga.Controls.Tree.NodeControls.NodeTextBox ValueNodeTextBox; } } diff --git a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs index 20e831a636..568f05b5d6 100644 --- a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs +++ b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs @@ -1,10 +1,13 @@ using System; using System.Drawing; using System.Windows.Forms; +using ASCompletion.Helpers; using Aga.Controls.Tree; using System.Collections.Generic; using System.Collections.ObjectModel; using Aga.Controls.Tree.NodeControls; +using FlashDebugger.Controls.DataTree.NodeControls; +using PluginCore.Controls; using PluginCore.Managers; using flash.tools.debugger; using FlashDebugger.Controls.DataTree; @@ -14,7 +17,7 @@ namespace FlashDebugger.Controls { - public partial class DataTreeControl : UserControl, IToolTipProvider + public partial class DataTreeControl : UserControl, IToolTipProvider, ASCompletionListBackend.IBackendFileGetter { public event EventHandler ValueChanged; @@ -26,6 +29,10 @@ public partial class DataTreeControl : UserControl, IToolTipProvider private bool watchMode; private bool addingNewExpression; + // Autocompletion + private CompletionListControl completionList; + private ASCompletionListBackend completionBackend; + public Collection Nodes { get @@ -50,7 +57,8 @@ public ViewerForm Viewer } } - public DataTreeControl():this(false) + public DataTreeControl() + : this(false) { } @@ -67,19 +75,20 @@ public DataTreeControl(bool watchMode) NameNodeTextBox.EditEnabled = true; NameNodeTextBox.DrawText += NameNodeTextBox_DrawText; NameNodeTextBox.EditorShowing += NameNodeTextBox_EditorShowing; + NameNodeTextBox.EditorCreated += NameNodeTextBox_EditorCreated; NameNodeTextBox.EditorHided += NameNodeTextBox_EditorHided; NameNodeTextBox.IsEditEnabledValueNeeded += NameNodeTextBox_IsEditEnabledValueNeeded; NameNodeTextBox.LabelChanged += NameNodeTextBox_LabelChanged; _tree.KeyDown += Tree_KeyDown; _tree.NodeMouseClick += Tree_NameNodeMouseClick; } - + _model = new DataTreeModel(); _tree.Model = _model; _tree.FullRowSelect = true; Controls.Add(_tree); _tree.Expanding += TreeExpanding; - _tree.SelectionChanged += TreeSelectionChanged; + _tree.SelectionChanged += Tree_SelectionChanged; _tree.NodeMouseDoubleClick += Tree_NodeMouseDoubleClick; _tree.LoadOnDemand = true; _tree.AutoRowHeight = true; @@ -99,13 +108,13 @@ public DataTreeControl(bool watchMode) this.ValueTreeColumn.Header = TextHelper.GetString("Label.Value"); copyMenuItem = new ToolStripMenuItem(TextHelper.GetString("Label.Copy"), null, new EventHandler(this.CopyItemClick)); viewerMenuItem = new ToolStripMenuItem(TextHelper.GetString("Label.Viewer"), null, new EventHandler(this.ViewerItemClick)); - _contextMenuStrip.Items.AddRange(new ToolStripMenuItem[] { copyMenuItem, viewerMenuItem}); + _contextMenuStrip.Items.AddRange(new ToolStripMenuItem[] { copyMenuItem, viewerMenuItem }); if (watchMode) watchMenuItem = new ToolStripMenuItem(TextHelper.GetString("Label.Unwatch"), null, new EventHandler(this.WatchItemClick)); else watchMenuItem = new ToolStripMenuItem(TextHelper.GetString("Label.Watch"), null, new EventHandler(this.WatchItemClick)); _contextMenuStrip.Items.Add(watchMenuItem); - TreeSelectionChanged(null, null); + Tree_SelectionChanged(null, null); viewerForm = new ViewerForm(); viewerForm.StartPosition = FormStartPosition.Manual; } @@ -127,7 +136,7 @@ void NameNodeTextBox_EditorHided(object sender, EventArgs e) { if (addingNewExpression) { - NodeTextBox box = sender as NodeTextBox; + var box = sender as NodeTextBoxEx; var node = box.Parent.CurrentNode.Tag as Node; if (node.Text.Trim() == "") node.Text = TextHelper.GetString("Label.AddExpression"); addingNewExpression = false; @@ -139,7 +148,7 @@ void NameNodeTextBox_EditorHided(object sender, EventArgs e) void NameNodeTextBox_EditorShowing(object sender, System.ComponentModel.CancelEventArgs e) { - NodeTextBox box = sender as NodeTextBox; + var box = sender as NodeTextBoxEx; var node = box.Parent.CurrentNode.Tag as Node; if (box.Parent.CurrentNode.NextNode == null) { @@ -150,6 +159,15 @@ void NameNodeTextBox_EditorShowing(object sender, System.ComponentModel.CancelEv addingNewExpression = false; } + void NameNodeTextBox_EditorCreated(object sender, ControlEventArgs e) + { + var controlHost = new ImmediateUI.TextBoxTarget((ImmediateUI.TextBoxEx)e.Control); + completionList = new CompletionListControl(controlHost); + // We need this because TreeViewAdv handles the control LostFocus event itself and the resulting behaviour doesn't seeem very nice + completionList.Tip.Selectable = completionList.CallTip.Selectable = false; + completionBackend = new ASCompletionListBackend(completionList, this); + } + void NameNodeTextBox_IsEditEnabledValueNeeded(object sender, NodeControlValueEventArgs e) { e.Value = e.Node.Level == 1; @@ -157,7 +175,7 @@ void NameNodeTextBox_IsEditEnabledValueNeeded(object sender, NodeControlValueEve void NameNodeTextBox_LabelChanged(object sender, LabelEventArgs e) { - NodeTextBox box = sender as NodeTextBox; + var box = sender as NodeTextBoxEx; if (box.Parent.CurrentNode == null) return; DataNode node = box.Parent.CurrentNode.Tag as DataNode; @@ -297,6 +315,7 @@ private void CopyItemClick(Object sender, System.EventArgs e) DataNode node = Tree.SelectedNode.Tag as DataNode; Clipboard.SetText(string.Format("{0} = {1}",node.Text, node.Value)); } + } } private void ViewerItemClick(Object sender, System.EventArgs e) { @@ -342,7 +361,7 @@ private void WatchItemClick(Object sender, EventArgs e) } } - void TreeSelectionChanged(Object sender, EventArgs e) + void Tree_SelectionChanged(Object sender, EventArgs e) { foreach (ToolStripMenuItem item in _contextMenuStrip.Items) { @@ -587,6 +606,86 @@ public string GetToolTip(TreeNodeAdv node, NodeControl nodeControl) #endregion + #region Auto Completion + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before + if (keyData == (Keys.Control | Keys.Space) || keyData == (Keys.Control | Keys.Shift | Keys.Space)) + { + var box = Tree.CurrentEditor as ImmediateUI.TextBoxEx; + if (box != null) + { + if (keyData == (Keys.Control | Keys.Space)) + completionBackend.ShowAutoCompletioList(); + else + completionBackend.ShowFunctionDetails(); + + return true; + } + } + return base.ProcessCmdKey(ref msg, keyData); + } + + PluginCore.Helpers.EncodingFileInfo ASCompletionListBackend.IBackendFileGetter.GetFileContent(ASCompletionListBackend.BackendFileInfo file) + { + var debugger = PluginMain.debugManager.FlashInterface; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) + return null; + var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); + + // Could somebody want to pass a file pointing to a file different to the one being debugged? highly unlikely + + var sourceFile = location.getFile(); + var sourceFileText = new System.Text.StringBuilder(); + if (sourceFile != null) + { + for (int i = 1, count = sourceFile.getLineCount(); i <= count; i++) + { + sourceFileText.Append(sourceFile.getLine(i).ToString()).Append(PluginCore.Utilities.LineEndDetector.GetNewLineMarker((int)PluginBase.Settings.EOLMode)); + } + } + + if (sourceFileText.Length == 0) + { + if (file.File != null && System.IO.File.Exists(file.File) && + file.File == PluginMain.debugManager.GetLocalPath(sourceFile)) + { + // Notify the user of this case? + //MessageBox.Show("Source code no available, but potential matching file found on disk, do you want to use it?"); + return PluginCore.Helpers.FileHelper.GetEncodingFileInfo(file.File); + } + + return null; + } + + // Maybe we should convert from UTF-16 to UTF-8? no problems so far + return new PluginCore.Helpers.EncodingFileInfo { CodePage = System.Text.Encoding.UTF8.CodePage, Contents = sourceFileText.ToString() }; + } + + bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionListBackend.BackendFileInfo file) + { + file = default(ASCompletionListBackend.BackendFileInfo); + var debugger = PluginMain.debugManager.FlashInterface; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) + return false; + var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); + file.File = PluginMain.debugManager.GetLocalPath(location.getFile()); + if (file.File == null) + return false; + + file.Line = location.getLine() - 1; + + return true; + } + + string ASCompletionListBackend.IBackendFileGetter.GetExpression() + { + return Tree.CurrentEditor.Text.Substring(0, ((ImmediateUI.TextBoxEx)Tree.CurrentEditor).SelectionStart); + } + + #endregion + #region State Class private class DataTreeState diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs index 3c9a2e6205..136669684c 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs @@ -29,7 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.textBox = new System.Windows.Forms.TextBox(); + this.textBox = new TextBoxEx(); this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.cutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -46,6 +46,7 @@ private void InitializeComponent() this.textBox.Location = new System.Drawing.Point(0, 0); this.textBox.Multiline = true; this.textBox.Name = "textBox"; + this.textBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBox.Size = new System.Drawing.Size(148, 150); this.textBox.TabIndex = 0; this.textBox.WordWrap = false; @@ -110,7 +111,7 @@ private void InitializeComponent() #endregion - private System.Windows.Forms.TextBox textBox; + private TextBoxEx textBox; private System.Windows.Forms.ContextMenuStrip contextMenuStrip; private System.Windows.Forms.ToolStripMenuItem clearAllToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem cutToolStripMenuItem; diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index 4c2e435878..992b181ca3 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -3,25 +3,30 @@ using System.Drawing; using System.Text; using System.Windows.Forms; +using ASCompletion.Completion; +using ASCompletion.Helpers; +using ASCompletion.Model; using flash.tools.debugger; using flash.tools.debugger.expression; using PluginCore.Controls; +using PluginCore; namespace FlashDebugger.Controls { - public partial class ImmediateUI : DockPanelControl + public partial class ImmediateUI : DockPanelControl, ASCompletionListBackend.IBackendFileGetter { private List history; private int historyPos; private CompletionListControl completionList; + private ASCompletionListBackend completionBackend; public ImmediateUI() { this.InitializeComponent(); this.contextMenuStrip.Renderer = new DockPanelStripRenderer(false); - var completionTarget = new TextBoxTarget(textBox); - this.completionList = new CompletionListControl(completionTarget); + this.completionList = new CompletionListControl(new TextBoxTarget(textBox)); + this.completionBackend = new ASCompletionListBackend(completionList, this); this.history = new List(); } @@ -62,11 +67,12 @@ private void TextBox_KeyDown(object sender, KeyEventArgs e) e.SuppressKeyPress = true; int curLine = this.textBox.GetLineFromCharIndex(this.textBox.SelectionStart); string line = ""; - if (curLine 0 && !this.textBox.Lines[this.textBox.Lines.Length - 1].Trim().Equals("")) this.textBox.AppendText(Environment.NewLine); try { - this.history.Add(line); + if (history.Count == 0 || history[history.Count - 1] != line) + this.history.Add(line); this.historyPos = this.history.Count; if (line == "swfs") { @@ -110,46 +116,91 @@ private void TextBox_KeyDown(object sender, KeyEventArgs e) protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before - if ((keyData & Keys.KeyCode) == Keys.Space && (keyData & Keys.Modifiers & Keys.Control) > 0) + if (keyData == (Keys.Control | Keys.Space) || keyData == (Keys.Control | Keys.Shift | Keys.Space)) { int curLine = this.textBox.GetLineFromCharIndex(this.textBox.SelectionStart); string line = (curLine < this.textBox.Lines.Length) ? this.textBox.Lines[curLine] : ""; - if (line == "" || !line.StartsWith("p ")) return true; + if (curLine != textBox.Lines.Length - 1 || !line.StartsWith("p ") && !line.StartsWith("g ")) + return false; - var debugger = PluginMain.debugManager.FlashInterface; - if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) - return true; - var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); - string file = PluginMain.debugManager.GetLocalPath(location.getFile()); - if (file == null) return true; - var info = PluginCore.Helpers.FileHelper.GetEncodingFileInfo(file); - if (info.CodePage == -1) return true; - using (var sci = new ScintillaNet.ScintillaControl()) + int lineLength = textBox.SelectionStart - textBox.GetFirstCharIndexFromLine(textBox.Lines.Length - 1) - 2; + if (lineLength < 0) + return false; + + ASCompletionListBackend.BackendFileInfo file; + if (!((ASCompletionListBackend.IBackendFileGetter)this).GetFileInfo(out file)) + return false; + + if (line.StartsWith("g ")) { - sci.Text = info.Contents; - sci.CodePage = info.CodePage; - sci.Encoding = Encoding.GetEncoding(info.CodePage); - sci.ConfigurationLanguage = PluginCore.PluginBase.CurrentProject.Language; - - sci.CurrentPos = sci.PositionFromLine(location.getLine() - 1); - string expression = line.Substring(2); - sci.SetSel(sci.CurrentPos, sci.CurrentPos); - sci.ReplaceSel(expression); - - ASCompletion.Completion.ASExpr expr = - ASCompletion.Completion.ASComplete.GetExpressionType(sci, sci.CurrentPos).Context; - var list = new List(); - if (expr.Value != null) + string expression = line.Substring(2, lineLength).TrimStart(); + if (expression.IndexOfAny(".,_();:[]{}=-+*\'\"\\/|<>?! ".ToCharArray()) > -1) + return false; + + var fileModel = ASFileParser.ParseFile(new FileModel(file.File)); + + var members = new MemberList(); + + // We could use Context.GetTopLevelElements, but neither AS2 or super are supported... + members.Add(new MemberModel("this", "", FlagType.Variable | FlagType.Intrinsic, Visibility.Public)); + + // root types & packages + var newContext = ASCompletion.Context.ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); + FileModel baseElements = newContext.ResolvePackage(null, false); + if (baseElements != null) { - ASCompletion.Model.MemberList locals = ASCompletion.Completion.ASComplete.ParseLocalVars(expr); - foreach (ASCompletion.Model.MemberModel local in locals) - list.Add(new ASCompletion.Completion.MemberItem(local)); + foreach (var m in baseElements.Members.Items) + { + members.Add(m); + } + foreach (var m in baseElements.Imports.Items) + { + if (m.Flags == FlagType.Package) continue; + members.Add(m); + } } - completionList.Show(list, true, line.Substring(line.LastIndexOfAny(new[]{' ', '.'}) + 1)); + + for (int i = fileModel.Classes.Count - 1; i >= 0; i--) + { + var c = fileModel.Classes[i]; + if (c.LineFrom <= file.Line && c.LineTo >= file.Line) + { + foreach (var m in c.Members.Items) + { + if (m.Access != Visibility.Public || (m.Flags & FlagType.Variable) == 0) continue; + members.Add(m); + } + + break; + } + } + + members.Sort(); + + var language = ScintillaNet.ScintillaControl.Configuration.GetLanguage(PluginBase.CurrentProject.Language); + if (language != null) // Should we provide some custom string otherwise? + completionList.CharacterClass = language.characterclass.Characters; + + members.Sort(); + var items = new List(); + foreach (var m in members.Items) items.Add(new MemberItem(m)); + completionList.Show(items, true, expression); + + return true; + } + + if (completionBackend.SetCompletionBackend(file, line.Substring(2, lineLength))) + { + if (keyData == (Keys.Control | Keys.Space)) + completionBackend.ShowAutoCompletioList(); + else + completionBackend.ShowFunctionDetails(); + + return true; } - return true; + return false; } return base.ProcessCmdKey(ref msg, keyData); } @@ -209,7 +260,147 @@ private void PasteToolStripMenuItem_Click(object sender, EventArgs e) this.textBox.Paste(); } - private class TextBoxTarget : ICompletionListHost + #region ASCompletionListBackend.BackendFileInfo Methods + + PluginCore.Helpers.EncodingFileInfo ASCompletionListBackend.IBackendFileGetter.GetFileContent(ASCompletionListBackend.BackendFileInfo file) + { + var debugger = PluginMain.debugManager.FlashInterface; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) + return null; + var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); + + // Could somebody want to pass a file pointing to a file different to the one being debugged? highly unlikely + + var sourceFile = location.getFile(); + var sourceFileText = new StringBuilder(); + if (sourceFile != null) + { + for (int i = 1, count = sourceFile.getLineCount(); i <= count; i++) + { + sourceFileText.Append(sourceFile.getLine(i).ToString()).Append(PluginCore.Utilities.LineEndDetector.GetNewLineMarker((int)PluginBase.Settings.EOLMode)); + } + } + + if (sourceFileText.Length == 0) + { + if (file.File != null && System.IO.File.Exists(file.File) && + file.File == PluginMain.debugManager.GetLocalPath(sourceFile)) + { + // Notify the user of this case? + //MessageBox.Show("Source code no available, but potential matching file found on disk, do you want to use it?"); + return PluginCore.Helpers.FileHelper.GetEncodingFileInfo(file.File); + } + + return null; + } + + // Maybe we should convert from UTF-16 to UTF-8? no problems so far + return new PluginCore.Helpers.EncodingFileInfo { CodePage = Encoding.UTF8.CodePage, Contents = sourceFileText.ToString() }; + } + + bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionListBackend.BackendFileInfo file) + { + file = default(ASCompletionListBackend.BackendFileInfo); + var debugger = PluginMain.debugManager.FlashInterface; + if (!debugger.isDebuggerStarted || !debugger.isDebuggerSuspended || PluginMain.debugManager.CurrentFrame >= debugger.GetFrames().Length) + return false; + var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); + file.File = PluginMain.debugManager.GetLocalPath(location.getFile()); + if (file.File == null) + return false; + + file.Line = location.getLine() - 1; + + return true; + } + + string ASCompletionListBackend.IBackendFileGetter.GetExpression() + { + int curLine = this.textBox.GetLineFromCharIndex(this.textBox.SelectionStart); + string line = (curLine < this.textBox.Lines.Length) ? this.textBox.Lines[curLine] : ""; + + if (curLine != textBox.Lines.Length - 1 || !line.StartsWith("p ")) + return null; + + int lineLength = textBox.SelectionStart - textBox.GetFirstCharIndexFromLine(textBox.Lines.Length - 1) - 2; + if (lineLength < 0) + return null; + + return line.Substring(2, lineLength); + } + + #endregion + + public class TextBoxEx : TextBox + { + private const int WM_SYSKEYDOWN = 0x0104; + + public event KeyEventHandler KeyPosted; //Hacky event for MethodCallTip, although with some rather valid use cases + public event ScrollEventHandler Scroll; + + protected override void DefWndProc(ref Message m) + { + base.DefWndProc(ref m); + + if (m.Msg == Win32.WM_KEYDOWN || m.Msg == WM_SYSKEYDOWN) // If we're worried about performance/GC, we can store latest OnKeyDown e + OnKeyPosted(new KeyEventArgs((Keys)((int)m.WParam) | ModifierKeys)); + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case Win32.WM_HSCROLL: + case Win32.WM_VSCROLL: + case Win32.WM_MOUSEWHEEL: + WmScroll(ref m); + break; + default: + base.WndProc(ref m); + break; + } + + } + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected virtual void OnScroll(ScrollEventArgs e) + { + if (Scroll != null) + Scroll(this, e); + } + + protected virtual void OnKeyPosted(KeyEventArgs e) + { + if (KeyPosted != null) + KeyPosted(this, e); + } + + private void WmScroll(ref Message m) + { + ScrollOrientation so; + ScrollEventType set = (ScrollEventType)((short)((int)(long)m.WParam & 0xffff)); + + // We're not interested in the actual scroll change right now + if (m.Msg == Win32.WM_HSCROLL) + { + so = ScrollOrientation.HorizontalScroll; + base.WndProc(ref m); + } + else + { + so = ScrollOrientation.VerticalScroll; + base.WndProc(ref m); + } + + OnScroll(new ScrollEventArgs(set, 0, 0, so)); + } + + } + + public class TextBoxTarget : ICompletionListHost { #region ICompletionListTarget Members @@ -220,7 +411,28 @@ public event EventHandler LostFocus remove { _owner.LostFocus -= value; } } - public event EventHandler PositionChanged; + private EventHandler positionChanged; + public event EventHandler PositionChanged + { + add + { + if (positionChanged == null || positionChanged.GetInvocationList().Length == 0) + { + _owner.Scroll += Owner_Scroll; + BuildControlHierarchy(_owner); + } + positionChanged += value; + } + remove + { + positionChanged -= value; + if (positionChanged == null || positionChanged.GetInvocationList().Length < 1) + { + _owner.Scroll -= Owner_Scroll; + ClearControlHierarchy(); + } + } + } public event EventHandler SizeChanged { @@ -234,7 +446,11 @@ public event KeyEventHandler KeyDown remove { _owner.KeyDown -= value; } } - public event KeyEventHandler KeyPosted; + public event KeyEventHandler KeyPosted + { + add { _owner.KeyPosted += value; } + remove { _owner.KeyPosted -= value; } + } public event KeyPressEventHandler KeyPress { @@ -248,7 +464,7 @@ public event MouseEventHandler MouseDown remove { _owner.MouseDown -= value; } } - private TextBox _owner; + private TextBoxEx _owner; public Control Owner { get { return _owner; } @@ -282,7 +498,7 @@ public bool IsEditable get { return !_owner.ReadOnly; } } - public TextBoxTarget(TextBox owner) + public TextBoxTarget(TextBoxEx owner) { _owner = owner; } @@ -299,8 +515,8 @@ public Point GetPositionFromCharIndex(int pos) public int GetLineHeight() { - using (Graphics g = _owner.CreateGraphics()) - { + using (Graphics g = _owner.CreateGraphics()) + { SizeF textSize = g.MeasureString("S", _owner.Font); return (int)Math.Ceiling(textSize.Height); } @@ -323,8 +539,51 @@ public void EndUndoAction() } #endregion - } + private List controlHierarchy = new List(); + + private void BuildControlHierarchy(Control current) + { + while (current != null) + { + current.LocationChanged += Control_LocationChanged; + current.ParentChanged += Control_ParentChanged; + controlHierarchy.Add(current); + current = current.Parent; + } + } + + private void ClearControlHierarchy() + { + foreach (var control in controlHierarchy) + { + control.LocationChanged -= Control_LocationChanged; + control.ParentChanged -= Control_ParentChanged; + } + controlHierarchy.Clear(); + } + + private void Control_LocationChanged(object sender, EventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Control_ParentChanged(object sender, EventArgs e) + { + ClearControlHierarchy(); + BuildControlHierarchy(_owner); + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Owner_Scroll(object sender, ScrollEventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + } } } diff --git a/External/Plugins/FlashDebugger/FlashDebugger.csproj b/External/Plugins/FlashDebugger/FlashDebugger.csproj index 311a13f8d4..8eff525e57 100644 --- a/External/Plugins/FlashDebugger/FlashDebugger.csproj +++ b/External/Plugins/FlashDebugger/FlashDebugger.csproj @@ -100,6 +100,9 @@ + + Component + diff --git a/PluginCore/PluginCore/Controls/CompletionListControl.cs b/PluginCore/PluginCore/Controls/CompletionListControl.cs index 6f061adf15..4f0c0bff95 100644 --- a/PluginCore/PluginCore/Controls/CompletionListControl.cs +++ b/PluginCore/PluginCore/Controls/CompletionListControl.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Drawing; using System.Collections.Generic; using System.Text.RegularExpressions; @@ -14,9 +15,9 @@ public class CompletionListControl : IMessageFilter { public event CompletionListInsertedTextHandler OnInsert; public event CompletionListInsertedTextHandler OnCancel; - public event EventHandler OnShowing; + public event CancelEventHandler OnShowing; public event EventHandler OnHidden; - + /// /// Properties of the class /// @@ -25,6 +26,7 @@ public class CompletionListControl : IMessageFilter private System.Windows.Forms.ListBox completionList; private System.Windows.Forms.ToolStripControlHost listContainer; private System.Windows.Forms.ToolStripDropDown listHost; + private CompletionListWindow completionListWindow; #region State Properties @@ -50,7 +52,7 @@ public class CompletionListControl : IMessageFilter private ICompletionListHost host; private RichToolTip tip; - private MethodCallTip callTip; // Used only by the main completion list so far, would it be better to control this case in another way? like the cl, we'd like to show this everywhere possible + private MethodCallTip callTip; #endregion @@ -356,6 +358,7 @@ public void Hide() currentItem = null; allItems = null; Tip.Hide(); + tempoTip.Enabled = false; if (visible && OnHidden != null) OnHidden(this, EventArgs.Empty); } } @@ -442,7 +445,7 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) Tip.Redraw(false); var screen = Screen.FromControl(listHost); - int rightWidth = screen.WorkingArea.Right - listHost.Right - 10; + int rightWidth = screen.WorkingArea.Right - listHost.Right - 1; int leftWidth = listHost.Left; Point posTarget = new Point(listHost.Right, listHost.Top); @@ -450,16 +453,15 @@ public void UpdateTip(Object sender, System.Timers.ElapsedEventArgs e) if (rightWidth < 220 && leftWidth > 220) { widthTarget = leftWidth; - posTarget.X = 0; + posTarget.X = listHost.Left - Tip.Size.Width; } Tip.Location = posTarget; + Tip.Show(); Tip.AutoSize(widthTarget, 500); if (widthTarget == leftWidth) Tip.Location = new Point(listHost.Left - Tip.Size.Width, posTarget.Y); - - Tip.Show(); } private void UpdatePosition() @@ -472,7 +474,6 @@ private void UpdatePosition() return; } coord = host.Owner.PointToScreen(coord); - coord.X += host.Owner.Left; var screen = Screen.FromHandle(host.Owner.Handle); listUp = CallTip.CallTipActive || (coord.Y - listHost.Height > screen.WorkingArea.Top && coord.Y + host.GetLineHeight() + listHost.Height > screen.WorkingArea.Bottom); if (listUp) coord.Y -= listHost.Height; @@ -484,11 +485,23 @@ private void UpdatePosition() } if (listHost.Visible) + { listHost.Show(coord); + if (Tip.Visible) UpdateTip(null, null); + } else { Redraw(); - if (OnShowing != null) OnShowing(this, EventArgs.Empty); + if (OnShowing != null) + { + var cancelArgs = new CancelEventArgs(); + OnShowing(this, cancelArgs); + if (cancelArgs.Cancel) + { + Hide(); + return; + } + } listHost.Opacity = 1; listHost.Show(coord); if (CallTip.CallTipActive) CallTip.PositionControl(); @@ -925,6 +938,8 @@ private void AddHandlers() host.KeyPress += Target_KeyPress; host.PositionChanged += Target_PositionChanged; host.SizeChanged += Target_SizeChanged; + + completionListWindow = new CompletionListWindow(this); } private void RemoveHandlers() @@ -937,11 +952,15 @@ private void RemoveHandlers() host.KeyPress -= Target_KeyPress; host.PositionChanged -= Target_PositionChanged; host.SizeChanged -= Target_SizeChanged; + + if (completionListWindow != null) + completionListWindow.ReleaseHandle(); + completionListWindow = null; } private void Target_LostFocus(object sender, EventArgs e) { - if (!listHost.ContainsFocus && !Tip.Focused && !CallTip.Focused) + if (!listHost.ContainsFocus && !Tip.Focused && !CallTip.Focused && !host.Owner.ContainsFocus) Hide(); } @@ -959,8 +978,17 @@ private void Target_KeyDown(object sender, KeyEventArgs e) private void Target_KeyPress(object sender, KeyPressEventArgs e) { - if (!char.IsControl(e.KeyChar)) + if (!char.IsControl(e.KeyChar) && !e.Handled) + { + // Hacky... the current implementation relies on the OnChar Scintilla event, which happens after the KeyPress event + // We either create an OnChar event in ICompletionListHost and implement it, or change the current behaviour + e.Handled = true; + host.SelectedText = new string(e.KeyChar, 1); + int pos = host.CurrentPos + 1; + host.SetSelection(pos, pos); + OnChar(e.KeyChar); + } } private void Target_PositionChanged(object sender, EventArgs e) @@ -1103,7 +1131,8 @@ public bool HandleKeys(Keys key) break; case Keys.PageUp: - /*case Keys.PageUp | Keys.Control:*/ // Used to navigate through documents + /*case Keys.PageUp | Keys.Control:*/ + // Used to navigate through documents noAutoInsert = false; // the list was hidden and it should not appear if (!listHost.Visible) @@ -1122,7 +1151,8 @@ public bool HandleKeys(Keys key) break; case Keys.PageDown: - /*case Keys.PageDown | Keys.Control:*/ // Used to navigate through documents + /*case Keys.PageDown | Keys.Control:*/ + // Used to navigate through documents noAutoInsert = false; // the list was hidden and it should not appear if (!listHost.Visible) @@ -1141,6 +1171,10 @@ public bool HandleKeys(Keys key) break; case Keys.Home: + case Keys.End: + Hide(); + return false; + /* These could be interesting with some shortcut or condition... noAutoInsert = false; // go down the list if (completionList.SelectedIndex > 0) @@ -1162,7 +1196,7 @@ public bool HandleKeys(Keys key) completionList.SelectedIndex = index; } - break; + break;*/ case (Keys.Control | Keys.Space): break; @@ -1283,7 +1317,27 @@ public bool PreFilterMessage(ref Message m) } return false; } - + + private class CompletionListWindow : NativeWindow + { + private const int WM_ACTIVATEAPP = 0x1C; + + private CompletionListControl owner; + + public CompletionListWindow(CompletionListControl owner) + { + this.owner = owner; + AssignHandle(owner.listHost.Handle); + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == WM_ACTIVATEAPP && m.WParam == IntPtr.Zero) + owner.Hide(); + base.WndProc(ref m); + } + } + #endregion #region Unfocusable List @@ -1295,8 +1349,9 @@ protected override void DefWndProc(ref Message m) { const int WM_MOUSEACTIVATE = 0x21; const int WM_LBUTTONDOWN = 0x201; + const int WM_LBUTTONDBLCLK = 0x203; const int MA_NOACTIVATE = 0x0003; - + switch (m.Msg) { case WM_MOUSEACTIVATE: @@ -1306,6 +1361,9 @@ protected override void DefWndProc(ref Message m) SelectedIndex = IndexFromPoint((short)(m.LParam.ToInt32() & 0xFFFF), (short)((m.LParam.ToInt32() & 0xFFFF0000) >> 16)); m.Result = IntPtr.Zero; return; + case WM_LBUTTONDBLCLK: + m.Result = IntPtr.Zero; + return; } base.DefWndProc(ref m); } diff --git a/PluginCore/PluginCore/Controls/InactiveForm.cs b/PluginCore/PluginCore/Controls/InactiveForm.cs index 5a75bde35c..f5954a3344 100644 --- a/PluginCore/PluginCore/Controls/InactiveForm.cs +++ b/PluginCore/PluginCore/Controls/InactiveForm.cs @@ -8,6 +8,7 @@ namespace PluginCore.Controls public class InactiveForm : Form { + private const int WS_EX_TOPMOST = 0x8; private const int WS_EX_NOACTIVATE = 0x8000000; protected override bool ShowWithoutActivation @@ -15,13 +16,48 @@ protected override bool ShowWithoutActivation get { return true; } } + private bool topMost; + /// + /// Determines whether the form should display as top most. Unlike Form.TopMost, this does not give focus + /// + public new bool TopMost + { + get { return topMost; } + set + { + if (topMost == value) return; + topMost = value; + if (IsHandleCreated) RecreateHandle(); + } + } + + private bool noActivate; + /// + /// Gets or sets if the form can become the foreground window. In the case of a top level window this only works for + /// other applications, not within the same one. + /// + public bool NoActivate + { + get { return noActivate; } + set + { + if (noActivate == value) return; + noActivate = value; + if (IsHandleCreated) RecreateHandle(); + } + } + protected override CreateParams CreateParams { get { CreateParams p = base.CreateParams; - p.ExStyle |= WS_EX_NOACTIVATE; + if (noActivate) + p.ExStyle |= WS_EX_NOACTIVATE; + + if (topMost) + p.ExStyle |= WS_EX_TOPMOST; return p; } diff --git a/PluginCore/PluginCore/Controls/MethodCallTip.cs b/PluginCore/PluginCore/Controls/MethodCallTip.cs index 2807c525cf..c53451b2ef 100644 --- a/PluginCore/PluginCore/Controls/MethodCallTip.cs +++ b/PluginCore/PluginCore/Controls/MethodCallTip.cs @@ -1,7 +1,5 @@ using System; -using System.Diagnostics; using System.Drawing; -using System.Text; using System.Windows.Forms; namespace PluginCore.Controls @@ -14,11 +12,10 @@ public class MethodCallTip: RichToolTip // events public event UpdateCallTipHandler OnUpdateCallTip; - - public static string HLTextStyleBeg = "[B]"; - public static string HLTextStyleEnd = "[/B]"; - public static string HLBgStyleBeg = "[BGCOLOR=#000:OVERLAY]"; - public static string HLBgStyleEnd = "[/BGCOLOR]"; + public static string HLTextStyleBeg = "[B]"; + public static string HLTextStyleEnd = "[/B]"; + public static string HLBgStyleBeg = "[BGCOLOR=#000:OVERLAY]"; + public static string HLBgStyleEnd = "[/BGCOLOR]"; // state @@ -28,7 +25,7 @@ public class MethodCallTip: RichToolTip protected bool isActive; protected int memberPos; protected int startPos; - protected int currentPos; + protected int currentPos; protected int currentLine; protected CompletionListControl completionList; @@ -44,12 +41,24 @@ public bool CallTipActive get { return isActive; } } + public int CurrentHLStart + { + get { return currentHLStart; } + } + + public int CurrentHLEnd + { + get { return currentHLEnd; } + } + + public int MemberPosition + { + get { return memberPos; } + } + public override void Hide() { - if (isActive) - { - isActive = false; - } + isActive = false; currentText = null; currentHLStart = -1; currentHLEnd = -1; @@ -61,10 +70,10 @@ public bool CheckPosition(int position) return position == currentPos; } - public void CallTipShow(int position, string text) - { - CallTipShow(position, text, true); - } + public void CallTipShow(int position, string text) + { + CallTipShow(position, text, true); + } public void CallTipShow(int position, string text, bool redraw) { if (host.Visible && position == memberPos && text == currentText) @@ -77,7 +86,8 @@ public void CallTipShow(int position, string text, bool redraw) host.Visible = false; currentText = text; - SetText(text, true); + currentHLEnd = currentHLStart = -1; + SetText(text, true); memberPos = position; startPos = memberPos + toolTipRTB.Text.IndexOf('('); @@ -116,10 +126,10 @@ public void PositionControl() } } - public void CallTipSetHlt(int start, int end) - { - CallTipSetHlt(start, end, true); - } + public void CallTipSetHlt(int start, int end) + { + CallTipSetHlt(start, end, true); + } public void CallTipSetHlt(int start, int end, bool forceRedraw) { if (currentHLStart == start && currentHLEnd == end) @@ -131,28 +141,28 @@ public void CallTipSetHlt(int start, int end, bool forceRedraw) currentHLStart = start; currentHLEnd = end; - if (start != end) - { - string savedRawText = rawText; - - try - { - rawText = rawText.Substring(0, start) - + HLBgStyleBeg + HLTextStyleBeg - + rawText.Substring(start, end - start) - + HLTextStyleEnd + HLBgStyleEnd - + rawText.Substring(end); - - Redraw(); - } - catch { } - - rawText = savedRawText; - } - else - { - Redraw(); - } + if (start != end) + { + string savedRawText = rawText; + + try + { + rawText = rawText.Substring(0, start) + + HLBgStyleBeg + HLTextStyleBeg + + rawText.Substring(start, end - start) + + HLTextStyleEnd + HLBgStyleEnd + + rawText.Substring(end); + + Redraw(); + } + catch { } + + rawText = savedRawText; + } + else + { + Redraw(); + } } private void Host_VisibleChanged(object sender, EventArgs e) @@ -280,8 +290,8 @@ private void HandlePostedKeys(Keys key) case Keys.Left | Keys.Shift: case Keys.Left | Keys.Control: currentPos = owner.CurrentPos; - if (currentPos < startPos) Hide(); if (OnUpdateCallTip != null) OnUpdateCallTip(owner.Owner, currentPos); + else if (currentPos < startPos) Hide(); break; case Keys.Up: @@ -309,8 +319,8 @@ private void HandlePostedKeys(Keys key) case Keys.Delete: case Keys.Delete | Keys.Control: currentPos = owner.CurrentPos; - if (currentPos < startPos) Hide(); if (OnUpdateCallTip != null) OnUpdateCallTip.BeginInvoke(owner.Owner, currentPos, null, null); + else if (currentPos < startPos) Hide(); break; case Keys.Escape: diff --git a/PluginCore/PluginCore/Controls/RichToolTip.cs b/PluginCore/PluginCore/Controls/RichToolTip.cs index ba68df2dff..2a028122db 100644 --- a/PluginCore/PluginCore/Controls/RichToolTip.cs +++ b/PluginCore/PluginCore/Controls/RichToolTip.cs @@ -1,51 +1,47 @@ using System; +using System.ComponentModel; using System.Drawing; using System.Windows.Forms; -using System.Collections; using System.Collections.Generic; -using System.Diagnostics; -using System.Text.RegularExpressions; -using System.Runtime.InteropServices; -using ScintillaNet; using PluginCore.BBCode; namespace PluginCore.Controls { - /// - /// RichTextBox-based tooltip - /// - public class RichToolTip - { + /// + /// RichTextBox-based tooltip + /// + public class RichToolTip + { public delegate void UpdateTipHandler(Control sender, Point mousePosition); // events public event UpdateTipHandler OnUpdateSimpleTip; + public event CancelEventHandler OnShowing; + public event EventHandler OnHidden; - // controls - protected InactiveForm host; - protected Panel toolTip; - protected RichTextBox toolTipRTB; + // controls + protected InactiveForm host; + protected Panel toolTip; + protected SelectableRichTextBox toolTipRTB; protected string rawText; - protected string lastRawText; - protected string cachedRtf; - protected Dictionary rtfCache; - protected List rtfCacheList; + protected Dictionary rtfCache; + protected List rtfCacheList; protected Point mousePos; - protected ICompletionListHost owner; // We could just use Control here, or pass a reference on each related call, as Control may be a problem with default implementation + protected ICompletionListHost owner; // We could just use Control here, or pass a reference on each related call, as Control may be a problem with default implementation - #region Public Properties + #region Public Properties public bool Focused { get { return toolTipRTB.Focused; } } - public bool Visible - { - get { return host.Visible; } - } + public bool Visible + { + get { return host.Visible; } + } public Size Size { @@ -53,65 +49,85 @@ public Size Size set { host.Size = value; } } - public Point Location - { - get { return host.Location; } - set { host.Location = value; } - } - - public string Text - { - get { return toolTipRTB.Text; } - set - { - SetText(value, true); - } - } - - #endregion - - #region Control creation - - public RichToolTip(ICompletionListHost owner) - { + public Point Location + { + get { return host.Location; } + set { host.Location = value; } + } + + public string RawText + { + get { return rawText; } + set + { + SetText(value, true); + } + } + + public bool Selectable + { + get { return toolTipRTB.Selectable; } + set + { + toolTipRTB.Selectable = value; + } + } + + public string Text + { + get { return toolTipRTB.Text; } + set + { + SetText(value, true); + } + } + + #endregion + + #region Control creation + + public RichToolTip(ICompletionListHost owner) + { // host - host = new InactiveForm(); - host.FormBorderStyle = FormBorderStyle.None; + host = new InactiveForm(); + host.FormBorderStyle = FormBorderStyle.None; host.ShowInTaskbar = false; + host.TopMost = true; host.StartPosition = FormStartPosition.Manual; host.KeyPreview = true; host.KeyDown += Host_KeyDown; - this.owner = owner; - - // panel - toolTip = new Panel(); - toolTip.Location = new System.Drawing.Point(0,0); + this.owner = owner; + + // panel + toolTip = new Panel(); + toolTip.Location = new System.Drawing.Point(0, 0); toolTip.BackColor = System.Drawing.SystemColors.Info; toolTip.ForeColor = System.Drawing.SystemColors.InfoText; - toolTip.BorderStyle = BorderStyle.FixedSingle; - toolTip.Dock = DockStyle.Fill; - host.Controls.Add(toolTip); - // text - toolTipRTB = new System.Windows.Forms.RichTextBox(); - toolTipRTB.Location = new System.Drawing.Point(2,1); + toolTip.BorderStyle = BorderStyle.FixedSingle; + toolTip.Dock = DockStyle.Fill; + host.Controls.Add(toolTip); + // text + toolTipRTB = new SelectableRichTextBox(); + toolTipRTB.Location = new System.Drawing.Point(2, 1); toolTipRTB.BackColor = System.Drawing.SystemColors.Info; toolTipRTB.ForeColor = System.Drawing.SystemColors.InfoText; - toolTipRTB.BorderStyle = BorderStyle.None; - toolTipRTB.ScrollBars = RichTextBoxScrollBars.None; + toolTipRTB.BorderStyle = BorderStyle.None; + toolTipRTB.ScrollBars = RichTextBoxScrollBars.None; toolTipRTB.DetectUrls = false; - toolTipRTB.ReadOnly = true; - toolTipRTB.WordWrap = false; - toolTipRTB.Visible = true; - toolTipRTB.Text = ""; - toolTip.Controls.Add(toolTipRTB); - - // rtf cache - rtfCache = new Dictionary(); - rtfCacheList = new List(); - } - - #endregion + toolTipRTB.ReadOnly = true; + toolTipRTB.WordWrap = false; + toolTipRTB.Visible = true; + toolTipRTB.Text = ""; + toolTipRTB.LostFocus += Host_LostFocus; + toolTip.Controls.Add(toolTipRTB); + + // rtf cache + rtfCache = new Dictionary(); + rtfCacheList = new List(); + } + + #endregion #region Event Handlers @@ -121,93 +137,99 @@ protected virtual void Host_KeyDown(object sender, KeyEventArgs e) Hide(); } + protected virtual void Host_LostFocus(object sender, EventArgs e) + { + if (!owner.Owner.ContainsFocus) + Hide(); + } + #endregion #region Tip Methods public bool AutoSize() - { - return AutoSize(0); - } - public bool AutoSize(int availableWidth) - { - return AutoSize(availableWidth, 1024); - } - public bool AutoSize(int availableWidth, int maxWidth) - { - bool tooSmall = false; - bool wordWrap = false; - Size txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, toolTipRTB.Width, toolTipRTB.Height, false); - - // tooltip larger than the window: wrap - var screenArea = Screen.FromControl(owner.Owner).WorkingArea; - int limitLeft = screenArea.Left + 10; - int limitRight = screenArea.Right - 10; + { + return AutoSize(0); + } + public bool AutoSize(int availableWidth) + { + return AutoSize(availableWidth, 1024); + } + public bool AutoSize(int availableWidth, int maxWidth) + { + bool tooSmall = false; + bool wordWrap = false; + Size txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, toolTipRTB.Width, toolTipRTB.Height, false); + + // tooltip larger than the window: wrap + var screenArea = Screen.FromControl(owner.Owner).WorkingArea; + int limitLeft = screenArea.Left + 1; + int limitRight = screenArea.Right - 1; int limitBottom = screenArea.Bottom - 26; - // - int maxW = availableWidth > 0 ? availableWidth : limitRight - limitLeft; - if (maxW > maxWidth && maxWidth > 0) - maxW = maxWidth; - - int w = txtSize.Width + 4; - if (w > maxW) - { - wordWrap = true; - w = maxW; - if (w < 200) - { - w = 200; - tooSmall = true; - } - - txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, w, 1000, true); - w = txtSize.Width + 4; - } - - int h = txtSize.Height + 2; - int dh = 1; - int dw = 2; - if (h > (limitBottom - host.Top)) - { - w += 15; - h = limitBottom - host.Top; - dh = 4; - dw = 5; - - toolTipRTB.ScrollBars = RichTextBoxScrollBars.Vertical; - } - - toolTipRTB.Size = new Size(w, h); - host.Size = new Size(w + dw, h + dh); - - if (host.Left < limitLeft) - host.Left = limitLeft; - - if (host.Left + host.Width > limitRight) - host.Left = limitRight - host.Width; - - if (toolTipRTB.WordWrap != wordWrap) - toolTipRTB.WordWrap = wordWrap; - - return !tooSmall; - } - - public void ShowAtMouseLocation(string text) - { + // + int maxW = availableWidth > 0 ? availableWidth : limitRight - limitLeft; + if (maxW > maxWidth && maxWidth > 0) + maxW = maxWidth; + + int w = txtSize.Width + 4; + if (w > maxW) + { + wordWrap = true; + w = maxW; + if (w < 200) + { + w = 200; + tooSmall = true; + } + + txtSize = WinFormUtils.MeasureRichTextBox(toolTipRTB, false, w, 1000, true); + w = txtSize.Width + 4; + } + + int h = txtSize.Height + 2; + int dh = 1; + int dw = 2; + if (h > (limitBottom - host.Top)) + { + w += 15; + h = limitBottom - host.Top; + dh = 4; + dw = 5; + + toolTipRTB.ScrollBars = RichTextBoxScrollBars.Vertical; + } + + toolTipRTB.Size = new Size(w, h); + host.Size = new Size(w + dw, h + dh); + + if (host.Left < limitLeft) + host.Left = limitLeft; + + if (host.Left + host.Width > limitRight) + host.Left = limitRight - host.Width; + + if (toolTipRTB.WordWrap != wordWrap) + toolTipRTB.WordWrap = wordWrap; + + return !tooSmall; + } + + public void ShowAtMouseLocation(string text) + { if (text != Text) { host.Visible = false; Text = text; } - ShowAtMouseLocation(); - } - - public void ShowAtMouseLocation() - { + ShowAtMouseLocation(); + } + + public void ShowAtMouseLocation() + { //ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; - mousePos = Control.MousePosition; + mousePos = Control.MousePosition; host.Left = mousePos.X;// +sci.Left; - var screen = Screen.FromPoint(mousePos); + var screen = Screen.FromPoint(mousePos); if (host.Right > screen.WorkingArea.Right) { host.Left -= (host.Right - screen.WorkingArea.Right); @@ -215,43 +237,58 @@ public void ShowAtMouseLocation() host.Top = mousePos.Y - host.Height - 10;// +sci.Top; if (host.Top < 5) host.Top = mousePos.Y + 10; - Show(); - } + Show(); + } public virtual void UpdateTip() { if (OnUpdateSimpleTip != null) OnUpdateSimpleTip(owner.Owner, mousePos); } - - public virtual void Hide() - { - if (host.Visible) - { - host.Visible = false; + + public virtual void Hide() + { + if (host.Visible) + { + host.Visible = false; toolTipRTB.ResetText(); - } - } + if (OnHidden != null) OnHidden(this, EventArgs.Empty); + } + } public virtual void Show() - { + { if (!host.Visible) - host.Show(owner.Owner); - } - - public void SetText(String rawText, bool redraw) - { - this.rawText = rawText ?? ""; - - if (redraw) - Redraw(); - } - - public void Redraw() - { - Redraw(true); - } - public void Redraw(bool autoSize) - { + { + if (OnShowing != null) + { + var cancelArgs = new CancelEventArgs(); + OnShowing(this, cancelArgs); + if (cancelArgs.Cancel) + { + Hide(); + return; + } + } + + // Not really needed to set an owner, it has some advantages currently unused + host.Owner = null; // To avoid circular references that may happen because of Floating -> Docking panels + host.Show(owner.Owner); + } + } + + public void SetText(String rawText, bool redraw) + { + this.rawText = rawText ?? ""; + if (redraw) + Redraw(); + } + + public void Redraw() + { + Redraw(true); + } + public void Redraw(bool autoSize) + { toolTipRTB.Rtf = getRtfFor(rawText); Color fore = PluginBase.MainForm.GetThemeColor("RichToolTip.ForeColor"); @@ -261,40 +298,105 @@ public void Redraw(bool autoSize) toolTipRTB.ForeColor = fore == Color.Empty ? System.Drawing.SystemColors.InfoText : fore; toolTipRTB.BackColor = back == Color.Empty ? System.Drawing.SystemColors.Info : back; - if (autoSize) - AutoSize(); - } - - protected String getRtfFor(String bbcodeText) - { - if (rtfCache.ContainsKey(bbcodeText)) - return rtfCache[bbcodeText]; - - if (rtfCacheList.Count >= 512) - { - String key = rtfCacheList[0]; - rtfCache[key] = null; - rtfCache.Remove(key); - rtfCacheList[0] = null; - rtfCacheList.RemoveAt(0); - } - - toolTipRTB.Text = ""; - toolTipRTB.ScrollBars = RichTextBoxScrollBars.None; - toolTipRTB.WordWrap = false; - - rtfCacheList.Add(bbcodeText); - rtfCache[bbcodeText] = BBCodeUtils.bbCodeToRtf(bbcodeText, toolTipRTB); - return rtfCache[bbcodeText]; - } + if (autoSize) + AutoSize(); + } + + protected String getRtfFor(String bbcodeText) + { + String rtfText; + + if (rtfCache.TryGetValue(bbcodeText, out rtfText)) + return rtfText; + + if (rtfCacheList.Count >= 512) + { + String key = rtfCacheList[0]; + rtfCache.Remove(key); + rtfCacheList.RemoveAt(0); + } + + toolTipRTB.Text = ""; + toolTipRTB.ScrollBars = RichTextBoxScrollBars.None; + toolTipRTB.WordWrap = false; + + rtfCacheList.Add(bbcodeText); + rtfText = BBCodeUtils.bbCodeToRtf(bbcodeText, toolTipRTB); + rtfCache[bbcodeText] = rtfText; + return rtfText; + } public bool IsMouseInside() { return host.Bounds.Contains(Control.MousePosition); } - #endregion + #endregion + + #region Selectable RichTextBox + + // If for some reason this is not compatible with CrossOver or we want some crossplatform alternative we could place a disabled Form with Opacity to 0.009 or something like that over the control's ClientRectangle + // The downside is that on standard Windows configuration it will play an annoying "Bong" sound when clicking. Another option would be to hide the control and draw it on the form, the problem is the scrollbar, + // but we could use the ones from Form or some Panel and draw the whole text instead of just the original visible area. + protected class SelectableRichTextBox : RichTextBox + { + + private bool _selectable = true; + public bool Selectable + { + get { return _selectable; } + set + { + if (_selectable == value) return; + _selectable = value; + if (_lastCursor == null || _lastCursor == DefaultCursor) + base.Cursor = !_selectable ? Cursors.Default : DefaultCursor; + } + } + + private Cursor _lastCursor; + public override Cursor Cursor + { + get + { + return base.Cursor; + } + set + { + _lastCursor = value; + base.Cursor = value; + } + } + + protected override void DefWndProc(ref Message m) + { + const int WM_MOUSEACTIVATE = 0x21; + const int WM_CONTEXTMENU = 0x7b; + const int WM_LBUTTONDOWN = 0x201; + const int WM_LBUTTONDBLCLK = 0x203; + const int MA_NOACTIVATE = 0x0003; + + if (!_selectable) + { + switch (m.Msg) + { + case WM_MOUSEACTIVATE: + m.Result = (IntPtr)MA_NOACTIVATE; + return; + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_CONTEXTMENU: + m.Result = IntPtr.Zero; + return; + } + } + base.DefWndProc(ref m); + } + + } + + #endregion - } + } } diff --git a/PluginCore/PluginCore/Controls/UITools.cs b/PluginCore/PluginCore/Controls/UITools.cs index 20cbea18ef..e7772d38dc 100644 --- a/PluginCore/PluginCore/Controls/UITools.cs +++ b/PluginCore/PluginCore/Controls/UITools.cs @@ -46,6 +46,11 @@ static public MethodCallTip CallTip get { return manager.callTip; } } + static public CompletionListControl CompletionList + { + get { return Controls.CompletionList.completionList; } + } + static public void Init() { if (manager == null) @@ -98,9 +103,9 @@ private UITools() // try { - CompletionList.CreateControl(PluginBase.MainForm); - simpleTip = CompletionList.completionList.Tip; - callTip = CompletionList.completionList.CallTip; + Controls.CompletionList.CreateControl(PluginBase.MainForm); + simpleTip = CompletionList.Tip; + callTip = CompletionList.CallTip; } catch(Exception ex) { @@ -314,10 +319,10 @@ private void OnTextDeleted(ScintillaControl sci, int position, int length, int l private void OnGotFocus(object sender, EventArgs e) { var sci = (ScintillaControl)sender; - ((CompletionList.ScintillaHost)CompletionList.completionList.Host).SciControl = sci; + ((CompletionList.ScintillaHost)CompletionList.Host).SciControl = sci; var language = ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage); if (language != null) // Should we provide some custom string otherwise? - CompletionList.completionList.CharacterClass = language.characterclass.Characters; + CompletionList.CharacterClass = language.characterclass.Characters; } private void OnChar(ScintillaControl sci, int value) @@ -338,7 +343,7 @@ private void OnChar(ScintillaControl sci, int value) //} if (callTip.CallTipActive) callTip.OnChar(value); - if (CompletionList.Active) CompletionList.OnChar(sci, value); + if (CompletionList.Active) Controls.CompletionList.OnChar(sci, value); else SendChar(sci, value); } From 837256650d24019ba2678597d45e26a2b4daf88f Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Thu, 23 Apr 2015 22:21:02 +0200 Subject: [PATCH 33/36] In the BreakPoint panel get the file contents from MainForm.Documents if available, that way we can get contents if not yet saved. In the Immediate and Watch panels check for either file presence or source available. Clean ASCompletionBackend a bit. Extract some classes into external files to increase reusability. --- .../FlashDebugger/Controls/BreakPointUI.cs | 321 +----------------- .../Controls/DataGridViewTextBoxExColumn.cs | 314 +++++++++++++++++ .../FlashDebugger/Controls/DataTreeControl.cs | 10 +- .../Controls/ImmediateUI.Designer.cs | 4 +- .../FlashDebugger/Controls/ImmediateUI.cs | 257 +------------- .../FlashDebugger/FlashDebugger.csproj | 3 + PluginCore/PluginCore.csproj | 3 + PluginCore/PluginCore/Controls/TextBoxEx.cs | 262 ++++++++++++++ 8 files changed, 600 insertions(+), 574 deletions(-) create mode 100644 External/Plugins/FlashDebugger/Controls/DataGridViewTextBoxExColumn.cs create mode 100644 PluginCore/PluginCore/Controls/TextBoxEx.cs diff --git a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs index 56efc4be95..ae7b3fe426 100644 --- a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs +++ b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs @@ -3,15 +3,16 @@ using System.Collections.Generic; using System.IO; using System.Drawing; +using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; using ASCompletion.Helpers; -using FlashDebugger.Properties; -using PluginCore.Localization; +using FlashDebugger.Controls; using PluginCore; +using PluginCore.Controls; using PluginCore.Helpers; +using PluginCore.Localization; using PluginCore.Managers; -using System.Linq; namespace FlashDebugger { @@ -212,7 +213,7 @@ void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingE if (ColumnBreakPointExp == dgv.CurrentCell.OwningColumn) { var listHost = - new Controls.ImmediateUI.TextBoxTarget((FlashDebugger.Controls.ImmediateUI.TextBoxEx) e.Control); + new TextBoxTarget((TextBoxEx) e.Control); completionList = new PluginCore.Controls.CompletionListControl(listHost); // We need this because MainForm.Activated event handler gives some conflicts completionList.Tip.Selectable = completionList.CallTip.Selectable = false; @@ -649,322 +650,20 @@ bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionList EncodingFileInfo ASCompletionListBackend.IBackendFileGetter.GetFileContent(ASCompletionListBackend.BackendFileInfo file) { - return FileHelper.GetEncodingFileInfo(file.File); - } - - #endregion - - } - - public class DataGridViewTextBoxExColumn : DataGridViewColumn - { - - public override DataGridViewCell CellTemplate - { - get { return base.CellTemplate; } - set - { - if (value != null && !(value is DataGridViewTextBoxExCell)) - { - throw new InvalidCastException("Cell type is not based upon the DataGridViewTextBoxExCell"); - } - base.CellTemplate = value; - } - } - - [System.ComponentModel.DefaultValue(32767)] - public int MaxInputLength - { - get + foreach (ITabbedDocument doc in PluginBase.MainForm.Documents) { - return ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength; - } - set - { - if (MaxInputLength != value) + if (doc.IsEditable && doc.FileName.ToUpper() == file.File.ToUpper()) { - ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength = value; - if (DataGridView != null) - { - DataGridViewRowCollection rows = DataGridView.Rows; - int count = rows.Count; - for (int i = 0; i < count; i++) - { - DataGridViewRow dataGridViewRow = rows.SharedRow(i); - var item = dataGridViewRow.Cells[Index] as DataGridViewTextBoxExCell; - if (item != null) - { - item.MaxInputLength = value; - } - } - } + var sci = doc.SciControl; + return new EncodingFileInfo {Contents = sci.Text, CodePage = sci.CodePage}; } } - } - - public DataGridViewTextBoxExColumn() - : base(new DataGridViewTextBoxExCell()) - { - SortMode = DataGridViewColumnSortMode.Automatic; - } - } - - public class DataGridViewTextBoxExCell : DataGridViewTextBoxCell - { - - private TextBox editingControl; - - public override Type EditType - { - get { return typeof(DataGridViewTextBoxExEditingControl); } - } - - private int maxInputLength = 32767; - public override int MaxInputLength - { - get { return maxInputLength; } - set - { - if (maxInputLength == value) return; - - maxInputLength = value; - if (editingControl != null && RowIndex == ((IDataGridViewEditingControl)editingControl).EditingControlRowIndex) - editingControl.MaxLength = value; - } - } - - public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) - { - base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); - - var ctl = DataGridView.EditingControl as TextBox; - if (ctl != null) - { - ctl.MaxLength = maxInputLength; - ctl.AcceptsReturn = ctl.Multiline = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True; - ctl.BorderStyle = BorderStyle.None; - if (initialFormattedValue != null) ctl.Text = (string) initialFormattedValue; - editingControl = ctl; - } - } - - public override void DetachEditingControl() - { - base.DetachEditingControl(); - editingControl = null; - } - - protected override void OnKeyDown(KeyEventArgs e, int rowIndex) - { - base.OnKeyDown(e, rowIndex); - } - - } - - public class DataGridViewTextBoxExEditingControl : Controls.ImmediateUI.TextBoxEx, IDataGridViewEditingControl - { - private static readonly DataGridViewContentAlignment anyRight = DataGridViewContentAlignment.BottomRight | - DataGridViewContentAlignment.MiddleRight | - DataGridViewContentAlignment.TopRight; - - private static readonly DataGridViewContentAlignment anyCenter = DataGridViewContentAlignment.BottomCenter | - DataGridViewContentAlignment.MiddleCenter | - DataGridViewContentAlignment.TopCenter; - - private static readonly DataGridViewContentAlignment anyTop = DataGridViewContentAlignment.TopCenter | - DataGridViewContentAlignment.TopLeft | - DataGridViewContentAlignment.TopRight; - - private Keys lastInputKey; - private bool repositionOnValueChange; - - public DataGridViewTextBoxExEditingControl() - { - TabStop = false; - } - - #region IDataGridViewEditingControl Members - - public bool RepositionEditingControlOnValueChange - { - get { return repositionOnValueChange; } - } - - public DataGridView EditingControlDataGridView { get; set; } - - public object EditingControlFormattedValue - { - get { return Text; } - set { Text = (string)value; } - } - - public int EditingControlRowIndex { get; set; } - - public bool EditingControlValueChanged { get; set; } - - public Cursor EditingPanelCursor - { - get { return Cursors.Default; } - } - - public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) - { - Font = dataGridViewCellStyle.Font; - if (dataGridViewCellStyle.BackColor.A < 255) - { - Color color = Color.FromArgb(255, dataGridViewCellStyle.BackColor); - BackColor = color; - EditingControlDataGridView.EditingPanel.BackColor = color; - } - else - { - BackColor = dataGridViewCellStyle.BackColor; - } - ForeColor = dataGridViewCellStyle.ForeColor; - if (dataGridViewCellStyle.WrapMode == DataGridViewTriState.True) - { - WordWrap = true; - } - TextAlign = TranslateAlignment(dataGridViewCellStyle.Alignment); - repositionOnValueChange = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True && - (dataGridViewCellStyle.Alignment & anyTop) == 0; - } - - public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) - { - if (keyData == lastInputKey) return true; - Keys key = keyData & Keys.KeyCode; - if (key != Keys.Return) - { - switch (key) - { - case Keys.Prior: - case Keys.Next: - if (!EditingControlValueChanged) - { - break; - } - return true; - case Keys.End: - case Keys.Home: - if (this.SelectionLength == this.Text.Length) - { - break; - } - return true; - case Keys.Left: - if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == 0) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length)) - { - break; - } - return true; - case Keys.Up: - if (this.Text.IndexOf("\r\n") < 0 || base.SelectionStart + this.SelectionLength < this.Text.IndexOf("\r\n")) - { - break; - } - return true; - case Keys.Right: - if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == 0)) - { - break; - } - return true; - case Keys.Down: - int selectionStart = base.SelectionStart + this.SelectionLength; - if (this.Text.IndexOf("\r\n", selectionStart) == -1) - { - break; - } - return true; - case Keys.Delete: - if (this.SelectionLength <= 0 && base.SelectionStart >= this.Text.Length) - { - break; - } - return true; - } - } - else if ((keyData & (Keys.Shift | Keys.Control | Keys.Alt)) == Keys.Shift && this.Multiline && base.AcceptsReturn) - { - return true; - } - return !dataGridViewWantsInputKey; - } - - public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) - { - return Text; - } - - public void PrepareEditingControlForEdit(bool selectAll) - { - if (selectAll) - SelectAll(); - else - SelectionStart = Text.Length; + return FileHelper.GetEncodingFileInfo(file.File); } #endregion - private void NotifyDataGridViewOfValueChange() - { - EditingControlValueChanged = true; - EditingControlDataGridView.NotifyCurrentCellDirty(true); - } - - private static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align) - { - if ((align & anyRight) != 0) - return HorizontalAlignment.Right; - - if ((align & anyCenter) != 0) - return HorizontalAlignment.Center; - - return HorizontalAlignment.Left; - } - - protected override void OnTextChanged(EventArgs e) - { - base.OnTextChanged(e); - NotifyDataGridViewOfValueChange(); - } - - protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) - { - base.OnPreviewKeyDown(e); - - lastInputKey = e.IsInputKey ? e.KeyData : Keys.None; - } - - protected override bool ProcessKeyEventArgs(ref Message m) - { - Keys wParam = (Keys)((int)m.WParam); - if (wParam == Keys.LineFeed) - { - if (m.Msg == 258 && Control.ModifierKeys == Keys.Control && this.Multiline && base.AcceptsReturn) - { - return true; - } - } - else if (wParam != Keys.Return) - { - if (wParam == Keys.A) - { - if (m.Msg == 256 && Control.ModifierKeys == Keys.Control) - { - base.SelectAll(); - return true; - } - } - } - else if (m.Msg == 258 && (Control.ModifierKeys != Keys.Shift || !this.Multiline || !base.AcceptsReturn)) - { - return true; - } - return base.ProcessKeyEventArgs(ref m); - } } } diff --git a/External/Plugins/FlashDebugger/Controls/DataGridViewTextBoxExColumn.cs b/External/Plugins/FlashDebugger/Controls/DataGridViewTextBoxExColumn.cs new file mode 100644 index 0000000000..ff26c2f214 --- /dev/null +++ b/External/Plugins/FlashDebugger/Controls/DataGridViewTextBoxExColumn.cs @@ -0,0 +1,314 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using PluginCore.Controls; + +namespace FlashDebugger.Controls +{ + public class DataGridViewTextBoxExColumn : DataGridViewColumn + { + + public override DataGridViewCell CellTemplate + { + get { return base.CellTemplate; } + set + { + if (value != null && !(value is DataGridViewTextBoxExCell)) + { + throw new InvalidCastException("Cell type is not based upon the DataGridViewTextBoxExCell"); + } + base.CellTemplate = value; + } + } + + [System.ComponentModel.DefaultValue(32767)] + public int MaxInputLength + { + get + { + return ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength; + } + set + { + if (MaxInputLength != value) + { + ((DataGridViewTextBoxExCell)CellTemplate).MaxInputLength = value; + if (DataGridView != null) + { + DataGridViewRowCollection rows = DataGridView.Rows; + int count = rows.Count; + for (int i = 0; i < count; i++) + { + DataGridViewRow dataGridViewRow = rows.SharedRow(i); + var item = dataGridViewRow.Cells[Index] as DataGridViewTextBoxExCell; + if (item != null) + { + item.MaxInputLength = value; + } + } + } + } + } + } + + public DataGridViewTextBoxExColumn() + : base(new DataGridViewTextBoxExCell()) + { + SortMode = DataGridViewColumnSortMode.Automatic; + } + } + + public class DataGridViewTextBoxExCell : DataGridViewTextBoxCell + { + + private TextBox editingControl; + + public override Type EditType + { + get { return typeof(DataGridViewTextBoxExEditingControl); } + } + + private int maxInputLength = 32767; + public override int MaxInputLength + { + get { return maxInputLength; } + set + { + if (maxInputLength == value) return; + + maxInputLength = value; + if (editingControl != null && RowIndex == ((IDataGridViewEditingControl)editingControl).EditingControlRowIndex) + editingControl.MaxLength = value; + } + } + + public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) + { + base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); + + var ctl = DataGridView.EditingControl as TextBox; + if (ctl != null) + { + ctl.MaxLength = maxInputLength; + ctl.AcceptsReturn = ctl.Multiline = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True; + ctl.BorderStyle = BorderStyle.None; + if (initialFormattedValue != null) ctl.Text = (string)initialFormattedValue; + editingControl = ctl; + } + } + + public override void DetachEditingControl() + { + base.DetachEditingControl(); + editingControl = null; + } + + } + + public class DataGridViewTextBoxExEditingControl : TextBoxEx, IDataGridViewEditingControl + { + + private static readonly DataGridViewContentAlignment anyRight = DataGridViewContentAlignment.BottomRight | + DataGridViewContentAlignment.MiddleRight | + DataGridViewContentAlignment.TopRight; + + private static readonly DataGridViewContentAlignment anyCenter = DataGridViewContentAlignment.BottomCenter | + DataGridViewContentAlignment.MiddleCenter | + DataGridViewContentAlignment.TopCenter; + + private static readonly DataGridViewContentAlignment anyTop = DataGridViewContentAlignment.TopCenter | + DataGridViewContentAlignment.TopLeft | + DataGridViewContentAlignment.TopRight; + + private Keys lastInputKey; + private bool repositionOnValueChange; + + public DataGridViewTextBoxExEditingControl() + { + TabStop = false; + } + + #region IDataGridViewEditingControl Members + + public bool RepositionEditingControlOnValueChange + { + get { return repositionOnValueChange; } + } + + public DataGridView EditingControlDataGridView { get; set; } + + public object EditingControlFormattedValue + { + get { return Text; } + set { Text = (string)value; } + } + + public int EditingControlRowIndex { get; set; } + + public bool EditingControlValueChanged { get; set; } + + public Cursor EditingPanelCursor + { + get { return Cursors.Default; } + } + + public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) + { + Font = dataGridViewCellStyle.Font; + if (dataGridViewCellStyle.BackColor.A < 255) + { + Color color = Color.FromArgb(255, dataGridViewCellStyle.BackColor); + BackColor = color; + EditingControlDataGridView.EditingPanel.BackColor = color; + } + else + { + BackColor = dataGridViewCellStyle.BackColor; + } + ForeColor = dataGridViewCellStyle.ForeColor; + if (dataGridViewCellStyle.WrapMode == DataGridViewTriState.True) + { + WordWrap = true; + } + TextAlign = TranslateAlignment(dataGridViewCellStyle.Alignment); + repositionOnValueChange = dataGridViewCellStyle.WrapMode == DataGridViewTriState.True && + (dataGridViewCellStyle.Alignment & anyTop) == 0; + } + + public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) + { + if (keyData == lastInputKey) return true; + Keys key = keyData & Keys.KeyCode; + if (key != Keys.Return) + { + switch (key) + { + case Keys.Prior: + case Keys.Next: + if (!EditingControlValueChanged) + { + break; + } + return true; + case Keys.End: + case Keys.Home: + if (this.SelectionLength == this.Text.Length) + { + break; + } + return true; + case Keys.Left: + if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == 0) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length)) + { + break; + } + return true; + case Keys.Up: + if (this.Text.IndexOf("\r\n") < 0 || base.SelectionStart + this.SelectionLength < this.Text.IndexOf("\r\n")) + { + break; + } + return true; + case Keys.Right: + if ((this.RightToLeft != RightToLeft.No || this.SelectionLength == 0 && base.SelectionStart == this.Text.Length) && (this.RightToLeft != RightToLeft.Yes || this.SelectionLength == 0 && base.SelectionStart == 0)) + { + break; + } + return true; + case Keys.Down: + int selectionStart = base.SelectionStart + this.SelectionLength; + if (this.Text.IndexOf("\r\n", selectionStart) == -1) + { + break; + } + return true; + case Keys.Delete: + if (this.SelectionLength <= 0 && base.SelectionStart >= this.Text.Length) + { + break; + } + return true; + } + } + else if ((keyData & (Keys.Shift | Keys.Control | Keys.Alt)) == Keys.Shift && this.Multiline && base.AcceptsReturn) + { + return true; + } + return !dataGridViewWantsInputKey; + } + + public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) + { + return Text; + } + + public void PrepareEditingControlForEdit(bool selectAll) + { + if (selectAll) + SelectAll(); + else + SelectionStart = Text.Length; + } + + #endregion + + private void NotifyDataGridViewOfValueChange() + { + EditingControlValueChanged = true; + EditingControlDataGridView.NotifyCurrentCellDirty(true); + } + + private static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align) + { + if ((align & anyRight) != 0) + return HorizontalAlignment.Right; + + if ((align & anyCenter) != 0) + return HorizontalAlignment.Center; + + return HorizontalAlignment.Left; + } + + protected override void OnTextChanged(EventArgs e) + { + base.OnTextChanged(e); + NotifyDataGridViewOfValueChange(); + } + + protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) + { + base.OnPreviewKeyDown(e); + + lastInputKey = e.IsInputKey ? e.KeyData : Keys.None; + } + + protected override bool ProcessKeyEventArgs(ref Message m) + { + Keys wParam = (Keys)((int)m.WParam); + if (wParam == Keys.LineFeed) + { + if (m.Msg == 258 && Control.ModifierKeys == Keys.Control && this.Multiline && base.AcceptsReturn) + { + return true; + } + } + else if (wParam != Keys.Return) + { + if (wParam == Keys.A) + { + if (m.Msg == 256 && Control.ModifierKeys == Keys.Control) + { + base.SelectAll(); + return true; + } + } + } + else if (m.Msg == 258 && (Control.ModifierKeys != Keys.Shift || !this.Multiline || !base.AcceptsReturn)) + { + return true; + } + return base.ProcessKeyEventArgs(ref m); + } + } + +} diff --git a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs index ae72d948a8..d366a6d6f3 100644 --- a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs +++ b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs @@ -217,7 +217,7 @@ void NameNodeTextBox_EditorShowing(object sender, System.ComponentModel.CancelEv void NameNodeTextBox_EditorCreated(object sender, ControlEventArgs e) { - var controlHost = new ImmediateUI.TextBoxTarget((ImmediateUI.TextBoxEx)e.Control); + var controlHost = new TextBoxTarget((TextBoxEx)e.Control); completionList = new CompletionListControl(controlHost); // We need this because TreeViewAdv handles the control LostFocus event itself and the resulting behaviour doesn't seeem very nice completionList.Tip.Selectable = completionList.CallTip.Selectable = false; @@ -687,7 +687,7 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // Ctrl+Space is detected at the form level instead of the editor level, so when we are docked we need to catch it before if (keyData == (Keys.Control | Keys.Space) || keyData == (Keys.Control | Keys.Shift | Keys.Space)) { - var box = Tree.CurrentEditor as ImmediateUI.TextBoxEx; + var box = Tree.CurrentEditor as TextBoxEx; if (box != null) { if (keyData == (Keys.Control | Keys.Space)) @@ -726,7 +726,7 @@ PluginCore.Helpers.EncodingFileInfo ASCompletionListBackend.IBackendFileGetter.G file.File == PluginMain.debugManager.GetLocalPath(sourceFile)) { // Notify the user of this case? - //MessageBox.Show("Source code no available, but potential matching file found on disk, do you want to use it?"); + //MessageBox.Show("Source code not available, but potential matching file found on disk, do you want to use it?"); return PluginCore.Helpers.FileHelper.GetEncodingFileInfo(file.File); } @@ -745,7 +745,7 @@ bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionList return false; var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); file.File = PluginMain.debugManager.GetLocalPath(location.getFile()); - if (file.File == null) + if (file.File == null && (location.getFile() == null || location.getFile().getLineCount() == 0)) return false; file.Line = location.getLine() - 1; @@ -755,7 +755,7 @@ bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionList string ASCompletionListBackend.IBackendFileGetter.GetExpression() { - return Tree.CurrentEditor.Text.Substring(0, ((ImmediateUI.TextBoxEx)Tree.CurrentEditor).SelectionStart); + return Tree.CurrentEditor.Text.Substring(0, ((TextBoxEx)Tree.CurrentEditor).SelectionStart); } #endregion diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs index 136669684c..3918ea7df5 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.Designer.cs @@ -29,7 +29,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.textBox = new TextBoxEx(); + this.textBox = new PluginCore.Controls.TextBoxEx(); this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.cutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -111,7 +111,7 @@ private void InitializeComponent() #endregion - private TextBoxEx textBox; + private PluginCore.Controls.TextBoxEx textBox; private System.Windows.Forms.ContextMenuStrip contextMenuStrip; private System.Windows.Forms.ToolStripMenuItem clearAllToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem cutToolStripMenuItem; diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index 8f9670e2a8..a4fef67209 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Text; using System.Windows.Forms; using ASCompletion.Completion; @@ -318,7 +317,7 @@ bool ASCompletionListBackend.IBackendFileGetter.GetFileInfo(out ASCompletionList return false; var location = debugger.GetFrames()[PluginMain.debugManager.CurrentFrame].getLocation(); file.File = PluginMain.debugManager.GetLocalPath(location.getFile()); - if (file.File == null) + if (file.File == null && (location.getFile() == null || location.getFile().getLineCount() == 0)) return false; file.Line = location.getLine() - 1; @@ -343,259 +342,5 @@ string ASCompletionListBackend.IBackendFileGetter.GetExpression() #endregion - public class TextBoxEx : TextBox - { - private const int WM_SYSKEYDOWN = 0x0104; - - public event KeyEventHandler KeyPosted; //Hacky event for MethodCallTip, although with some rather valid use cases - public event ScrollEventHandler Scroll; - - protected override void DefWndProc(ref Message m) - { - base.DefWndProc(ref m); - - if (m.Msg == Win32.WM_KEYDOWN || m.Msg == WM_SYSKEYDOWN) // If we're worried about performance/GC, we can store latest OnKeyDown e - OnKeyPosted(new KeyEventArgs((Keys)((int)m.WParam) | ModifierKeys)); - } - - protected override void WndProc(ref Message m) - { - switch (m.Msg) - { - case Win32.WM_HSCROLL: - case Win32.WM_VSCROLL: - case Win32.WM_MOUSEWHEEL: - WmScroll(ref m); - break; - default: - base.WndProc(ref m); - break; - } - - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected virtual void OnScroll(ScrollEventArgs e) - { - if (Scroll != null) - Scroll(this, e); - } - - protected virtual void OnKeyPosted(KeyEventArgs e) - { - if (KeyPosted != null) - KeyPosted(this, e); - } - - private void WmScroll(ref Message m) - { - ScrollOrientation so; - ScrollEventType set = (ScrollEventType)((short)((int)(long)m.WParam & 0xffff)); - - // We're not interested in the actual scroll change right now - if (m.Msg == Win32.WM_HSCROLL) - { - so = ScrollOrientation.HorizontalScroll; - base.WndProc(ref m); - } - else - { - so = ScrollOrientation.VerticalScroll; - base.WndProc(ref m); - } - - OnScroll(new ScrollEventArgs(set, 0, 0, so)); - } - - } - - public class TextBoxTarget : ICompletionListHost - { - - #region ICompletionListTarget Members - - public event EventHandler LostFocus - { - add { _owner.LostFocus += value; } - remove { _owner.LostFocus -= value; } - } - - private EventHandler positionChanged; - public event EventHandler PositionChanged - { - add - { - if (positionChanged == null || positionChanged.GetInvocationList().Length == 0) - { - _owner.Scroll += Owner_Scroll; - BuildControlHierarchy(_owner); - } - positionChanged += value; - } - remove - { - positionChanged -= value; - if (positionChanged == null || positionChanged.GetInvocationList().Length < 1) - { - _owner.Scroll -= Owner_Scroll; - ClearControlHierarchy(); - } - } - } - - public event EventHandler SizeChanged - { - add { Owner.SizeChanged += value; } - remove { Owner.SizeChanged -= value; } - } - - public event KeyEventHandler KeyDown - { - add { _owner.KeyDown += value; } - remove { _owner.KeyDown -= value; } - } - - public event KeyEventHandler KeyPosted - { - add { _owner.KeyPosted += value; } - remove { _owner.KeyPosted -= value; } - } - - public event KeyPressEventHandler KeyPress - { - add { _owner.KeyPress += value; } - remove { _owner.KeyPress -= value; } - } - - public event MouseEventHandler MouseDown - { - add { _owner.MouseDown += value; } - remove { _owner.MouseDown -= value; } - } - - private TextBoxEx _owner; - public Control Owner - { - get { return _owner; } - } - - public string SelectedText - { - get { return _owner.SelectedText; } - set { _owner.SelectedText = value; } - } - - public int SelectionEnd - { - get { return _owner.SelectionStart + _owner.SelectionLength; } - set { _owner.SelectionLength = value - _owner.SelectionStart; } - } - - public int SelectionStart - { - get { return _owner.SelectionStart; } - set { _owner.SelectionStart = value; } - } - - public int CurrentPos - { - get { return _owner.SelectionStart; } - } - - public bool IsEditable - { - get { return !_owner.ReadOnly; } - } - - public TextBoxTarget(TextBoxEx owner) - { - _owner = owner; - } - - public int GetLineFromCharIndex(int pos) - { - return _owner.GetLineFromCharIndex(pos); - } - - public Point GetPositionFromCharIndex(int pos) - { - return _owner.GetPositionFromCharIndex(pos == _owner.TextLength ? pos - 1 : pos); - } - - public int GetLineHeight() - { - using (Graphics g = _owner.CreateGraphics()) - { - SizeF textSize = g.MeasureString("S", _owner.Font); - return (int)Math.Ceiling(textSize.Height); - } - } - - public void SetSelection(int start, int end) - { - _owner.SelectionStart = start; - _owner.SelectionLength = end - start; - } - - public void BeginUndoAction() - { - // TODO - } - - public void EndUndoAction() - { - // TODO - } - - #endregion - - private List controlHierarchy = new List(); - - private void BuildControlHierarchy(Control current) - { - while (current != null) - { - current.LocationChanged += Control_LocationChanged; - current.ParentChanged += Control_ParentChanged; - controlHierarchy.Add(current); - current = current.Parent; - } - } - - private void ClearControlHierarchy() - { - foreach (var control in controlHierarchy) - { - control.LocationChanged -= Control_LocationChanged; - control.ParentChanged -= Control_ParentChanged; - } - controlHierarchy.Clear(); - } - - private void Control_LocationChanged(object sender, EventArgs e) - { - if (positionChanged != null) - positionChanged(sender, e); - } - - private void Control_ParentChanged(object sender, EventArgs e) - { - ClearControlHierarchy(); - BuildControlHierarchy(_owner); - if (positionChanged != null) - positionChanged(sender, e); - } - - private void Owner_Scroll(object sender, ScrollEventArgs e) - { - if (positionChanged != null) - positionChanged(sender, e); - } - - } - } } diff --git a/External/Plugins/FlashDebugger/FlashDebugger.csproj b/External/Plugins/FlashDebugger/FlashDebugger.csproj index 8f0c89ac25..420859d65c 100644 --- a/External/Plugins/FlashDebugger/FlashDebugger.csproj +++ b/External/Plugins/FlashDebugger/FlashDebugger.csproj @@ -97,6 +97,9 @@ + + Component + diff --git a/PluginCore/PluginCore.csproj b/PluginCore/PluginCore.csproj index a6b5621823..bf65e741ed 100644 --- a/PluginCore/PluginCore.csproj +++ b/PluginCore/PluginCore.csproj @@ -321,6 +321,9 @@ Form + + Component + Component diff --git a/PluginCore/PluginCore/Controls/TextBoxEx.cs b/PluginCore/PluginCore/Controls/TextBoxEx.cs new file mode 100644 index 0000000000..0544e093b3 --- /dev/null +++ b/PluginCore/PluginCore/Controls/TextBoxEx.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace PluginCore.Controls +{ + public class TextBoxEx : TextBox + { + private const int WM_SYSKEYDOWN = 0x0104; + + public event KeyEventHandler KeyPosted; //Hacky event for MethodCallTip, although with some rather valid use cases + public event ScrollEventHandler Scroll; + + protected override void DefWndProc(ref Message m) + { + base.DefWndProc(ref m); + + if (m.Msg == Win32.WM_KEYDOWN || m.Msg == WM_SYSKEYDOWN) // If we're worried about performance/GC, we can store latest OnKeyDown e + OnKeyPosted(new KeyEventArgs((Keys)((int)m.WParam) | ModifierKeys)); + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case Win32.WM_HSCROLL: + case Win32.WM_VSCROLL: + case Win32.WM_MOUSEWHEEL: + WmScroll(ref m); + break; + default: + base.WndProc(ref m); + break; + } + + } + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected virtual void OnScroll(ScrollEventArgs e) + { + if (Scroll != null) + Scroll(this, e); + } + + protected virtual void OnKeyPosted(KeyEventArgs e) + { + if (KeyPosted != null) + KeyPosted(this, e); + } + + private void WmScroll(ref Message m) + { + ScrollOrientation so; + ScrollEventType set = (ScrollEventType)((short)((int)(long)m.WParam & 0xffff)); + + // We're not interested in the actual scroll change right now + if (m.Msg == Win32.WM_HSCROLL) + { + so = ScrollOrientation.HorizontalScroll; + base.WndProc(ref m); + } + else + { + so = ScrollOrientation.VerticalScroll; + base.WndProc(ref m); + } + + OnScroll(new ScrollEventArgs(set, 0, 0, so)); + } + + } + + public class TextBoxTarget : ICompletionListHost + { + + #region ICompletionListTarget Members + + public event EventHandler LostFocus + { + add { _owner.LostFocus += value; } + remove { _owner.LostFocus -= value; } + } + + private EventHandler positionChanged; + public event EventHandler PositionChanged + { + add + { + if (positionChanged == null || positionChanged.GetInvocationList().Length == 0) + { + _owner.Scroll += Owner_Scroll; + BuildControlHierarchy(_owner); + } + positionChanged += value; + } + remove + { + positionChanged -= value; + if (positionChanged == null || positionChanged.GetInvocationList().Length < 1) + { + _owner.Scroll -= Owner_Scroll; + ClearControlHierarchy(); + } + } + } + + public event EventHandler SizeChanged + { + add { Owner.SizeChanged += value; } + remove { Owner.SizeChanged -= value; } + } + + public event KeyEventHandler KeyDown + { + add { _owner.KeyDown += value; } + remove { _owner.KeyDown -= value; } + } + + public event KeyEventHandler KeyPosted + { + add { _owner.KeyPosted += value; } + remove { _owner.KeyPosted -= value; } + } + + public event KeyPressEventHandler KeyPress + { + add { _owner.KeyPress += value; } + remove { _owner.KeyPress -= value; } + } + + public event MouseEventHandler MouseDown + { + add { _owner.MouseDown += value; } + remove { _owner.MouseDown -= value; } + } + + private TextBoxEx _owner; + public Control Owner + { + get { return _owner; } + } + + public string SelectedText + { + get { return _owner.SelectedText; } + set { _owner.SelectedText = value; } + } + + public int SelectionEnd + { + get { return _owner.SelectionStart + _owner.SelectionLength; } + set { _owner.SelectionLength = value - _owner.SelectionStart; } + } + + public int SelectionStart + { + get { return _owner.SelectionStart; } + set { _owner.SelectionStart = value; } + } + + public int CurrentPos + { + get { return _owner.SelectionStart; } + } + + public bool IsEditable + { + get { return !_owner.ReadOnly; } + } + + public TextBoxTarget(TextBoxEx owner) + { + _owner = owner; + } + + public int GetLineFromCharIndex(int pos) + { + return _owner.GetLineFromCharIndex(pos); + } + + public Point GetPositionFromCharIndex(int pos) + { + return _owner.GetPositionFromCharIndex(pos == _owner.TextLength ? pos - 1 : pos); + } + + public int GetLineHeight() + { + using (Graphics g = _owner.CreateGraphics()) + { + SizeF textSize = g.MeasureString("S", _owner.Font); + return (int)Math.Ceiling(textSize.Height); + } + } + + public void SetSelection(int start, int end) + { + _owner.SelectionStart = start; + _owner.SelectionLength = end - start; + } + + public void BeginUndoAction() + { + // TODO + } + + public void EndUndoAction() + { + // TODO + } + + #endregion + + private List controlHierarchy = new List(); + + private void BuildControlHierarchy(Control current) + { + while (current != null) + { + current.LocationChanged += Control_LocationChanged; + current.ParentChanged += Control_ParentChanged; + controlHierarchy.Add(current); + current = current.Parent; + } + } + + private void ClearControlHierarchy() + { + foreach (var control in controlHierarchy) + { + control.LocationChanged -= Control_LocationChanged; + control.ParentChanged -= Control_ParentChanged; + } + controlHierarchy.Clear(); + } + + private void Control_LocationChanged(object sender, EventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Control_ParentChanged(object sender, EventArgs e) + { + ClearControlHierarchy(); + BuildControlHierarchy(_owner); + if (positionChanged != null) + positionChanged(sender, e); + } + + private void Owner_Scroll(object sender, ScrollEventArgs e) + { + if (positionChanged != null) + positionChanged(sender, e); + } + + } + +} From 53c151664e808ea8aa9f1f1425397a6694b14c95 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 24 Apr 2015 03:16:14 +0200 Subject: [PATCH 34/36] Finished for now. Added Haxe support to ASCompletionBacked. Possibly can be improved. ASCompletion/Helpers/ASCompletionBackend.cs has been missing all this time. --- .../Plugins/ASCompletion/Context/ASContext.cs | 11 + .../Helpers/ASCompletionBackend.cs | 408 ++++++++++++++++++ .../FlashDebugger/Controls/BreakPointUI.cs | 2 +- .../FlashDebugger/Controls/DataTreeControl.cs | 2 +- .../FlashDebugger/Controls/ImmediateUI.cs | 2 +- .../HaXeContext/Completion/HaxeComplete.cs | 2 +- 6 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 External/Plugins/ASCompletion/Helpers/ASCompletionBackend.cs diff --git a/External/Plugins/ASCompletion/Context/ASContext.cs b/External/Plugins/ASCompletion/Context/ASContext.cs index d04e57475c..9950a00bb7 100644 --- a/External/Plugins/ASCompletion/Context/ASContext.cs +++ b/External/Plugins/ASCompletion/Context/ASContext.cs @@ -80,13 +80,24 @@ static public IMainForm MainForm get { return PluginBase.MainForm; } } + private static WeakReference curSciControl; static public ScintillaNet.ScintillaControl CurSciControl { get { + if (curSciControl != null && curSciControl.IsAlive) + return (ScintillaNet.ScintillaControl) curSciControl.Target; + ITabbedDocument doc = PluginBase.MainForm.CurrentDocument; return doc != null ? doc.SciControl : null; } + internal set + { + // Used for ASCompletionBackend. + // Maybe another option would be to inherit HaxeContext and modify the DotContextResolved call. One question + // would be where to place ASCompletionBackend. + curSciControl = value != null ? new WeakReference(value) : null; + } } static public PluginUI Panel diff --git a/External/Plugins/ASCompletion/Helpers/ASCompletionBackend.cs b/External/Plugins/ASCompletion/Helpers/ASCompletionBackend.cs new file mode 100644 index 0000000000..90e2c73348 --- /dev/null +++ b/External/Plugins/ASCompletion/Helpers/ASCompletionBackend.cs @@ -0,0 +1,408 @@ +using System; +using System.ComponentModel; +using System.IO; +using System.Text; +using System.Windows.Forms; +using ASCompletion.Completion; +using PluginCore; +using PluginCore.Controls; + +namespace ASCompletion.Helpers +{ + + /** + * Helper class to overcome some ASComplete design choices: + * - Some methods that may be helpful are either private or directly call the default CompletionList instead of returning results. + * - Being a fully static class complicates some reuse. + * - It needs a Scintilla control to work. + * + * Making the current ASComplete.CompletionList to be interchangeable is the fastest and easiest way to achieve what we want. + * + * Another rather particular case is that of Haxe. To use the compiler output or the completion server we use a temporal file. + */ + public class ASCompletionListBackend : IDisposable, IEventHandler + { + + // Current code file state + private ScintillaNet.ScintillaControl sci; + private string currentLine; + private BackendFileInfo lastFileInfo; + + // ASCompletion state + private ASCompletion.Context.IASContext context; + private string contextFile; + private int contextLine; + private int memberPosition; + + // Haxe backend file + private string haxeTmpFile; + + private CompletionListControl completionList; + private IBackendFileGetter backendFileGetter; + + public ASCompletionListBackend(CompletionListControl completionList, IBackendFileGetter backendFileGetter) + { + if (completionList == null) + throw new ArgumentNullException("completionList"); + + if (backendFileGetter == null) + throw new ArgumentNullException("backendFileGetter"); + + this.completionList = completionList; + this.backendFileGetter = backendFileGetter; + + this.completionList.CallTip.OnShowing += CallTip_OnShowing; + this.completionList.CallTip.OnUpdateCallTip += CallTip_OnUpdateCallTip; + this.completionList.Host.KeyPress += CompletionListHost_KeyPress; + } + + public void ShowAutoCompletionList() + { + if (!UpdateCompletionBackend()) + { + CleanBackend(); + return; + } + + if (haxeTmpFile != null) + PluginCore.Helpers.FileHelper.WriteFile(haxeTmpFile, sci.Text, sci.Encoding, sci.SaveBOM); + + ASComplete.OnChar(sci, '.', true); + } + + public void ShowFunctionDetails() + { + if (!UpdateCompletionBackend()) + { + CleanBackend(); + return; + } + + if (haxeTmpFile != null) + PluginCore.Helpers.FileHelper.WriteFile(haxeTmpFile, sci.Text, sci.Encoding, sci.SaveBOM); + + ASComplete.HandleFunctionCompletion(sci, true); + } + + public bool SetCompletionBackend(BackendFileInfo file, string expression) + { + var info = backendFileGetter.GetFileContent(file); + if (info == null || info.CodePage == -1) + return false; + + if (sci != null && sci.ConfigurationLanguage == "haxe" && haxeTmpFile != null) + { + PluginCore.Managers.EventManager.RemoveEventHandler(this); + if (File.Exists(haxeTmpFile)) + File.Delete(haxeTmpFile); + haxeTmpFile = null; + } + + sci = new ScintillaNet.ScintillaControl(); + sci.Text = info.Contents; + sci.CodePage = info.CodePage; + sci.Encoding = Encoding.GetEncoding(info.CodePage); + sci.ConfigurationLanguage = PluginBase.CurrentProject.Language; + + if (sci.ConfigurationLanguage == "haxe") + { + string tmpFile = Path.Combine(Path.GetDirectoryName(file.File), + Path.GetFileNameWithoutExtension(file.File) + "___" + + Path.GetExtension(file.File)); + if (!File.Exists(tmpFile)) + { + haxeTmpFile = tmpFile; + sci.FileName = haxeTmpFile; + PluginCore.Managers.EventManager.AddEventHandler(this, EventType.FileSaving); + ASCompletion.Context.ASContext.CurSciControl = sci; + } + } + + currentLine = sci.GetLine(file.Line); + sci.CurrentPos = sci.PositionFromLine(file.Line); + sci.SetSel(sci.CurrentPos, sci.CurrentPos); + sci.ReplaceSel(expression); + + context = ASCompletion.Context.ASContext.Context; + contextFile = context.CurrentFile; + contextLine = context.CurrentLine; + var newContext = ASCompletion.Context.ASContext.GetLanguageContext(PluginBase.CurrentProject.Language); + newContext.CurrentFile = file.File; + newContext.CurrentLine = sci.CurrentLine; + ASCompletion.Context.ASContext.Context = newContext; + + var language = ScintillaNet.ScintillaControl.Configuration.GetLanguage(sci.ConfigurationLanguage); + if (language != null) // Should we provide some custom string otherwise? + completionList.CharacterClass = language.characterclass.Characters; + + completionList.Host.LostFocus += CompletionListHost_LostFocus; + completionList.OnHidden += CompletionList_Hidden; + + ASComplete.CompletionList = completionList; + + lastFileInfo = file; + + return true; + } + + public bool UpdateCompletionBackend() + { + BackendFileInfo newFileInfo; + string expression; + + if (!backendFileGetter.GetFileInfo(out newFileInfo)) + return false; + + expression = backendFileGetter.GetExpression(); + if (expression == null) + return false; + + if (sci != null && lastFileInfo == newFileInfo) + { + sci.CurrentPos = sci.PositionFromLine(lastFileInfo.Line); + sci.SetSel(sci.CurrentPos, sci.CurrentPos + sci.LineLength(lastFileInfo.Line)); + sci.ReplaceSel(currentLine); + sci.SetSel(sci.CurrentPos, sci.CurrentPos); + sci.ReplaceSel(expression); + + return true; + } + + return SetCompletionBackend(newFileInfo, expression); + } + + private void CompletionList_Hidden(object sender, EventArgs e) + { + if (completionList.Host.Owner.ContainsFocus) + return; + + CleanBackend(); + } + + private void CompletionListHost_KeyPress(object sender, KeyPressEventArgs e) + { + char c = e.KeyChar; + + if (char.IsControl(c)) + return; + + BackendFileInfo file; + if (!backendFileGetter.GetFileInfo(out file)) + return; + + string expression = backendFileGetter.GetExpression(); + + if (expression == null) + return; + + bool active = completionList.Active; + // Hacky... the current CompletionListControl implementation relies on the OnChar Scintilla event, which happens after the KeyPress event + // We either create an OnChar event in ICompletionListHost and implement it, or change how CompletionListControl works + e.Handled = true; + completionList.Host.SelectedText = new string(e.KeyChar, 1); + completionList.Host.SelectionStart++; + bool charHandled = active && completionList.OnChar(c); + if (!UpdateCompletionBackend()) + { + CleanBackend(); + return; + } + + if (!charHandled) + { + if (".,()".IndexOf(c) > -1 && haxeTmpFile != null) + PluginCore.Helpers.FileHelper.WriteFile(haxeTmpFile, sci.Text, sci.Encoding, sci.SaveBOM); + ASComplete.OnChar(sci, c, true); + } + } + + private void CompletionListHost_LostFocus(object sender, EventArgs e) + { + if (completionList.Active) + return; + + CleanBackend(); + } + + private void CallTip_OnShowing(object sender, CancelEventArgs e) + { + var callTip = (MethodCallTip)sender; + + if (callTip.MemberPosition == memberPosition) return; + + e.Cancel = true; + + memberPosition = completionList.Host.SelectionStart - (sci.CurrentPos - callTip.MemberPosition); + + completionList.Host.Owner.BeginInvoke(new Action(() => + { + int hlsStart = completionList.CallTip.CurrentHLStart; + int hlsEnd = completionList.CallTip.CurrentHLEnd; + callTip.CallTipShow(memberPosition, callTip.RawText); + callTip.CallTipSetHlt(hlsStart, hlsEnd); + })); + } + + private void CallTip_OnUpdateCallTip(Control owner, int position) + { + if (!UpdateCompletionBackend()) + { + completionList.CallTip.Hide(); + CleanBackend(); + + return; + } + + if (!ASComplete.HandleFunctionCompletion(sci, false, true)) + completionList.CallTip.Hide(); + else if (completionList.CallTip.MemberPosition != memberPosition) + { + int hlsStart = completionList.CallTip.CurrentHLStart; + int hlsEnd = completionList.CallTip.CurrentHLEnd; + memberPosition = completionList.Host.SelectionStart - (sci.CurrentPos - completionList.CallTip.MemberPosition); + completionList.CallTip.CallTipShow(memberPosition, completionList.CallTip.RawText); + completionList.CallTip.CallTipSetHlt(hlsStart, hlsEnd, true); + } + } + + private void CleanBackend() + { + completionList.Host.LostFocus -= CompletionListHost_LostFocus; + completionList.OnHidden -= CompletionList_Hidden; + if (context != null) + { + ASCompletion.Context.ASContext.Context = context; + context.CurrentFile = contextFile; + context.CurrentLine = contextLine; + context = null; + } + ASComplete.CompletionList = UITools.CompletionList; + lastFileInfo = default(BackendFileInfo); + if (sci != null) + { + sci.Dispose(); + sci = null; + } + if (haxeTmpFile != null) + { + PluginCore.Managers.EventManager.RemoveEventHandler(this); + if (File.Exists(haxeTmpFile)) + File.Delete(haxeTmpFile); + haxeTmpFile = null; + ASCompletion.Context.ASContext.CurSciControl = null; + } + } + + public void Dispose() + { + if (sci != null) + { + sci.Dispose(); + sci = null; + } + + if (context != null) + { + ASCompletion.Context.ASContext.Context = context; + context.CurrentFile = contextFile; + context.CurrentLine = contextLine; + context = null; + } + + if (completionList != null) + { + completionList.CallTip.OnShowing -= CallTip_OnShowing; + completionList.CallTip.OnUpdateCallTip -= CallTip_OnUpdateCallTip; + completionList.Host.KeyPress -= CompletionListHost_KeyPress; + completionList.Host.LostFocus -= CompletionListHost_LostFocus; + completionList.OnHidden -= CompletionList_Hidden; + + completionList.Hide(); + completionList = null; + + ASComplete.CompletionList = UITools.CompletionList; + } + + if (haxeTmpFile != null) + { + PluginCore.Managers.EventManager.RemoveEventHandler(this); + if (File.Exists(haxeTmpFile)) + File.Delete(haxeTmpFile); + haxeTmpFile = null; + ASCompletion.Context.ASContext.CurSciControl = null; + } + + backendFileGetter = null; + } + + void IEventHandler.HandleEvent(object sender, NotifyEvent e, HandlingPriority priority) + { + // Note: With this we avoid some unwanted saves on Haxe projects, but we also disable wanted ones through Ctrl+S if we're + //both "running" this class, and placed in MainForm. + TextEvent se = (TextEvent)e; + if (se.Value != lastFileInfo.File) return; + se.Handled = true; + try + { + sci.FileName = haxeTmpFile; + PluginCore.Helpers.FileHelper.WriteFile(haxeTmpFile, sci.Text, sci.Encoding, sci.SaveBOM); + } + catch (Exception) + { + } + } + + #region Used Types + + public struct BackendFileInfo + { + public string File { get; set; } + public int Line { get; set; } + public DateTime LastUpdate { get; set; } + + public static bool operator ==(BackendFileInfo a, BackendFileInfo b) + { + return a.File == b.File && a.Line == b.Line && a.LastUpdate == b.LastUpdate; + } + + public static bool operator !=(BackendFileInfo a, BackendFileInfo b) + { + return a.File != b.File || a.Line != b.Line || a.LastUpdate != b.LastUpdate; + } + + public bool Equals(BackendFileInfo other) + { + return this == other; + } + + public override bool Equals(object obj) + { + return obj is BackendFileInfo && this == (BackendFileInfo)obj; + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = (File != null ? File.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ Line; + hashCode = (hashCode * 397) ^ LastUpdate.GetHashCode(); + return hashCode; + } + } + + } + + public interface IBackendFileGetter + { + + bool GetFileInfo(out BackendFileInfo file); + string GetExpression(); + PluginCore.Helpers.EncodingFileInfo GetFileContent(BackendFileInfo file); + + } + + } + + #endregion +} diff --git a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs index ae7b3fe426..3153996c75 100644 --- a/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs +++ b/External/Plugins/FlashDebugger/Controls/BreakPointUI.cs @@ -618,7 +618,7 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) if (box != null && completionBackend != null) { if (keyData == (Keys.Control | Keys.Space)) - completionBackend.ShowAutoCompletioList(); + completionBackend.ShowAutoCompletionList(); else completionBackend.ShowFunctionDetails(); diff --git a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs index d366a6d6f3..6ab2a59186 100644 --- a/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs +++ b/External/Plugins/FlashDebugger/Controls/DataTreeControl.cs @@ -691,7 +691,7 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) if (box != null) { if (keyData == (Keys.Control | Keys.Space)) - completionBackend.ShowAutoCompletioList(); + completionBackend.ShowAutoCompletionList(); else completionBackend.ShowFunctionDetails(); diff --git a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs index a4fef67209..21a7baa754 100644 --- a/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs +++ b/External/Plugins/FlashDebugger/Controls/ImmediateUI.cs @@ -204,7 +204,7 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData) if (completionBackend.SetCompletionBackend(file, line.Substring(2, lineLength))) { if (keyData == (Keys.Control | Keys.Space)) - completionBackend.ShowAutoCompletioList(); + completionBackend.ShowAutoCompletionList(); else completionBackend.ShowFunctionDetails(); diff --git a/External/Plugins/HaXeContext/Completion/HaxeComplete.cs b/External/Plugins/HaXeContext/Completion/HaxeComplete.cs index fcb7603f34..9b60e6a280 100644 --- a/External/Plugins/HaXeContext/Completion/HaxeComplete.cs +++ b/External/Plugins/HaXeContext/Completion/HaxeComplete.cs @@ -43,7 +43,7 @@ public HaxeComplete(ScintillaControl sci, ASExpr expr, bool autoHide, IHaxeCompl AutoHide = autoHide; handler = completionHandler; Status = HaxeCompleteStatus.NONE; - FileName = PluginBase.MainForm.CurrentDocument.FileName; + FileName = sci.FileName; } /* EXECUTION */ From 2e04bd0c54bca392d4327fa8a62ef89af67f6bbb Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Mon, 11 May 2015 23:10:37 +0200 Subject: [PATCH 35/36] Missing file --- .../DataTree/NodeControls/NodeTextBoxEx.cs | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 External/Plugins/FlashDebugger/Controls/DataTree/NodeControls/NodeTextBoxEx.cs diff --git a/External/Plugins/FlashDebugger/Controls/DataTree/NodeControls/NodeTextBoxEx.cs b/External/Plugins/FlashDebugger/Controls/DataTree/NodeControls/NodeTextBoxEx.cs new file mode 100644 index 0000000000..3e29312fd7 --- /dev/null +++ b/External/Plugins/FlashDebugger/Controls/DataTree/NodeControls/NodeTextBoxEx.cs @@ -0,0 +1,150 @@ +/* + * Control created to replace NodeTextBox to overcome some limitations: + * - There is no proper event to know when the editor is created, although there are some limited workarounds + * - There is no way to prevent Enter and Escape behaviour in a satisfactory way. TreeViewAdv should override some of the Key methods, and + * check with the current EditableControl what to do. This would allow us to use Handled or IsInputKey. DGV works this way basically. + * - Due to how CallTip works, a simple TextBox isn't enough. + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Aga.Controls.Tree; +using Aga.Controls.Tree.NodeControls; +using PluginCore.Controls; + +namespace FlashDebugger.Controls.DataTree.NodeControls +{ + public class NodeTextBoxEx : BaseTextControl + { + private const int MinTextBoxWidth = 30; + + protected override Size CalculateEditorSize(EditorContext context) + { + if (Parent.UseColumns) + return context.Bounds.Size; + else + { + Size size = GetLabelSize(context.CurrentNode, context.DrawContext, _label); + int width = Math.Max(size.Width + Font.Height, MinTextBoxWidth); // reserve a place for new typed character + return new Size(width, size.Height); + } + } + + public override void KeyDown(KeyEventArgs args) + { + if (args.KeyCode == Keys.F2 && Parent.CurrentNode != null && EditEnabled) + { + args.Handled = true; + BeginEdit(); + } + } + + protected override Control CreateEditor(TreeNodeAdv node) + { + var textBox = CreateTextBox(); + OnEditorCreated(new ControlEventArgs(textBox)); + textBox.TextAlign = TextAlign; + textBox.Text = GetLabel(node); + textBox.BorderStyle = BorderStyle.FixedSingle; + textBox.TextChanged += EditorTextChanged; + _label = textBox.Text; + SetEditControlProperties(textBox, node); + textBox.PreviewKeyDown += new PreviewKeyDownEventHandler(textBox_PreviewKeyDown); + textBox.KeyPosted += textBox_KeyPosted; + return textBox; + } + + void textBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Enter: + case Keys.Escape: + e.IsInputKey = true; + break; + } + } + + void textBox_KeyPosted(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Escape) + EndEdit(false); + else if (e.KeyCode == Keys.Enter) + EndEdit(true); + } + + protected override void DisposeEditor(Control editor) + { + var textBox = editor as TextBoxEx; + textBox.TextChanged -= EditorTextChanged; + textBox.KeyPosted -= textBox_KeyPosted; + textBox.PreviewKeyDown -= textBox_PreviewKeyDown; + } + + private string _label; + private void EditorTextChanged(object sender, EventArgs e) + { + var textBox = sender as TextBox; + _label = textBox.Text; + Parent.UpdateEditorBounds(); + } + + protected virtual TextBoxEx CreateTextBox() + { + return new TextBoxEx(); + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + var label = (editor as TextBox).Text; + string oldLabel = GetLabel(node); + if (oldLabel != label) + { + SetLabel(node, label); + OnLabelChanged(node.Tag, oldLabel, label); + } + } + + public override void Cut(Control control) + { + (control as TextBox).Cut(); + } + + public override void Copy(Control control) + { + (control as TextBox).Copy(); + } + + public override void Paste(Control control) + { + (control as TextBox).Paste(); + } + + public override void Delete(Control control) + { + var textBox = control as TextBox; + int len = Math.Max(textBox.SelectionLength, 1); + if (textBox.SelectionStart < textBox.Text.Length) + { + int start = textBox.SelectionStart; + textBox.Text = textBox.Text.Remove(textBox.SelectionStart, len); + textBox.SelectionStart = start; + } + } + + public event EventHandler LabelChanged; + protected void OnLabelChanged(object subject, string oldLabel, string newLabel) + { + if (LabelChanged != null) + LabelChanged(this, new LabelEventArgs(subject, oldLabel, newLabel)); + } + + public event ControlEventHandler EditorCreated; + protected virtual void OnEditorCreated(ControlEventArgs e) + { + if (EditorCreated != null) + EditorCreated(this, e); + } + } +} From 3e9328543cb76df92ee13bf2c5debcb263db88d2 Mon Sep 17 00:00:00 2001 From: Neverbirth Date: Fri, 6 Nov 2015 21:26:07 +0100 Subject: [PATCH 36/36] Left some dummy code... (still more in there, but doesn't matter that much for now). --- PluginCore/ScintillaNet/ScintillaControl.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/PluginCore/ScintillaNet/ScintillaControl.cs b/PluginCore/ScintillaNet/ScintillaControl.cs index 19dbe3faea..b8e646b098 100644 --- a/PluginCore/ScintillaNet/ScintillaControl.cs +++ b/PluginCore/ScintillaNet/ScintillaControl.cs @@ -271,8 +271,6 @@ protected void OnResize2(object sender, EventArgs e) Int32 vsbWidth = this.Controls.Contains(this.vScrollBar) && this.vScrollBar.Visible ? this.vScrollBar.Width : 0; Int32 hsbHeight = this.Controls.Contains(this.hScrollBar) && this.hScrollBar.Visible ? this.hScrollBar.Height : 0; //if (Win32.ShouldUseWin32()) SetWindowPos(this.hwndScintilla, 0, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - vsbWidth, ClientRectangle.Height - hsbHeight, 0); - this.size = new Size(this.Width - vsbWidth, this.Height - hsbHeight); - mar } protected override CreateParams CreateParams