### 2023-02-21更新

------
#### SuperDesign    V3.0.2302.2101
- *.[新增]全新文本编辑器,支持高亮、FTP查看和编辑、目录浏览,历史版本等众多功能。
This commit is contained in:
鑫Intel committed 2023-02-21 09:46:13 +08:00
1 parent c7b33920bd
commit 03bcb8c5fd
406 files changed
+312053 -48889

No files matched your search

@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace AutocompleteMenuNS
{
/// <summary>
/// Item of autocomplete menu
/// </summary>
public class AutocompleteItem
{
public object Tag;
string toolTipTitle;
string toolTipText;
string menuText;
/// <summary>
/// Parent AutocompleteMenu
/// </summary>
public AutocompleteMenu Parent { get; internal set; }
/// <summary>
/// Text for inserting into textbox
/// </summary>
public string Text { get; set; }
/// <summary>
/// Image index for this item
/// </summary>
public int ImageIndex{get; set; }
/// <summary>
/// Alignment. The direction the text shows.
/// </summary>
public StringAlignment Alignment { get; set; }
/// <summary>
/// Title for tooltip.
/// </summary>
/// <remarks>Return null for disable tooltip for this item</remarks>
public virtual string ToolTipTitle
{
get { return toolTipTitle; }
set { toolTipTitle = value; }
}
/// <summary>
/// Tooltip text.
/// </summary>
/// <remarks>For display tooltip text, ToolTipTitle must be not null</remarks>
public virtual string ToolTipText
{
get { return toolTipText; }
set { toolTipText = value; }
}
/// <summary>
/// Menu text. This text is displayed in the drop-down menu.
/// </summary>
public virtual string MenuText
{
get { return menuText; }
set { menuText = value; }
}
public AutocompleteItem()
{
ImageIndex = -1;
}
public AutocompleteItem(string text):this()
{
Text = text;
Alignment = StringAlignment.Near;
}
public AutocompleteItem(string text, int imageIndex)
: this(text)
{
this.ImageIndex = imageIndex;
}
public AutocompleteItem(string text, int imageIndex, string menuText)
: this(text, imageIndex)
{
this.menuText = menuText;
}
public AutocompleteItem(string text, int imageIndex, string menuText, string toolTipTitle, string toolTipText)
: this(text, imageIndex, menuText)
{
this.toolTipTitle = toolTipTitle;
this.toolTipText = toolTipText;
}
/// <summary>
/// Returns text for inserting into Textbox
/// </summary>
public virtual string GetTextForReplace()
{
return Text;
}
/// <summary>
/// Compares fragment text with this item
/// </summary>
public virtual CompareResult Compare(string fragmentText)
{
if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&
Text != fragmentText)
return CompareResult.VisibleAndSelected;
return CompareResult.Hidden;
}
/// <summary>
/// Returns text for display into popup menu
/// </summary>
public override string ToString()
{
return menuText ?? Text;
}
/// <summary>
/// This method is called after item was inserted into text
/// </summary>
public virtual void OnSelected(SelectedEventArgs e)
{
}
public virtual void OnPaint(PaintItemEventArgs e)
{
using(var brush = new SolidBrush(e.IsSelected ? e.Colors.SelectedForeColor : e.Colors.ForeColor))
e.Graphics.DrawString(ToString(), e.Font, brush, e.TextRect, new StringFormat() {Alignment = Alignment});
}
}
public enum CompareResult
{
/// <summary>
/// Item do not appears
/// </summary>
Hidden,
/// <summary>
/// Item appears
/// </summary>
Visible,
/// <summary>
/// Item appears and will selected
/// </summary>
VisibleAndSelected
}
}
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
/// <summary>
/// This autocomplete item appears after dot
/// </summary>
public class MethodAutocompleteItem : AutocompleteItem
{
string firstPart;
string lowercaseText;
public MethodAutocompleteItem(string text)
: base(text)
{
lowercaseText = Text.ToLower();
}
public override CompareResult Compare(string fragmentText)
{
int i = fragmentText.LastIndexOf('.');
if (i < 0)
return CompareResult.Hidden;
string lastPart = fragmentText.Substring(i + 1);
firstPart = fragmentText.Substring(0, i);
if (lastPart == "") return CompareResult.Visible;
if (Text.StartsWith(lastPart, StringComparison.InvariantCultureIgnoreCase))
return CompareResult.VisibleAndSelected;
if (lowercaseText.Contains(lastPart.ToLower()))
return CompareResult.Visible;
return CompareResult.Hidden;
}
public override string GetTextForReplace()
{
return firstPart + "." + Text;
}
}
/// <summary>
/// Autocomplete item for code snippets
/// </summary>
/// <remarks>Snippet can contain special char ^ for caret position.</remarks>
public class SnippetAutocompleteItem : AutocompleteItem
{
public SnippetAutocompleteItem(string snippet)
{
Text = snippet.Replace("\r", "");
ToolTipTitle = "Code snippet:";
ToolTipText = Text;
}
public override string ToString()
{
return MenuText ?? Text.Replace("\n", " ").Replace("^", "");
}
public override string GetTextForReplace()
{
return Text;
}
public override void OnSelected(SelectedEventArgs e)
{
var tb = Parent.TargetControlWrapper;
//
if (!Text.Contains("^"))
return;
var text = tb.Text;
for (int i = Parent.Fragment.Start; i < text.Length; i++)
if (text[i] == '^')
{
tb.SelectionStart = i;
tb.SelectionLength = 1;
tb.SelectedText = "";
return;
}
}
/// <summary>
/// Compares fragment text with this item
/// </summary>
public override CompareResult Compare(string fragmentText)
{
if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&
Text != fragmentText)
return CompareResult.Visible;
return CompareResult.Hidden;
}
}
/// <summary>
/// This class finds items by substring
/// </summary>
public class SubstringAutocompleteItem : AutocompleteItem
{
protected readonly string lowercaseText;
protected readonly bool ignoreCase;
public SubstringAutocompleteItem(string text, bool ignoreCase = true)
: base(text)
{
this.ignoreCase = ignoreCase;
if(ignoreCase)
lowercaseText = text.ToLower();
}
public override CompareResult Compare(string fragmentText)
{
if(ignoreCase)
{
if (lowercaseText.Contains(fragmentText.ToLower()))
return CompareResult.Visible;
}
else
{
if (Text.Contains(fragmentText))
return CompareResult.Visible;
}
return CompareResult.Hidden;
}
}
/// <summary>
/// This item draws multicolumn menu
/// </summary>
public class MulticolumnAutocompleteItem : SubstringAutocompleteItem
{
public bool CompareBySubstring { get; set; }
public string[] MenuTextByColumns { get; set; }
public int[] ColumnWidth { get; set; }
public StringAlignment[] Alignments { get; set; }
public MulticolumnAutocompleteItem(string[] menuTextByColumns, string insertingText, bool compareBySubstring = true, bool ignoreCase = true)
: base(insertingText, ignoreCase)
{
this.CompareBySubstring = compareBySubstring;
this.MenuTextByColumns = menuTextByColumns;
var tmp = new List<StringAlignment>();
for(int i = 0; i < menuTextByColumns.Length; i++)
tmp.Add(StringAlignment.Near);
this.Alignments = tmp.ToArray();
}
public override CompareResult Compare(string fragmentText)
{
if (CompareBySubstring)
return base.Compare(fragmentText);
if(ignoreCase)
{
if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase))
return CompareResult.VisibleAndSelected;
} else
if (Text.StartsWith(fragmentText))
return CompareResult.VisibleAndSelected;
return CompareResult.Hidden;
}
public override void OnPaint(PaintItemEventArgs e)
{
if (ColumnWidth != null && ColumnWidth.Length != MenuTextByColumns.Length)
throw new Exception("ColumnWidth.Length != MenuTextByColumns.Length");
int[] columnWidth = ColumnWidth;
if(columnWidth == null)
{
columnWidth = new int[MenuTextByColumns.Length];
float step = e.TextRect.Width/MenuTextByColumns.Length;
for (int i = 0; i < MenuTextByColumns.Length; i++)
columnWidth[i] = (int)step;
}
//draw columns
Pen pen = Pens.Silver;
float x = e.TextRect.X;
e.StringFormat.FormatFlags = e.StringFormat.FormatFlags | StringFormatFlags.NoWrap;
using (var brush = new SolidBrush(e.IsSelected ? e.Colors.SelectedForeColor : e.Colors.ForeColor))
for (int i=0;i<MenuTextByColumns.Length;i++)
{
var width = columnWidth[i];
var rect = new RectangleF(x, e.TextRect.Top, width, e.TextRect.Height);
e.Graphics.DrawLine(pen, new PointF(x, e.TextRect.Top), new PointF(x, e.TextRect.Bottom));
e.Graphics.DrawString(MenuTextByColumns[i], e.Font, brush, rect, new StringFormat() {Alignment = Alignments[i]});
x += width;
}
}
}
}
@@ -0,0 +1,420 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
[System.ComponentModel.ToolboxItem(false)]
public class AutocompleteListView : UserControl, IAutocompleteListView
{
private readonly ToolTip toolTip = new ToolTip();
public int HighlightedItemIndex { get; set; }
private int oldItemCount;
private int selectedItemIndex = -1;
private IList<AutocompleteItem> visibleItems;
/// <summary>
/// Duration (ms) of tooltip showing
/// </summary>
public int ToolTipDuration { get; set; }
/// <summary>
/// Occurs when user selected item for inserting into text
/// </summary>
public event EventHandler ItemSelected;
/// <summary>
/// Occurs when current hovered item is changing
/// </summary>
public event EventHandler<HoveredEventArgs> ItemHovered;
/// <summary>
/// Colors
/// </summary>
public Colors Colors { get; set; }
internal AutocompleteListView()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
base.Font = new Font(FontFamily.GenericSansSerif, 11);
ItemHeight = Font.Height + 2;
VerticalScroll.SmallChange = ItemHeight;
BackColor = Color.White;
LeftPadding = 18;
ToolTipDuration = 3000;
Colors = new Colors();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
toolTip.Dispose();
}
base.Dispose(disposing);
}
private int itemHeight;
public int ItemHeight
{
get { return itemHeight; }
set {
itemHeight = value;
VerticalScroll.SmallChange = value;
oldItemCount = -1;
AdjustScroll();
}
}
public override Font Font
{
get { return base.Font; }
set
{
base.Font = value;
ItemHeight = Font.Height + 2;
}
}
public int LeftPadding { get; set; }
public ImageList ImageList { get; set; }
public string[] ColumnsTitle { get; set; } = null;
public int[] ColumnsWidth { get; set; } = null;
public IList<AutocompleteItem> VisibleItems
{
get { return visibleItems; }
set
{
visibleItems = value;
SelectedItemIndex = -1;
AdjustScroll();
Invalidate();
}
}
public int SelectedItemIndex
{
get { return selectedItemIndex; }
set
{
AutocompleteItem item = null;
if (value >= 0 && value < VisibleItems.Count)
item = VisibleItems[value];
selectedItemIndex = value;
OnItemHovered(new HoveredEventArgs() { Item = item });
if (item != null)
{
ShowToolTip(item, this.Parent);
ScrollToSelected();
}
Invalidate();
}
}
private void OnItemHovered(HoveredEventArgs e)
{
if (ItemHovered != null)
ItemHovered(this, e);
}
private void AdjustScroll()
{
if (VisibleItems == null)
return;
if (oldItemCount == VisibleItems.Count)
return;
int needHeight = ItemHeight*VisibleItems.Count + 1;
if (HasColumn) needHeight += ItemHeight;
Height = Math.Min(needHeight, MaximumSize.Height);
AutoScrollMinSize = new Size(0, needHeight);
oldItemCount = VisibleItems.Count;
}
private void ScrollToSelected()
{
int y;
if(HasColumn)
y = (SelectedItemIndex + 1)*ItemHeight - VerticalScroll.Value;
else
y = SelectedItemIndex * ItemHeight - VerticalScroll.Value;
//if (HasColumn) y += ItemHeight;
if (y < 0)
if(HasColumn)
VerticalScroll.Value = (SelectedItemIndex + 1) * ItemHeight;
else
VerticalScroll.Value = SelectedItemIndex * ItemHeight;
if (y > ClientSize.Height - ItemHeight)
VerticalScroll.Value = Math.Min(VerticalScroll.Maximum,
(HasColumn ? (SelectedItemIndex*ItemHeight) + ItemHeight : SelectedItemIndex * ItemHeight) - ClientSize.Height + ItemHeight);
//Show headers if index 0 is selected.
if (HasColumn && SelectedItemIndex == 0)
VerticalScroll.Value = 0;
//some magic for update scrolls
AutoScrollMinSize -= new Size(1, 0);
AutoScrollMinSize += new Size(1, 0);
}
public Rectangle GetItemRectangle(int itemIndex)
{
var y = itemIndex * ItemHeight - VerticalScroll.Value;
return new Rectangle(0, y, ClientSize.Width - 1, ItemHeight - 1);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(Colors.BackColor);
}
private bool HasColumn
{
get
{
return ColumnsTitle != null && ColumnsTitle.Length != 0;
}
}
protected override void OnPaint(PaintEventArgs e)
{
bool rtl = RightToLeft == RightToLeft.Yes;
AdjustScroll();
int startI = VerticalScroll.Value/ItemHeight - 1;
int finishI = (VerticalScroll.Value + ClientSize.Height)/ItemHeight + 1;
int y = 0;
var sf = new StringFormat();
if (rtl)
sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
if (HasColumn && VerticalScroll.Value == 0)
{
var textRect = new Rectangle(LeftPadding, y, ClientSize.Width - 1 - LeftPadding, ItemHeight - 1);
if (rtl)
textRect = new Rectangle(1, y, ClientSize.Width - 1 - LeftPadding, ItemHeight - 1);
int[] columnWidth = ColumnsWidth;
if (columnWidth == null)
{
columnWidth = new int[ColumnsTitle.Length];
float step = textRect.Width / ColumnsTitle.Length;
for (int i = 0; i < ColumnsTitle.Length; i++)
columnWidth[i] = (int)step;
}
float x = textRect.X;
sf.Alignment = StringAlignment.Center;
for (int i = 0; i < ColumnsTitle.Length; i++)
{
using (var brush = new SolidBrush(Colors.ForeColor))
{
var width = columnWidth[i];
var rect = new RectangleF(x, textRect.Top, width, textRect.Height);
e.Graphics.DrawLine(Pens.Silver, new PointF(x, textRect.Top), new PointF(x, textRect.Bottom));
e.Graphics.DrawString(ColumnsTitle[i], Font, brush, rect, sf);
x += width;
}
}
if (rtl)
sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
else
sf = new StringFormat();
}
startI = Math.Max(startI, 0);
finishI = Math.Min(finishI, VisibleItems.Count);
for (int i = startI; i < finishI; i++)
{
if(HasColumn)
y = (i * ItemHeight - VerticalScroll.Value) + ItemHeight;
else
y = i * ItemHeight - VerticalScroll.Value;
if (ImageList != null && VisibleItems[i].ImageIndex >= 0)
if (rtl)
e.Graphics.DrawImage(ImageList.Images[VisibleItems[i].ImageIndex], Width - 1 - LeftPadding, y);
else
e.Graphics.DrawImage(ImageList.Images[VisibleItems[i].ImageIndex], 1, y);
var textRect = new Rectangle(LeftPadding, y, ClientSize.Width - 1 - LeftPadding, ItemHeight - 1);
if (rtl)
textRect = new Rectangle(1, y, ClientSize.Width - 1 - LeftPadding, ItemHeight - 1);
if (i == SelectedItemIndex)
{
Brush selectedBrush = new LinearGradientBrush(new Point(0, y - 3), new Point(0, y + ItemHeight),
Colors.SelectedBackColor2, Colors.SelectedBackColor);
e.Graphics.FillRectangle(selectedBrush, textRect);
using(var pen = new Pen(Colors.SelectedBackColor2))
e.Graphics.DrawRectangle(pen, textRect);
}
if (i == HighlightedItemIndex)
using (var pen = new Pen(Colors.HighlightingColor))
e.Graphics.DrawRectangle(pen, textRect);
var args = new PaintItemEventArgs(e.Graphics, e.ClipRectangle)
{
Font = Font,
TextRect = new RectangleF(textRect.Location, textRect.Size),
StringFormat = sf,
IsSelected = i == SelectedItemIndex,
IsHovered = i == HighlightedItemIndex,
Colors = Colors
};
//call drawing
VisibleItems[i].OnPaint(args);
}
}
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
Invalidate(true);
}
protected override void OnMouseClick(MouseEventArgs e)
{
int i = PointToItemIndex(e.Location);
if (i >= 0)
{
base.OnMouseClick(e);
if (e.Button == MouseButtons.Left)
{
SelectedItemIndex = i;
ScrollToSelected();
Invalidate();
}
}
}
private Point mouseEnterPoint;
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
mouseEnterPoint = Control.MousePosition;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (mouseEnterPoint != Control.MousePosition)
{
int i = PointToItemIndex(e.Location);
if (i >= 0)
{
HighlightedItemIndex = i;
Invalidate();
}
}
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
int i = PointToItemIndex(e.Location);
if (i >= 0)
{
base.OnMouseDoubleClick(e);
SelectedItemIndex = i;
Invalidate();
OnItemSelected();
}
}
private void OnItemSelected()
{
if (ItemSelected != null)
ItemSelected(this, EventArgs.Empty);
}
private int PointToItemIndex(Point p)
{
var t = (p.Y + VerticalScroll.Value);
if (HasColumn)
t -= ItemHeight;
return (float)t / ItemHeight < 0 ? -1 : t / ItemHeight;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
var host = Parent as AutocompleteMenuHost;
if (host != null)
if (host.Menu.ProcessKey((char) keyData, Keys.None))
return true;
return base.ProcessCmdKey(ref msg, keyData);
}
public void SelectItem(int itemIndex)
{
SelectedItemIndex = itemIndex;
ScrollToSelected();
Invalidate();
}
public void SetItems(List<AutocompleteItem> items)
{
VisibleItems = items;
SelectedItemIndex = -1;
AdjustScroll();
Invalidate();
}
public void ShowToolTip(AutocompleteItem autocompleteItem, Control control = null)
{
string title = autocompleteItem.ToolTipTitle;
string text = autocompleteItem.ToolTipText;
if (control == null)
control = this;
if (string.IsNullOrEmpty(title))
{
toolTip.ToolTipTitle = null;
toolTip.SetToolTip(control, null);
return;
}
if (string.IsNullOrEmpty(text))
{
toolTip.ToolTipTitle = null;
toolTip.Show(title, control, Width + 3, 0, ToolTipDuration);
}
else
{
toolTip.ToolTipTitle = title;
toolTip.Show(text, control, Width + 3, 0, ToolTipDuration);
}
}
public void HideToolTip(Control control)
{
toolTip.Hide(control);
}
public Control GetParentControl()
{
return this.Parent;
}
}
}
@@ -0,0 +1,903 @@
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// License: GNU Lesser General Public License (LGPLv3)
//
// Email: p_torgashov@ukr.net.
//
// Copyright (C) Pavel Torgashov, 2012-2015.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Collections;
using System.Diagnostics;
namespace AutocompleteMenuNS
{
[ProvideProperty("AutocompleteMenu", typeof(Control))]
public class AutocompleteMenu : Component, IExtenderProvider
{
private static readonly Dictionary<Control, AutocompleteMenu> AutocompleteMenuByControls =
new Dictionary<Control, AutocompleteMenu>();
private static readonly Dictionary<Control, ITextBoxWrapper> WrapperByControls =
new Dictionary<Control, ITextBoxWrapper>();
private ITextBoxWrapper targetControlWrapper;
private readonly Timer timer = new Timer();
private IEnumerable<AutocompleteItem> sourceItems = new List<AutocompleteItem>();
[Browsable(false)]
public IList<AutocompleteItem> VisibleItems { get { return Host.ListView.VisibleItems; } private set { Host.ListView.VisibleItems = value;} }
private Size maximumSize;
/// <summary>
/// Duration (ms) of tooltip showing
/// </summary>
[Description("Duration (ms) of tooltip showing")]
[DefaultValue(3000)]
public int ToolTipDuration
{
get { return Host.ListView.ToolTipDuration; }
set { Host.ListView.ToolTipDuration = value; }
}
public AutocompleteMenu()
{
Host = new AutocompleteMenuHost(this);
Host.ListView.ItemSelected += new EventHandler(ListView_ItemSelected);
Host.ListView.ItemHovered += new EventHandler<HoveredEventArgs>(ListView_ItemHovered);
VisibleItems = new List<AutocompleteItem>();
Enabled = true;
AppearInterval = 500;
timer.Tick += timer_Tick;
MaximumSize = new Size(180, 200);
AutoPopup = true;
SearchPattern = @"[\w\.]";
MinFragmentLength = 2;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
timer.Dispose();
Host.Dispose();
}
base.Dispose(disposing);
}
void ListView_ItemSelected(object sender, EventArgs e)
{
OnSelecting();
}
void ListView_ItemHovered(object sender, HoveredEventArgs e)
{
OnHovered(e);
}
public void OnHovered(HoveredEventArgs e)
{
if (Hovered != null)
Hovered(this, e);
}
[Browsable(false)]
public int SelectedItemIndex { get { return Host.ListView.SelectedItemIndex; }
internal set { Host.ListView.SelectedItemIndex = value; }
}
internal AutocompleteMenuHost Host { get; set; }
/// <summary>
/// Called when user selected the control and needed wrapper over it.
/// You can assign own Wrapper for target control.
/// </summary>
[Description("Called when user selected the control and needed wrapper over it. You can assign own Wrapper for target control.")]
public event EventHandler<WrapperNeededEventArgs> WrapperNeeded;
protected void OnWrapperNeeded(WrapperNeededEventArgs args)
{
if (WrapperNeeded != null)
WrapperNeeded(this, args);
if (args.Wrapper == null)
args.Wrapper = TextBoxWrapper.Create(args.TargetControl);
}
ITextBoxWrapper CreateWrapper(Control control)
{
if (WrapperByControls.ContainsKey(control))
return WrapperByControls[control];
var args = new WrapperNeededEventArgs(control);
OnWrapperNeeded(args);
if (args.Wrapper != null)
WrapperByControls[control] = args.Wrapper;
return args.Wrapper;
}
/// <summary>
/// Current target control wrapper
/// </summary>
[Browsable(false)]
public ITextBoxWrapper TargetControlWrapper
{
get { return targetControlWrapper; }
set {
targetControlWrapper = value;
if (value != null && !WrapperByControls.ContainsKey(value.TargetControl))
{
WrapperByControls[value.TargetControl] = value;
SetAutocompleteMenu(value.TargetControl, this);
}
}
}
/// <summary>
/// Maximum size of popup menu
/// </summary>
[DefaultValue(typeof(Size), "180, 200")]
[Description("Maximum size of popup menu")]
public Size MaximumSize
{
get { return maximumSize; }
set {
maximumSize = value;
(Host.ListView as Control).MaximumSize = maximumSize;
(Host.ListView as Control).Size = maximumSize;
Host.CalcSize();
}
}
/// <summary>
/// Font
/// </summary>
public Font Font
{
get { return (Host.ListView as Control).Font; }
set { (Host.ListView as Control).Font = value; }
}
/// <summary>
/// Left padding of text
/// </summary>
[DefaultValue(18)]
[Description("Left padding of text")]
public int LeftPadding
{
get {
if (Host.ListView is AutocompleteListView)
return (Host.ListView as AutocompleteListView).LeftPadding;
else
return 0;
}
set {
if (Host.ListView is AutocompleteListView)
(Host.ListView as AutocompleteListView).LeftPadding = value;
}
}
/// <summary>
/// Colors of foreground and background
/// </summary>
[Browsable(true)]
[Description("Colors of foreground and background.")]
[TypeConverter(typeof(ExpandableObjectConverter))]
public Colors Colors
{
get { return (Host.ListView as IAutocompleteListView).Colors; }
set { (Host.ListView as IAutocompleteListView).Colors = value; }
}
/// <summary>
/// AutocompleteMenu will popup automatically (when user writes text). Otherwise it will popup only programmatically or by Ctrl-Space.
/// </summary>
[DefaultValue(true)]
[Description("AutocompleteMenu will popup automatically (when user writes text). Otherwise it will popup only programmatically or by Ctrl-Space.")]
public bool AutoPopup { get; set; }
/// <summary>
/// AutocompleteMenu will capture focus when opening.
/// </summary>
[DefaultValue(false)]
[Description("AutocompleteMenu will capture focus when opening.")]
public bool CaptureFocus { get; set; }
/// <summary>
/// Indicates whether the component should draw right-to-left for RTL languages.
/// </summary>
[DefaultValue(typeof(RightToLeft), "No")]
[Description("Indicates whether the component should draw right-to-left for RTL languages.")]
public RightToLeft RightToLeft {
get { return Host.RightToLeft; }
set { Host.RightToLeft = value; }
}
/// <summary>
/// Image list
/// </summary>
public ImageList ImageList {
get { return Host.ListView.ImageList; }
set { Host.ListView.ImageList = value; }
}
/// <summary>
/// Fragment
/// </summary>
[Browsable(false)]
public Range Fragment { get; internal set; }
/// <summary>
/// Regex pattern for serach fragment around caret
/// </summary>
[Description("Regex pattern for serach fragment around caret")]
[DefaultValue(@"[\w\.]")]
public string SearchPattern { get; set; }
/// <summary>
/// Minimum fragment length for popup
/// </summary>
[Description("Minimum fragment length for popup")]
[DefaultValue(2)]
public int MinFragmentLength { get; set; }
/// <summary>
/// Allows TAB for select menu item
/// </summary>
[Description("Allows TAB for select menu item")]
[DefaultValue(false)]
public bool AllowsTabKey { get; set; }
/// <summary>
/// Interval of menu appear (ms)
/// </summary>
[Description("Interval of menu appear (ms)")]
[DefaultValue(500)]
public int AppearInterval { get; set; }
[DefaultValue(null)]
public string[] Items
{
get
{
if (sourceItems == null)
return null;
var list = new List<string>();
foreach (AutocompleteItem item in sourceItems)
list.Add(item.ToString());
return list.ToArray();
}
set { SetAutocompleteItems(value); }
}
/// <summary>
/// The control for menu displaying.
/// Set to null for restore default ListView (AutocompleteListView).
/// </summary>
[Browsable(false)]
public IAutocompleteListView ListView
{
get { return Host.ListView; }
set
{
if (ListView != null)
{
var ctrl = value as Control;
value.ImageList = ImageList;
ctrl.RightToLeft = RightToLeft;
ctrl.Font = Font;
ctrl.MaximumSize = MaximumSize;
}
Host.ListView = value;
Host.ListView.ItemSelected += new EventHandler(ListView_ItemSelected);
Host.ListView.ItemHovered += new EventHandler<HoveredEventArgs>(ListView_ItemHovered);
}
}
[DefaultValue(true)]
public bool Enabled { get; set; }
/// <summary>
/// Updates size of the menu
/// </summary>
public void Update()
{
Host.CalcSize();
}
/// <summary>
/// Returns rectangle of item
/// </summary>
public Rectangle GetItemRectangle(int itemIndex)
{
return Host.ListView.GetItemRectangle(itemIndex);
}
#region IExtenderProvider Members
bool IExtenderProvider.CanExtend(object extendee)
{
//find AutocompleteMenu with lowest hashcode
if (Container != null)
foreach (object comp in Container.Components)
if (comp is AutocompleteMenu)
if (comp.GetHashCode() < GetHashCode())
return false;
//we are main autocomplete menu on form ...
//check extendee as TextBox
if (!(extendee is Control))
return false;
var temp = TextBoxWrapper.Create(extendee as Control);
return temp!=null;
}
public void SetAutocompleteMenu(Control control, AutocompleteMenu menu)
{
if (menu != null)
{
if (WrapperByControls.ContainsKey(control))
{
var wrapper = WrapperByControls[control];
if (wrapper == null) return;
//
if (control.IsHandleCreated)
menu.SubscribeForm(wrapper);
else
control.HandleCreated += (o, e) => menu.SubscribeForm(wrapper);
//
AutocompleteMenuByControls[control] = this;
//
wrapper.LostFocus += menu.control_LostFocus;
wrapper.Scroll += menu.control_Scroll;
wrapper.KeyDown += menu.control_KeyDown;
wrapper.MouseDown += menu.control_MouseDown;
}
else
{
var wrapper = menu.CreateWrapper(control);
if (wrapper == null) return;
//
if (control.IsHandleCreated)
menu.SubscribeForm(wrapper);
else
control.HandleCreated += (o, e) => menu.SubscribeForm(wrapper);
//
AutocompleteMenuByControls[control] = this;
//
wrapper.LostFocus += menu.control_LostFocus;
wrapper.Scroll += menu.control_Scroll;
wrapper.KeyDown += menu.control_KeyDown;
wrapper.MouseDown += menu.control_MouseDown;
}
}
else
{
AutocompleteMenuByControls.TryGetValue(control, out menu);
AutocompleteMenuByControls.Remove(control);
ITextBoxWrapper wrapper = null;
WrapperByControls.TryGetValue(control, out wrapper);
WrapperByControls.Remove(control);
if (wrapper != null && menu != null)
{
wrapper.LostFocus -= menu.control_LostFocus;
wrapper.Scroll -= menu.control_Scroll;
wrapper.KeyDown -= menu.control_KeyDown;
wrapper.MouseDown -= menu.control_MouseDown;
}
}
}
#endregion
/// <summary>
/// User selects item
/// </summary>
[Description("Occurs when user selects item.")]
public event EventHandler<SelectingEventArgs> Selecting;
/// <summary>
/// It fires after item was inserting
/// </summary>
[Description("Occurs after user selected item.")]
public event EventHandler<SelectedEventArgs> Selected;
/// <summary>
/// It fires when item was hovered
/// </summary>
[Description("Occurs when user hovered item.")]
public event EventHandler<HoveredEventArgs> Hovered;
/// <summary>
/// Occurs when popup menu is opening
/// </summary>
public event EventHandler<CancelEventArgs> Opening;
private void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
if(TargetControlWrapper!=null)
ShowAutocomplete(false);
}
private Form myForm;
void SubscribeForm(ITextBoxWrapper wrapper)
{
if (wrapper == null) return;
var form = wrapper.TargetControl.FindForm();
if (form == null) return;
if (myForm != null)
{
if (myForm == form)
return;
UnsubscribeForm(wrapper);
}
myForm = form;
form.LocationChanged += new EventHandler(form_LocationChanged);
form.ResizeBegin += new EventHandler(form_LocationChanged);
form.FormClosing += new FormClosingEventHandler(form_FormClosing);
form.LostFocus += new EventHandler(form_LocationChanged);
}
void UnsubscribeForm(ITextBoxWrapper wrapper)
{
if (wrapper == null) return;
var form = wrapper.TargetControl.FindForm();
if (form == null) return;
form.LocationChanged -= new EventHandler(form_LocationChanged);
form.ResizeBegin -= new EventHandler(form_LocationChanged);
form.FormClosing -= new FormClosingEventHandler(form_FormClosing);
form.LostFocus -= new EventHandler(form_LocationChanged);
}
private void form_FormClosing(object sender, FormClosingEventArgs e)
{
Close();
}
private void form_LocationChanged(object sender, EventArgs e)
{
Close();
}
private void control_MouseDown(object sender, MouseEventArgs e)
{
Close();
}
ITextBoxWrapper FindWrapper(Control sender)
{
while (sender != null)
{
if (WrapperByControls.ContainsKey(sender))
return WrapperByControls[sender];
sender = sender.Parent;
}
return null;
}
private void control_KeyDown(object sender, KeyEventArgs e)
{
TargetControlWrapper = FindWrapper(sender as Control);
bool backspaceORdel = e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete;
if (Host.Visible)
{
if (ProcessKey((char)e.KeyCode, Control.ModifierKeys))
e.SuppressKeyPress = true;
else
if (!backspaceORdel)
ResetTimer(1);
else
ResetTimer();
return;
}
if (!Host.Visible)
{
switch (e.KeyCode)
{
case Keys.Up:
case Keys.Down:
case Keys.PageUp:
case Keys.PageDown:
case Keys.Left:
case Keys.Right:
case Keys.End:
case Keys.Home:
case Keys.ControlKey:
case Keys.Escape:
case Keys.Tab:
{
timer.Stop();
return;
}
}
if (Control.ModifierKeys== Keys.Alt)
{
timer.Stop();
return;
}
if (Control.ModifierKeys == Keys.Control && e.KeyCode == Keys.Space)
{
ShowAutocomplete(true);
e.SuppressKeyPress = true;
return;
}
}
ResetTimer();
}
void ResetTimer()
{
ResetTimer(-1);
}
void ResetTimer(int interval)
{
if (interval <= 0)
timer.Interval = AppearInterval;
else
timer.Interval = interval;
timer.Stop();
timer.Start();
}
private void control_Scroll(object sender, ScrollEventArgs e)
{
Close();
}
private void control_LostFocus(object sender, EventArgs e)
{
if (!Host.Focused) Close();
}
public AutocompleteMenu GetAutocompleteMenu(Control control)
{
if (AutocompleteMenuByControls.ContainsKey(control))
return AutocompleteMenuByControls[control];
else
return null;
}
bool forcedOpened = false;
internal void ShowAutocomplete(bool forced)
{
if (forced)
forcedOpened = true;
if (TargetControlWrapper != null && TargetControlWrapper.Readonly)
{
Close();
return;
}
if (!Enabled)
{
Close();
return;
}
if (!forcedOpened && !AutoPopup)
{
Close();
return;
}
//build list
BuildAutocompleteList(forcedOpened);
//show popup menu
if (VisibleItems.Count > 0)
{
if (forced && VisibleItems.Count == 1 && Host.ListView.SelectedItemIndex == 0)
{
//do autocomplete if menu contains only one line and user press CTRL-SPACE
OnSelecting();
Close();
}
else
ShowMenu();
}
else
Close();
}
private void ShowMenu()
{
if (!Host.Visible)
{
var args = new CancelEventArgs();
OnOpening(args);
if (!args.Cancel)
{
//calc screen point for popup menu
Point point = TargetControlWrapper.TargetControl.Location;
point.Offset(2, TargetControlWrapper.TargetControl.Height + 2);
point = TargetControlWrapper.GetPositionFromCharIndex(Fragment.Start);
point.Offset(2, TargetControlWrapper.TargetControl.Font.Height + 2);
//
Host.Show(TargetControlWrapper.TargetControl, point);
if (CaptureFocus)
{
(Host.ListView as Control).Focus();
//ProcessKey((char) Keys.Down, Keys.None);
}
}
}
else
(Host.ListView as Control).Invalidate();
}
private void BuildAutocompleteList(bool forced)
{
var visibleItems = new List<AutocompleteItem>();
bool foundSelected = false;
int selectedIndex = -1;
//get fragment around caret
Range fragment = GetFragment(SearchPattern);
string text = fragment.Text;
//
if (sourceItems != null)
if (forced || (text.Length >= MinFragmentLength /* && tb.Selection.Start == tb.Selection.End*/))
{
Fragment = fragment;
//build popup menu
foreach (AutocompleteItem item in sourceItems)
{
item.Parent = this;
CompareResult res = item.Compare(text);
if (res != CompareResult.Hidden)
visibleItems.Add(item);
if (res == CompareResult.VisibleAndSelected && !foundSelected)
{
foundSelected = true;
selectedIndex = visibleItems.Count - 1;
}
}
}
VisibleItems = visibleItems;
if (foundSelected)
Host.ListView.SelectedItemIndex = selectedIndex;
else
Host.ListView.SelectedItemIndex = 0;
Host.ListView.HighlightedItemIndex = -1;
Host.CalcSize();
}
internal void OnOpening(CancelEventArgs args)
{
if (Opening != null)
Opening(this, args);
}
private Range GetFragment(string searchPattern)
{
var tb = TargetControlWrapper;
if (tb.SelectionLength > 0) return new Range(tb);
string text = tb.Text;
var regex = new Regex(searchPattern);
var result = new Range(tb);
int startPos = tb.SelectionStart;
//go forward
int i = startPos;
while (i >= 0 && i < text.Length)
{
if (!regex.IsMatch(text[i].ToString()))
break;
i++;
}
result.End = i;
//go backward
i = startPos;
while (i > 0 && (i - 1) < text.Length)
{
if (!regex.IsMatch(text[i - 1].ToString()))
break;
i--;
}
result.Start = i;
return result;
}
public void Close()
{
Host.ListView.HideToolTip(Host.ListView.GetParentControl());
Host.Close();
forcedOpened = false;
}
public void SetAutocompleteItems(IEnumerable<string> items)
{
var list = new List<AutocompleteItem>();
if (items == null)
{
sourceItems = null;
return;
}
foreach (string item in items)
list.Add(new AutocompleteItem(item));
SetAutocompleteItems(list);
}
public void SetAutocompleteItems(IEnumerable<AutocompleteItem> items)
{
sourceItems = items;
}
public void AddItem(string item)
{
AddItem(new AutocompleteItem(item));
}
public void AddItem(AutocompleteItem item)
{
if (sourceItems == null)
sourceItems = new List<AutocompleteItem>();
if (sourceItems is IList)
(sourceItems as IList).Add(item);
else
throw new Exception("Current autocomplete items does not support adding");
}
/// <summary>
/// Shows popup menu immediately
/// </summary>
/// <param name="forced">If True - MinFragmentLength will be ignored</param>
public void Show(Control control, bool forced)
{
SetAutocompleteMenu(control, this);
this.TargetControlWrapper = FindWrapper(control);
ShowAutocomplete(forced);
}
internal virtual void OnSelecting()
{
if (SelectedItemIndex < 0 || SelectedItemIndex >= VisibleItems.Count)
return;
AutocompleteItem item = VisibleItems[SelectedItemIndex];
var args = new SelectingEventArgs
{
Item = item,
SelectedIndex = SelectedItemIndex
};
OnSelecting(args);
if (args.Cancel)
{
SelectedItemIndex = args.SelectedIndex;
(Host.ListView as Control).Invalidate(true);
return;
}
if (!args.Handled)
{
Range fragment = Fragment;
ApplyAutocomplete(item, fragment);
}
Close();
//
var args2 = new SelectedEventArgs
{
Item = item,
Control = TargetControlWrapper.TargetControl
};
item.OnSelected(args2);
OnSelected(args2);
}
private void ApplyAutocomplete(AutocompleteItem item, Range fragment)
{
string newText = item.GetTextForReplace();
//replace text of fragment
fragment.Text = newText;
fragment.TargetWrapper.TargetControl.Focus();
}
internal void OnSelecting(SelectingEventArgs args)
{
if (Selecting != null)
Selecting(this, args);
}
public void OnSelected(SelectedEventArgs args)
{
if (Selected != null)
Selected(this, args);
}
public void SetColumns(string[] columns, int[] columnsWidth = null)
{
ListView.ColumnsTitle = columns;
ListView.ColumnsWidth = columnsWidth;
}
public void SelectNext(int shift)
{
SelectedItemIndex = Math.Max(0, Math.Min(SelectedItemIndex + shift, VisibleItems.Count - 1));
//
(Host.ListView as Control).Invalidate();
}
public bool ProcessKey(char c, Keys keyModifiers)
{
var page = Host.Height / (Font.Height + 4);
if (keyModifiers == Keys.None)
switch ((Keys) c)
{
case Keys.Down:
SelectNext(+1);
return true;
case Keys.PageDown:
SelectNext(+page);
return true;
case Keys.Up:
SelectNext(-1);
return true;
case Keys.PageUp:
SelectNext(-page);
return true;
case Keys.Enter:
OnSelecting();
return true;
case Keys.Tab:
if (!AllowsTabKey)
break;
OnSelecting();
return true;
case Keys.Left:
case Keys.Right:
Close();
return false;
case Keys.Escape:
Close();
return true;
}
return false;
}
/// <summary>
/// Menu is visible
/// </summary>
public bool Visible
{
get { return Host != null && Host.Visible; }
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,98 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
[System.ComponentModel.ToolboxItem(false)]
internal class AutocompleteMenuHost : ToolStripDropDown
{
private IAutocompleteListView listView;
public ToolStripControlHost Host { get; set; }
public readonly AutocompleteMenu Menu;
public IAutocompleteListView ListView
{
get { return listView; }
set {
if(listView != null)
(listView as Control).LostFocus -= new EventHandler(ListView_LostFocus);
if (value == null)
listView = new AutocompleteListView();
else
{
if (!(value is Control))
throw new Exception("ListView must be derived from Control class");
listView = value;
}
Host = new ToolStripControlHost(ListView as Control);
Host.Margin = new Padding(2, 2, 2, 2);
Host.Padding = Padding.Empty;
Host.AutoSize = false;
Host.AutoToolTip = false;
(ListView as Control).MaximumSize = Menu.MaximumSize;
(ListView as Control).Size = Menu.MaximumSize;
(ListView as Control).LostFocus += new EventHandler(ListView_LostFocus);
CalcSize();
base.Items.Clear();
base.Items.Add(Host);
(ListView as Control).Parent = this;
}
}
public AutocompleteMenuHost(AutocompleteMenu menu)
{
AutoClose = false;
AutoSize = false;
Margin = Padding.Empty;
Padding = Padding.Empty;
Menu = menu;
ListView = new AutocompleteListView();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
using (var brush = new SolidBrush(listView.Colors.BackColor))
e.Graphics.FillRectangle(brush, e.ClipRectangle);
}
internal void CalcSize()
{
Host.Size = (ListView as Control).Size;
Size = new System.Drawing.Size((ListView as Control).Size.Width + 4, (ListView as Control).Size.Height + 4);
}
public override RightToLeft RightToLeft
{
get
{
return base.RightToLeft;
}
set
{
base.RightToLeft = value;
(ListView as Control).RightToLeft = value;
}
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
if(!(ListView as Control).Focused)
Close();
}
void ListView_LostFocus(object sender, EventArgs e)
{
if (!Focused)
Close();
}
}
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace AutocompleteMenuNS
{
[Serializable]
public class Colors
{
public Color ForeColor { get; set; }
public Color BackColor { get; set; }
public Color SelectedForeColor { get; set; }
public Color SelectedBackColor { get; set; }
public Color SelectedBackColor2 { get; set; }
public Color HighlightingColor { get; set; }
public Colors()
{
ForeColor = Color.Black;
BackColor = Color.White;
SelectedForeColor = Color.Black;
SelectedBackColor = Color.Orange;
SelectedBackColor2 = Color.White;
HighlightingColor = Color.Orange;
}
}
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
public class SelectingEventArgs : EventArgs
{
public AutocompleteItem Item { get; internal set; }
public bool Cancel { get; set; }
public int SelectedIndex { get; set; }
public bool Handled { get; set; }
}
public class SelectedEventArgs : EventArgs
{
public AutocompleteItem Item { get; internal set; }
public Control Control { get; set; }
}
public class HoveredEventArgs : EventArgs
{
public AutocompleteItem Item { get; internal set; }
}
public class PaintItemEventArgs : PaintEventArgs
{
public RectangleF TextRect { get; internal set; }
public StringFormat StringFormat { get; internal set; }
public Font Font { get; internal set; }
public bool IsSelected { get; internal set; }
public bool IsHovered { get; internal set; }
public Colors Colors { get; internal set; }
public PaintItemEventArgs(Graphics graphics, Rectangle clipRect):base(graphics, clipRect)
{
}
}
public class WrapperNeededEventArgs : EventArgs
{
public Control TargetControl { get; private set; }
public ITextBoxWrapper Wrapper { get; set; }
public WrapperNeededEventArgs(Control targetControl)
{
this.TargetControl = targetControl;
}
}
}
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
/// <summary>
/// Control for displaying menu items, hosted in AutocompleteMenu.
/// </summary>
public interface IAutocompleteListView
{
/// <summary>
/// Image list
/// </summary>
ImageList ImageList { get; set; }
string[] ColumnsTitle { get; set; }
int[] ColumnsWidth { get; set; }
/// <summary>
/// Index of current selected item
/// </summary>
int SelectedItemIndex { get; set; }
/// <summary>
/// Index of current selected item
/// </summary>
int HighlightedItemIndex { get; set; }
/// <summary>
/// List of visible elements
/// </summary>
IList<AutocompleteItem> VisibleItems { get;set;}
/// <summary>
/// Duration (ms) of tooltip showing
/// </summary>
int ToolTipDuration { get; set; }
/// <summary>
/// Occurs when user selected item for inserting into text
/// </summary>
event EventHandler ItemSelected;
/// <summary>
/// Occurs when current hovered item is changing
/// </summary>
event EventHandler<HoveredEventArgs> ItemHovered;
/// <summary>
/// Shows tooltip
/// </summary>
/// <param name="autocompleteItem"></param>
/// <param name="control"></param>
void ShowToolTip(AutocompleteItem autocompleteItem, Control control = null);
/// <summary>
/// Hides tooltip
/// </summary>
/// <param name="control"></param>
void HideToolTip(Control control);
/// <summary>
/// Returns rectangle of item
/// </summary>
Rectangle GetItemRectangle(int itemIndex);
/// <summary>
/// Colors
/// </summary>
Colors Colors { get; set; }
Control GetParentControl();
}
}
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
/// <summary>
/// Wrapper over the control like TextBox.
/// </summary>
public interface ITextBoxWrapper
{
Control TargetControl { get; }
string Text { get; }
string SelectedText { get; set; }
int SelectionLength { get; set; }
int SelectionStart { get; set; }
Point GetPositionFromCharIndex(int pos);
bool Readonly { get; }
event EventHandler LostFocus;
event ScrollEventHandler Scroll;
event KeyEventHandler KeyDown;
event MouseEventHandler MouseDown;
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
public class Range
{
public ITextBoxWrapper TargetWrapper { get; private set; }
public int Start { get; set; }
public int End { get; set; }
public Range(ITextBoxWrapper targetWrapper)
{
this.TargetWrapper = targetWrapper;
}
public string Text
{
get
{
var text = TargetWrapper.Text;
if (string.IsNullOrEmpty(text))
return "";
if (Start >= text.Length)
return "";
if (End > text.Length)
return "";
return TargetWrapper.Text.Substring(Start, End - Start);
}
set
{
TargetWrapper.SelectionStart = Start;
TargetWrapper.SelectionLength = End - Start;
TargetWrapper.SelectedText = value;
}
}
}
}
@@ -0,0 +1,96 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using AutocompleteMenuNS;
using ScintillaNET;
public class ScintillaWrapper : ITextBoxWrapper
{
public Scintilla target;
public ScintillaWrapper(Scintilla trgt)
{
target = trgt;
//Now add handler for the UpdateUI event.
target.UpdateUI += (sender, args) =>
{
if (args?.Change == UpdateChange.HScroll || args?.Change == UpdateChange.VScroll)
{
Scroll?.Invoke(sender, new ScrollEventArgs(ScrollEventType.LargeIncrement, 0));
}
};
}
public bool Readonly
{
get{ return target.ReadOnly; }
}
public string SelectedText
{
get { return target.SelectedText; }
set
{
//Store the start of the selection.
int start = target.SelectionStart;
//Delete the current text between selections.
target.DeleteRange(target.SelectionStart, (target.SelectionEnd - target.SelectionStart));
//Add the text in the same postion.
target.InsertText(start, value);
//Clear selection and make sure the caret is at the end.
target.SelectionStart = (start + value.Length);
target.SelectionEnd = (start + value.Length);
}
}
public int SelectionLength
{
get { return (target.SelectionEnd - target.SelectionStart); }
set { target.SelectionEnd = (target.SelectionStart + value); }
}
public int SelectionStart
{
get { return target.SelectionStart; }
set { target.SelectionStart = value; }
}
public Control TargetControl
{
get { return target; }
}
public string Text
{
get { return target.Text; }
}
public Point GetPositionFromCharIndex(int pos)
{
return new Point(target.PointXFromPosition(pos), target.PointYFromPosition(pos));
}
//Events
public virtual event KeyEventHandler KeyDown
{
add { target.KeyDown += value; }
remove { target.KeyDown -= value; }
}
public virtual event EventHandler LostFocus
{
add { target.LostFocus += value; }
remove { target.LostFocus -= value; }
}
public virtual event MouseEventHandler MouseDown
{
add { target.MouseDown += value; }
remove { target.MouseDown -= value; }
}
public event ScrollEventHandler Scroll;
}
@@ -0,0 +1,138 @@
using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace AutocompleteMenuNS
{
/// <summary>
/// Wrapper over the control like TextBox.
/// </summary>
public class TextBoxWrapper : ITextBoxWrapper
{
private Control target;
private PropertyInfo selectionStart;
private PropertyInfo selectionLength;
private PropertyInfo selectedText;
private PropertyInfo readonlyProperty;
private MethodInfo getPositionFromCharIndex;
private event ScrollEventHandler RTBScroll;
private TextBoxWrapper(Control targetControl)
{
this.target = targetControl;
Init();
}
protected virtual void Init()
{
var t = target.GetType();
selectedText = t.GetProperty("SelectedText");
selectionLength = t.GetProperty("SelectionLength");
selectionStart = t.GetProperty("SelectionStart");
readonlyProperty = t.GetProperty("ReadOnly");
getPositionFromCharIndex = t.GetMethod("GetPositionFromCharIndex") ?? t.GetMethod("PositionToPoint");
if (target is RichTextBox)
(target as RichTextBox).VScroll += new EventHandler(TextBoxWrapper_VScroll);
}
void TextBoxWrapper_VScroll(object sender, EventArgs e)
{
if (RTBScroll != null)
RTBScroll(sender, new ScrollEventArgs(ScrollEventType.EndScroll, 0, 1));
}
public static TextBoxWrapper Create(Control targetControl)
{
var result = new TextBoxWrapper(targetControl);
if (result.selectedText == null || result.selectionLength == null || result.selectionStart == null ||
result.getPositionFromCharIndex == null)
return null;
return result;
}
public virtual string Text
{
get { return target.Text; }
set { target.Text = value; }
}
public virtual string SelectedText
{
get { return (string) selectedText.GetValue(target, null); }
set { selectedText.SetValue(target, value, null); }
}
public virtual int SelectionLength
{
get { return (int) selectionLength.GetValue(target, null); }
set { selectionLength.SetValue(target, value, null); }
}
public virtual int SelectionStart
{
get { return (int) selectionStart.GetValue(target, null); }
set { selectionStart.SetValue(target, value, null); }
}
public virtual Point GetPositionFromCharIndex(int pos)
{
return (Point) getPositionFromCharIndex.Invoke(target, new object[] {pos});
}
public virtual Form FindForm()
{
return target.FindForm();
}
public virtual event EventHandler LostFocus
{
add { target.LostFocus += value; }
remove { target.LostFocus -= value; }
}
public virtual event ScrollEventHandler Scroll
{
add {
if(target is RichTextBox)
RTBScroll += value;
else
if(target is ScrollableControl)(target as ScrollableControl).Scroll += value;
}
remove {
if (target is RichTextBox)
RTBScroll -= value;
else
if(target is ScrollableControl)(target as ScrollableControl).Scroll -= value;
}
}
public virtual event KeyEventHandler KeyDown
{
add { target.KeyDown += value; }
remove { target.KeyDown -= value; }
}
public virtual event MouseEventHandler MouseDown
{
add { target.MouseDown += value; }
remove { target.MouseDown -= value; }
}
public virtual Control TargetControl
{
get { return target; }
}
public bool Readonly
{
get { return (bool) readonlyProperty.GetValue(target, null); }
}
}
}