NEU
This commit is contained in:
266
FastColoredTextBox/AutocompleteItem.cs
Normal file
266
FastColoredTextBox/AutocompleteItem.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Printing;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Item of autocomplete menu
|
||||
/// </summary>
|
||||
public class AutocompleteItem
|
||||
{
|
||||
public string Text;
|
||||
public int ImageIndex = -1;
|
||||
public object Tag;
|
||||
string toolTipTitle;
|
||||
string toolTipText;
|
||||
string menuText;
|
||||
public AutocompleteMenu Parent { get; internal set; }
|
||||
|
||||
|
||||
public AutocompleteItem()
|
||||
{
|
||||
}
|
||||
|
||||
public AutocompleteItem(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
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 inserted into text
|
||||
/// </summary>
|
||||
public virtual void OnSelected(AutocompleteMenu popupMenu, SelectedEventArgs e)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fore color of text of item
|
||||
/// </summary>
|
||||
public virtual Color ForeColor
|
||||
{
|
||||
get { return Color.Transparent; }
|
||||
set { throw new NotImplementedException("Override this property to change color"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Back color of item
|
||||
/// </summary>
|
||||
public virtual Color BackColor
|
||||
{
|
||||
get { return Color.Transparent; }
|
||||
set { throw new NotImplementedException("Override this property to change color"); }
|
||||
}
|
||||
}
|
||||
|
||||
public enum CompareResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Item do not appears
|
||||
/// </summary>
|
||||
Hidden,
|
||||
/// <summary>
|
||||
/// Item appears
|
||||
/// </summary>
|
||||
Visible,
|
||||
/// <summary>
|
||||
/// Item appears and will selected
|
||||
/// </summary>
|
||||
VisibleAndSelected
|
||||
}
|
||||
|
||||
/// <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(AutocompleteMenu popupMenu, SelectedEventArgs e)
|
||||
{
|
||||
e.Tb.BeginUpdate();
|
||||
e.Tb.Selection.BeginUpdate();
|
||||
//remember places
|
||||
var p1 = popupMenu.Fragment.Start;
|
||||
var p2 = e.Tb.Selection.Start;
|
||||
//do auto indent
|
||||
if (e.Tb.AutoIndent)
|
||||
{
|
||||
for (int iLine = p1.iLine + 1; iLine <= p2.iLine; iLine++)
|
||||
{
|
||||
e.Tb.Selection.Start = new Place(0, iLine);
|
||||
e.Tb.DoAutoIndent(iLine);
|
||||
}
|
||||
}
|
||||
e.Tb.Selection.Start = p1;
|
||||
//move caret position right and find char ^
|
||||
while (e.Tb.Selection.CharBeforeStart != '^')
|
||||
if (!e.Tb.Selection.GoRightThroughFolded())
|
||||
break;
|
||||
//remove char ^
|
||||
e.Tb.Selection.GoLeft(true);
|
||||
e.Tb.InsertText("");
|
||||
//
|
||||
e.Tb.Selection.EndUpdate();
|
||||
e.Tb.EndUpdate();
|
||||
}
|
||||
|
||||
/// <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 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>
|
||||
/// This Item does not check correspondence to current text fragment.
|
||||
/// SuggestItem is intended for dynamic menus.
|
||||
/// </summary>
|
||||
public class SuggestItem : AutocompleteItem
|
||||
{
|
||||
public SuggestItem(string text, int imageIndex):base(text, imageIndex)
|
||||
{
|
||||
}
|
||||
|
||||
public override CompareResult Compare(string fragmentText)
|
||||
{
|
||||
return CompareResult.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
723
FastColoredTextBox/AutocompleteMenu.cs
Normal file
723
FastColoredTextBox/AutocompleteMenu.cs
Normal file
@@ -0,0 +1,723 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Popup menu for autocomplete
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public class AutocompleteMenu : ToolStripDropDown
|
||||
{
|
||||
AutocompleteListView listView;
|
||||
public ToolStripControlHost host;
|
||||
public Range Fragment { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Regex pattern for serach fragment around caret
|
||||
/// </summary>
|
||||
public string SearchPattern { get; set; }
|
||||
/// <summary>
|
||||
/// Minimum fragment length for popup
|
||||
/// </summary>
|
||||
public int MinFragmentLength { get; set; }
|
||||
/// <summary>
|
||||
/// User selects item
|
||||
/// </summary>
|
||||
public event EventHandler<SelectingEventArgs> Selecting;
|
||||
/// <summary>
|
||||
/// It fires after item inserting
|
||||
/// </summary>
|
||||
public event EventHandler<SelectedEventArgs> Selected;
|
||||
/// <summary>
|
||||
/// Occurs when popup menu is opening
|
||||
/// </summary>
|
||||
public new event EventHandler<CancelEventArgs> Opening;
|
||||
/// <summary>
|
||||
/// Allow TAB for select menu item
|
||||
/// </summary>
|
||||
public bool AllowTabKey { get { return listView.AllowTabKey; } set { listView.AllowTabKey = value; } }
|
||||
/// <summary>
|
||||
/// Interval of menu appear (ms)
|
||||
/// </summary>
|
||||
public int AppearInterval { get { return listView.AppearInterval; } set { listView.AppearInterval = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Back color of selected item
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "Orange")]
|
||||
public Color SelectedColor
|
||||
{
|
||||
get { return listView.SelectedColor; }
|
||||
set { listView.SelectedColor = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Border color of hovered item
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "Red")]
|
||||
public Color HoveredColor
|
||||
{
|
||||
get { return listView.HoveredColor; }
|
||||
set { listView.HoveredColor = value; }
|
||||
}
|
||||
|
||||
public AutocompleteMenu(FastColoredTextBox tb)
|
||||
{
|
||||
// create a new popup and add the list view to it
|
||||
AutoClose = false;
|
||||
AutoSize = false;
|
||||
Margin = Padding.Empty;
|
||||
Padding = Padding.Empty;
|
||||
BackColor = Color.White;
|
||||
listView = new AutocompleteListView(tb);
|
||||
host = new ToolStripControlHost(listView);
|
||||
host.Margin = new Padding(2, 2, 2, 2);
|
||||
host.Padding = Padding.Empty;
|
||||
host.AutoSize = false;
|
||||
host.AutoToolTip = false;
|
||||
CalcSize();
|
||||
base.Items.Add(host);
|
||||
listView.Parent = this;
|
||||
SearchPattern = @"[\w\.]";
|
||||
MinFragmentLength = 2;
|
||||
|
||||
}
|
||||
|
||||
public new Font Font
|
||||
{
|
||||
get { return listView.Font; }
|
||||
set { listView.Font = value; }
|
||||
}
|
||||
|
||||
new internal void OnOpening(CancelEventArgs args)
|
||||
{
|
||||
if (Opening != null)
|
||||
Opening(this, args);
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
{
|
||||
listView.toolTip.Hide(listView);
|
||||
base.Close();
|
||||
}
|
||||
|
||||
internal void CalcSize()
|
||||
{
|
||||
host.Size = listView.Size;
|
||||
Size = new System.Drawing.Size(listView.Size.Width + 4, listView.Size.Height + 4);
|
||||
}
|
||||
|
||||
public virtual void OnSelecting()
|
||||
{
|
||||
listView.OnSelecting();
|
||||
}
|
||||
|
||||
public void SelectNext(int shift)
|
||||
{
|
||||
listView.SelectNext(shift);
|
||||
}
|
||||
|
||||
internal void OnSelecting(SelectingEventArgs args)
|
||||
{
|
||||
if (Selecting != null)
|
||||
Selecting(this, args);
|
||||
}
|
||||
|
||||
public void OnSelected(SelectedEventArgs args)
|
||||
{
|
||||
if (Selected != null)
|
||||
Selected(this, args);
|
||||
}
|
||||
|
||||
public new AutocompleteListView Items
|
||||
{
|
||||
get { return listView; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows popup menu immediately
|
||||
/// </summary>
|
||||
/// <param name="forced">If True - MinFragmentLength will be ignored</param>
|
||||
public void Show(bool forced)
|
||||
{
|
||||
Items.DoAutocomplete(forced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimal size of menu
|
||||
/// </summary>
|
||||
public new Size MinimumSize
|
||||
{
|
||||
get { return Items.MinimumSize; }
|
||||
set { Items.MinimumSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Image list of menu
|
||||
/// </summary>
|
||||
public new ImageList ImageList
|
||||
{
|
||||
get { return Items.ImageList; }
|
||||
set { Items.ImageList = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tooltip duration (ms)
|
||||
/// </summary>
|
||||
public int ToolTipDuration
|
||||
{
|
||||
get { return Items.ToolTipDuration; }
|
||||
set { Items.ToolTipDuration = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tooltip
|
||||
/// </summary>
|
||||
public ToolTip ToolTip
|
||||
{
|
||||
get { return Items.toolTip; }
|
||||
set { Items.toolTip = value; }
|
||||
}
|
||||
}
|
||||
|
||||
[System.ComponentModel.ToolboxItem(false)]
|
||||
public class AutocompleteListView : UserControl
|
||||
{
|
||||
public event EventHandler FocussedItemIndexChanged;
|
||||
|
||||
internal List<AutocompleteItem> visibleItems;
|
||||
IEnumerable<AutocompleteItem> sourceItems = new List<AutocompleteItem>();
|
||||
int focussedItemIndex = 0;
|
||||
int hoveredItemIndex = -1;
|
||||
|
||||
private int ItemHeight
|
||||
{
|
||||
get { return Font.Height + 2; }
|
||||
}
|
||||
|
||||
AutocompleteMenu Menu { get { return Parent as AutocompleteMenu; } }
|
||||
int oldItemCount = 0;
|
||||
FastColoredTextBox tb;
|
||||
internal ToolTip toolTip = new ToolTip();
|
||||
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
|
||||
|
||||
internal bool AllowTabKey { get; set; }
|
||||
public ImageList ImageList { get; set; }
|
||||
internal int AppearInterval { get { return timer.Interval; } set { timer.Interval = value; } }
|
||||
internal int ToolTipDuration { get; set; }
|
||||
|
||||
public Color SelectedColor { get; set; }
|
||||
public Color HoveredColor { get; set; }
|
||||
public int FocussedItemIndex
|
||||
{
|
||||
get { return focussedItemIndex; }
|
||||
set
|
||||
{
|
||||
if (focussedItemIndex != value)
|
||||
{
|
||||
focussedItemIndex = value;
|
||||
if (FocussedItemIndexChanged != null)
|
||||
FocussedItemIndexChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AutocompleteItem FocussedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FocussedItemIndex >= 0 && focussedItemIndex < visibleItems.Count)
|
||||
return visibleItems[focussedItemIndex];
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
FocussedItemIndex = visibleItems.IndexOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal AutocompleteListView(FastColoredTextBox tb)
|
||||
{
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
base.Font = new Font(FontFamily.GenericSansSerif, 9);
|
||||
visibleItems = new List<AutocompleteItem>();
|
||||
VerticalScroll.SmallChange = ItemHeight;
|
||||
MaximumSize = new Size(Size.Width, 180);
|
||||
toolTip.ShowAlways = false;
|
||||
AppearInterval = 500;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
SelectedColor = Color.Orange;
|
||||
HoveredColor = Color.Red;
|
||||
ToolTipDuration = 3000;
|
||||
|
||||
this.tb = tb;
|
||||
|
||||
tb.KeyDown += new KeyEventHandler(tb_KeyDown);
|
||||
tb.SelectionChanged += new EventHandler(tb_SelectionChanged);
|
||||
tb.KeyPressed += new KeyPressEventHandler(tb_KeyPressed);
|
||||
|
||||
Form form = tb.FindForm();
|
||||
if (form != null)
|
||||
{
|
||||
form.LocationChanged += (o, e) => Menu.Close();
|
||||
form.ResizeBegin += (o, e) => Menu.Close();
|
||||
form.FormClosing += (o, e) => Menu.Close();
|
||||
form.LostFocus += (o, e) => Menu.Close();
|
||||
}
|
||||
|
||||
tb.LostFocus += (o, e) =>
|
||||
{
|
||||
if (!Menu.Focused) Menu.Close();
|
||||
};
|
||||
|
||||
tb.Scroll += (o, e) => Menu.Close();
|
||||
|
||||
this.VisibleChanged += (o, e) =>
|
||||
{
|
||||
if (this.Visible)
|
||||
DoSelectedVisible();
|
||||
};
|
||||
}
|
||||
|
||||
void tb_KeyPressed(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
bool backspaceORdel = e.KeyChar == '\b' || e.KeyChar == 0xff;
|
||||
|
||||
/*
|
||||
if (backspaceORdel)
|
||||
prevSelection = tb.Selection.Start;*/
|
||||
|
||||
if (Menu.Visible && !backspaceORdel)
|
||||
DoAutocomplete(false);
|
||||
else
|
||||
ResetTimer(timer);
|
||||
}
|
||||
|
||||
void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
timer.Stop();
|
||||
DoAutocomplete(false);
|
||||
}
|
||||
|
||||
void ResetTimer(System.Windows.Forms.Timer timer)
|
||||
{
|
||||
timer.Stop();
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
internal void DoAutocomplete()
|
||||
{
|
||||
DoAutocomplete(false);
|
||||
}
|
||||
|
||||
internal void DoAutocomplete(bool forced)
|
||||
{
|
||||
if (!Menu.Enabled)
|
||||
{
|
||||
Menu.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
visibleItems.Clear();
|
||||
FocussedItemIndex = 0;
|
||||
VerticalScroll.Value = 0;
|
||||
//some magic for update scrolls
|
||||
AutoScrollMinSize -= new Size(1, 0);
|
||||
AutoScrollMinSize += new Size(1, 0);
|
||||
//get fragment around caret
|
||||
Range fragment = tb.Selection.GetFragment(Menu.SearchPattern);
|
||||
string text = fragment.Text;
|
||||
//calc screen point for popup menu
|
||||
Point point = tb.PlaceToPoint(fragment.End);
|
||||
point.Offset(2, tb.CharHeight);
|
||||
//
|
||||
if (forced || (text.Length >= Menu.MinFragmentLength
|
||||
&& tb.Selection.IsEmpty /*pops up only if selected range is empty*/
|
||||
&& (tb.Selection.Start > fragment.Start || text.Length == 0/*pops up only if caret is after first letter*/)))
|
||||
{
|
||||
Menu.Fragment = fragment;
|
||||
bool foundSelected = false;
|
||||
//build popup menu
|
||||
foreach (var item in sourceItems)
|
||||
{
|
||||
item.Parent = Menu;
|
||||
CompareResult res = item.Compare(text);
|
||||
if(res != CompareResult.Hidden)
|
||||
visibleItems.Add(item);
|
||||
if (res == CompareResult.VisibleAndSelected && !foundSelected)
|
||||
{
|
||||
foundSelected = true;
|
||||
FocussedItemIndex = visibleItems.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundSelected)
|
||||
{
|
||||
AdjustScroll();
|
||||
DoSelectedVisible();
|
||||
}
|
||||
}
|
||||
|
||||
//show popup menu
|
||||
if (Count > 0)
|
||||
{
|
||||
if (!Menu.Visible)
|
||||
{
|
||||
CancelEventArgs args = new CancelEventArgs();
|
||||
Menu.OnOpening(args);
|
||||
if(!args.Cancel)
|
||||
Menu.Show(tb, point);
|
||||
}
|
||||
else
|
||||
Invalidate();
|
||||
}
|
||||
else
|
||||
Menu.Close();
|
||||
}
|
||||
|
||||
void tb_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
/*
|
||||
FastColoredTextBox tb = sender as FastColoredTextBox;
|
||||
|
||||
if (Math.Abs(prevSelection.iChar - tb.Selection.Start.iChar) > 1 ||
|
||||
prevSelection.iLine != tb.Selection.Start.iLine)
|
||||
Menu.Close();
|
||||
prevSelection = tb.Selection.Start;*/
|
||||
if (Menu.Visible)
|
||||
{
|
||||
bool needClose = false;
|
||||
|
||||
if (!tb.Selection.IsEmpty)
|
||||
needClose = true;
|
||||
else
|
||||
if (!Menu.Fragment.Contains(tb.Selection.Start))
|
||||
{
|
||||
if (tb.Selection.Start.iLine == Menu.Fragment.End.iLine && tb.Selection.Start.iChar == Menu.Fragment.End.iChar + 1)
|
||||
{
|
||||
//user press key at end of fragment
|
||||
char c = tb.Selection.CharBeforeStart;
|
||||
if (!Regex.IsMatch(c.ToString(), Menu.SearchPattern))//check char
|
||||
needClose = true;
|
||||
}
|
||||
else
|
||||
needClose = true;
|
||||
}
|
||||
|
||||
if (needClose)
|
||||
Menu.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tb_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
var tb = sender as FastColoredTextBox;
|
||||
|
||||
if (Menu.Visible)
|
||||
if (ProcessKey(e.KeyCode, e.Modifiers))
|
||||
e.Handled = true;
|
||||
|
||||
if (!Menu.Visible)
|
||||
{
|
||||
if (tb.HotkeysMapping.ContainsKey(e.KeyData) && tb.HotkeysMapping[e.KeyData] == FCTBAction.AutocompleteMenu)
|
||||
{
|
||||
DoAutocomplete();
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape && timer.Enabled)
|
||||
timer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustScroll()
|
||||
{
|
||||
if (oldItemCount == visibleItems.Count)
|
||||
return;
|
||||
|
||||
int needHeight = ItemHeight * visibleItems.Count + 1;
|
||||
Height = Math.Min(needHeight, MaximumSize.Height);
|
||||
Menu.CalcSize();
|
||||
|
||||
AutoScrollMinSize = new Size(0, needHeight);
|
||||
oldItemCount = visibleItems.Count;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
AdjustScroll();
|
||||
|
||||
var itemHeight = ItemHeight;
|
||||
int startI = VerticalScroll.Value / itemHeight - 1;
|
||||
int finishI = (VerticalScroll.Value + ClientSize.Height) / itemHeight + 1;
|
||||
startI = Math.Max(startI, 0);
|
||||
finishI = Math.Min(finishI, visibleItems.Count);
|
||||
int y = 0;
|
||||
int leftPadding = 18;
|
||||
for (int i = startI; i < finishI; i++)
|
||||
{
|
||||
y = i * itemHeight - VerticalScroll.Value;
|
||||
|
||||
var item = visibleItems[i];
|
||||
|
||||
if(item.BackColor != Color.Transparent)
|
||||
using (var brush = new SolidBrush(item.BackColor))
|
||||
e.Graphics.FillRectangle(brush, 1, y, ClientSize.Width - 1 - 1, itemHeight - 1);
|
||||
|
||||
if (ImageList != null && visibleItems[i].ImageIndex >= 0)
|
||||
e.Graphics.DrawImage(ImageList.Images[item.ImageIndex], 1, y);
|
||||
|
||||
if (i == FocussedItemIndex)
|
||||
using (var selectedBrush = new LinearGradientBrush(new Point(0, y - 3), new Point(0, y + itemHeight), Color.Transparent, SelectedColor))
|
||||
using (var pen = new Pen(SelectedColor))
|
||||
{
|
||||
e.Graphics.FillRectangle(selectedBrush, leftPadding, y, ClientSize.Width - 1 - leftPadding, itemHeight - 1);
|
||||
e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - 1 - leftPadding, itemHeight - 1);
|
||||
}
|
||||
|
||||
if (i == hoveredItemIndex)
|
||||
using(var pen = new Pen(HoveredColor))
|
||||
e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - 1 - leftPadding, itemHeight - 1);
|
||||
|
||||
using (var brush = new SolidBrush(item.ForeColor != Color.Transparent ? item.ForeColor : ForeColor))
|
||||
e.Graphics.DrawString(item.ToString(), Font, brush, leftPadding, y);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnScroll(ScrollEventArgs se)
|
||||
{
|
||||
base.OnScroll(se);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseClick(e);
|
||||
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
{
|
||||
FocussedItemIndex = PointToItemIndex(e.Location);
|
||||
DoSelectedVisible();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDoubleClick(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDoubleClick(e);
|
||||
FocussedItemIndex = PointToItemIndex(e.Location);
|
||||
Invalidate();
|
||||
OnSelecting();
|
||||
}
|
||||
|
||||
internal virtual void OnSelecting()
|
||||
{
|
||||
if (FocussedItemIndex < 0 || FocussedItemIndex >= visibleItems.Count)
|
||||
return;
|
||||
tb.TextSource.Manager.BeginAutoUndoCommands();
|
||||
try
|
||||
{
|
||||
AutocompleteItem item = FocussedItem;
|
||||
SelectingEventArgs args = new SelectingEventArgs()
|
||||
{
|
||||
Item = item,
|
||||
SelectedIndex = FocussedItemIndex
|
||||
};
|
||||
|
||||
Menu.OnSelecting(args);
|
||||
|
||||
if (args.Cancel)
|
||||
{
|
||||
FocussedItemIndex = args.SelectedIndex;
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.Handled)
|
||||
{
|
||||
var fragment = Menu.Fragment;
|
||||
DoAutocomplete(item, fragment);
|
||||
}
|
||||
|
||||
Menu.Close();
|
||||
//
|
||||
SelectedEventArgs args2 = new SelectedEventArgs()
|
||||
{
|
||||
Item = item,
|
||||
Tb = Menu.Fragment.tb
|
||||
};
|
||||
item.OnSelected(Menu, args2);
|
||||
Menu.OnSelected(args2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tb.TextSource.Manager.EndAutoUndoCommands();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoAutocomplete(AutocompleteItem item, Range fragment)
|
||||
{
|
||||
string newText = item.GetTextForReplace();
|
||||
|
||||
//replace text of fragment
|
||||
var tb = fragment.tb;
|
||||
|
||||
tb.BeginAutoUndo();
|
||||
tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));
|
||||
if (tb.Selection.ColumnSelectionMode)
|
||||
{
|
||||
var start = tb.Selection.Start;
|
||||
var end = tb.Selection.End;
|
||||
start.iChar = fragment.Start.iChar;
|
||||
end.iChar = fragment.End.iChar;
|
||||
tb.Selection.Start = start;
|
||||
tb.Selection.End = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
tb.Selection.Start = fragment.Start;
|
||||
tb.Selection.End = fragment.End;
|
||||
}
|
||||
tb.InsertText(newText);
|
||||
tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));
|
||||
tb.EndAutoUndo();
|
||||
tb.Focus();
|
||||
}
|
||||
|
||||
int PointToItemIndex(Point p)
|
||||
{
|
||||
return (p.Y + VerticalScroll.Value) / ItemHeight;
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
ProcessKey(keyData, Keys.None);
|
||||
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
private bool ProcessKey(Keys keyData, Keys keyModifiers)
|
||||
{
|
||||
if (keyModifiers == Keys.None)
|
||||
switch (keyData)
|
||||
{
|
||||
case Keys.Down:
|
||||
SelectNext(+1);
|
||||
return true;
|
||||
case Keys.PageDown:
|
||||
SelectNext(+10);
|
||||
return true;
|
||||
case Keys.Up:
|
||||
SelectNext(-1);
|
||||
return true;
|
||||
case Keys.PageUp:
|
||||
SelectNext(-10);
|
||||
return true;
|
||||
case Keys.Enter:
|
||||
OnSelecting();
|
||||
return true;
|
||||
case Keys.Tab:
|
||||
if (!AllowTabKey)
|
||||
break;
|
||||
OnSelecting();
|
||||
return true;
|
||||
case Keys.Escape:
|
||||
Menu.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SelectNext(int shift)
|
||||
{
|
||||
FocussedItemIndex = Math.Max(0, Math.Min(FocussedItemIndex + shift, visibleItems.Count - 1));
|
||||
DoSelectedVisible();
|
||||
//
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void DoSelectedVisible()
|
||||
{
|
||||
if (FocussedItem != null)
|
||||
SetToolTip(FocussedItem);
|
||||
|
||||
var y = FocussedItemIndex * ItemHeight - VerticalScroll.Value;
|
||||
if (y < 0)
|
||||
VerticalScroll.Value = FocussedItemIndex * ItemHeight;
|
||||
if (y > ClientSize.Height - ItemHeight)
|
||||
VerticalScroll.Value = Math.Min(VerticalScroll.Maximum, FocussedItemIndex * ItemHeight - ClientSize.Height + ItemHeight);
|
||||
//some magic for update scrolls
|
||||
AutoScrollMinSize -= new Size(1, 0);
|
||||
AutoScrollMinSize += new Size(1, 0);
|
||||
}
|
||||
|
||||
private void SetToolTip(AutocompleteItem autocompleteItem)
|
||||
{
|
||||
var title = autocompleteItem.ToolTipTitle;
|
||||
var text = autocompleteItem.ToolTipText;
|
||||
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
toolTip.ToolTipTitle = null;
|
||||
toolTip.SetToolTip(this, null);
|
||||
return;
|
||||
}
|
||||
|
||||
IWin32Window window = this.Parent ?? this;
|
||||
Point location = new Point((window == this ? Width : Right) + 3, 0);
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
toolTip.ToolTipTitle = null;
|
||||
toolTip.Show(title, window, location.X, location.Y, ToolTipDuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
toolTip.ToolTipTitle = title;
|
||||
toolTip.Show(text, window, location.X, location.Y, ToolTipDuration);
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return visibleItems.Count; }
|
||||
}
|
||||
|
||||
public void SetAutocompleteItems(ICollection<string> items)
|
||||
{
|
||||
List<AutocompleteItem> list = new List<AutocompleteItem>(items.Count);
|
||||
foreach (var item in items)
|
||||
list.Add(new AutocompleteItem(item));
|
||||
SetAutocompleteItems(list);
|
||||
}
|
||||
|
||||
public void SetAutocompleteItems(IEnumerable<AutocompleteItem> items)
|
||||
{
|
||||
sourceItems = items;
|
||||
}
|
||||
}
|
||||
|
||||
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 FastColoredTextBox Tb { get; set; }
|
||||
}
|
||||
}
|
||||
256
FastColoredTextBox/Bookmarks.cs
Normal file
256
FastColoredTextBox/Bookmarks.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for bookmark collection
|
||||
/// </summary>
|
||||
public abstract class BaseBookmarks : ICollection<Bookmark>, IDisposable
|
||||
{
|
||||
#region ICollection
|
||||
public abstract void Add(Bookmark item);
|
||||
public abstract void Clear();
|
||||
public abstract bool Contains(Bookmark item);
|
||||
public abstract void CopyTo(Bookmark[] array, int arrayIndex);
|
||||
public abstract int Count { get; }
|
||||
public abstract bool IsReadOnly { get; }
|
||||
public abstract bool Remove(Bookmark item);
|
||||
public abstract IEnumerator<Bookmark> GetEnumerator();
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public abstract void Dispose();
|
||||
#endregion
|
||||
|
||||
#region Additional properties
|
||||
|
||||
public abstract void Add(int lineIndex, string bookmarkName);
|
||||
public abstract void Add(int lineIndex);
|
||||
public abstract bool Contains(int lineIndex);
|
||||
public abstract bool Remove(int lineIndex);
|
||||
public abstract Bookmark GetBookmark(int i);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of bookmarks
|
||||
/// </summary>
|
||||
public class Bookmarks : BaseBookmarks
|
||||
{
|
||||
protected FastColoredTextBox tb;
|
||||
protected List<Bookmark> items = new List<Bookmark>();
|
||||
protected int counter;
|
||||
|
||||
public Bookmarks(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
tb.LineInserted += tb_LineInserted;
|
||||
tb.LineRemoved += tb_LineRemoved;
|
||||
}
|
||||
|
||||
protected virtual void tb_LineRemoved(object sender, LineRemovedEventArgs e)
|
||||
{
|
||||
for(int i=0; i<Count; i++)
|
||||
if (items[i].LineIndex >= e.Index)
|
||||
{
|
||||
if (items[i].LineIndex >= e.Index + e.Count)
|
||||
{
|
||||
items[i].LineIndex = items[i].LineIndex - e.Count;
|
||||
continue;
|
||||
}
|
||||
|
||||
var was = e.Index <= 0;
|
||||
foreach (var b in items)
|
||||
if (b.LineIndex == e.Index - 1)
|
||||
was = true;
|
||||
|
||||
if(was)
|
||||
{
|
||||
items.RemoveAt(i);
|
||||
i--;
|
||||
}else
|
||||
items[i].LineIndex = e.Index - 1;
|
||||
|
||||
//if (items[i].LineIndex == e.Index + e.Count - 1)
|
||||
//{
|
||||
// items[i].LineIndex = items[i].LineIndex - e.Count;
|
||||
// continue;
|
||||
//}
|
||||
//
|
||||
//items.RemoveAt(i);
|
||||
//i--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void tb_LineInserted(object sender, LineInsertedEventArgs e)
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (items[i].LineIndex >= e.Index)
|
||||
{
|
||||
items[i].LineIndex = items[i].LineIndex + e.Count;
|
||||
}else
|
||||
if (items[i].LineIndex == e.Index - 1 && e.Count == 1)
|
||||
{
|
||||
if(tb[e.Index - 1].StartSpacesCount == tb[e.Index - 1].Count)
|
||||
items[i].LineIndex = items[i].LineIndex + e.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
tb.LineInserted -= tb_LineInserted;
|
||||
tb.LineRemoved -= tb_LineRemoved;
|
||||
}
|
||||
|
||||
public override IEnumerator<Bookmark> GetEnumerator()
|
||||
{
|
||||
foreach (var item in items)
|
||||
yield return item;
|
||||
}
|
||||
|
||||
public override void Add(int lineIndex, string bookmarkName)
|
||||
{
|
||||
Add(new Bookmark(tb, bookmarkName ?? "Bookmark " + counter, lineIndex));
|
||||
}
|
||||
|
||||
public override void Add(int lineIndex)
|
||||
{
|
||||
Add(new Bookmark(tb, "Bookmark " + counter, lineIndex));
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
items.Clear();
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
public override void Add(Bookmark bookmark)
|
||||
{
|
||||
foreach (var bm in items)
|
||||
if (bm.LineIndex == bookmark.LineIndex)
|
||||
return;
|
||||
|
||||
items.Add(bookmark);
|
||||
counter++;
|
||||
tb.Invalidate();
|
||||
}
|
||||
|
||||
public override bool Contains(Bookmark item)
|
||||
{
|
||||
return items.Contains(item);
|
||||
}
|
||||
|
||||
public override bool Contains(int lineIndex)
|
||||
{
|
||||
foreach (var item in items)
|
||||
if (item.LineIndex == lineIndex)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void CopyTo(Bookmark[] array, int arrayIndex)
|
||||
{
|
||||
items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public override int Count
|
||||
{
|
||||
get { return items.Count; }
|
||||
}
|
||||
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool Remove(Bookmark item)
|
||||
{
|
||||
tb.Invalidate();
|
||||
return items.Remove(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes bookmark by line index
|
||||
/// </summary>
|
||||
public override bool Remove(int lineIndex)
|
||||
{
|
||||
bool was = false;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (items[i].LineIndex == lineIndex)
|
||||
{
|
||||
items.RemoveAt(i);
|
||||
i--;
|
||||
was = true;
|
||||
}
|
||||
tb.Invalidate();
|
||||
|
||||
return was;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Bookmark by index.
|
||||
/// </summary>
|
||||
public override Bookmark GetBookmark(int i)
|
||||
{
|
||||
return items[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bookmark of FastColoredTextbox
|
||||
/// </summary>
|
||||
public class Bookmark
|
||||
{
|
||||
public FastColoredTextBox TB { get; private set; }
|
||||
/// <summary>
|
||||
/// Name of bookmark
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Line index
|
||||
/// </summary>
|
||||
public int LineIndex {get; set; }
|
||||
/// <summary>
|
||||
/// Color of bookmark sign
|
||||
/// </summary>
|
||||
public Color Color { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scroll textbox to the bookmark
|
||||
/// </summary>
|
||||
public virtual void DoVisible()
|
||||
{
|
||||
TB.Selection.Start = new Place(0, LineIndex);
|
||||
TB.DoRangeVisible(TB.Selection, true);
|
||||
TB.Invalidate();
|
||||
}
|
||||
|
||||
public Bookmark(FastColoredTextBox tb, string name, int lineIndex)
|
||||
{
|
||||
this.TB = tb;
|
||||
this.Name = name;
|
||||
this.LineIndex = lineIndex;
|
||||
Color = tb.BookmarkColor;
|
||||
}
|
||||
|
||||
public virtual void Paint(Graphics gr, Rectangle lineRect)
|
||||
{
|
||||
var size = TB.CharHeight - 1;
|
||||
using (var brush = new LinearGradientBrush(new Rectangle(0, lineRect.Top, size, size), Color.White, Color, 45))
|
||||
gr.FillEllipse(brush, 0, lineRect.Top, size, size);
|
||||
using (var pen = new Pen(Color))
|
||||
gr.DrawEllipse(pen, 0, lineRect.Top, size, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
FastColoredTextBox/Char.cs
Normal file
26
FastColoredTextBox/Char.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Char and style
|
||||
/// </summary>
|
||||
public struct Char
|
||||
{
|
||||
/// <summary>
|
||||
/// Unicode character
|
||||
/// </summary>
|
||||
public char c;
|
||||
/// <summary>
|
||||
/// Style bit mask
|
||||
/// </summary>
|
||||
/// <remarks>Bit 1 in position n means that this char will rendering by FastColoredTextBox.Styles[n]</remarks>
|
||||
public StyleIndex style;
|
||||
|
||||
public Char(char c)
|
||||
{
|
||||
this.c = c;
|
||||
style = StyleIndex.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
239
FastColoredTextBox/CommandManager.cs
Normal file
239
FastColoredTextBox/CommandManager.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class CommandManager
|
||||
{
|
||||
readonly int maxHistoryLength = 200;
|
||||
LimitedStack<UndoableCommand> history;
|
||||
Stack<UndoableCommand> redoStack = new Stack<UndoableCommand>();
|
||||
public TextSource TextSource{ get; private set; }
|
||||
public bool UndoRedoStackIsEnabled { get; set; }
|
||||
|
||||
public CommandManager(TextSource ts)
|
||||
{
|
||||
history = new LimitedStack<UndoableCommand>(maxHistoryLength);
|
||||
TextSource = ts;
|
||||
UndoRedoStackIsEnabled = true;
|
||||
}
|
||||
|
||||
public virtual void ExecuteCommand(Command cmd)
|
||||
{
|
||||
if (disabledCommands > 0)
|
||||
return;
|
||||
|
||||
//multirange ?
|
||||
if (cmd.ts.CurrentTB.Selection.ColumnSelectionMode)
|
||||
if (cmd is UndoableCommand)
|
||||
//make wrapper
|
||||
cmd = new MultiRangeCommand((UndoableCommand)cmd);
|
||||
|
||||
|
||||
if (cmd is UndoableCommand)
|
||||
{
|
||||
//if range is ColumnRange, then create wrapper
|
||||
(cmd as UndoableCommand).autoUndo = autoUndoCommands > 0;
|
||||
history.Push(cmd as UndoableCommand);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
cmd.Execute();
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
//OnTextChanging cancels enter of the text
|
||||
if (cmd is UndoableCommand)
|
||||
history.Pop();
|
||||
}
|
||||
//
|
||||
if (!UndoRedoStackIsEnabled)
|
||||
ClearHistory();
|
||||
//
|
||||
redoStack.Clear();
|
||||
//
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (history.Count > 0)
|
||||
{
|
||||
var cmd = history.Pop();
|
||||
//
|
||||
BeginDisableCommands();//prevent text changing into handlers
|
||||
try
|
||||
{
|
||||
cmd.Undo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndDisableCommands();
|
||||
}
|
||||
//
|
||||
redoStack.Push(cmd);
|
||||
}
|
||||
|
||||
//undo next autoUndo command
|
||||
if (history.Count > 0)
|
||||
{
|
||||
if (history.Peek().autoUndo)
|
||||
Undo();
|
||||
}
|
||||
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
protected int disabledCommands = 0;
|
||||
|
||||
private void EndDisableCommands()
|
||||
{
|
||||
disabledCommands--;
|
||||
}
|
||||
|
||||
private void BeginDisableCommands()
|
||||
{
|
||||
disabledCommands++;
|
||||
}
|
||||
|
||||
int autoUndoCommands = 0;
|
||||
|
||||
public void EndAutoUndoCommands()
|
||||
{
|
||||
autoUndoCommands--;
|
||||
if (autoUndoCommands == 0)
|
||||
if (history.Count > 0)
|
||||
history.Peek().autoUndo = false;
|
||||
}
|
||||
|
||||
public void BeginAutoUndoCommands()
|
||||
{
|
||||
autoUndoCommands++;
|
||||
}
|
||||
|
||||
internal void ClearHistory()
|
||||
{
|
||||
history.Clear();
|
||||
redoStack.Clear();
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
internal void Redo()
|
||||
{
|
||||
if (redoStack.Count == 0)
|
||||
return;
|
||||
UndoableCommand cmd;
|
||||
BeginDisableCommands();//prevent text changing into handlers
|
||||
try
|
||||
{
|
||||
cmd = redoStack.Pop();
|
||||
if (TextSource.CurrentTB.Selection.ColumnSelectionMode)
|
||||
TextSource.CurrentTB.Selection.ColumnSelectionMode = false;
|
||||
TextSource.CurrentTB.Selection.Start = cmd.sel.Start;
|
||||
TextSource.CurrentTB.Selection.End = cmd.sel.End;
|
||||
cmd.Execute();
|
||||
history.Push(cmd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndDisableCommands();
|
||||
}
|
||||
|
||||
//redo command after autoUndoable command
|
||||
if (cmd.autoUndo)
|
||||
Redo();
|
||||
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
public bool UndoEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return history.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RedoEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return redoStack.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Command
|
||||
{
|
||||
public TextSource ts;
|
||||
public abstract void Execute();
|
||||
}
|
||||
|
||||
internal class RangeInfo
|
||||
{
|
||||
public Place Start { get; set; }
|
||||
public Place End { get; set; }
|
||||
|
||||
public RangeInfo(Range r)
|
||||
{
|
||||
Start = r.Start;
|
||||
End = r.End;
|
||||
}
|
||||
|
||||
internal int FromX
|
||||
{
|
||||
get
|
||||
{
|
||||
if (End.iLine < Start.iLine) return End.iChar;
|
||||
if (End.iLine > Start.iLine) return Start.iChar;
|
||||
return Math.Min(End.iChar, Start.iChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class UndoableCommand : Command
|
||||
{
|
||||
internal RangeInfo sel;
|
||||
internal RangeInfo lastSel;
|
||||
internal bool autoUndo;
|
||||
|
||||
public UndoableCommand(TextSource ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
public virtual void Undo()
|
||||
{
|
||||
OnTextChanged(true);
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
lastSel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
OnTextChanged(false);
|
||||
}
|
||||
|
||||
protected virtual void OnTextChanged(bool invert)
|
||||
{
|
||||
bool b = sel.Start.iLine < lastSel.Start.iLine;
|
||||
if (invert)
|
||||
{
|
||||
if (b)
|
||||
ts.OnTextChanged(sel.Start.iLine, sel.Start.iLine);
|
||||
else
|
||||
ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b)
|
||||
ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);
|
||||
else
|
||||
ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract UndoableCommand Clone();
|
||||
}
|
||||
}
|
||||
809
FastColoredTextBox/Commands.cs
Normal file
809
FastColoredTextBox/Commands.cs
Normal file
@@ -0,0 +1,809 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Insert single char
|
||||
/// </summary>
|
||||
/// <remarks>This operation includes also insertion of new line and removing char by backspace</remarks>
|
||||
public class InsertCharCommand : UndoableCommand
|
||||
{
|
||||
public char c;
|
||||
char deletedChar = '\x0';
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="c">Inserting char</param>
|
||||
public InsertCharCommand(TextSource ts, char c): base(ts)
|
||||
{
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.OnTextChanging();
|
||||
switch (c)
|
||||
{
|
||||
case '\n': MergeLines(sel.Start.iLine, ts); break;
|
||||
case '\r': break;
|
||||
case '\b':
|
||||
ts.CurrentTB.Selection.Start = lastSel.Start;
|
||||
char cc = '\x0';
|
||||
if (deletedChar != '\x0')
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
InsertChar(deletedChar, ref cc, ts);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
for (int i = sel.FromX; i < lastSel.FromX; i++)
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
default:
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
}
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(sel.Start.iLine, sel.Start.iLine));
|
||||
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
string s = c.ToString();
|
||||
ts.OnTextChanging(ref s);
|
||||
if (s.Length == 1)
|
||||
c = s[0];
|
||||
|
||||
if (String.IsNullOrEmpty(s))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertChar(c, ref deletedChar, ts);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(ts.CurrentTB.Selection.Start.iLine, ts.CurrentTB.Selection.Start.iLine));
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertChar(char c, ref char deletedChar, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertLine(ts);
|
||||
break;
|
||||
case '\r': break;
|
||||
case '\b'://backspace
|
||||
if (tb.Selection.Start.iChar == 0 && tb.Selection.Start.iLine == 0)
|
||||
return;
|
||||
if (tb.Selection.Start.iChar == 0)
|
||||
{
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (tb.LineInfos[tb.Selection.Start.iLine - 1].VisibleState != VisibleState.Visible)
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine - 1);
|
||||
deletedChar = '\n';
|
||||
MergeLines(tb.Selection.Start.iLine - 1, ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
deletedChar = ts[tb.Selection.Start.iLine][tb.Selection.Start.iChar - 1].c;
|
||||
ts[tb.Selection.Start.iLine].RemoveAt(tb.Selection.Start.iChar - 1);
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar - 1, tb.Selection.Start.iLine);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
int spaceCountNextTabStop = tb.TabLength - (tb.Selection.Start.iChar % tb.TabLength);
|
||||
if (spaceCountNextTabStop == 0)
|
||||
spaceCountNextTabStop = tb.TabLength;
|
||||
|
||||
for (int i = 0; i < spaceCountNextTabStop; i++)
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(' '));
|
||||
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + spaceCountNextTabStop, tb.Selection.Start.iLine);
|
||||
break;
|
||||
default:
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(c));
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + 1, tb.Selection.Start.iLine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InsertLine(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (!tb.Multiline && tb.LinesCount > 0)
|
||||
return;
|
||||
|
||||
if (ts.Count == 0)
|
||||
ts.InsertLine(0, ts.CreateLine());
|
||||
else
|
||||
BreakLines(tb.Selection.Start.iLine, tb.Selection.Start.iChar, ts);
|
||||
|
||||
tb.Selection.Start = new Place(0, tb.Selection.Start.iLine + 1);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merge lines i and i+1
|
||||
/// </summary>
|
||||
internal static void MergeLines(int i, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (i + 1 >= ts.Count)
|
||||
return;
|
||||
tb.ExpandBlock(i);
|
||||
tb.ExpandBlock(i + 1);
|
||||
int pos = ts[i].Count;
|
||||
//
|
||||
/*
|
||||
if(ts[i].Count == 0)
|
||||
ts.RemoveLine(i);
|
||||
else*/
|
||||
if (ts[i + 1].Count == 0)
|
||||
ts.RemoveLine(i + 1);
|
||||
else
|
||||
{
|
||||
ts[i].AddRange(ts[i + 1]);
|
||||
ts.RemoveLine(i + 1);
|
||||
}
|
||||
tb.Selection.Start = new Place(pos, i);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
internal static void BreakLines(int iLine, int pos, TextSource ts)
|
||||
{
|
||||
Line newLine = ts.CreateLine();
|
||||
for(int i=pos;i<ts[iLine].Count;i++)
|
||||
newLine.Add(ts[iLine][i]);
|
||||
ts[iLine].RemoveRange(pos, ts[iLine].Count - pos);
|
||||
//
|
||||
ts.InsertLine(iLine+1, newLine);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertCharCommand(ts, c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text
|
||||
/// </summary>
|
||||
public class InsertTextCommand : UndoableCommand
|
||||
{
|
||||
public string InsertedText;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public InsertTextCommand(TextSource ts, string insertedText): base(ts)
|
||||
{
|
||||
this.InsertedText = insertedText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = lastSel.Start;
|
||||
ts.OnTextChanging();
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.OnTextChanging(ref InsertedText);
|
||||
InsertText(InsertedText, ts);
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertText(string insertedText, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
try
|
||||
{
|
||||
tb.Selection.BeginUpdate();
|
||||
char cc = '\x0';
|
||||
|
||||
if (ts.Count == 0)
|
||||
{
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = Place.Empty;
|
||||
}
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine);
|
||||
var len = insertedText.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var c = insertedText[i];
|
||||
if(c == '\r' && (i >= len - 1 || insertedText[i + 1] != '\n'))
|
||||
InsertCharCommand.InsertChar('\n', ref cc, ts);
|
||||
else
|
||||
InsertCharCommand.InsertChar(c, ref cc, ts);
|
||||
}
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
finally {
|
||||
tb.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertTextCommand(ts, InsertedText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text into given ranges
|
||||
/// </summary>
|
||||
public class ReplaceTextCommand : UndoableCommand
|
||||
{
|
||||
string insertedText;
|
||||
List<Range> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public ReplaceTextCommand(TextSource ts, List<Range> ranges, string insertedText)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2)=>
|
||||
{
|
||||
if (r1.Start.iLine == r2.Start.iLine)
|
||||
return r1.Start.iChar.CompareTo(r2.Start.iChar);
|
||||
return r1.Start.iLine.CompareTo(r2.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
this.insertedText = insertedText;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
tb.BeginUpdate();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i<ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
for (int j = 0; j < insertedText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(prevText[prevText.Count - i - 1], ts);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
tb.EndUpdate();
|
||||
|
||||
if (ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging(ref insertedText);
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
tb.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
tb.Selection.End = ranges[i].End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelected(ts);
|
||||
if (insertedText != "")
|
||||
InsertTextCommand.InsertText(insertedText, ts);
|
||||
}
|
||||
if(ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceTextCommand(ts, new List<Range>(ranges), insertedText);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
tb.Selection.Normalize();
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear selected text
|
||||
/// </summary>
|
||||
public class ClearSelectedCommand : UndoableCommand
|
||||
{
|
||||
string deletedText;
|
||||
|
||||
/// <summary>
|
||||
/// Construstor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
public ClearSelectedCommand(TextSource ts): base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(sel.FromX, Math.Min(sel.Start.iLine, sel.End.iLine));
|
||||
ts.OnTextChanging();
|
||||
InsertTextCommand.InsertText(deletedText, ts);
|
||||
ts.OnTextChanged(sel.Start.iLine, sel.End.iLine);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = sel.End;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
string temp = null;
|
||||
ts.OnTextChanging(ref temp);
|
||||
if (temp == "")
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
deletedText = tb.Selection.Text;
|
||||
ClearSelected(ts);
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
//
|
||||
tb.Selection.Start = new Place(fromChar, fromLine);
|
||||
//
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(fromLine, toLine));
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ClearSelectedCommand(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces text
|
||||
/// </summary>
|
||||
public class ReplaceMultipleTextCommand : UndoableCommand
|
||||
{
|
||||
List<ReplaceRange> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
public class ReplaceRange
|
||||
{
|
||||
public Range ReplacedRange { get; set; }
|
||||
public String ReplaceText { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="ts">Underlaying textsource</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
public ReplaceMultipleTextCommand(TextSource ts, List<ReplaceRange> ranges)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2) =>
|
||||
{
|
||||
if (r1.ReplacedRange.Start.iLine == r2.ReplacedRange.Start.iLine)
|
||||
return r1.ReplacedRange.Start.iChar.CompareTo(r2.ReplacedRange.Start.iChar);
|
||||
return r1.ReplacedRange.Start.iLine.CompareTo(r2.ReplacedRange.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i < ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
for (int j = 0; j < ranges[i].ReplaceText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
var prevTextIndex = ranges.Count - 1 - i;
|
||||
InsertTextCommand.InsertText(prevText[prevTextIndex], ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.Start.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
tb.Selection.End = ranges[i].ReplacedRange.End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(ranges[i].ReplaceText, ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.End.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceMultipleTextCommand(ts, new List<ReplaceRange>(ranges));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes lines
|
||||
/// </summary>
|
||||
public class RemoveLinesCommand : UndoableCommand
|
||||
{
|
||||
List<int> iLines;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public RemoveLinesCommand(TextSource ts, List<int> iLines)
|
||||
: base(ts)
|
||||
{
|
||||
//sort iLines
|
||||
iLines.Sort();
|
||||
//
|
||||
this.iLines = iLines;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
//tb.BeginUpdate();
|
||||
for (int i = 0; i < iLines.Count; i++)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
if(iLine < ts.Count)
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
else
|
||||
tb.Selection.Start = new Place(ts[ts.Count - 1].Count, ts.Count - 1);
|
||||
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
var text = prevText[prevText.Count - i - 1];
|
||||
InsertTextCommand.InsertText(text, ts);
|
||||
ts[iLine].IsChanged = true;
|
||||
if (iLine < ts.Count - 1)
|
||||
ts[iLine + 1].IsChanged = true;
|
||||
else
|
||||
ts[iLine - 1].IsChanged = true;
|
||||
if(text.Trim() != string.Empty)
|
||||
ts.OnTextChanged(iLine, iLine);
|
||||
}
|
||||
//tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for(int i = iLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
prevText.Add(ts[iLine].Text);//backward
|
||||
ts.RemoveLine(iLine);
|
||||
//ts.OnTextChanged(ranges[i].Start.iLine, ranges[i].End.iLine);
|
||||
}
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new RemoveLinesCommand(ts, new List<int>(iLines));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for multirange commands
|
||||
/// </summary>
|
||||
public class MultiRangeCommand : UndoableCommand
|
||||
{
|
||||
private UndoableCommand cmd;
|
||||
private Range range;
|
||||
private List<UndoableCommand> commandsByRanges = new List<UndoableCommand>();
|
||||
|
||||
public MultiRangeCommand(UndoableCommand command):base(command.ts)
|
||||
{
|
||||
this.cmd = command;
|
||||
range = ts.CurrentTB.Selection.Clone();
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
commandsByRanges.Clear();
|
||||
var prevSelection = range.Clone();
|
||||
var iChar = -1;
|
||||
var iStartLine = prevSelection.Start.iLine;
|
||||
var iEndLine = prevSelection.End.iLine;
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = false;
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.AllowInsertRemoveLines = false;
|
||||
try
|
||||
{
|
||||
if (cmd is InsertTextCommand)
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertTextCommand).InsertedText);
|
||||
else
|
||||
if (cmd is InsertCharCommand && (cmd as InsertCharCommand).c != '\x0' && (cmd as InsertCharCommand).c != '\b')//if not DEL or BACKSPACE
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertCharCommand).c.ToString());
|
||||
else
|
||||
ExecuteCommand(ref iChar);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.AllowInsertRemoveLines = true;
|
||||
ts.CurrentTB.EndUpdate();
|
||||
|
||||
ts.CurrentTB.Selection = range;
|
||||
if (iChar >= 0)
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(iChar, iStartLine);
|
||||
ts.CurrentTB.Selection.End = new Place(iChar, iEndLine);
|
||||
}
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteInsertTextCommand(ref int iChar, string text)
|
||||
{
|
||||
var lines = text.Split('\n');
|
||||
var iLine = 0;
|
||||
foreach (var r in range.GetSubRanges(true))
|
||||
{
|
||||
var line = ts.CurrentTB[r.Start.iLine];
|
||||
var lineIsEmpty = r.End < r.Start && line.StartSpacesCount == line.Count;
|
||||
if (!lineIsEmpty)
|
||||
{
|
||||
var insertedText = lines[iLine%lines.Length];
|
||||
if (r.End < r.Start && insertedText!="")
|
||||
{
|
||||
//add forwarding spaces
|
||||
insertedText = new string(' ', r.Start.iChar - r.End.iChar) + insertedText;
|
||||
r.Start = r.End;
|
||||
}
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = new InsertTextCommand(ts, insertedText);
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
iLine++;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteCommand(ref int iChar)
|
||||
{
|
||||
foreach (var r in range.GetSubRanges(false))
|
||||
{
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = cmd.Clone();
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
try
|
||||
{
|
||||
for (int i = commandsByRanges.Count - 1; i >= 0; i--)
|
||||
commandsByRanges[i].Undo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
ts.CurrentTB.EndUpdate();
|
||||
}
|
||||
ts.CurrentTB.Selection = range.Clone();
|
||||
ts.CurrentTB.OnTextChanged(range);
|
||||
ts.CurrentTB.OnSelectionChanged();
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remembers current selection and restore it after Undo
|
||||
/// </summary>
|
||||
public class SelectCommand : UndoableCommand
|
||||
{
|
||||
public SelectCommand(TextSource ts):base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
//remember selection
|
||||
lastSel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(bool invert)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
//restore selection
|
||||
ts.CurrentTB.Selection = new Range(ts.CurrentTB, lastSel.Start, lastSel.End);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
var result = new SelectCommand(ts);
|
||||
if(lastSel!=null)
|
||||
result.lastSel = new RangeInfo(new Range(ts.CurrentTB, lastSel.Start, lastSel.End));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
250
FastColoredTextBox/DocumentMap.cs
Normal file
250
FastColoredTextBox/DocumentMap.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows document map of FCTB
|
||||
/// </summary>
|
||||
public class DocumentMap : Control
|
||||
{
|
||||
public EventHandler TargetChanged;
|
||||
|
||||
FastColoredTextBox target;
|
||||
private float scale = 0.3f;
|
||||
private bool needRepaint = true;
|
||||
private Place startPlace = Place.Empty;
|
||||
private bool scrollbarVisible = true;
|
||||
|
||||
[Description("Target FastColoredTextBox")]
|
||||
public FastColoredTextBox Target
|
||||
{
|
||||
get { return target; }
|
||||
set
|
||||
{
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
|
||||
target = value;
|
||||
if (value != null)
|
||||
{
|
||||
Subscribe(target);
|
||||
}
|
||||
OnTargetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale
|
||||
/// </summary>
|
||||
[Description("Scale")]
|
||||
[DefaultValue(0.3f)]
|
||||
public float Scale
|
||||
{
|
||||
get { return scale; }
|
||||
set
|
||||
{
|
||||
scale = value;
|
||||
NeedRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrollbar visibility
|
||||
/// </summary>
|
||||
[Description("Scrollbar visibility")]
|
||||
[DefaultValue(true)]
|
||||
public bool ScrollbarVisible
|
||||
{
|
||||
get { return scrollbarVisible; }
|
||||
set
|
||||
{
|
||||
scrollbarVisible = value;
|
||||
NeedRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentMap()
|
||||
{
|
||||
ForeColor = Color.Maroon;
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true);
|
||||
Application.Idle += Application_Idle;
|
||||
}
|
||||
|
||||
void Application_Idle(object sender, EventArgs e)
|
||||
{
|
||||
if(needRepaint)
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected virtual void OnTargetChanged()
|
||||
{
|
||||
NeedRepaint();
|
||||
|
||||
if (TargetChanged != null)
|
||||
TargetChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void UnSubscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll -= new ScrollEventHandler(Target_Scroll);
|
||||
target.SelectionChangedDelayed -= new EventHandler(Target_SelectionChanged);
|
||||
target.VisibleRangeChanged -= new EventHandler(Target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Subscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll += new ScrollEventHandler(Target_Scroll);
|
||||
target.SelectionChangedDelayed += new EventHandler(Target_SelectionChanged);
|
||||
target.VisibleRangeChanged += new EventHandler(Target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Target_VisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected virtual void Target_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected virtual void Target_Scroll(object sender, ScrollEventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
public void NeedRepaint()
|
||||
{
|
||||
needRepaint = true;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
var zoom = this.Scale * 100 / target.Zoom;
|
||||
|
||||
if (zoom <= float.Epsilon)
|
||||
return;
|
||||
|
||||
//calc startPlace
|
||||
var r = target.VisibleRange;
|
||||
if (startPlace.iLine > r.Start.iLine)
|
||||
startPlace.iLine = r.Start.iLine;
|
||||
else
|
||||
{
|
||||
var endP = target.PlaceToPoint(r.End);
|
||||
endP.Offset(0, -(int)(ClientSize.Height / zoom) + target.CharHeight);
|
||||
var pp = target.PointToPlace(endP);
|
||||
if (pp.iLine > startPlace.iLine)
|
||||
startPlace.iLine = pp.iLine;
|
||||
}
|
||||
startPlace.iChar = 0;
|
||||
//calc scroll pos
|
||||
var linesCount = target.Lines.Count;
|
||||
var sp1 = (float)r.Start.iLine / linesCount;
|
||||
var sp2 = (float)r.End.iLine / linesCount;
|
||||
|
||||
//scale graphics
|
||||
e.Graphics.ScaleTransform(zoom, zoom);
|
||||
//draw text
|
||||
var size = new SizeF(ClientSize.Width / zoom, ClientSize.Height / zoom);
|
||||
target.DrawText(e.Graphics, startPlace, size.ToSize());
|
||||
|
||||
//draw visible rect
|
||||
var p0 = target.PlaceToPoint(startPlace);
|
||||
var p1 = target.PlaceToPoint(r.Start);
|
||||
var p2 = target.PlaceToPoint(r.End);
|
||||
var y1 = p1.Y - p0.Y;
|
||||
var y2 = p2.Y + target.CharHeight - p0.Y;
|
||||
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
using (var brush = new SolidBrush(Color.FromArgb(50, ForeColor)))
|
||||
using (var pen = new Pen(brush, 1 / zoom))
|
||||
{
|
||||
var rect = new Rectangle(0, y1, (int)((ClientSize.Width - 1) / zoom), y2 - y1);
|
||||
e.Graphics.FillRectangle(brush, rect);
|
||||
e.Graphics.DrawRectangle(pen, rect);
|
||||
}
|
||||
|
||||
//draw scrollbar
|
||||
if (scrollbarVisible)
|
||||
{
|
||||
e.Graphics.ResetTransform();
|
||||
e.Graphics.SmoothingMode = SmoothingMode.None;
|
||||
|
||||
using (var brush = new SolidBrush(Color.FromArgb(200, ForeColor)))
|
||||
{
|
||||
var rect = new RectangleF(ClientSize.Width - 3, ClientSize.Height*sp1, 2,
|
||||
ClientSize.Height*(sp2 - sp1));
|
||||
e.Graphics.FillRectangle(brush, rect);
|
||||
}
|
||||
}
|
||||
|
||||
needRepaint = false;
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
Scroll(e.Location);
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
Scroll(e.Location);
|
||||
base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
private void Scroll(Point point)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
var zoom = this.Scale*100/target.Zoom;
|
||||
|
||||
if (zoom <= float.Epsilon)
|
||||
return;
|
||||
|
||||
var p0 = target.PlaceToPoint(startPlace);
|
||||
p0 = new Point(0, p0.Y + (int) (point.Y/zoom));
|
||||
var pp = target.PointToPlace(p0);
|
||||
target.DoRangeVisible(new Range(target, pp, pp), true);
|
||||
BeginInvoke((MethodInvoker)OnScroll);
|
||||
}
|
||||
|
||||
private void OnScroll()
|
||||
{
|
||||
Refresh();
|
||||
target.Refresh();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Application.Idle -= Application_Idle;
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
363
FastColoredTextBox/EncodingDetector.cs
Normal file
363
FastColoredTextBox/EncodingDetector.cs
Normal file
@@ -0,0 +1,363 @@
|
||||
// Copyright Tao Klerks, 2010-2012, tao@klerks.biz
|
||||
// Licensed under the modified BSD license.
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public static class EncodingDetector
|
||||
{
|
||||
const long _defaultHeuristicSampleSize = 0x10000; //completely arbitrary - inappropriate for high numbers of files / high speed requirements
|
||||
|
||||
public static Encoding DetectTextFileEncoding(string InputFilename)
|
||||
{
|
||||
using (FileStream textfileStream = File.OpenRead(InputFilename))
|
||||
{
|
||||
return DetectTextFileEncoding(textfileStream, _defaultHeuristicSampleSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize)
|
||||
{
|
||||
bool uselessBool = false;
|
||||
return DetectTextFileEncoding(InputFileStream, _defaultHeuristicSampleSize, out uselessBool);
|
||||
}
|
||||
|
||||
public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize, out bool HasBOM)
|
||||
{
|
||||
Encoding encodingFound = null;
|
||||
|
||||
long originalPos = InputFileStream.Position;
|
||||
|
||||
InputFileStream.Position = 0;
|
||||
|
||||
|
||||
//First read only what we need for BOM detection
|
||||
byte[] bomBytes = new byte[InputFileStream.Length > 4 ? 4 : InputFileStream.Length];
|
||||
InputFileStream.Read(bomBytes, 0, bomBytes.Length);
|
||||
|
||||
encodingFound = DetectBOMBytes(bomBytes);
|
||||
|
||||
if (encodingFound != null)
|
||||
{
|
||||
InputFileStream.Position = originalPos;
|
||||
HasBOM = true;
|
||||
return encodingFound;
|
||||
}
|
||||
|
||||
|
||||
//BOM Detection failed, going for heuristics now.
|
||||
// create sample byte array and populate it
|
||||
byte[] sampleBytes = new byte[HeuristicSampleSize > InputFileStream.Length ? InputFileStream.Length : HeuristicSampleSize];
|
||||
Array.Copy(bomBytes, sampleBytes, bomBytes.Length);
|
||||
if (InputFileStream.Length > bomBytes.Length)
|
||||
InputFileStream.Read(sampleBytes, bomBytes.Length, sampleBytes.Length - bomBytes.Length);
|
||||
InputFileStream.Position = originalPos;
|
||||
|
||||
//test byte array content
|
||||
encodingFound = DetectUnicodeInByteSampleByHeuristics(sampleBytes);
|
||||
|
||||
HasBOM = false;
|
||||
return encodingFound;
|
||||
}
|
||||
|
||||
public static Encoding DetectBOMBytes(byte[] BOMBytes)
|
||||
{
|
||||
if (BOMBytes.Length < 2)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xff
|
||||
&& BOMBytes[1] == 0xfe
|
||||
&& (BOMBytes.Length < 4
|
||||
|| BOMBytes[2] != 0
|
||||
|| BOMBytes[3] != 0
|
||||
)
|
||||
)
|
||||
return Encoding.Unicode;
|
||||
|
||||
if (BOMBytes[0] == 0xfe
|
||||
&& BOMBytes[1] == 0xff
|
||||
)
|
||||
return Encoding.BigEndianUnicode;
|
||||
|
||||
if (BOMBytes.Length < 3)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xef && BOMBytes[1] == 0xbb && BOMBytes[2] == 0xbf)
|
||||
return Encoding.UTF8;
|
||||
|
||||
if (BOMBytes[0] == 0x2b && BOMBytes[1] == 0x2f && BOMBytes[2] == 0x76)
|
||||
return Encoding.UTF7;
|
||||
|
||||
if (BOMBytes.Length < 4)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xff && BOMBytes[1] == 0xfe && BOMBytes[2] == 0 && BOMBytes[3] == 0)
|
||||
return Encoding.UTF32;
|
||||
|
||||
if (BOMBytes[0] == 0 && BOMBytes[1] == 0 && BOMBytes[2] == 0xfe && BOMBytes[3] == 0xff)
|
||||
return Encoding.GetEncoding(12001);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Encoding DetectUnicodeInByteSampleByHeuristics(byte[] SampleBytes)
|
||||
{
|
||||
long oddBinaryNullsInSample = 0;
|
||||
long evenBinaryNullsInSample = 0;
|
||||
long suspiciousUTF8SequenceCount = 0;
|
||||
long suspiciousUTF8BytesTotal = 0;
|
||||
long likelyUSASCIIBytesInSample = 0;
|
||||
|
||||
//Cycle through, keeping count of binary null positions, possible UTF-8
|
||||
// sequences from upper ranges of Windows-1252, and probable US-ASCII
|
||||
// character counts.
|
||||
|
||||
long currentPos = 0;
|
||||
int skipUTF8Bytes = 0;
|
||||
|
||||
while (currentPos < SampleBytes.Length)
|
||||
{
|
||||
//binary null distribution
|
||||
if (SampleBytes[currentPos] == 0)
|
||||
{
|
||||
if (currentPos % 2 == 0)
|
||||
evenBinaryNullsInSample++;
|
||||
else
|
||||
oddBinaryNullsInSample++;
|
||||
}
|
||||
|
||||
//likely US-ASCII characters
|
||||
if (IsCommonUSASCIIByte(SampleBytes[currentPos]))
|
||||
likelyUSASCIIBytesInSample++;
|
||||
|
||||
//suspicious sequences (look like UTF-8)
|
||||
if (skipUTF8Bytes == 0)
|
||||
{
|
||||
int lengthFound = DetectSuspiciousUTF8SequenceLength(SampleBytes, currentPos);
|
||||
|
||||
if (lengthFound > 0)
|
||||
{
|
||||
suspiciousUTF8SequenceCount++;
|
||||
suspiciousUTF8BytesTotal += lengthFound;
|
||||
skipUTF8Bytes = lengthFound - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skipUTF8Bytes--;
|
||||
}
|
||||
|
||||
currentPos++;
|
||||
}
|
||||
|
||||
//1: UTF-16 LE - in english / european environments, this is usually characterized by a
|
||||
// high proportion of odd binary nulls (starting at 0), with (as this is text) a low
|
||||
// proportion of even binary nulls.
|
||||
// The thresholds here used (less than 20% nulls where you expect non-nulls, and more than
|
||||
// 60% nulls where you do expect nulls) are completely arbitrary.
|
||||
|
||||
if (((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2
|
||||
&& ((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6
|
||||
)
|
||||
return Encoding.Unicode;
|
||||
|
||||
|
||||
//2: UTF-16 BE - in english / european environments, this is usually characterized by a
|
||||
// high proportion of even binary nulls (starting at 0), with (as this is text) a low
|
||||
// proportion of odd binary nulls.
|
||||
// The thresholds here used (less than 20% nulls where you expect non-nulls, and more than
|
||||
// 60% nulls where you do expect nulls) are completely arbitrary.
|
||||
|
||||
if (((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2
|
||||
&& ((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6
|
||||
)
|
||||
return Encoding.BigEndianUnicode;
|
||||
|
||||
|
||||
//3: UTF-8 - Martin Dürst outlines a method for detecting whether something CAN be UTF-8 content
|
||||
// using regexp, in his w3c.org unicode FAQ entry:
|
||||
// http://www.w3.org/International/questions/qa-forms-utf-8
|
||||
// adapted here for C#.
|
||||
string potentiallyMangledString = Encoding.ASCII.GetString(SampleBytes);
|
||||
Regex UTF8Validator = new Regex(@"\A("
|
||||
+ @"[\x09\x0A\x0D\x20-\x7E]"
|
||||
+ @"|[\xC2-\xDF][\x80-\xBF]"
|
||||
+ @"|\xE0[\xA0-\xBF][\x80-\xBF]"
|
||||
+ @"|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}"
|
||||
+ @"|\xED[\x80-\x9F][\x80-\xBF]"
|
||||
+ @"|\xF0[\x90-\xBF][\x80-\xBF]{2}"
|
||||
+ @"|[\xF1-\xF3][\x80-\xBF]{3}"
|
||||
+ @"|\xF4[\x80-\x8F][\x80-\xBF]{2}"
|
||||
+ @")*\z");
|
||||
if (UTF8Validator.IsMatch(potentiallyMangledString))
|
||||
{
|
||||
//Unfortunately, just the fact that it CAN be UTF-8 doesn't tell you much about probabilities.
|
||||
//If all the characters are in the 0-127 range, no harm done, most western charsets are same as UTF-8 in these ranges.
|
||||
//If some of the characters were in the upper range (western accented characters), however, they would likely be mangled to 2-byte by the UTF-8 encoding process.
|
||||
// So, we need to play stats.
|
||||
|
||||
// The "Random" likelihood of any pair of randomly generated characters being one
|
||||
// of these "suspicious" character sequences is:
|
||||
// 128 / (256 * 256) = 0.2%.
|
||||
//
|
||||
// In western text data, that is SIGNIFICANTLY reduced - most text data stays in the <127
|
||||
// character range, so we assume that more than 1 in 500,000 of these character
|
||||
// sequences indicates UTF-8. The number 500,000 is completely arbitrary - so sue me.
|
||||
//
|
||||
// We can only assume these character sequences will be rare if we ALSO assume that this
|
||||
// IS in fact western text - in which case the bulk of the UTF-8 encoded data (that is
|
||||
// not already suspicious sequences) should be plain US-ASCII bytes. This, I
|
||||
// arbitrarily decided, should be 80% (a random distribution, eg binary data, would yield
|
||||
// approx 40%, so the chances of hitting this threshold by accident in random data are
|
||||
// VERY low).
|
||||
|
||||
if ((suspiciousUTF8SequenceCount * 500000.0 / SampleBytes.Length >= 1) //suspicious sequences
|
||||
&& (
|
||||
//all suspicious, so cannot evaluate proportion of US-Ascii
|
||||
SampleBytes.Length - suspiciousUTF8BytesTotal == 0
|
||||
||
|
||||
likelyUSASCIIBytesInSample * 1.0 / (SampleBytes.Length - suspiciousUTF8BytesTotal) >= 0.8
|
||||
)
|
||||
)
|
||||
return Encoding.UTF8;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsCommonUSASCIIByte(byte testByte)
|
||||
{
|
||||
if (testByte == 0x0A //lf
|
||||
|| testByte == 0x0D //cr
|
||||
|| testByte == 0x09 //tab
|
||||
|| (testByte >= 0x20 && testByte <= 0x2F) //common punctuation
|
||||
|| (testByte >= 0x30 && testByte <= 0x39) //digits
|
||||
|| (testByte >= 0x3A && testByte <= 0x40) //common punctuation
|
||||
|| (testByte >= 0x41 && testByte <= 0x5A) //capital letters
|
||||
|| (testByte >= 0x5B && testByte <= 0x60) //common punctuation
|
||||
|| (testByte >= 0x61 && testByte <= 0x7A) //lowercase letters
|
||||
|| (testByte >= 0x7B && testByte <= 0x7E) //common punctuation
|
||||
)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int DetectSuspiciousUTF8SequenceLength(byte[] SampleBytes, long currentPos)
|
||||
{
|
||||
int lengthFound = 0;
|
||||
|
||||
if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC2
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x81
|
||||
|| SampleBytes[currentPos + 1] == 0x8D
|
||||
|| SampleBytes[currentPos + 1] == 0x8F
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0x90
|
||||
|| SampleBytes[currentPos + 1] == 0x9D
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] >= 0xA0
|
||||
&& SampleBytes[currentPos + 1] <= 0xBF
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC3
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] >= 0x80
|
||||
&& SampleBytes[currentPos + 1] <= 0xBF
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC5
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x92
|
||||
|| SampleBytes[currentPos + 1] == 0x93
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0xA0
|
||||
|| SampleBytes[currentPos + 1] == 0xA1
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0xB8
|
||||
|| SampleBytes[currentPos + 1] == 0xBD
|
||||
|| SampleBytes[currentPos + 1] == 0xBE
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC6
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x92)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xCB
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x86
|
||||
|| SampleBytes[currentPos + 1] == 0x9C
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 2
|
||||
&& SampleBytes[currentPos] == 0xE2
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x80)
|
||||
{
|
||||
if (SampleBytes[currentPos + 2] == 0x93
|
||||
|| SampleBytes[currentPos + 2] == 0x94
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0x98
|
||||
|| SampleBytes[currentPos + 2] == 0x99
|
||||
|| SampleBytes[currentPos + 2] == 0x9A
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0x9C
|
||||
|| SampleBytes[currentPos + 2] == 0x9D
|
||||
|| SampleBytes[currentPos + 2] == 0x9E
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xA0
|
||||
|| SampleBytes[currentPos + 2] == 0xA1
|
||||
|| SampleBytes[currentPos + 2] == 0xA2
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xA6)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xB0)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xB9
|
||||
|| SampleBytes[currentPos + 2] == 0xBA
|
||||
)
|
||||
lengthFound = 3;
|
||||
}
|
||||
else if (SampleBytes[currentPos + 1] == 0x82
|
||||
&& SampleBytes[currentPos + 2] == 0xAC
|
||||
)
|
||||
lengthFound = 3;
|
||||
else if (SampleBytes[currentPos + 1] == 0x84
|
||||
&& SampleBytes[currentPos + 2] == 0xA2
|
||||
)
|
||||
lengthFound = 3;
|
||||
}
|
||||
|
||||
return lengthFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
FastColoredTextBox/ExportToHTML.cs
Normal file
222
FastColoredTextBox/ExportToHTML.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Exports colored text as HTML
|
||||
/// </summary>
|
||||
/// <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>
|
||||
public class ExportToHTML
|
||||
{
|
||||
public string LineNumbersCSS = "<style type=\"text/css\"> .lineNumber{font-family : monospace; font-size : small; font-style : normal; font-weight : normal; color : Teal; background-color : ThreedFace;} </style>";
|
||||
|
||||
/// <summary>
|
||||
/// Use nbsp; instead space
|
||||
/// </summary>
|
||||
public bool UseNbsp { get; set; }
|
||||
/// <summary>
|
||||
/// Use nbsp; instead space in beginning of line
|
||||
/// </summary>
|
||||
public bool UseForwardNbsp { get; set; }
|
||||
/// <summary>
|
||||
/// Use original font
|
||||
/// </summary>
|
||||
public bool UseOriginalFont { get; set; }
|
||||
/// <summary>
|
||||
/// Use style tag instead style attribute
|
||||
/// </summary>
|
||||
public bool UseStyleTag { get; set; }
|
||||
/// <summary>
|
||||
/// Use 'br' tag instead of '\n'
|
||||
/// </summary>
|
||||
public bool UseBr { get; set; }
|
||||
/// <summary>
|
||||
/// Includes line numbers
|
||||
/// </summary>
|
||||
public bool IncludeLineNumbers { get; set; }
|
||||
|
||||
FastColoredTextBox tb;
|
||||
|
||||
public ExportToHTML()
|
||||
{
|
||||
UseNbsp = true;
|
||||
UseOriginalFont = true;
|
||||
UseStyleTag = true;
|
||||
UseBr = true;
|
||||
}
|
||||
|
||||
public string GetHtml(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
Range sel = new Range(tb);
|
||||
sel.SelectAll();
|
||||
return GetHtml(sel);
|
||||
}
|
||||
|
||||
public string GetHtml(Range r)
|
||||
{
|
||||
this.tb = r.tb;
|
||||
Dictionary<StyleIndex, object> styles = new Dictionary<StyleIndex, object>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder tempSB = new StringBuilder();
|
||||
StyleIndex currentStyleId = StyleIndex.None;
|
||||
r.Normalize();
|
||||
int currentLine = r.Start.iLine;
|
||||
styles[currentStyleId] = null;
|
||||
//
|
||||
if (UseOriginalFont)
|
||||
sb.AppendFormat("<font style=\"font-family: {0}, monospace; font-size: {1}pt; line-height: {2}px;\">",
|
||||
r.tb.Font.Name, r.tb.Font.SizeInPoints, r.tb.CharHeight);
|
||||
|
||||
//
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat("<span class=lineNumber>{0}</span> ", currentLine + 1);
|
||||
//
|
||||
bool hasNonSpace = false;
|
||||
foreach (Place p in r)
|
||||
{
|
||||
Char c = r.tb[p.iLine][p.iChar];
|
||||
if (c.style != currentStyleId)
|
||||
{
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
currentStyleId = c.style;
|
||||
styles[currentStyleId] = null;
|
||||
}
|
||||
|
||||
if (p.iLine != currentLine)
|
||||
{
|
||||
for (int i = currentLine; i < p.iLine; i++)
|
||||
{
|
||||
tempSB.Append(UseBr ? "<br>" : "\r\n");
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat("<span class=lineNumber>{0}</span> ", i + 2);
|
||||
}
|
||||
currentLine = p.iLine;
|
||||
hasNonSpace = false;
|
||||
}
|
||||
switch (c.c)
|
||||
{
|
||||
case ' ':
|
||||
if ((hasNonSpace || !UseForwardNbsp) && !UseNbsp)
|
||||
goto default;
|
||||
|
||||
tempSB.Append(" ");
|
||||
break;
|
||||
case '<':
|
||||
tempSB.Append("<");
|
||||
break;
|
||||
case '>':
|
||||
tempSB.Append(">");
|
||||
break;
|
||||
case '&':
|
||||
tempSB.Append("&");
|
||||
break;
|
||||
default:
|
||||
hasNonSpace = true;
|
||||
tempSB.Append(c.c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
|
||||
if (UseOriginalFont)
|
||||
sb.Append("</font>");
|
||||
|
||||
//build styles
|
||||
if (UseStyleTag)
|
||||
{
|
||||
tempSB.Length = 0;
|
||||
tempSB.Append("<style type=\"text/css\">");
|
||||
foreach (var styleId in styles.Keys)
|
||||
tempSB.AppendFormat(".fctb{0}{{ {1} }}\r\n", GetStyleName(styleId), GetCss(styleId));
|
||||
tempSB.Append("</style>");
|
||||
|
||||
sb.Insert(0, tempSB.ToString());
|
||||
}
|
||||
|
||||
if (IncludeLineNumbers)
|
||||
sb.Insert(0, LineNumbersCSS);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string GetCss(StyleIndex styleIndex)
|
||||
{
|
||||
List<Style> styles = new List<Style>();
|
||||
//find text renderer
|
||||
TextStyle textStyle = null;
|
||||
int mask = 1;
|
||||
bool hasTextStyle = false;
|
||||
for (int i = 0; i < tb.Styles.Length; i++)
|
||||
{
|
||||
if (tb.Styles[i] != null && ((int)styleIndex & mask) != 0)
|
||||
if (tb.Styles[i].IsExportable)
|
||||
{
|
||||
var style = tb.Styles[i];
|
||||
styles.Add(style);
|
||||
|
||||
bool isTextStyle = style is TextStyle;
|
||||
if (isTextStyle)
|
||||
if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)
|
||||
{
|
||||
hasTextStyle = true;
|
||||
textStyle = style as TextStyle;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
//add TextStyle css
|
||||
string result = "";
|
||||
|
||||
if (!hasTextStyle)
|
||||
{
|
||||
//draw by default renderer
|
||||
result = tb.DefaultStyle.GetCSS();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = textStyle.GetCSS();
|
||||
}
|
||||
//add no TextStyle css
|
||||
foreach(var style in styles)
|
||||
// if (style != textStyle)
|
||||
if(!(style is TextStyle))
|
||||
result += style.GetCSS();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetColorAsString(Color color)
|
||||
{
|
||||
if(color==Color.Transparent)
|
||||
return "";
|
||||
return string.Format("#{0:x2}{1:x2}{2:x2}", color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
string GetStyleName(StyleIndex styleIndex)
|
||||
{
|
||||
return styleIndex.ToString().Replace(" ", "").Replace(",", "");
|
||||
}
|
||||
|
||||
private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)
|
||||
{
|
||||
//find textRenderer
|
||||
if (tempSB.Length == 0)
|
||||
return;
|
||||
if (UseStyleTag)
|
||||
sb.AppendFormat("<font class=fctb{0}>{1}</font>", GetStyleName(currentStyle), tempSB.ToString());
|
||||
else
|
||||
{
|
||||
string css = GetCss(currentStyle);
|
||||
if(css!="")
|
||||
sb.AppendFormat("<font style=\"{0}\">", css);
|
||||
sb.Append(tempSB.ToString());
|
||||
if (css != "")
|
||||
sb.Append("</font>");
|
||||
}
|
||||
tempSB.Length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
FastColoredTextBox/ExportToRTF.cs
Normal file
217
FastColoredTextBox/ExportToRTF.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Exports colored text as RTF
|
||||
/// </summary>
|
||||
/// <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>
|
||||
public class ExportToRTF
|
||||
{
|
||||
/// <summary>
|
||||
/// Includes line numbers
|
||||
/// </summary>
|
||||
public bool IncludeLineNumbers { get; set; }
|
||||
/// <summary>
|
||||
/// Use original font
|
||||
/// </summary>
|
||||
public bool UseOriginalFont { get; set; }
|
||||
|
||||
FastColoredTextBox tb;
|
||||
Dictionary<Color, int> colorTable = new Dictionary<Color, int>();
|
||||
|
||||
public ExportToRTF()
|
||||
{
|
||||
UseOriginalFont = true;
|
||||
}
|
||||
|
||||
public string GetRtf(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
Range sel = new Range(tb);
|
||||
sel.SelectAll();
|
||||
return GetRtf(sel);
|
||||
}
|
||||
|
||||
public string GetRtf(Range r)
|
||||
{
|
||||
this.tb = r.tb;
|
||||
var styles = new Dictionary<StyleIndex, object>();
|
||||
var sb = new StringBuilder();
|
||||
var tempSB = new StringBuilder();
|
||||
var currentStyleId = StyleIndex.None;
|
||||
r.Normalize();
|
||||
int currentLine = r.Start.iLine;
|
||||
styles[currentStyleId] = null;
|
||||
colorTable.Clear();
|
||||
//
|
||||
var lineNumberColor = GetColorTableNumber(r.tb.LineNumberColor);
|
||||
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat(@"{{\cf{1} {0}}}\tab", currentLine + 1, lineNumberColor);
|
||||
//
|
||||
foreach (Place p in r)
|
||||
{
|
||||
Char c = r.tb[p.iLine][p.iChar];
|
||||
if (c.style != currentStyleId)
|
||||
{
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
currentStyleId = c.style;
|
||||
styles[currentStyleId] = null;
|
||||
}
|
||||
|
||||
if (p.iLine != currentLine)
|
||||
{
|
||||
for (int i = currentLine; i < p.iLine; i++)
|
||||
{
|
||||
tempSB.AppendLine(@"\line");
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat(@"{{\cf{1} {0}}}\tab", i + 2, lineNumberColor);
|
||||
}
|
||||
currentLine = p.iLine;
|
||||
}
|
||||
switch (c.c)
|
||||
{
|
||||
case '\\':
|
||||
tempSB.Append(@"\\");
|
||||
break;
|
||||
case '{':
|
||||
tempSB.Append(@"\{");
|
||||
break;
|
||||
case '}':
|
||||
tempSB.Append(@"\}");
|
||||
break;
|
||||
default:
|
||||
var ch = c.c;
|
||||
var code = (int)ch;
|
||||
if(code < 128)
|
||||
tempSB.Append(c.c);
|
||||
else
|
||||
tempSB.AppendFormat(@"{{\u{0}}}", code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
|
||||
//build color table
|
||||
var list = new SortedList<int, Color>();
|
||||
foreach (var pair in colorTable)
|
||||
list.Add(pair.Value, pair.Key);
|
||||
|
||||
tempSB.Length = 0;
|
||||
tempSB.AppendFormat(@"{{\colortbl;");
|
||||
|
||||
foreach (var pair in list)
|
||||
tempSB.Append(GetColorAsString(pair.Value)+";");
|
||||
tempSB.AppendLine("}");
|
||||
|
||||
//
|
||||
if (UseOriginalFont)
|
||||
{
|
||||
sb.Insert(0, string.Format(@"{{\fonttbl{{\f0\fmodern {0};}}}}{{\fs{1} ",
|
||||
tb.Font.Name, (int)(2 * tb.Font.SizeInPoints), tb.CharHeight));
|
||||
sb.AppendLine(@"}");
|
||||
}
|
||||
|
||||
sb.Insert(0, tempSB.ToString());
|
||||
|
||||
sb.Insert(0, @"{\rtf1\ud\deff0");
|
||||
sb.AppendLine(@"}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private RTFStyleDescriptor GetRtfDescriptor(StyleIndex styleIndex)
|
||||
{
|
||||
List<Style> styles = new List<Style>();
|
||||
//find text renderer
|
||||
TextStyle textStyle = null;
|
||||
int mask = 1;
|
||||
bool hasTextStyle = false;
|
||||
for (int i = 0; i < tb.Styles.Length; i++)
|
||||
{
|
||||
if (tb.Styles[i] != null && ((int)styleIndex & mask) != 0)
|
||||
if (tb.Styles[i].IsExportable)
|
||||
{
|
||||
var style = tb.Styles[i];
|
||||
styles.Add(style);
|
||||
|
||||
bool isTextStyle = style is TextStyle;
|
||||
if (isTextStyle)
|
||||
if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)
|
||||
{
|
||||
hasTextStyle = true;
|
||||
textStyle = style as TextStyle;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
//add TextStyle css
|
||||
RTFStyleDescriptor result = null;
|
||||
|
||||
if (!hasTextStyle)
|
||||
{
|
||||
//draw by default renderer
|
||||
result = tb.DefaultStyle.GetRTF();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = textStyle.GetRTF();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetColorAsString(Color color)
|
||||
{
|
||||
if (color == Color.Transparent)
|
||||
return "";
|
||||
return string.Format(@"\red{0}\green{1}\blue{2}", color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)
|
||||
{
|
||||
//find textRenderer
|
||||
if (tempSB.Length == 0)
|
||||
return;
|
||||
|
||||
var desc = GetRtfDescriptor(currentStyle);
|
||||
var cf = GetColorTableNumber(desc.ForeColor);
|
||||
var cb = GetColorTableNumber(desc.BackColor);
|
||||
var tags = new StringBuilder();
|
||||
if (cf >= 0)
|
||||
tags.AppendFormat(@"\cf{0}", cf);
|
||||
if (cb >= 0)
|
||||
tags.AppendFormat(@"\highlight{0}", cb);
|
||||
if(!string.IsNullOrEmpty(desc.AdditionalTags))
|
||||
tags.Append(desc.AdditionalTags.Trim());
|
||||
|
||||
if(tags.Length > 0)
|
||||
sb.AppendFormat(@"{{{0} {1}}}", tags, tempSB.ToString());
|
||||
else
|
||||
sb.Append(tempSB.ToString());
|
||||
tempSB.Length = 0;
|
||||
}
|
||||
|
||||
private int GetColorTableNumber(Color color)
|
||||
{
|
||||
if (color.A == 0)
|
||||
return -1;
|
||||
|
||||
if (!colorTable.ContainsKey(color))
|
||||
colorTable[color] = colorTable.Count + 1;
|
||||
|
||||
return colorTable[color];
|
||||
}
|
||||
}
|
||||
|
||||
public class RTFStyleDescriptor
|
||||
{
|
||||
public Color ForeColor { get; set; }
|
||||
public Color BackColor { get; set; }
|
||||
public string AdditionalTags { get; set; }
|
||||
}
|
||||
}
|
||||
BIN
FastColoredTextBox/FCTB_key.snk
Normal file
BIN
FastColoredTextBox/FCTB_key.snk
Normal file
Binary file not shown.
8481
FastColoredTextBox/FastColoredTextBox.cs
Normal file
8481
FastColoredTextBox/FastColoredTextBox.cs
Normal file
File diff suppressed because it is too large
Load Diff
147
FastColoredTextBox/FastColoredTextBox.csproj
Normal file
147
FastColoredTextBox/FastColoredTextBox.csproj
Normal file
@@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{6DD14A85-CCFC-4774-BD26-0F5772512319}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>FastColoredTextBoxNS</RootNamespace>
|
||||
<AssemblyName>FastColoredTextBox</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\FastColoredTextBox.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>FCTB_key.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutocompleteItem.cs" />
|
||||
<Compile Include="AutocompleteMenu.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Bookmarks.cs" />
|
||||
<Compile Include="Char.cs" />
|
||||
<Compile Include="DocumentMap.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="EncodingDetector.cs" />
|
||||
<Compile Include="ExportToHTML.cs" />
|
||||
<Compile Include="ExportToRTF.cs" />
|
||||
<Compile Include="GoToForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GoToForm.Designer.cs">
|
||||
<DependentUpon>GoToForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Hints.cs" />
|
||||
<Compile Include="HotkeysEditorForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="HotkeysEditorForm.Designer.cs">
|
||||
<DependentUpon>HotkeysEditorForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LinesAccessor.cs" />
|
||||
<Compile Include="MacrosManager.cs" />
|
||||
<Compile Include="PlatformType.cs" />
|
||||
<Compile Include="Hotkeys.cs" />
|
||||
<Compile Include="Ruler.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Ruler.Designer.cs">
|
||||
<DependentUpon>Ruler.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SyntaxDescriptor.cs" />
|
||||
<Compile Include="SyntaxHighlighter.cs" />
|
||||
<Compile Include="ReplaceForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ReplaceForm.Designer.cs">
|
||||
<DependentUpon>ReplaceForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FastColoredTextBox.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CommandManager.cs" />
|
||||
<Compile Include="Commands.cs" />
|
||||
<Compile Include="FindForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FindForm.Designer.cs">
|
||||
<DependentUpon>FindForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LimitedStack.cs" />
|
||||
<Compile Include="Line.cs" />
|
||||
<Compile Include="Place.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Range.cs" />
|
||||
<Compile Include="Style.cs" />
|
||||
<Compile Include="TextSource.cs" />
|
||||
<Compile Include="TypeDescriptor.cs" />
|
||||
<Compile Include="FileTextSource.cs" />
|
||||
<Compile Include="UnfocusablePanel.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="VisualMarker.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="FastColoredTextBox.resx">
|
||||
<DependentUpon>FastColoredTextBox.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="FindForm.resx">
|
||||
<DependentUpon>FindForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="GoToForm.resx">
|
||||
<DependentUpon>GoToForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="HotkeysEditorForm.resx">
|
||||
<DependentUpon>HotkeysEditorForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="ReplaceForm.resx">
|
||||
<DependentUpon>ReplaceForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="FCTB_key.snk" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
120
FastColoredTextBox/FastColoredTextBox.resx
Normal file
120
FastColoredTextBox/FastColoredTextBox.resx
Normal file
@@ -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>
|
||||
453
FastColoredTextBox/FileTextSource.cs
Normal file
453
FastColoredTextBox/FileTextSource.cs
Normal file
@@ -0,0 +1,453 @@
|
||||
//#define debug
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains the source text (chars and styles).
|
||||
/// It stores a text lines, the manager of commands, undo/redo stack, styles.
|
||||
/// </summary>
|
||||
public class FileTextSource : TextSource, IDisposable
|
||||
{
|
||||
List<int> sourceFileLinePositions = new List<int>();
|
||||
FileStream fs;
|
||||
Encoding fileEncoding;
|
||||
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when need to display line in the textbox
|
||||
/// </summary>
|
||||
public event EventHandler<LineNeededEventArgs> LineNeeded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when need to save line in the file
|
||||
/// </summary>
|
||||
public event EventHandler<LinePushedEventArgs> LinePushed;
|
||||
|
||||
public FileTextSource(FastColoredTextBox currentTB)
|
||||
: base(currentTB)
|
||||
{
|
||||
timer.Interval = 10000;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
timer.Enabled = true;
|
||||
|
||||
SaveEOL = Environment.NewLine;
|
||||
}
|
||||
|
||||
void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
timer.Enabled = false;
|
||||
try
|
||||
{
|
||||
UnloadUnusedLines();
|
||||
}
|
||||
finally
|
||||
{
|
||||
timer.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnloadUnusedLines()
|
||||
{
|
||||
const int margin = 2000;
|
||||
var iStartVisibleLine = CurrentTB.VisibleRange.Start.iLine;
|
||||
var iFinishVisibleLine = CurrentTB.VisibleRange.End.iLine;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (base.lines[i] != null && !base.lines[i].IsChanged && Math.Abs(i - iFinishVisibleLine) > margin)
|
||||
{
|
||||
base.lines[i] = null;
|
||||
count++;
|
||||
}
|
||||
#if debug
|
||||
Console.WriteLine("UnloadUnusedLines: " + count);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OpenFile(string fileName, Encoding enc)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (fs != null)
|
||||
fs.Dispose();
|
||||
|
||||
SaveEOL = Environment.NewLine;
|
||||
|
||||
//read lines of file
|
||||
fs = new FileStream(fileName, FileMode.Open);
|
||||
var length = fs.Length;
|
||||
//read signature
|
||||
enc = DefineEncoding(enc, fs);
|
||||
int shift = DefineShift(enc);
|
||||
//first line
|
||||
sourceFileLinePositions.Add((int)fs.Position);
|
||||
base.lines.Add(null);
|
||||
//other lines
|
||||
sourceFileLinePositions.Capacity = (int)(length/7 + 1000);
|
||||
int prev = 0;
|
||||
while(fs.Position < length)
|
||||
{
|
||||
var b = fs.ReadByte();
|
||||
|
||||
if (b == 10)// \n
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position) + shift);
|
||||
base.lines.Add(null);
|
||||
}else
|
||||
if (prev == 13)// \r (Mac format)
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position - 1) + shift);
|
||||
base.lines.Add(null);
|
||||
SaveEOL = "\r";
|
||||
}
|
||||
|
||||
prev = b;
|
||||
}
|
||||
|
||||
if (prev == 13)
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position) + shift);
|
||||
base.lines.Add(null);
|
||||
}
|
||||
|
||||
if(length > 2000000)
|
||||
GC.Collect();
|
||||
|
||||
Line[] temp = new Line[100];
|
||||
|
||||
var c = base.lines.Count;
|
||||
base.lines.AddRange(temp);
|
||||
base.lines.TrimExcess();
|
||||
base.lines.RemoveRange(c, temp.Length);
|
||||
|
||||
|
||||
int[] temp2 = new int[100];
|
||||
c = base.lines.Count;
|
||||
sourceFileLinePositions.AddRange(temp2);
|
||||
sourceFileLinePositions.TrimExcess();
|
||||
sourceFileLinePositions.RemoveRange(c, temp.Length);
|
||||
|
||||
|
||||
fileEncoding = enc;
|
||||
|
||||
OnLineInserted(0, Count);
|
||||
//load first lines for calc width of the text
|
||||
var linesCount = Math.Min(lines.Count, CurrentTB.ClientRectangle.Height/CurrentTB.CharHeight);
|
||||
for (int i = 0; i < linesCount; i++)
|
||||
LoadLineFromSourceFile(i);
|
||||
//
|
||||
NeedRecalc(new TextChangedEventArgs(0, linesCount - 1));
|
||||
if (CurrentTB.WordWrap)
|
||||
OnRecalcWordWrap(new TextChangedEventArgs(0, linesCount - 1));
|
||||
}
|
||||
|
||||
private int DefineShift(Encoding enc)
|
||||
{
|
||||
if (enc.IsSingleByte)
|
||||
return 0;
|
||||
|
||||
if (enc.HeaderName == "unicodeFFFE")
|
||||
return 0;//UTF16 BE
|
||||
|
||||
if (enc.HeaderName == "utf-16")
|
||||
return 1;//UTF16 LE
|
||||
|
||||
if (enc.HeaderName == "utf-32BE")
|
||||
return 0;//UTF32 BE
|
||||
|
||||
if (enc.HeaderName == "utf-32")
|
||||
return 3;//UTF32 LE
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Encoding DefineEncoding(Encoding enc, FileStream fs)
|
||||
{
|
||||
int bytesPerSignature = 0;
|
||||
byte[] signature = new byte[4];
|
||||
int c = fs.Read(signature, 0, 4);
|
||||
if (signature[0] == 0xFF && signature[1] == 0xFE && signature[2] == 0x00 && signature[3] == 0x00 && c >= 4)
|
||||
{
|
||||
enc = Encoding.UTF32;//UTF32 LE
|
||||
bytesPerSignature = 4;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0x00 && signature[1] == 0x00 && signature[2] == 0xFE && signature[3] == 0xFF)
|
||||
{
|
||||
enc = new UTF32Encoding(true, true);//UTF32 BE
|
||||
bytesPerSignature = 4;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xEF && signature[1] == 0xBB && signature[2] == 0xBF)
|
||||
{
|
||||
enc = Encoding.UTF8;//UTF8
|
||||
bytesPerSignature = 3;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xFE && signature[1] == 0xFF)
|
||||
{
|
||||
enc = Encoding.BigEndianUnicode;//UTF16 BE
|
||||
bytesPerSignature = 2;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xFF && signature[1] == 0xFE)
|
||||
{
|
||||
enc = Encoding.Unicode;//UTF16 LE
|
||||
bytesPerSignature = 2;
|
||||
}
|
||||
|
||||
fs.Seek(bytesPerSignature, SeekOrigin.Begin);
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
public void CloseFile()
|
||||
{
|
||||
if(fs!=null)
|
||||
try
|
||||
{
|
||||
fs.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
;
|
||||
}
|
||||
fs = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End Of Line characters used for saving
|
||||
/// </summary>
|
||||
public string SaveEOL { get; set; }
|
||||
|
||||
public override void SaveToFile(string fileName, Encoding enc)
|
||||
{
|
||||
//
|
||||
var newLinePos = new List<int>(Count);
|
||||
//create temp file
|
||||
var dir = Path.GetDirectoryName(fileName);
|
||||
var tempFileName = Path.Combine(dir, Path.GetFileNameWithoutExtension(fileName) + ".tmp");
|
||||
|
||||
StreamReader sr = new StreamReader(fs, fileEncoding);
|
||||
using (FileStream tempFs = new FileStream(tempFileName, FileMode.Create))
|
||||
using (StreamWriter sw = new StreamWriter(tempFs, enc))
|
||||
{
|
||||
sw.Flush();
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
newLinePos.Add((int)tempFs.Length);
|
||||
|
||||
var sourceLine = ReadLine(sr, i);//read line from source file
|
||||
string line;
|
||||
|
||||
bool lineIsChanged = lines[i] != null && lines[i].IsChanged;
|
||||
|
||||
if (lineIsChanged)
|
||||
line = lines[i].Text;
|
||||
else
|
||||
line = sourceLine;
|
||||
|
||||
//call event handler
|
||||
if (LinePushed != null)
|
||||
{
|
||||
var args = new LinePushedEventArgs(sourceLine, i, lineIsChanged ? line : null);
|
||||
LinePushed(this, args);
|
||||
|
||||
if(args.SavedText != null)
|
||||
line = args.SavedText;
|
||||
}
|
||||
|
||||
//save line to file
|
||||
sw.Write(line);
|
||||
|
||||
if (i < Count - 1)
|
||||
sw.Write(SaveEOL);
|
||||
|
||||
sw.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
//clear lines buffer
|
||||
for (int i = 0; i < Count; i++)
|
||||
lines[i] = null;
|
||||
//deattach from source file
|
||||
sr.Dispose();
|
||||
fs.Dispose();
|
||||
//delete target file
|
||||
if (File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
//rename temp file
|
||||
File.Move(tempFileName, fileName);
|
||||
|
||||
//binding to new file
|
||||
sourceFileLinePositions = newLinePos;
|
||||
fs = new FileStream(fileName, FileMode.Open);
|
||||
this.fileEncoding = enc;
|
||||
}
|
||||
|
||||
private string ReadLine(StreamReader sr, int i)
|
||||
{
|
||||
string line;
|
||||
var filePos = sourceFileLinePositions[i];
|
||||
if (filePos < 0)
|
||||
return "";
|
||||
fs.Seek(filePos, SeekOrigin.Begin);
|
||||
sr.DiscardBufferedData();
|
||||
line = sr.ReadLine();
|
||||
return line;
|
||||
}
|
||||
|
||||
public override void ClearIsChanged()
|
||||
{
|
||||
foreach (var line in lines)
|
||||
if(line!=null)
|
||||
line.IsChanged = false;
|
||||
}
|
||||
|
||||
public override Line this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.lines[i] != null)
|
||||
return lines[i];
|
||||
else
|
||||
LoadLineFromSourceFile(i);
|
||||
|
||||
return lines[i];
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadLineFromSourceFile(int i)
|
||||
{
|
||||
var line = CreateLine();
|
||||
fs.Seek(sourceFileLinePositions[i], SeekOrigin.Begin);
|
||||
StreamReader sr = new StreamReader(fs, fileEncoding);
|
||||
|
||||
var s = sr.ReadLine();
|
||||
if (s == null)
|
||||
s = "";
|
||||
|
||||
//call event handler
|
||||
if(LineNeeded!=null)
|
||||
{
|
||||
var args = new LineNeededEventArgs(s, i);
|
||||
LineNeeded(this, args);
|
||||
s = args.DisplayedLineText;
|
||||
if (s == null)
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in s)
|
||||
line.Add(new Char(c));
|
||||
base.lines[i] = line;
|
||||
|
||||
if (CurrentTB.WordWrap)
|
||||
OnRecalcWordWrap(new TextChangedEventArgs(i, i));
|
||||
}
|
||||
|
||||
public override void InsertLine(int index, Line line)
|
||||
{
|
||||
sourceFileLinePositions.Insert(index, -1);
|
||||
base.InsertLine(index, line);
|
||||
}
|
||||
|
||||
public override void RemoveLine(int index, int count)
|
||||
{
|
||||
sourceFileLinePositions.RemoveRange(index, count);
|
||||
base.RemoveLine(index, count);
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
}
|
||||
|
||||
public override int GetLineLength(int i)
|
||||
{
|
||||
if (base.lines[i] == null)
|
||||
return 0;
|
||||
else
|
||||
return base.lines[i].Count;
|
||||
}
|
||||
|
||||
public override bool LineHasFoldingStartMarker(int iLine)
|
||||
{
|
||||
if (lines[iLine] == null)
|
||||
return false;
|
||||
else
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);
|
||||
}
|
||||
|
||||
public override bool LineHasFoldingEndMarker(int iLine)
|
||||
{
|
||||
if (lines[iLine] == null)
|
||||
return false;
|
||||
else
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (fs != null)
|
||||
fs.Dispose();
|
||||
|
||||
timer.Dispose();
|
||||
}
|
||||
|
||||
internal void UnloadLine(int iLine)
|
||||
{
|
||||
if (lines[iLine] != null && !lines[iLine].IsChanged)
|
||||
lines[iLine] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class LineNeededEventArgs : EventArgs
|
||||
{
|
||||
public string SourceLineText { get; private set; }
|
||||
public int DisplayedLineIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// This text will be displayed in textbox
|
||||
/// </summary>
|
||||
public string DisplayedLineText { get; set; }
|
||||
|
||||
public LineNeededEventArgs(string sourceLineText, int displayedLineIndex)
|
||||
{
|
||||
this.SourceLineText = sourceLineText;
|
||||
this.DisplayedLineIndex = displayedLineIndex;
|
||||
this.DisplayedLineText = sourceLineText;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinePushedEventArgs : EventArgs
|
||||
{
|
||||
public string SourceLineText { get; private set; }
|
||||
public int DisplayedLineIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// This property contains only changed text.
|
||||
/// If text of line is not changed, this property contains null.
|
||||
/// </summary>
|
||||
public string DisplayedLineText { get; private set; }
|
||||
/// <summary>
|
||||
/// This text will be saved in the file
|
||||
/// </summary>
|
||||
public string SavedText { get; set; }
|
||||
|
||||
public LinePushedEventArgs(string sourceLineText, int displayedLineIndex, string displayedLineText)
|
||||
{
|
||||
this.SourceLineText = sourceLineText;
|
||||
this.DisplayedLineIndex = displayedLineIndex;
|
||||
this.DisplayedLineText = displayedLineText;
|
||||
this.SavedText = displayedLineText;
|
||||
}
|
||||
}
|
||||
}
|
||||
146
FastColoredTextBox/FindForm.Designer.cs
generated
Normal file
146
FastColoredTextBox/FindForm.Designer.cs
generated
Normal file
@@ -0,0 +1,146 @@
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class FindForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btClose = new System.Windows.Forms.Button();
|
||||
this.btFindNext = new System.Windows.Forms.Button();
|
||||
this.tbFind = new System.Windows.Forms.TextBox();
|
||||
this.cbRegex = new System.Windows.Forms.CheckBox();
|
||||
this.cbMatchCase = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.cbWholeWord = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btClose
|
||||
//
|
||||
this.btClose.Location = new System.Drawing.Point(273, 73);
|
||||
this.btClose.Name = "btClose";
|
||||
this.btClose.Size = new System.Drawing.Size(75, 23);
|
||||
this.btClose.TabIndex = 5;
|
||||
this.btClose.Text = "Close";
|
||||
this.btClose.UseVisualStyleBackColor = true;
|
||||
this.btClose.Click += new System.EventHandler(this.btClose_Click);
|
||||
//
|
||||
// btFindNext
|
||||
//
|
||||
this.btFindNext.Location = new System.Drawing.Point(192, 73);
|
||||
this.btFindNext.Name = "btFindNext";
|
||||
this.btFindNext.Size = new System.Drawing.Size(75, 23);
|
||||
this.btFindNext.TabIndex = 4;
|
||||
this.btFindNext.Text = "Find next";
|
||||
this.btFindNext.UseVisualStyleBackColor = true;
|
||||
this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);
|
||||
//
|
||||
// tbFind
|
||||
//
|
||||
this.tbFind.Location = new System.Drawing.Point(42, 12);
|
||||
this.tbFind.Name = "tbFind";
|
||||
this.tbFind.Size = new System.Drawing.Size(306, 20);
|
||||
this.tbFind.TabIndex = 0;
|
||||
this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// cbRegex
|
||||
//
|
||||
this.cbRegex.AutoSize = true;
|
||||
this.cbRegex.Location = new System.Drawing.Point(249, 38);
|
||||
this.cbRegex.Name = "cbRegex";
|
||||
this.cbRegex.Size = new System.Drawing.Size(57, 17);
|
||||
this.cbRegex.TabIndex = 3;
|
||||
this.cbRegex.Text = "Regex";
|
||||
this.cbRegex.UseVisualStyleBackColor = true;
|
||||
this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// cbMatchCase
|
||||
//
|
||||
this.cbMatchCase.AutoSize = true;
|
||||
this.cbMatchCase.Location = new System.Drawing.Point(42, 38);
|
||||
this.cbMatchCase.Name = "cbMatchCase";
|
||||
this.cbMatchCase.Size = new System.Drawing.Size(82, 17);
|
||||
this.cbMatchCase.TabIndex = 1;
|
||||
this.cbMatchCase.Text = "Match case";
|
||||
this.cbMatchCase.UseVisualStyleBackColor = true;
|
||||
this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(6, 15);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(33, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Find: ";
|
||||
//
|
||||
// cbWholeWord
|
||||
//
|
||||
this.cbWholeWord.AutoSize = true;
|
||||
this.cbWholeWord.Location = new System.Drawing.Point(130, 38);
|
||||
this.cbWholeWord.Name = "cbWholeWord";
|
||||
this.cbWholeWord.Size = new System.Drawing.Size(113, 17);
|
||||
this.cbWholeWord.TabIndex = 2;
|
||||
this.cbWholeWord.Text = "Match whole word";
|
||||
this.cbWholeWord.UseVisualStyleBackColor = true;
|
||||
this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// FindForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(360, 108);
|
||||
this.Controls.Add(this.cbWholeWord);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.cbMatchCase);
|
||||
this.Controls.Add(this.cbRegex);
|
||||
this.Controls.Add(this.tbFind);
|
||||
this.Controls.Add(this.btFindNext);
|
||||
this.Controls.Add(this.btClose);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Name = "FindForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Find";
|
||||
this.TopMost = true;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FindForm_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btClose;
|
||||
private System.Windows.Forms.Button btFindNext;
|
||||
private System.Windows.Forms.CheckBox cbRegex;
|
||||
private System.Windows.Forms.CheckBox cbMatchCase;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox cbWholeWord;
|
||||
public System.Windows.Forms.TextBox tbFind;
|
||||
}
|
||||
}
|
||||
129
FastColoredTextBox/FindForm.cs
Normal file
129
FastColoredTextBox/FindForm.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class FindForm : Form
|
||||
{
|
||||
bool firstSearch = true;
|
||||
Place startPlace;
|
||||
FastColoredTextBox tb;
|
||||
|
||||
public FindForm(FastColoredTextBox tb)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.tb = tb;
|
||||
}
|
||||
|
||||
private void btClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btFindNext_Click(object sender, EventArgs e)
|
||||
{
|
||||
FindNext(tbFind.Text);
|
||||
}
|
||||
|
||||
public virtual void FindNext(string pattern)
|
||||
{
|
||||
try
|
||||
{
|
||||
RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
Range range = tb.Selection.Clone();
|
||||
range.Normalize();
|
||||
//
|
||||
if (firstSearch)
|
||||
{
|
||||
startPlace = range.Start;
|
||||
firstSearch = false;
|
||||
}
|
||||
//
|
||||
range.Start = range.End;
|
||||
if (range.Start >= startPlace)
|
||||
range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);
|
||||
else
|
||||
range.End = startPlace;
|
||||
//
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
{
|
||||
tb.Selection = r;
|
||||
tb.DoSelectionVisible();
|
||||
tb.Invalidate();
|
||||
return;
|
||||
}
|
||||
//
|
||||
if (range.Start >= startPlace && startPlace > Place.Empty)
|
||||
{
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
FindNext(pattern);
|
||||
return;
|
||||
}
|
||||
MessageBox.Show("Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void tbFind_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == '\r')
|
||||
{
|
||||
btFindNext.PerformClick();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (e.KeyChar == '\x1b')
|
||||
{
|
||||
Hide();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FindForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
Hide();
|
||||
}
|
||||
this.tb.Focus();
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if (keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
tbFind.Focus();
|
||||
ResetSerach();
|
||||
}
|
||||
|
||||
void ResetSerach()
|
||||
{
|
||||
firstSearch = true;
|
||||
}
|
||||
|
||||
private void cbMatchCase_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ResetSerach();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
FastColoredTextBox/FindForm.resx
Normal file
120
FastColoredTextBox/FindForm.resx
Normal file
@@ -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>
|
||||
110
FastColoredTextBox/GoToForm.Designer.cs
generated
Normal file
110
FastColoredTextBox/GoToForm.Designer.cs
generated
Normal file
@@ -0,0 +1,110 @@
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class GoToForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.label = new System.Windows.Forms.Label();
|
||||
this.tbLineNumber = new System.Windows.Forms.TextBox();
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label
|
||||
//
|
||||
this.label.AutoSize = true;
|
||||
this.label.Location = new System.Drawing.Point(12, 9);
|
||||
this.label.Name = "label";
|
||||
this.label.Size = new System.Drawing.Size(96, 13);
|
||||
this.label.TabIndex = 0;
|
||||
this.label.Text = "Line Number (1/1):";
|
||||
//
|
||||
// tbLineNumber
|
||||
//
|
||||
this.tbLineNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.tbLineNumber.Location = new System.Drawing.Point(12, 29);
|
||||
this.tbLineNumber.Name = "tbLineNumber";
|
||||
this.tbLineNumber.Size = new System.Drawing.Size(296, 20);
|
||||
this.tbLineNumber.TabIndex = 1;
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnOk.Location = new System.Drawing.Point(152, 71);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 2;
|
||||
this.btnOk.Text = "OK";
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(233, 71);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 3;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// GoToForm
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(320, 106);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOk);
|
||||
this.Controls.Add(this.tbLineNumber);
|
||||
this.Controls.Add(this.label);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "GoToForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Go To Line";
|
||||
this.TopMost = true;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label label;
|
||||
private System.Windows.Forms.TextBox tbLineNumber;
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
}
|
||||
}
|
||||
53
FastColoredTextBox/GoToForm.cs
Normal file
53
FastColoredTextBox/GoToForm.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class GoToForm : Form
|
||||
{
|
||||
public int SelectedLineNumber { get; set; }
|
||||
public int TotalLineCount { get; set; }
|
||||
|
||||
public GoToForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
this.tbLineNumber.Text = this.SelectedLineNumber.ToString();
|
||||
|
||||
this.label.Text = String.Format("Line number (1 - {0}):", this.TotalLineCount);
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
|
||||
this.tbLineNumber.Focus();
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
int enteredLine;
|
||||
if (int.TryParse(this.tbLineNumber.Text, out enteredLine))
|
||||
{
|
||||
enteredLine = Math.Min(enteredLine, this.TotalLineCount);
|
||||
enteredLine = Math.Max(1, enteredLine);
|
||||
|
||||
this.SelectedLineNumber = enteredLine;
|
||||
}
|
||||
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
FastColoredTextBox/GoToForm.resx
Normal file
120
FastColoredTextBox/GoToForm.resx
Normal file
@@ -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>
|
||||
364
FastColoredTextBox/Hints.cs
Normal file
364
FastColoredTextBox/Hints.cs
Normal file
@@ -0,0 +1,364 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of Hints.
|
||||
/// This is temporary buffer for currently displayed hints.
|
||||
/// </summary>
|
||||
public class Hints : ICollection<Hint>, IDisposable
|
||||
{
|
||||
FastColoredTextBox tb;
|
||||
List<Hint> items = new List<Hint>();
|
||||
|
||||
public Hints(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
tb.TextChanged += OnTextBoxTextChanged;
|
||||
tb.KeyDown += OnTextBoxKeyDown;
|
||||
tb.VisibleRangeChanged += OnTextBoxVisibleRangeChanged;
|
||||
}
|
||||
|
||||
protected virtual void OnTextBoxKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == System.Windows.Forms.Keys.Escape && e.Modifiers == System.Windows.Forms.Keys.None)
|
||||
Clear();
|
||||
}
|
||||
|
||||
protected virtual void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
tb.TextChanged -= OnTextBoxTextChanged;
|
||||
tb.KeyDown -= OnTextBoxKeyDown;
|
||||
tb.VisibleRangeChanged -= OnTextBoxVisibleRangeChanged;
|
||||
}
|
||||
|
||||
void OnTextBoxVisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
return;
|
||||
|
||||
tb.NeedRecalc(true);
|
||||
foreach (var item in items)
|
||||
{
|
||||
LayoutHint(item);
|
||||
item.HostPanel.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void LayoutHint(Hint hint)
|
||||
{
|
||||
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
|
||||
{
|
||||
if (hint.Range.Start.iLine < tb.LineInfos.Count - 1)
|
||||
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - hint.TopPadding - hint.HostPanel.Height - tb.VerticalScroll.Value;
|
||||
else
|
||||
hint.HostPanel.Top = tb.TextHeight + tb.Paddings.Top - hint.HostPanel.Height - tb.VerticalScroll.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - tb.VerticalScroll.Value;
|
||||
}
|
||||
|
||||
if (hint.Dock == DockStyle.Fill)
|
||||
{
|
||||
hint.Width = tb.ClientSize.Width - tb.LeftIndent - 2;
|
||||
hint.HostPanel.Left = tb.LeftIndent;
|
||||
}
|
||||
else
|
||||
{
|
||||
var p1 = tb.PlaceToPoint(hint.Range.Start);
|
||||
var p2 = tb.PlaceToPoint(hint.Range.End);
|
||||
var cx = (p1.X + p2.X) / 2;
|
||||
hint.HostPanel.Left = Math.Max( tb.LeftIndent, cx - hint.HostPanel.Width / 2);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<Hint> GetEnumerator()
|
||||
{
|
||||
foreach (var item in items)
|
||||
yield return item;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all displayed hints
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
items.Clear();
|
||||
if (tb.Controls.Count != 0)
|
||||
{
|
||||
var toDelete = new List<Control>();
|
||||
foreach (Control item in tb.Controls)
|
||||
if (item is UnfocusablePanel)
|
||||
toDelete.Add(item);
|
||||
|
||||
foreach (var item in toDelete)
|
||||
tb.Controls.Remove(item);
|
||||
|
||||
for (int i = 0; i < tb.LineInfos.Count; i++)
|
||||
{
|
||||
var li = tb.LineInfos[i];
|
||||
li.bottomPadding = 0;
|
||||
tb.LineInfos[i] = li;
|
||||
}
|
||||
tb.NeedRecalc();
|
||||
tb.Invalidate();
|
||||
tb.Select();
|
||||
tb.ActiveControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add and shows the hint
|
||||
/// </summary>
|
||||
/// <param name="hint"></param>
|
||||
public void Add(Hint hint)
|
||||
{
|
||||
items.Add(hint);
|
||||
|
||||
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
|
||||
{
|
||||
var li = tb.LineInfos[hint.Range.Start.iLine];
|
||||
hint.TopPadding = li.bottomPadding;
|
||||
li.bottomPadding += hint.HostPanel.Height;
|
||||
tb.LineInfos[hint.Range.Start.iLine] = li;
|
||||
tb.NeedRecalc(true);
|
||||
}
|
||||
|
||||
LayoutHint(hint);
|
||||
|
||||
tb.OnVisibleRangeChanged();
|
||||
|
||||
hint.HostPanel.Parent = tb;
|
||||
|
||||
tb.Select();
|
||||
tb.ActiveControl = null;
|
||||
tb.Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is collection contains the hint?
|
||||
/// </summary>
|
||||
public bool Contains(Hint item)
|
||||
{
|
||||
return items.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(Hint[] array, int arrayIndex)
|
||||
{
|
||||
items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of hints
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return items.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public bool Remove(Hint item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hint of FastColoredTextbox
|
||||
/// </summary>
|
||||
public class Hint
|
||||
{
|
||||
/// <summary>
|
||||
/// Text of simple hint
|
||||
/// </summary>
|
||||
public string Text { get { return HostPanel.Text; } set { HostPanel.Text = value; } }
|
||||
/// <summary>
|
||||
/// Linked range
|
||||
/// </summary>
|
||||
public Range Range { get; set; }
|
||||
/// <summary>
|
||||
/// Backcolor
|
||||
/// </summary>
|
||||
public Color BackColor { get { return HostPanel.BackColor; } set { HostPanel.BackColor = value; } }
|
||||
/// <summary>
|
||||
/// Second backcolor
|
||||
/// </summary>
|
||||
public Color BackColor2 { get { return HostPanel.BackColor2; } set { HostPanel.BackColor2 = value; } }
|
||||
/// <summary>
|
||||
/// Border color
|
||||
/// </summary>
|
||||
public Color BorderColor { get { return HostPanel.BorderColor; } set { HostPanel.BorderColor = value; } }
|
||||
/// <summary>
|
||||
/// Fore color
|
||||
/// </summary>
|
||||
public Color ForeColor { get { return HostPanel.ForeColor; } set { HostPanel.ForeColor = value; } }
|
||||
/// <summary>
|
||||
/// Text alignment
|
||||
/// </summary>
|
||||
public StringAlignment TextAlignment { get { return HostPanel.TextAlignment; } set { HostPanel.TextAlignment = value; } }
|
||||
/// <summary>
|
||||
/// Font
|
||||
/// </summary>
|
||||
public Font Font { get { return HostPanel.Font; } set { HostPanel.Font = value; } }
|
||||
/// <summary>
|
||||
/// Occurs when user click on simple hint
|
||||
/// </summary>
|
||||
public event EventHandler Click
|
||||
{
|
||||
add { HostPanel.Click += value; }
|
||||
remove { HostPanel.Click -= value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Inner control
|
||||
/// </summary>
|
||||
public Control InnerControl { get; set; }
|
||||
/// <summary>
|
||||
/// Docking (allows None and Fill only)
|
||||
/// </summary>
|
||||
public DockStyle Dock { get; set; }
|
||||
/// <summary>
|
||||
/// Width of hint (if Dock is None)
|
||||
/// </summary>
|
||||
public int Width { get { return HostPanel.Width; } set { HostPanel.Width = value; } }
|
||||
/// <summary>
|
||||
/// Height of hint
|
||||
/// </summary>
|
||||
public int Height { get { return HostPanel.Height; } set { HostPanel.Height = value; } }
|
||||
/// <summary>
|
||||
/// Host panel
|
||||
/// </summary>
|
||||
public UnfocusablePanel HostPanel { get; private set; }
|
||||
|
||||
internal int TopPadding { get; set; }
|
||||
/// <summary>
|
||||
/// Tag
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
/// <summary>
|
||||
/// Cursor
|
||||
/// </summary>
|
||||
public Cursor Cursor { get { return HostPanel.Cursor; } set { HostPanel.Cursor = value; } }
|
||||
/// <summary>
|
||||
/// Inlining. If True then hint will moves apart text.
|
||||
/// </summary>
|
||||
public bool Inline{get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Scroll textbox to the hint
|
||||
/// </summary>
|
||||
public virtual void DoVisible()
|
||||
{
|
||||
Range.tb.DoRangeVisible(Range, true);
|
||||
Range.tb.Invalidate();
|
||||
}
|
||||
|
||||
private Hint(Range range, Control innerControl, string text, bool inline, bool dock)
|
||||
{
|
||||
this.Range = range;
|
||||
this.Inline = inline;
|
||||
this.InnerControl = innerControl;
|
||||
|
||||
Init();
|
||||
|
||||
Dock = dock ? DockStyle.Fill : DockStyle.None;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="text">Text for simple hint</param>
|
||||
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
|
||||
/// <param name="dock">Docking. If True then hint will fill whole line</param>
|
||||
public Hint(Range range, string text, bool inline, bool dock)
|
||||
: this(range, null, text, inline, dock)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="text">Text for simple hint</param>
|
||||
public Hint(Range range, string text)
|
||||
: this(range, null, text, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="innerControl">Inner control</param>
|
||||
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
|
||||
/// <param name="dock">Docking. If True then hint will fill whole line</param>
|
||||
public Hint(Range range, Control innerControl, bool inline, bool dock)
|
||||
: this(range, innerControl, null, inline, dock)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="innerControl">Inner control</param>
|
||||
public Hint(Range range, Control innerControl)
|
||||
: this(range, innerControl, null, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Init()
|
||||
{
|
||||
HostPanel = new UnfocusablePanel();
|
||||
HostPanel.Click += OnClick;
|
||||
|
||||
if (InnerControl != null)
|
||||
{
|
||||
HostPanel.Controls.Add(InnerControl);
|
||||
HostPanel.Width = InnerControl.Width + 2;
|
||||
HostPanel.Height = InnerControl.Height + 2;
|
||||
InnerControl.Dock = DockStyle.Fill;
|
||||
InnerControl.Visible = true;
|
||||
BackColor = SystemColors.Control;
|
||||
}
|
||||
else
|
||||
{
|
||||
HostPanel.Height = Range.tb.CharHeight + 5;
|
||||
}
|
||||
|
||||
Cursor = Cursors.Default;
|
||||
BorderColor = Color.Silver;
|
||||
BackColor2 = Color.White;
|
||||
BackColor = InnerControl == null ? Color.Silver : SystemColors.Control;
|
||||
ForeColor = Color.Black;
|
||||
TextAlignment = StringAlignment.Near;
|
||||
Font = Range.tb.Parent == null ? Range.tb.Font : Range.tb.Parent.Font;
|
||||
}
|
||||
|
||||
protected virtual void OnClick(object sender, EventArgs e)
|
||||
{
|
||||
Range.tb.OnHintClick(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
251
FastColoredTextBox/Hotkeys.cs
Normal file
251
FastColoredTextBox/Hotkeys.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Design;
|
||||
using KEYS = System.Windows.Forms.Keys;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Dictionary of shortcuts for FCTB
|
||||
/// </summary>
|
||||
public class HotkeysMapping : SortedDictionary<Keys, FCTBAction>
|
||||
{
|
||||
public virtual void InitDefault()
|
||||
{
|
||||
this[KEYS.Control | KEYS.G] = FCTBAction.GoToDialog;
|
||||
this[KEYS.Control | KEYS.F] = FCTBAction.FindDialog;
|
||||
this[KEYS.Alt | KEYS.F] = FCTBAction.FindChar;
|
||||
this[KEYS.F3] = FCTBAction.FindNext;
|
||||
this[KEYS.Control | KEYS.H] = FCTBAction.ReplaceDialog;
|
||||
this[KEYS.Control | KEYS.C] = FCTBAction.Copy;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.C] = FCTBAction.CommentSelected;
|
||||
this[KEYS.Control | KEYS.X] = FCTBAction.Cut;
|
||||
this[KEYS.Control | KEYS.V] = FCTBAction.Paste;
|
||||
this[KEYS.Control | KEYS.A] = FCTBAction.SelectAll;
|
||||
this[KEYS.Control | KEYS.Z] = FCTBAction.Undo;
|
||||
this[KEYS.Control | KEYS.R] = FCTBAction.Redo;
|
||||
this[KEYS.Control | KEYS.U] = FCTBAction.UpperCase;
|
||||
this[KEYS.Shift | KEYS.Control | KEYS.U] = FCTBAction.LowerCase;
|
||||
this[KEYS.Control | KEYS.OemMinus] = FCTBAction.NavigateBackward;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.OemMinus] = FCTBAction.NavigateForward;
|
||||
this[KEYS.Control | KEYS.B] = FCTBAction.BookmarkLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.B] = FCTBAction.UnbookmarkLine;
|
||||
this[KEYS.Control | KEYS.N] = FCTBAction.GoNextBookmark;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.N] = FCTBAction.GoPrevBookmark;
|
||||
this[KEYS.Alt | KEYS.Back] = FCTBAction.Undo;
|
||||
this[KEYS.Control | KEYS.Back] = FCTBAction.ClearWordLeft;
|
||||
this[KEYS.Insert] = FCTBAction.ReplaceMode;
|
||||
this[KEYS.Control | KEYS.Insert] = FCTBAction.Copy;
|
||||
this[KEYS.Shift | KEYS.Insert] = FCTBAction.Paste;
|
||||
this[KEYS.Delete] = FCTBAction.DeleteCharRight;
|
||||
this[KEYS.Control | KEYS.Delete] = FCTBAction.ClearWordRight;
|
||||
this[KEYS.Shift | KEYS.Delete] = FCTBAction.Cut;
|
||||
this[KEYS.Left] = FCTBAction.GoLeft;
|
||||
this[KEYS.Shift | KEYS.Left] = FCTBAction.GoLeftWithSelection;
|
||||
this[KEYS.Control | KEYS.Left] = FCTBAction.GoWordLeft;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Left] = FCTBAction.GoWordLeftWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Left] = FCTBAction.GoLeft_ColumnSelectionMode;
|
||||
this[KEYS.Right] = FCTBAction.GoRight;
|
||||
this[KEYS.Shift | KEYS.Right] = FCTBAction.GoRightWithSelection;
|
||||
this[KEYS.Control | KEYS.Right] = FCTBAction.GoWordRight;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Right] = FCTBAction.GoWordRightWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Right] = FCTBAction.GoRight_ColumnSelectionMode;
|
||||
this[KEYS.Up] = FCTBAction.GoUp;
|
||||
this[KEYS.Shift | KEYS.Up] = FCTBAction.GoUpWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Up] = FCTBAction.GoUp_ColumnSelectionMode;
|
||||
this[KEYS.Alt | KEYS.Up] = FCTBAction.MoveSelectedLinesUp;
|
||||
this[KEYS.Control | KEYS.Up] = FCTBAction.ScrollUp;
|
||||
this[KEYS.Down] = FCTBAction.GoDown;
|
||||
this[KEYS.Shift | KEYS.Down] = FCTBAction.GoDownWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Down] = FCTBAction.GoDown_ColumnSelectionMode;
|
||||
this[KEYS.Alt | KEYS.Down] = FCTBAction.MoveSelectedLinesDown;
|
||||
this[KEYS.Control | KEYS.Down] = FCTBAction.ScrollDown;
|
||||
this[KEYS.PageUp] = FCTBAction.GoPageUp;
|
||||
this[KEYS.Shift | KEYS.PageUp] = FCTBAction.GoPageUpWithSelection;
|
||||
this[KEYS.PageDown] = FCTBAction.GoPageDown;
|
||||
this[KEYS.Shift | KEYS.PageDown] = FCTBAction.GoPageDownWithSelection;
|
||||
this[KEYS.Home] = FCTBAction.GoHome;
|
||||
this[KEYS.Shift | KEYS.Home] = FCTBAction.GoHomeWithSelection;
|
||||
this[KEYS.Control | KEYS.Home] = FCTBAction.GoFirstLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Home] = FCTBAction.GoFirstLineWithSelection;
|
||||
this[KEYS.End] = FCTBAction.GoEnd;
|
||||
this[KEYS.Shift | KEYS.End] = FCTBAction.GoEndWithSelection;
|
||||
this[KEYS.Control | KEYS.End] = FCTBAction.GoLastLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.End] = FCTBAction.GoLastLineWithSelection;
|
||||
this[KEYS.Escape] = FCTBAction.ClearHints;
|
||||
this[KEYS.Control | KEYS.M] = FCTBAction.MacroRecord;
|
||||
this[KEYS.Control | KEYS.E] = FCTBAction.MacroExecute;
|
||||
this[KEYS.Control | KEYS.Space] = FCTBAction.AutocompleteMenu;
|
||||
this[KEYS.Tab] = FCTBAction.IndentIncrease;
|
||||
this[KEYS.Shift | KEYS.Tab] = FCTBAction.IndentDecrease;
|
||||
this[KEYS.Control | KEYS.Subtract] = FCTBAction.ZoomOut;
|
||||
this[KEYS.Control | KEYS.Add] = FCTBAction.ZoomIn;
|
||||
this[KEYS.Control | KEYS.D0] = FCTBAction.ZoomNormal;
|
||||
this[KEYS.Control | KEYS.I] = FCTBAction.AutoIndentChars;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var kc = new KeysConverter();
|
||||
foreach (var pair in this)
|
||||
{
|
||||
sb.AppendFormat("{0}={1}, ", kc.ConvertToString(pair.Key), pair.Value);
|
||||
}
|
||||
|
||||
if (sb.Length > 1)
|
||||
sb.Remove(sb.Length - 2, 2);
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static HotkeysMapping Parse(string s)
|
||||
{
|
||||
var result = new HotkeysMapping();
|
||||
result.Clear();
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
var kc = new KeysConverter();
|
||||
|
||||
foreach (var p in s.Split(','))
|
||||
{
|
||||
var pp = p.Split('=');
|
||||
var k = (Keys)kc.ConvertFromString(pp[0].Trim());
|
||||
var a = (FCTBAction)Enum.Parse(typeof(FCTBAction), pp[1].Trim());
|
||||
result[k] = a;
|
||||
}
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actions for shortcuts
|
||||
/// </summary>
|
||||
public enum FCTBAction
|
||||
{
|
||||
None,
|
||||
AutocompleteMenu,
|
||||
AutoIndentChars,
|
||||
BookmarkLine,
|
||||
ClearHints,
|
||||
ClearWordLeft,
|
||||
ClearWordRight,
|
||||
CommentSelected,
|
||||
Copy,
|
||||
Cut,
|
||||
DeleteCharRight,
|
||||
FindChar,
|
||||
FindDialog,
|
||||
FindNext,
|
||||
GoDown,
|
||||
GoDownWithSelection,
|
||||
GoDown_ColumnSelectionMode,
|
||||
GoEnd,
|
||||
GoEndWithSelection,
|
||||
GoFirstLine,
|
||||
GoFirstLineWithSelection,
|
||||
GoHome,
|
||||
GoHomeWithSelection,
|
||||
GoLastLine,
|
||||
GoLastLineWithSelection,
|
||||
GoLeft,
|
||||
GoLeftWithSelection,
|
||||
GoLeft_ColumnSelectionMode,
|
||||
GoPageDown,
|
||||
GoPageDownWithSelection,
|
||||
GoPageUp,
|
||||
GoPageUpWithSelection,
|
||||
GoRight,
|
||||
GoRightWithSelection,
|
||||
GoRight_ColumnSelectionMode,
|
||||
GoToDialog,
|
||||
GoNextBookmark,
|
||||
GoPrevBookmark,
|
||||
GoUp,
|
||||
GoUpWithSelection,
|
||||
GoUp_ColumnSelectionMode,
|
||||
GoWordLeft,
|
||||
GoWordLeftWithSelection,
|
||||
GoWordRight,
|
||||
GoWordRightWithSelection,
|
||||
IndentIncrease,
|
||||
IndentDecrease,
|
||||
LowerCase,
|
||||
MacroExecute,
|
||||
MacroRecord,
|
||||
MoveSelectedLinesDown,
|
||||
MoveSelectedLinesUp,
|
||||
NavigateBackward,
|
||||
NavigateForward,
|
||||
Paste,
|
||||
Redo,
|
||||
ReplaceDialog,
|
||||
ReplaceMode,
|
||||
ScrollDown,
|
||||
ScrollUp,
|
||||
SelectAll,
|
||||
UnbookmarkLine,
|
||||
Undo,
|
||||
UpperCase,
|
||||
ZoomIn,
|
||||
ZoomNormal,
|
||||
ZoomOut,
|
||||
CustomAction1,
|
||||
CustomAction2,
|
||||
CustomAction3,
|
||||
CustomAction4,
|
||||
CustomAction5,
|
||||
CustomAction6,
|
||||
CustomAction7,
|
||||
CustomAction8,
|
||||
CustomAction9,
|
||||
CustomAction10,
|
||||
CustomAction11,
|
||||
CustomAction12,
|
||||
CustomAction13,
|
||||
CustomAction14,
|
||||
CustomAction15,
|
||||
CustomAction16,
|
||||
CustomAction17,
|
||||
CustomAction18,
|
||||
CustomAction19,
|
||||
CustomAction20
|
||||
}
|
||||
|
||||
internal class HotkeysEditor : UITypeEditor
|
||||
{
|
||||
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
if ((provider != null) && (((IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService))) != null))
|
||||
{
|
||||
var form = new HotkeysEditorForm(HotkeysMapping.Parse(value as string));
|
||||
|
||||
if (form.ShowDialog() == DialogResult.OK)
|
||||
value = form.GetHotkeys().ToString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
210
FastColoredTextBox/HotkeysEditorForm.Designer.cs
generated
Normal file
210
FastColoredTextBox/HotkeysEditorForm.Designer.cs
generated
Normal file
@@ -0,0 +1,210 @@
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class HotkeysEditorForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.dgv = new System.Windows.Forms.DataGridView();
|
||||
this.cbModifiers = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.cbKey = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.cbAction = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.btAdd = new System.Windows.Forms.Button();
|
||||
this.btRemove = new System.Windows.Forms.Button();
|
||||
this.btCancel = new System.Windows.Forms.Button();
|
||||
this.btOk = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.btResore = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// dgv
|
||||
//
|
||||
this.dgv.AllowUserToAddRows = false;
|
||||
this.dgv.AllowUserToDeleteRows = false;
|
||||
this.dgv.AllowUserToResizeColumns = false;
|
||||
this.dgv.AllowUserToResizeRows = false;
|
||||
this.dgv.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dgv.BackgroundColor = System.Drawing.SystemColors.Control;
|
||||
this.dgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.cbModifiers,
|
||||
this.cbKey,
|
||||
this.cbAction});
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.LightSteelBlue;
|
||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.dgv.DefaultCellStyle = dataGridViewCellStyle1;
|
||||
this.dgv.GridColor = System.Drawing.SystemColors.Control;
|
||||
this.dgv.Location = new System.Drawing.Point(12, 28);
|
||||
this.dgv.Name = "dgv";
|
||||
this.dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
|
||||
this.dgv.RowHeadersVisible = false;
|
||||
this.dgv.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
|
||||
this.dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgv.Size = new System.Drawing.Size(525, 278);
|
||||
this.dgv.TabIndex = 0;
|
||||
this.dgv.RowsAdded += new System.Windows.Forms.DataGridViewRowsAddedEventHandler(this.dgv_RowsAdded);
|
||||
//
|
||||
// cbModifiers
|
||||
//
|
||||
this.cbModifiers.DataPropertyName = "Modifiers";
|
||||
this.cbModifiers.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbModifiers.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbModifiers.HeaderText = "Modifiers";
|
||||
this.cbModifiers.Name = "cbModifiers";
|
||||
//
|
||||
// cbKey
|
||||
//
|
||||
this.cbKey.DataPropertyName = "Key";
|
||||
this.cbKey.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbKey.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbKey.HeaderText = "Key";
|
||||
this.cbKey.Name = "cbKey";
|
||||
this.cbKey.Resizable = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.cbKey.Width = 120;
|
||||
//
|
||||
// cbAction
|
||||
//
|
||||
this.cbAction.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
|
||||
this.cbAction.DataPropertyName = "Action";
|
||||
this.cbAction.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbAction.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbAction.HeaderText = "Action";
|
||||
this.cbAction.Name = "cbAction";
|
||||
//
|
||||
// btAdd
|
||||
//
|
||||
this.btAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btAdd.Location = new System.Drawing.Point(13, 322);
|
||||
this.btAdd.Name = "btAdd";
|
||||
this.btAdd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btAdd.TabIndex = 1;
|
||||
this.btAdd.Text = "Add";
|
||||
this.btAdd.UseVisualStyleBackColor = true;
|
||||
this.btAdd.Click += new System.EventHandler(this.btAdd_Click);
|
||||
//
|
||||
// btRemove
|
||||
//
|
||||
this.btRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btRemove.Location = new System.Drawing.Point(103, 322);
|
||||
this.btRemove.Name = "btRemove";
|
||||
this.btRemove.Size = new System.Drawing.Size(75, 23);
|
||||
this.btRemove.TabIndex = 2;
|
||||
this.btRemove.Text = "Remove";
|
||||
this.btRemove.UseVisualStyleBackColor = true;
|
||||
this.btRemove.Click += new System.EventHandler(this.btRemove_Click);
|
||||
//
|
||||
// btCancel
|
||||
//
|
||||
this.btCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btCancel.Location = new System.Drawing.Point(460, 322);
|
||||
this.btCancel.Name = "btCancel";
|
||||
this.btCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btCancel.TabIndex = 4;
|
||||
this.btCancel.Text = "Cancel";
|
||||
this.btCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btOk
|
||||
//
|
||||
this.btOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btOk.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btOk.Location = new System.Drawing.Point(379, 322);
|
||||
this.btOk.Name = "btOk";
|
||||
this.btOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btOk.TabIndex = 3;
|
||||
this.btOk.Text = "OK";
|
||||
this.btOk.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
this.label1.Location = new System.Drawing.Point(12, 9);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(114, 16);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Hotkeys mapping";
|
||||
//
|
||||
// btResore
|
||||
//
|
||||
this.btResore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btResore.Location = new System.Drawing.Point(194, 322);
|
||||
this.btResore.Name = "btResore";
|
||||
this.btResore.Size = new System.Drawing.Size(105, 23);
|
||||
this.btResore.TabIndex = 6;
|
||||
this.btResore.Text = "Restore default";
|
||||
this.btResore.UseVisualStyleBackColor = true;
|
||||
this.btResore.Click += new System.EventHandler(this.btResore_Click);
|
||||
//
|
||||
// HotkeysEditorForm
|
||||
//
|
||||
this.AcceptButton = this.btOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btCancel;
|
||||
this.ClientSize = new System.Drawing.Size(549, 357);
|
||||
this.Controls.Add(this.btResore);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.btCancel);
|
||||
this.Controls.Add(this.btOk);
|
||||
this.Controls.Add(this.btRemove);
|
||||
this.Controls.Add(this.btAdd);
|
||||
this.Controls.Add(this.dgv);
|
||||
this.MaximumSize = new System.Drawing.Size(565, 700);
|
||||
this.MinimumSize = new System.Drawing.Size(565, 395);
|
||||
this.Name = "HotkeysEditorForm";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "Hotkeys Editor";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HotkeysEditorForm_FormClosing);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.DataGridView dgv;
|
||||
private System.Windows.Forms.Button btAdd;
|
||||
private System.Windows.Forms.Button btRemove;
|
||||
private System.Windows.Forms.Button btCancel;
|
||||
private System.Windows.Forms.Button btOk;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Button btResore;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbModifiers;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbKey;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbAction;
|
||||
}
|
||||
}
|
||||
179
FastColoredTextBox/HotkeysEditorForm.cs
Normal file
179
FastColoredTextBox/HotkeysEditorForm.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class HotkeysEditorForm : Form
|
||||
{
|
||||
BindingList<HotkeyWrapper> wrappers = new BindingList<HotkeyWrapper>();
|
||||
|
||||
public HotkeysEditorForm(HotkeysMapping hotkeys)
|
||||
{
|
||||
InitializeComponent();
|
||||
BuildWrappers(hotkeys);
|
||||
dgv.DataSource = wrappers;
|
||||
}
|
||||
|
||||
int CompereKeys(Keys key1, Keys key2)
|
||||
{
|
||||
var res = ((int)key1 & 0xff).CompareTo((int)key2 & 0xff);
|
||||
if (res == 0)
|
||||
res = key1.CompareTo(key2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void BuildWrappers(HotkeysMapping hotkeys)
|
||||
{
|
||||
var keys = new List<Keys>(hotkeys.Keys);
|
||||
keys.Sort(CompereKeys);
|
||||
|
||||
wrappers.Clear();
|
||||
foreach (var k in keys)
|
||||
wrappers.Add(new HotkeyWrapper(k, hotkeys[k]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns edited hotkey map
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public HotkeysMapping GetHotkeys()
|
||||
{
|
||||
var result = new HotkeysMapping();
|
||||
foreach (var w in wrappers)
|
||||
result[w.ToKeyData()] = w.Action;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void btAdd_Click(object sender, EventArgs e)
|
||||
{
|
||||
wrappers.Add(new HotkeyWrapper(Keys.None, FCTBAction.None));
|
||||
}
|
||||
|
||||
private void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
|
||||
{
|
||||
var cell = (dgv[0, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if(cell.Items.Count == 0)
|
||||
foreach(var item in new string[]{"", "Ctrl", "Ctrl + Shift", "Ctrl + Alt", "Shift", "Shift + Alt", "Alt", "Ctrl + Shift + Alt"})
|
||||
cell.Items.Add(item);
|
||||
|
||||
cell = (dgv[1, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if (cell.Items.Count == 0)
|
||||
foreach (var item in Enum.GetValues(typeof(Keys)))
|
||||
cell.Items.Add(item);
|
||||
|
||||
cell = (dgv[2, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if (cell.Items.Count == 0)
|
||||
foreach (var item in Enum.GetValues(typeof(FCTBAction)))
|
||||
cell.Items.Add(item);
|
||||
}
|
||||
|
||||
private void btResore_Click(object sender, EventArgs e)
|
||||
{
|
||||
HotkeysMapping h = new HotkeysMapping();
|
||||
h.InitDefault();
|
||||
BuildWrappers(h);
|
||||
}
|
||||
|
||||
private void btRemove_Click(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = dgv.RowCount - 1; i >= 0; i--)
|
||||
if (dgv.Rows[i].Selected) dgv.Rows.RemoveAt(i);
|
||||
}
|
||||
|
||||
private void HotkeysEditorForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if(DialogResult == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
var actions = GetUnAssignedActions();
|
||||
if (!string.IsNullOrEmpty(actions))
|
||||
{
|
||||
if (MessageBox.Show("Some actions are not assigned!\r\nActions: " + actions + "\r\nPress Yes to save and exit, press No to continue editing", "Some actions is not assigned", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetUnAssignedActions()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var dic = new Dictionary<FCTBAction, FCTBAction>();
|
||||
|
||||
foreach (var w in wrappers)
|
||||
dic[w.Action] = w.Action;
|
||||
|
||||
foreach (var item in Enum.GetValues(typeof(FCTBAction)))
|
||||
if ((FCTBAction)item != FCTBAction.None)
|
||||
if(!((FCTBAction)item).ToString().StartsWith("CustomAction"))
|
||||
{
|
||||
if(!dic.ContainsKey((FCTBAction)item))
|
||||
sb.Append(item+", ");
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd(' ', ',');
|
||||
}
|
||||
}
|
||||
|
||||
internal class HotkeyWrapper
|
||||
{
|
||||
public HotkeyWrapper(Keys keyData, FCTBAction action)
|
||||
{
|
||||
KeyEventArgs a = new KeyEventArgs(keyData);
|
||||
Ctrl = a.Control;
|
||||
Shift = a.Shift;
|
||||
Alt = a.Alt;
|
||||
|
||||
Key = a.KeyCode;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public Keys ToKeyData()
|
||||
{
|
||||
var res = Key;
|
||||
if (Ctrl) res |= Keys.Control;
|
||||
if (Alt) res |= Keys.Alt;
|
||||
if (Shift) res |= Keys.Shift;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Ctrl;
|
||||
bool Shift;
|
||||
bool Alt;
|
||||
|
||||
public string Modifiers
|
||||
{
|
||||
get
|
||||
{
|
||||
var res = "";
|
||||
if (Ctrl) res += "Ctrl + ";
|
||||
if (Shift) res += "Shift + ";
|
||||
if (Alt) res += "Alt + ";
|
||||
|
||||
return res.Trim(' ', '+');
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Ctrl = Alt = Shift = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ctrl = value.Contains("Ctrl");
|
||||
Shift = value.Contains("Shift");
|
||||
Alt = value.Contains("Alt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Keys Key { get; set; }
|
||||
public FCTBAction Action { get; set; }
|
||||
}
|
||||
}
|
||||
129
FastColoredTextBox/HotkeysEditorForm.resx
Normal file
129
FastColoredTextBox/HotkeysEditorForm.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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>
|
||||
<metadata name="cbModifiers.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="cbKey.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="cbAction.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
</root>
|
||||
105
FastColoredTextBox/LimitedStack.cs
Normal file
105
FastColoredTextBox/LimitedStack.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Limited stack
|
||||
/// </summary>
|
||||
public class LimitedStack<T>
|
||||
{
|
||||
T[] items;
|
||||
int count;
|
||||
int start;
|
||||
|
||||
/// <summary>
|
||||
/// Max stack length
|
||||
/// </summary>
|
||||
public int MaxItemCount
|
||||
{
|
||||
get { return items.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current length of stack
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="maxItemCount">Maximum length of stack</param>
|
||||
public LimitedStack(int maxItemCount)
|
||||
{
|
||||
items = new T[maxItemCount];
|
||||
count = 0;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop item
|
||||
/// </summary>
|
||||
public T Pop()
|
||||
{
|
||||
if (count == 0)
|
||||
throw new Exception("Stack is empty");
|
||||
|
||||
int i = LastIndex;
|
||||
T item = items[i];
|
||||
items[i] = default(T);
|
||||
|
||||
count--;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
int LastIndex
|
||||
{
|
||||
get { return (start + count - 1) % items.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peek item
|
||||
/// </summary>
|
||||
public T Peek()
|
||||
{
|
||||
if (count == 0)
|
||||
return default(T);
|
||||
|
||||
return items[LastIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Push item
|
||||
/// </summary>
|
||||
public void Push(T item)
|
||||
{
|
||||
if (count == items.Length)
|
||||
start = (start + 1) % items.Length;
|
||||
else
|
||||
count++;
|
||||
|
||||
items[LastIndex] = item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear stack
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
items = new T[items.Length];
|
||||
count = 0;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] result = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = items[(start + i) % items.Length];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
289
FastColoredTextBox/Line.cs
Normal file
289
FastColoredTextBox/Line.cs
Normal file
@@ -0,0 +1,289 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Line of text
|
||||
/// </summary>
|
||||
public class Line : IList<Char>
|
||||
{
|
||||
protected List<Char> chars;
|
||||
|
||||
public string FoldingStartMarker { get; set; }
|
||||
public string FoldingEndMarker { get; set; }
|
||||
/// <summary>
|
||||
/// Text of line was changed
|
||||
/// </summary>
|
||||
public bool IsChanged { get; set; }
|
||||
/// <summary>
|
||||
/// Time of last visit of caret in this line
|
||||
/// </summary>
|
||||
/// <remarks>This property can be used for forward/backward navigating</remarks>
|
||||
public DateTime LastVisit { get; set; }
|
||||
/// <summary>
|
||||
/// Background brush.
|
||||
/// </summary>
|
||||
public Brush BackgroundBrush { get; set;}
|
||||
/// <summary>
|
||||
/// Unique ID
|
||||
/// </summary>
|
||||
public int UniqueId { get; private set; }
|
||||
/// <summary>
|
||||
/// Count of needed start spaces for AutoIndent
|
||||
/// </summary>
|
||||
public int AutoIndentSpacesNeededCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal Line(int uid)
|
||||
{
|
||||
this.UniqueId = uid;
|
||||
chars = new List<Char>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears style of chars, delete folding markers
|
||||
/// </summary>
|
||||
public void ClearStyle(StyleIndex styleIndex)
|
||||
{
|
||||
FoldingStartMarker = null;
|
||||
FoldingEndMarker = null;
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Char c = this[i];
|
||||
c.style &= ~styleIndex;
|
||||
this[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text of the line
|
||||
/// </summary>
|
||||
public virtual string Text
|
||||
{
|
||||
get{
|
||||
StringBuilder sb = new StringBuilder(Count);
|
||||
foreach(Char c in this)
|
||||
sb.Append(c.c);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears folding markers
|
||||
/// </summary>
|
||||
public void ClearFoldingMarkers()
|
||||
{
|
||||
FoldingStartMarker = null;
|
||||
FoldingEndMarker = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of start spaces
|
||||
/// </summary>
|
||||
public int StartSpacesCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int spacesCount = 0;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (this[i].c == ' ')
|
||||
spacesCount++;
|
||||
else
|
||||
break;
|
||||
return spacesCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(Char item)
|
||||
{
|
||||
return chars.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, Char item)
|
||||
{
|
||||
chars.Insert(index, item);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
chars.RemoveAt(index);
|
||||
}
|
||||
|
||||
public Char this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return chars[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
chars[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Char item)
|
||||
{
|
||||
chars.Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
chars.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(Char item)
|
||||
{
|
||||
return chars.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(Char[] array, int arrayIndex)
|
||||
{
|
||||
chars.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chars count
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return chars.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public bool Remove(Char item)
|
||||
{
|
||||
return chars.Remove(item);
|
||||
}
|
||||
|
||||
public IEnumerator<Char> GetEnumerator()
|
||||
{
|
||||
return chars.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return chars.GetEnumerator() as System.Collections.IEnumerator;
|
||||
}
|
||||
|
||||
public virtual void RemoveRange(int index, int count)
|
||||
{
|
||||
if (index >= Count)
|
||||
return;
|
||||
chars.RemoveRange(index, Math.Min(Count - index, count));
|
||||
}
|
||||
|
||||
public virtual void TrimExcess()
|
||||
{
|
||||
chars.TrimExcess();
|
||||
}
|
||||
|
||||
public virtual void AddRange(IEnumerable<Char> collection)
|
||||
{
|
||||
chars.AddRange(collection);
|
||||
}
|
||||
}
|
||||
|
||||
public struct LineInfo
|
||||
{
|
||||
List<int> cutOffPositions;
|
||||
//Y coordinate of line on screen
|
||||
internal int startY;
|
||||
internal int bottomPadding;
|
||||
//indent of secondary wordwrap strings (in chars)
|
||||
internal int wordWrapIndent;
|
||||
/// <summary>
|
||||
/// Visible state
|
||||
/// </summary>
|
||||
public VisibleState VisibleState;
|
||||
|
||||
public LineInfo(int startY)
|
||||
{
|
||||
cutOffPositions = null;
|
||||
VisibleState = VisibleState.Visible;
|
||||
this.startY = startY;
|
||||
bottomPadding = 0;
|
||||
wordWrapIndent = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Positions for wordwrap cutoffs
|
||||
/// </summary>
|
||||
public List<int> CutOffPositions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cutOffPositions == null)
|
||||
cutOffPositions = new List<int>();
|
||||
return cutOffPositions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of wordwrap string count for this line
|
||||
/// </summary>
|
||||
public int WordWrapStringsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (VisibleState)
|
||||
{
|
||||
case VisibleState.Visible:
|
||||
if (cutOffPositions == null)
|
||||
return 1;
|
||||
else
|
||||
return cutOffPositions.Count + 1;
|
||||
case VisibleState.Hidden: return 0;
|
||||
case VisibleState.StartOfHiddenBlock: return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetWordWrapStringStartPosition(int iWordWrapLine)
|
||||
{
|
||||
return iWordWrapLine == 0 ? 0 : CutOffPositions[iWordWrapLine - 1];
|
||||
}
|
||||
|
||||
internal int GetWordWrapStringFinishPosition(int iWordWrapLine, Line line)
|
||||
{
|
||||
if (WordWrapStringsCount <= 0)
|
||||
return 0;
|
||||
return iWordWrapLine == WordWrapStringsCount - 1 ? line.Count - 1 : CutOffPositions[iWordWrapLine] - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets index of wordwrap string for given char position
|
||||
/// </summary>
|
||||
public int GetWordWrapStringIndex(int iChar)
|
||||
{
|
||||
if (cutOffPositions == null || cutOffPositions.Count == 0) return 0;
|
||||
for (int i = 0; i < cutOffPositions.Count; i++)
|
||||
if (cutOffPositions[i] >/*>=*/ iChar)
|
||||
return i;
|
||||
return cutOffPositions.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public enum VisibleState: byte
|
||||
{
|
||||
Visible, StartOfHiddenBlock, Hidden
|
||||
}
|
||||
|
||||
public enum IndentMarker
|
||||
{
|
||||
None,
|
||||
Increased,
|
||||
Decreased
|
||||
}
|
||||
}
|
||||
98
FastColoredTextBox/LinesAccessor.cs
Normal file
98
FastColoredTextBox/LinesAccessor.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class LinesAccessor : IList<string>
|
||||
{
|
||||
IList<Line> ts;
|
||||
|
||||
public LinesAccessor(IList<Line> ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public int IndexOf(string item)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
if (ts[i].Text == item)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return ts[index].Text;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(string item)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
if (ts[i].Text == item)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
array[i + arrayIndex] = ts[i].Text;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return ts.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public bool Remove(string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
yield return ts[i].Text;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
183
FastColoredTextBox/MacrosManager.cs
Normal file
183
FastColoredTextBox/MacrosManager.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class records, stores and executes the macros.
|
||||
/// </summary>
|
||||
public class MacrosManager
|
||||
{
|
||||
private readonly List<object> macro = new List<object>();
|
||||
|
||||
internal MacrosManager(FastColoredTextBox ctrl)
|
||||
{
|
||||
UnderlayingControl = ctrl;
|
||||
AllowMacroRecordingByUser = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows to user to record macros
|
||||
/// </summary>
|
||||
public bool AllowMacroRecordingByUser { get;set; }
|
||||
|
||||
private bool isRecording;
|
||||
|
||||
/// <summary>
|
||||
/// Returns current recording state. Set to True/False to start/stop recording programmatically.
|
||||
/// </summary>
|
||||
public bool IsRecording
|
||||
{
|
||||
get { return isRecording; }
|
||||
set { isRecording = value; UnderlayingControl.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FCTB
|
||||
/// </summary>
|
||||
public FastColoredTextBox UnderlayingControl { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes recorded macro
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void ExecuteMacros()
|
||||
{
|
||||
IsRecording = false;
|
||||
UnderlayingControl.BeginUpdate();
|
||||
UnderlayingControl.Selection.BeginUpdate();
|
||||
UnderlayingControl.BeginAutoUndo();
|
||||
foreach (var item in macro)
|
||||
{
|
||||
if (item is Keys)
|
||||
{
|
||||
UnderlayingControl.ProcessKey((Keys)item);
|
||||
}
|
||||
if (item is KeyValuePair<char, Keys>)
|
||||
{
|
||||
var p = (KeyValuePair<char, Keys>)item;
|
||||
UnderlayingControl.ProcessKey(p.Key, p.Value);
|
||||
}
|
||||
|
||||
}
|
||||
UnderlayingControl.EndAutoUndo();
|
||||
UnderlayingControl.Selection.EndUpdate();
|
||||
UnderlayingControl.EndUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the char to current macro
|
||||
/// </summary>
|
||||
public void AddCharToMacros(char c, Keys modifiers)
|
||||
{
|
||||
macro.Add(new KeyValuePair<char, Keys>(c, modifiers));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds keyboard key to current macro
|
||||
/// </summary>
|
||||
public void AddKeyToMacros(Keys keyData)
|
||||
{
|
||||
macro.Add(keyData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears last recorded macro
|
||||
/// </summary>
|
||||
public void ClearMacros()
|
||||
{
|
||||
macro.Clear();
|
||||
}
|
||||
|
||||
|
||||
internal void ProcessKey(Keys keyData)
|
||||
{
|
||||
if (IsRecording)
|
||||
AddKeyToMacros(keyData);
|
||||
}
|
||||
|
||||
internal void ProcessKey(char c, Keys modifiers)
|
||||
{
|
||||
if (IsRecording)
|
||||
AddCharToMacros(c, modifiers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns True if last macro is empty
|
||||
/// </summary>
|
||||
public bool MacroIsEmpty { get { return macro.Count == 0; }}
|
||||
|
||||
/// <summary>
|
||||
/// Macros as string.
|
||||
/// </summary>
|
||||
public string Macros
|
||||
{
|
||||
get
|
||||
{
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var kc = new KeysConverter();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("<macros>");
|
||||
foreach (var item in macro)
|
||||
{
|
||||
if (item is Keys)
|
||||
{
|
||||
sb.AppendFormat("<item key='{0}' />\r\n", kc.ConvertToString((Keys)item));
|
||||
}
|
||||
else if (item is KeyValuePair<char, Keys>)
|
||||
{
|
||||
var p = (KeyValuePair<char, Keys>)item;
|
||||
sb.AppendFormat("<item char='{0}' key='{1}' />\r\n", (int)p.Key, kc.ConvertToString(p.Value));
|
||||
}
|
||||
}
|
||||
sb.AppendLine("</macros>");
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
isRecording = false;
|
||||
ClearMacros();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return;
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(value);
|
||||
var list = doc.SelectNodes("./macros/item");
|
||||
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var kc = new KeysConverter();
|
||||
|
||||
if(list != null)
|
||||
foreach (XmlElement node in list)
|
||||
{
|
||||
var ca = node.GetAttributeNode("char");
|
||||
var ka = node.GetAttributeNode("key");
|
||||
if (ca != null)
|
||||
{
|
||||
if(ka!=null)
|
||||
AddCharToMacros((char)int.Parse(ca.Value), (Keys)kc.ConvertFromString(ka.Value));
|
||||
else
|
||||
AddCharToMacros((char)int.Parse(ca.Value), Keys.None);
|
||||
}else
|
||||
if(ka!=null)
|
||||
AddKeyToMacros((Keys)kc.ConvertFromString(ka.Value));
|
||||
}
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
FastColoredTextBox/Place.cs
Normal file
99
FastColoredTextBox/Place.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Line index and char index
|
||||
/// </summary>
|
||||
public struct Place : IEquatable<Place>
|
||||
{
|
||||
public int iChar;
|
||||
public int iLine;
|
||||
|
||||
public Place(int iChar, int iLine)
|
||||
{
|
||||
this.iChar = iChar;
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Offset(int dx, int dy)
|
||||
{
|
||||
iChar += dx;
|
||||
iLine += dy;
|
||||
}
|
||||
|
||||
public bool Equals(Place other)
|
||||
{
|
||||
return iChar == other.iChar && iLine == other.iLine;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is Place) && Equals((Place)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return iChar.GetHashCode() ^ iLine.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator !=(Place p1, Place p2)
|
||||
{
|
||||
return !p1.Equals(p2);
|
||||
}
|
||||
|
||||
public static bool operator ==(Place p1, Place p2)
|
||||
{
|
||||
return p1.Equals(p2);
|
||||
}
|
||||
|
||||
public static bool operator <(Place p1, Place p2)
|
||||
{
|
||||
if (p1.iLine < p2.iLine) return true;
|
||||
if (p1.iLine > p2.iLine) return false;
|
||||
if (p1.iChar < p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator <=(Place p1, Place p2)
|
||||
{
|
||||
if (p1.Equals(p2)) return true;
|
||||
if (p1.iLine < p2.iLine) return true;
|
||||
if (p1.iLine > p2.iLine) return false;
|
||||
if (p1.iChar < p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator >(Place p1, Place p2)
|
||||
{
|
||||
if (p1.iLine > p2.iLine) return true;
|
||||
if (p1.iLine < p2.iLine) return false;
|
||||
if (p1.iChar > p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator >=(Place p1, Place p2)
|
||||
{
|
||||
if (p1.Equals(p2)) return true;
|
||||
if (p1.iLine > p2.iLine) return true;
|
||||
if (p1.iLine < p2.iLine) return false;
|
||||
if (p1.iChar > p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Place operator +(Place p1, Place p2)
|
||||
{
|
||||
return new Place(p1.iChar + p2.iChar, p1.iLine + p2.iLine);
|
||||
}
|
||||
|
||||
public static Place Empty
|
||||
{
|
||||
get { return new Place(); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + iChar + "," + iLine + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
75
FastColoredTextBox/PlatformType.cs
Normal file
75
FastColoredTextBox/PlatformType.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public static class PlatformType
|
||||
{
|
||||
const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;
|
||||
const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;
|
||||
const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;
|
||||
const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SYSTEM_INFO
|
||||
{
|
||||
public ushort wProcessorArchitecture;
|
||||
public ushort wReserved;
|
||||
public uint dwPageSize;
|
||||
public IntPtr lpMinimumApplicationAddress;
|
||||
public IntPtr lpMaximumApplicationAddress;
|
||||
public UIntPtr dwActiveProcessorMask;
|
||||
public uint dwNumberOfProcessors;
|
||||
public uint dwProcessorType;
|
||||
public uint dwAllocationGranularity;
|
||||
public ushort wProcessorLevel;
|
||||
public ushort wProcessorRevision;
|
||||
};
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);
|
||||
|
||||
public static Platform GetOperationSystemPlatform()
|
||||
{
|
||||
var sysInfo = new SYSTEM_INFO();
|
||||
|
||||
// WinXP and older - use GetNativeSystemInfo
|
||||
if (Environment.OSVersion.Version.Major > 5 ||
|
||||
(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1))
|
||||
{
|
||||
GetNativeSystemInfo(ref sysInfo);
|
||||
}
|
||||
// else use GetSystemInfo
|
||||
else
|
||||
{
|
||||
GetSystemInfo(ref sysInfo);
|
||||
}
|
||||
|
||||
switch (sysInfo.wProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return Platform.X64;
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return Platform.X86;
|
||||
|
||||
default:
|
||||
return Platform.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Platform
|
||||
{
|
||||
X86,
|
||||
X64,
|
||||
Unknown
|
||||
}
|
||||
|
||||
}
|
||||
37
FastColoredTextBox/Properties/AssemblyInfo.cs
Normal file
37
FastColoredTextBox/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("FastColoredTextBox")]
|
||||
[assembly: AssemblyDescription("Fast сolored textbox control")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Pavel Torgashov")]
|
||||
[assembly: AssemblyProduct("FastColoredTextBox")]
|
||||
[assembly: AssemblyCopyright("© Pavel Torgashov, 2011-2015, pavel_torgashov@ukr.net.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("95be11b3-45bc-4512-be26-a860a78bd1f1")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.16.11.0")]
|
||||
[assembly: AssemblyFileVersion("2.16.11.0")]
|
||||
|
||||
1678
FastColoredTextBox/Range.cs
Normal file
1678
FastColoredTextBox/Range.cs
Normal file
File diff suppressed because it is too large
Load Diff
196
FastColoredTextBox/ReplaceForm.Designer.cs
generated
Normal file
196
FastColoredTextBox/ReplaceForm.Designer.cs
generated
Normal file
@@ -0,0 +1,196 @@
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class ReplaceForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btClose = new System.Windows.Forms.Button();
|
||||
this.btFindNext = new System.Windows.Forms.Button();
|
||||
this.tbFind = new System.Windows.Forms.TextBox();
|
||||
this.cbRegex = new System.Windows.Forms.CheckBox();
|
||||
this.cbMatchCase = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.cbWholeWord = new System.Windows.Forms.CheckBox();
|
||||
this.btReplace = new System.Windows.Forms.Button();
|
||||
this.btReplaceAll = new System.Windows.Forms.Button();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tbReplace = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btClose
|
||||
//
|
||||
this.btClose.Location = new System.Drawing.Point(273, 153);
|
||||
this.btClose.Name = "btClose";
|
||||
this.btClose.Size = new System.Drawing.Size(75, 23);
|
||||
this.btClose.TabIndex = 8;
|
||||
this.btClose.Text = "Close";
|
||||
this.btClose.UseVisualStyleBackColor = true;
|
||||
this.btClose.Click += new System.EventHandler(this.btClose_Click);
|
||||
//
|
||||
// btFindNext
|
||||
//
|
||||
this.btFindNext.Location = new System.Drawing.Point(111, 124);
|
||||
this.btFindNext.Name = "btFindNext";
|
||||
this.btFindNext.Size = new System.Drawing.Size(75, 23);
|
||||
this.btFindNext.TabIndex = 5;
|
||||
this.btFindNext.Text = "Find next";
|
||||
this.btFindNext.UseVisualStyleBackColor = true;
|
||||
this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);
|
||||
//
|
||||
// tbFind
|
||||
//
|
||||
this.tbFind.Location = new System.Drawing.Point(62, 12);
|
||||
this.tbFind.Name = "tbFind";
|
||||
this.tbFind.Size = new System.Drawing.Size(286, 20);
|
||||
this.tbFind.TabIndex = 0;
|
||||
this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// cbRegex
|
||||
//
|
||||
this.cbRegex.AutoSize = true;
|
||||
this.cbRegex.Location = new System.Drawing.Point(273, 38);
|
||||
this.cbRegex.Name = "cbRegex";
|
||||
this.cbRegex.Size = new System.Drawing.Size(57, 17);
|
||||
this.cbRegex.TabIndex = 3;
|
||||
this.cbRegex.Text = "Regex";
|
||||
this.cbRegex.UseVisualStyleBackColor = true;
|
||||
this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// cbMatchCase
|
||||
//
|
||||
this.cbMatchCase.AutoSize = true;
|
||||
this.cbMatchCase.Location = new System.Drawing.Point(66, 38);
|
||||
this.cbMatchCase.Name = "cbMatchCase";
|
||||
this.cbMatchCase.Size = new System.Drawing.Size(82, 17);
|
||||
this.cbMatchCase.TabIndex = 1;
|
||||
this.cbMatchCase.Text = "Match case";
|
||||
this.cbMatchCase.UseVisualStyleBackColor = true;
|
||||
this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(23, 14);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(33, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Find: ";
|
||||
//
|
||||
// cbWholeWord
|
||||
//
|
||||
this.cbWholeWord.AutoSize = true;
|
||||
this.cbWholeWord.Location = new System.Drawing.Point(154, 38);
|
||||
this.cbWholeWord.Name = "cbWholeWord";
|
||||
this.cbWholeWord.Size = new System.Drawing.Size(113, 17);
|
||||
this.cbWholeWord.TabIndex = 2;
|
||||
this.cbWholeWord.Text = "Match whole word";
|
||||
this.cbWholeWord.UseVisualStyleBackColor = true;
|
||||
this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// btReplace
|
||||
//
|
||||
this.btReplace.Location = new System.Drawing.Point(192, 124);
|
||||
this.btReplace.Name = "btReplace";
|
||||
this.btReplace.Size = new System.Drawing.Size(75, 23);
|
||||
this.btReplace.TabIndex = 6;
|
||||
this.btReplace.Text = "Replace";
|
||||
this.btReplace.UseVisualStyleBackColor = true;
|
||||
this.btReplace.Click += new System.EventHandler(this.btReplace_Click);
|
||||
//
|
||||
// btReplaceAll
|
||||
//
|
||||
this.btReplaceAll.Location = new System.Drawing.Point(273, 124);
|
||||
this.btReplaceAll.Name = "btReplaceAll";
|
||||
this.btReplaceAll.Size = new System.Drawing.Size(75, 23);
|
||||
this.btReplaceAll.TabIndex = 7;
|
||||
this.btReplaceAll.Text = "Replace all";
|
||||
this.btReplaceAll.UseVisualStyleBackColor = true;
|
||||
this.btReplaceAll.Click += new System.EventHandler(this.btReplaceAll_Click);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 81);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(50, 13);
|
||||
this.label2.TabIndex = 9;
|
||||
this.label2.Text = "Replace:";
|
||||
//
|
||||
// tbReplace
|
||||
//
|
||||
this.tbReplace.Location = new System.Drawing.Point(62, 78);
|
||||
this.tbReplace.Name = "tbReplace";
|
||||
this.tbReplace.Size = new System.Drawing.Size(286, 20);
|
||||
this.tbReplace.TabIndex = 0;
|
||||
this.tbReplace.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbReplace.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// ReplaceForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(360, 191);
|
||||
this.Controls.Add(this.tbFind);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.tbReplace);
|
||||
this.Controls.Add(this.btReplaceAll);
|
||||
this.Controls.Add(this.btReplace);
|
||||
this.Controls.Add(this.cbWholeWord);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.cbMatchCase);
|
||||
this.Controls.Add(this.cbRegex);
|
||||
this.Controls.Add(this.btFindNext);
|
||||
this.Controls.Add(this.btClose);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Name = "ReplaceForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Find and replace";
|
||||
this.TopMost = true;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ReplaceForm_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btClose;
|
||||
private System.Windows.Forms.Button btFindNext;
|
||||
private System.Windows.Forms.CheckBox cbRegex;
|
||||
private System.Windows.Forms.CheckBox cbMatchCase;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox cbWholeWord;
|
||||
private System.Windows.Forms.Button btReplace;
|
||||
private System.Windows.Forms.Button btReplaceAll;
|
||||
private System.Windows.Forms.Label label2;
|
||||
public System.Windows.Forms.TextBox tbFind;
|
||||
public System.Windows.Forms.TextBox tbReplace;
|
||||
}
|
||||
}
|
||||
187
FastColoredTextBox/ReplaceForm.cs
Normal file
187
FastColoredTextBox/ReplaceForm.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class ReplaceForm : Form
|
||||
{
|
||||
FastColoredTextBox tb;
|
||||
bool firstSearch = true;
|
||||
Place startPlace;
|
||||
|
||||
public ReplaceForm(FastColoredTextBox tb)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.tb = tb;
|
||||
}
|
||||
|
||||
private void btClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btFindNext_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Find(tbFind.Text))
|
||||
MessageBox.Show("Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Range> FindAll(string pattern)
|
||||
{
|
||||
var opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
var range = tb.Selection.IsEmpty? tb.Range.Clone() : tb.Selection.Clone();
|
||||
//
|
||||
var list = new List<Range>();
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
list.Add(r);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public bool Find(string pattern)
|
||||
{
|
||||
RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
Range range = tb.Selection.Clone();
|
||||
range.Normalize();
|
||||
//
|
||||
if (firstSearch)
|
||||
{
|
||||
startPlace = range.Start;
|
||||
firstSearch = false;
|
||||
}
|
||||
//
|
||||
range.Start = range.End;
|
||||
if (range.Start >= startPlace)
|
||||
range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);
|
||||
else
|
||||
range.End = startPlace;
|
||||
//
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
{
|
||||
tb.Selection.Start = r.Start;
|
||||
tb.Selection.End = r.End;
|
||||
tb.DoSelectionVisible();
|
||||
tb.Invalidate();
|
||||
return true;
|
||||
}
|
||||
if (range.Start >= startPlace && startPlace > Place.Empty)
|
||||
{
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
return Find(pattern);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void tbFind_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == '\r')
|
||||
btFindNext_Click(sender, null);
|
||||
if (e.KeyChar == '\x1b')
|
||||
Hide();
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // David
|
||||
{
|
||||
if (keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
private void ReplaceForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
Hide();
|
||||
}
|
||||
this.tb.Focus();
|
||||
}
|
||||
|
||||
private void btReplace_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tb.SelectionLength != 0)
|
||||
if (!tb.Selection.ReadOnly)
|
||||
tb.InsertText(tbReplace.Text);
|
||||
btFindNext_Click(sender, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void btReplaceAll_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
tb.Selection.BeginUpdate();
|
||||
|
||||
//search
|
||||
var ranges = FindAll(tbFind.Text);
|
||||
//check readonly
|
||||
var ro = false;
|
||||
foreach (var r in ranges)
|
||||
if (r.ReadOnly)
|
||||
{
|
||||
ro = true;
|
||||
break;
|
||||
}
|
||||
//replace
|
||||
if (!ro)
|
||||
if (ranges.Count > 0)
|
||||
{
|
||||
tb.TextSource.Manager.ExecuteCommand(new ReplaceTextCommand(tb.TextSource, ranges, tbReplace.Text));
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
}
|
||||
//
|
||||
tb.Invalidate();
|
||||
MessageBox.Show(ranges.Count + " occurrence(s) replaced");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
tbFind.Focus();
|
||||
ResetSerach();
|
||||
}
|
||||
|
||||
void ResetSerach()
|
||||
{
|
||||
firstSearch = true;
|
||||
}
|
||||
|
||||
private void cbMatchCase_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ResetSerach();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
FastColoredTextBox/ReplaceForm.resx
Normal file
120
FastColoredTextBox/ReplaceForm.resx
Normal file
@@ -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>
|
||||
37
FastColoredTextBox/Ruler.Designer.cs
generated
Normal file
37
FastColoredTextBox/Ruler.Designer.cs
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class Ruler
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
138
FastColoredTextBox/Ruler.cs
Normal file
138
FastColoredTextBox/Ruler.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class Ruler : UserControl
|
||||
{
|
||||
public EventHandler TargetChanged;
|
||||
|
||||
[DefaultValue(typeof(Color), "ControlLight")]
|
||||
public Color BackColor2 { get; set; }
|
||||
|
||||
[DefaultValue(typeof(Color), "DarkGray")]
|
||||
public Color TickColor { get; set; }
|
||||
|
||||
[DefaultValue(typeof(Color), "Black")]
|
||||
public Color CaretTickColor { get; set; }
|
||||
|
||||
FastColoredTextBox target;
|
||||
|
||||
[Description("Target FastColoredTextBox")]
|
||||
public FastColoredTextBox Target
|
||||
{
|
||||
get { return target; }
|
||||
set
|
||||
{
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
target = value;
|
||||
Subscribe(target);
|
||||
OnTargetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public Ruler()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
MinimumSize = new Size(0, 24);
|
||||
MaximumSize = new Size(int.MaxValue/2, 24);
|
||||
|
||||
BackColor2 = SystemColors.ControlLight;
|
||||
TickColor = Color.DarkGray;
|
||||
CaretTickColor = Color.Black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnTargetChanged()
|
||||
{
|
||||
if (TargetChanged != null)
|
||||
TargetChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void UnSubscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll -= new ScrollEventHandler(target_Scroll);
|
||||
target.SelectionChanged -= new EventHandler(target_SelectionChanged);
|
||||
target.VisibleRangeChanged -= new EventHandler(target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Subscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll += new ScrollEventHandler(target_Scroll);
|
||||
target.SelectionChanged += new EventHandler(target_SelectionChanged);
|
||||
target.VisibleRangeChanged += new EventHandler(target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
void target_VisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void target_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected virtual void target_Scroll(object sender, ScrollEventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
Point car = PointToClient(target.PointToScreen(target.PlaceToPoint(target.Selection.Start)));
|
||||
|
||||
Size fontSize = TextRenderer.MeasureText("W", Font);
|
||||
|
||||
int column = 0;
|
||||
e.Graphics.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, Width, Height), BackColor, BackColor2, 270), new Rectangle(0, 0, Width, Height));
|
||||
|
||||
float columnWidth = target.CharWidth;
|
||||
var sf = new StringFormat();
|
||||
sf.Alignment = StringAlignment.Center;
|
||||
sf.LineAlignment = StringAlignment.Near;
|
||||
|
||||
var zeroPoint = target.PositionToPoint(0);
|
||||
zeroPoint = PointToClient(target.PointToScreen(zeroPoint));
|
||||
|
||||
using (var pen = new Pen(TickColor))
|
||||
using (var textBrush = new SolidBrush(ForeColor))
|
||||
for (float x = zeroPoint.X; x < Right; x += columnWidth, ++column)
|
||||
{
|
||||
if (column % 10 == 0)
|
||||
e.Graphics.DrawString(column.ToString(), Font, textBrush, x, 0f, sf);
|
||||
|
||||
e.Graphics.DrawLine(pen, (int)x, fontSize.Height + (column % 5 == 0 ? 1 : 3), (int)x, Height - 4);
|
||||
}
|
||||
|
||||
using (var pen = new Pen(TickColor))
|
||||
e.Graphics.DrawLine(pen, new Point(car.X - 3, Height - 3), new Point(car.X + 3, Height - 3));
|
||||
|
||||
using (var pen = new Pen(CaretTickColor))
|
||||
{
|
||||
e.Graphics.DrawLine(pen, new Point(car.X - 2, fontSize.Height + 3), new Point(car.X - 2, Height - 4));
|
||||
e.Graphics.DrawLine(pen, new Point(car.X, fontSize.Height + 1), new Point(car.X, Height - 4));
|
||||
e.Graphics.DrawLine(pen, new Point(car.X + 2, fontSize.Height + 3), new Point(car.X + 2, Height - 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
430
FastColoredTextBox/Style.cs
Normal file
430
FastColoredTextBox/Style.cs
Normal file
@@ -0,0 +1,430 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Style of chars
|
||||
/// </summary>
|
||||
/// <remarks>This is base class for all text and design renderers</remarks>
|
||||
public abstract class Style : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// This style is exported to outer formats (HTML for example)
|
||||
/// </summary>
|
||||
public virtual bool IsExportable { get; set; }
|
||||
/// <summary>
|
||||
/// Occurs when user click on StyleVisualMarker joined to this style
|
||||
/// </summary>
|
||||
public event EventHandler<VisualMarkerEventArgs> VisualMarkerClick;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public Style()
|
||||
{
|
||||
IsExportable = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders given range of text
|
||||
/// </summary>
|
||||
/// <param name="gr">Graphics object</param>
|
||||
/// <param name="position">Position of the range in absolute control coordinates</param>
|
||||
/// <param name="range">Rendering range of text</param>
|
||||
public abstract void Draw(Graphics gr, Point position, Range range);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when user click on StyleVisualMarker joined to this style
|
||||
/// </summary>
|
||||
public virtual void OnVisualMarkerClick(FastColoredTextBox tb, VisualMarkerEventArgs args)
|
||||
{
|
||||
if (VisualMarkerClick != null)
|
||||
VisualMarkerClick(tb, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows VisualMarker
|
||||
/// Call this method in Draw method, when you need to show VisualMarker for your style
|
||||
/// </summary>
|
||||
protected virtual void AddVisualMarker(FastColoredTextBox tb, StyleVisualMarker marker)
|
||||
{
|
||||
tb.AddVisualMarker(marker);
|
||||
}
|
||||
|
||||
public static Size GetSizeOfRange(Range range)
|
||||
{
|
||||
return new Size((range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
}
|
||||
|
||||
public static GraphicsPath GetRoundedRectangle(Rectangle rect, int d)
|
||||
{
|
||||
GraphicsPath gp = new GraphicsPath();
|
||||
|
||||
gp.AddArc(rect.X, rect.Y, d, d, 180, 90);
|
||||
gp.AddArc(rect.X + rect.Width - d, rect.Y, d, d, 270, 90);
|
||||
gp.AddArc(rect.X + rect.Width - d, rect.Y + rect.Height - d, d, d, 0, 90);
|
||||
gp.AddArc(rect.X, rect.Y + rect.Height - d, d, d, 90, 90);
|
||||
gp.AddLine(rect.X, rect.Y + rect.Height - d, rect.X, rect.Y + d / 2);
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns CSS for export to HTML
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GetCSS()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns RTF descriptor for export to RTF
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual RTFStyleDescriptor GetRTF()
|
||||
{
|
||||
return new RTFStyleDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Style for chars rendering
|
||||
/// This renderer can draws chars, with defined fore and back colors
|
||||
/// </summary>
|
||||
public class TextStyle : Style
|
||||
{
|
||||
public Brush ForeBrush { get; set; }
|
||||
public Brush BackgroundBrush { get; set; }
|
||||
public FontStyle FontStyle { get; set; }
|
||||
//public readonly Font Font;
|
||||
public StringFormat stringFormat;
|
||||
|
||||
public TextStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle)
|
||||
{
|
||||
this.ForeBrush = foreBrush;
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
this.FontStyle = fontStyle;
|
||||
stringFormat = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
gr.FillRectangle(BackgroundBrush, position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
//draw chars
|
||||
using(var f = new Font(range.tb.Font, FontStyle))
|
||||
{
|
||||
Line line = range.tb[range.Start.iLine];
|
||||
float dx = range.tb.CharWidth;
|
||||
float y = position.Y + range.tb.LineInterval/2;
|
||||
float x = position.X - range.tb.CharWidth/3;
|
||||
|
||||
if (ForeBrush == null)
|
||||
ForeBrush = new SolidBrush(range.tb.ForeColor);
|
||||
|
||||
if (range.tb.ImeAllowed)
|
||||
{
|
||||
//IME mode
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
{
|
||||
SizeF size = FastColoredTextBox.GetCharSize(f, line[i].c);
|
||||
|
||||
var gs = gr.Save();
|
||||
float k = size.Width > range.tb.CharWidth + 1 ? range.tb.CharWidth/size.Width : 1;
|
||||
gr.TranslateTransform(x, y + (1 - k)*range.tb.CharHeight/2);
|
||||
gr.ScaleTransform(k, (float) Math.Sqrt(k));
|
||||
gr.DrawString(line[i].c.ToString(), f, ForeBrush, 0, 0, stringFormat);
|
||||
gr.Restore(gs);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//classic mode
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
{
|
||||
//draw char
|
||||
gr.DrawString(line[i].c.ToString(), f, ForeBrush, x, y, stringFormat);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCSS()
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "background-color:" + s + ";";
|
||||
}
|
||||
if (ForeBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((ForeBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "color:" + s + ";";
|
||||
}
|
||||
if ((FontStyle & FontStyle.Bold) != 0)
|
||||
result += "font-weight:bold;";
|
||||
if ((FontStyle & FontStyle.Italic) != 0)
|
||||
result += "font-style:oblique;";
|
||||
if ((FontStyle & FontStyle.Strikeout) != 0)
|
||||
result += "text-decoration:line-through;";
|
||||
if ((FontStyle & FontStyle.Underline) != 0)
|
||||
result += "text-decoration:underline;";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override RTFStyleDescriptor GetRTF()
|
||||
{
|
||||
var result = new RTFStyleDescriptor();
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
result.BackColor = (BackgroundBrush as SolidBrush).Color;
|
||||
|
||||
if (ForeBrush is SolidBrush)
|
||||
result.ForeColor = (ForeBrush as SolidBrush).Color;
|
||||
|
||||
if ((FontStyle & FontStyle.Bold) != 0)
|
||||
result.AdditionalTags += @"\b";
|
||||
if ((FontStyle & FontStyle.Italic) != 0)
|
||||
result.AdditionalTags += @"\i";
|
||||
if ((FontStyle & FontStyle.Strikeout) != 0)
|
||||
result.AdditionalTags += @"\strike";
|
||||
if ((FontStyle & FontStyle.Underline) != 0)
|
||||
result.AdditionalTags += @"\ul";
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renderer for folded block
|
||||
/// </summary>
|
||||
public class FoldedBlockStyle : TextStyle
|
||||
{
|
||||
public FoldedBlockStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle):
|
||||
base(foreBrush, backgroundBrush, fontStyle)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
if (range.End.iChar > range.Start.iChar)
|
||||
{
|
||||
base.Draw(gr, position, range);
|
||||
|
||||
int firstNonSpaceSymbolX = position.X;
|
||||
|
||||
//find first non space symbol
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
if (range.tb[range.Start.iLine][i].c != ' ')
|
||||
break;
|
||||
else
|
||||
firstNonSpaceSymbolX += range.tb.CharWidth;
|
||||
|
||||
//create marker
|
||||
range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine, new Rectangle(firstNonSpaceSymbolX, position.Y, position.X + (range.End.iChar - range.Start.iChar) * range.tb.CharWidth - firstNonSpaceSymbolX, range.tb.CharHeight)));
|
||||
}
|
||||
else
|
||||
{
|
||||
//draw '...'
|
||||
using(Font f = new Font(range.tb.Font, FontStyle))
|
||||
gr.DrawString("...", f, ForeBrush, range.tb.LeftIndent, position.Y - 2);
|
||||
//create marker
|
||||
range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine, new Rectangle(range.tb.LeftIndent + 2, position.Y, 2 * range.tb.CharHeight, range.tb.CharHeight)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renderer for selected area
|
||||
/// </summary>
|
||||
public class SelectionStyle : Style
|
||||
{
|
||||
public Brush BackgroundBrush{ get; set;}
|
||||
public Brush ForegroundBrush { get; private set; }
|
||||
|
||||
public override bool IsExportable
|
||||
{
|
||||
get{return false;} set{}
|
||||
}
|
||||
|
||||
public SelectionStyle(Brush backgroundBrush, Brush foregroundBrush = null)
|
||||
{
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
this.ForegroundBrush = foregroundBrush;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
{
|
||||
gr.SmoothingMode = SmoothingMode.None;
|
||||
var rect = new Rectangle(position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
if (rect.Width == 0)
|
||||
return;
|
||||
gr.FillRectangle(BackgroundBrush, rect);
|
||||
//
|
||||
if (ForegroundBrush != null)
|
||||
{
|
||||
//draw text
|
||||
gr.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
var r = new Range(range.tb, range.Start.iChar, range.Start.iLine,
|
||||
Math.Min(range.tb[range.End.iLine].Count, range.End.iChar), range.End.iLine);
|
||||
using (var style = new TextStyle(ForegroundBrush, null, FontStyle.Regular))
|
||||
style.Draw(gr, new Point(position.X, position.Y - 1), r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker style
|
||||
/// Draws background color for text
|
||||
/// </summary>
|
||||
public class MarkerStyle : Style
|
||||
{
|
||||
public Brush BackgroundBrush{get;set;}
|
||||
|
||||
public MarkerStyle(Brush backgroundBrush)
|
||||
{
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
IsExportable = true;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
{
|
||||
Rectangle rect = new Rectangle(position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
if (rect.Width == 0)
|
||||
return;
|
||||
gr.FillRectangle(BackgroundBrush, rect);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCSS()
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "background-color:" + s + ";";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws small rectangle for popup menu
|
||||
/// </summary>
|
||||
public class ShortcutStyle : Style
|
||||
{
|
||||
public Pen borderPen;
|
||||
|
||||
public ShortcutStyle(Pen borderPen)
|
||||
{
|
||||
this.borderPen = borderPen;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//get last char coordinates
|
||||
Point p = range.tb.PlaceToPoint(range.End);
|
||||
//draw small square under char
|
||||
Rectangle rect = new Rectangle(p.X - 5, p.Y + range.tb.CharHeight - 2, 4, 3);
|
||||
gr.FillPath(Brushes.White, GetRoundedRectangle(rect, 1));
|
||||
gr.DrawPath(borderPen, GetRoundedRectangle(rect, 1));
|
||||
//add visual marker for handle mouse events
|
||||
AddVisualMarker(range.tb, new StyleVisualMarker(new Rectangle(p.X-range.tb.CharWidth, p.Y, range.tb.CharWidth, range.tb.CharHeight), this));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This style draws a wavy line below a given text range.
|
||||
/// </summary>
|
||||
/// <remarks>Thanks for Yallie</remarks>
|
||||
public class WavyLineStyle : Style
|
||||
{
|
||||
private Pen Pen { get; set; }
|
||||
|
||||
public WavyLineStyle(int alpha, Color color)
|
||||
{
|
||||
Pen = new Pen(Color.FromArgb(alpha, color));
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point pos, Range range)
|
||||
{
|
||||
var size = GetSizeOfRange(range);
|
||||
var start = new Point(pos.X, pos.Y + size.Height - 1);
|
||||
var end = new Point(pos.X + size.Width, pos.Y + size.Height - 1);
|
||||
DrawWavyLine(gr, start, end);
|
||||
}
|
||||
|
||||
private void DrawWavyLine(Graphics graphics, Point start, Point end)
|
||||
{
|
||||
if (end.X - start.X < 2)
|
||||
{
|
||||
graphics.DrawLine(Pen, start, end);
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = -1;
|
||||
var points = new List<Point>();
|
||||
|
||||
for (int i = start.X; i <= end.X; i += 2)
|
||||
{
|
||||
points.Add(new Point(i, start.Y + offset));
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
graphics.DrawLines(Pen, points.ToArray());
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
if (Pen != null)
|
||||
Pen.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This style is used to mark range of text as ReadOnly block
|
||||
/// </summary>
|
||||
/// <remarks>You can inherite this style to add visual effects of readonly text</remarks>
|
||||
public class ReadOnlyStyle : Style
|
||||
{
|
||||
public ReadOnlyStyle()
|
||||
{
|
||||
IsExportable = false;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
51
FastColoredTextBox/SyntaxDescriptor.cs
Normal file
51
FastColoredTextBox/SyntaxDescriptor.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class SyntaxDescriptor: IDisposable
|
||||
{
|
||||
public char leftBracket = '(';
|
||||
public char rightBracket = ')';
|
||||
public char leftBracket2 = '{';
|
||||
public char rightBracket2 = '}';
|
||||
public BracketsHighlightStrategy bracketsHighlightStrategy = BracketsHighlightStrategy.Strategy2;
|
||||
public readonly List<Style> styles = new List<Style>();
|
||||
public readonly List<RuleDesc> rules = new List<RuleDesc>();
|
||||
public readonly List<FoldingDesc> foldings = new List<FoldingDesc>();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var style in styles)
|
||||
style.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class RuleDesc
|
||||
{
|
||||
Regex regex;
|
||||
public string pattern;
|
||||
public RegexOptions options = RegexOptions.None;
|
||||
public Style style;
|
||||
|
||||
public Regex Regex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (regex == null)
|
||||
{
|
||||
regex = new Regex(pattern, SyntaxHighlighter.RegexCompiledOption | options);
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FoldingDesc
|
||||
{
|
||||
public string startMarkerRegex;
|
||||
public string finishMarkerRegex;
|
||||
public RegexOptions options = RegexOptions.None;
|
||||
}
|
||||
}
|
||||
1383
FastColoredTextBox/SyntaxHighlighter.cs
Normal file
1383
FastColoredTextBox/SyntaxHighlighter.cs
Normal file
File diff suppressed because it is too large
Load Diff
509
FastColoredTextBox/SyntaxHighlighter.cs.old
Normal file
509
FastColoredTextBox/SyntaxHighlighter.cs.old
Normal file
@@ -0,0 +1,509 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class SyntaxHighlighter: IDisposable
|
||||
{
|
||||
//styles
|
||||
public readonly Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular);
|
||||
public readonly Style BlueBoldStyle = new TextStyle(Brushes.Blue, null, FontStyle.Bold);
|
||||
public readonly Style BoldStyle = new TextStyle(null, null, FontStyle.Bold | FontStyle.Underline);
|
||||
public readonly Style GrayStyle = new TextStyle(Brushes.Gray, null, FontStyle.Regular);
|
||||
public readonly Style MagentaStyle = new TextStyle(Brushes.Magenta, null, FontStyle.Regular);
|
||||
public readonly Style GreenStyle = new TextStyle(Brushes.Green, null, FontStyle.Italic);
|
||||
public readonly Style BrownStyle = new TextStyle(Brushes.Brown, null, FontStyle.Italic);
|
||||
public readonly Style RedStyle = new TextStyle(Brushes.Red, null, FontStyle.Regular);
|
||||
public readonly Style MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);
|
||||
//
|
||||
Dictionary<string, SyntaxDescriptor> descByXMLfileNames = new Dictionary<string, SyntaxDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Highlights syntax for given language
|
||||
/// </summary>
|
||||
public virtual void HighlightSyntax(Language language, Range range)
|
||||
{
|
||||
switch (language)
|
||||
{
|
||||
case Language.CSharp: CSharpSyntaxHighlight(range); break;
|
||||
case Language.VB: VBSyntaxHighlight(range); break;
|
||||
case Language.HTML: HTMLSyntaxHighlight(range); break;
|
||||
case Language.SQL: SQLSyntaxHighlight(range); break;
|
||||
case Language.PHP: PHPSyntaxHighlight(range); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights syntax for given XML description file
|
||||
/// </summary>
|
||||
public virtual void HighlightSyntax(string XMLdescriptionFile, Range range)
|
||||
{
|
||||
SyntaxDescriptor desc = null;
|
||||
if (!descByXMLfileNames.TryGetValue(XMLdescriptionFile, out desc))
|
||||
{
|
||||
var doc = new XmlDocument();
|
||||
string file = XMLdescriptionFile;
|
||||
if (!File.Exists(file))
|
||||
file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.GetFileName(file));
|
||||
|
||||
doc.LoadXml(File.ReadAllText(file));
|
||||
desc = ParseXmlDescription(doc);
|
||||
descByXMLfileNames[XMLdescriptionFile] = desc;
|
||||
}
|
||||
HighlightSyntax(desc, range);
|
||||
}
|
||||
|
||||
public virtual void AutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
FastColoredTextBox tb = (sender as FastColoredTextBox);
|
||||
Language language = tb.Language;
|
||||
switch (language)
|
||||
{
|
||||
case Language.CSharp: CSharpAutoIndentNeeded(sender, args); break;
|
||||
case Language.VB: VBAutoIndentNeeded(sender, args); break;
|
||||
case Language.HTML: HTMLAutoIndentNeeded(sender, args); break;
|
||||
case Language.SQL: SQLAutoIndentNeeded(sender, args); break;
|
||||
case Language.PHP: PHPAutoIndentNeeded(sender, args); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PHPAutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
FastColoredTextBox tb = sender as FastColoredTextBox;
|
||||
tb.CalcAutoIndentShiftByCodeFolding(sender, args);
|
||||
}
|
||||
|
||||
private void SQLAutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
FastColoredTextBox tb = sender as FastColoredTextBox;
|
||||
tb.CalcAutoIndentShiftByCodeFolding(sender, args);
|
||||
}
|
||||
|
||||
private void HTMLAutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
FastColoredTextBox tb = sender as FastColoredTextBox;
|
||||
tb.CalcAutoIndentShiftByCodeFolding(sender, args);
|
||||
}
|
||||
|
||||
private void VBAutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
//end of block
|
||||
if (Regex.IsMatch(args.LineText, @"^\s*(End|EndIf|Next|Loop)\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
args.Shift = -args.TabLength;
|
||||
args.ShiftNextLines = -args.TabLength;
|
||||
return;
|
||||
}
|
||||
//start of declaration
|
||||
if (Regex.IsMatch(args.LineText, @"\b(Class|Property|Enum|Structure|Sub|Function|Namespace|Interface|Get|Set)\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
args.ShiftNextLines = args.TabLength;
|
||||
return;
|
||||
}
|
||||
// then ...
|
||||
if (Regex.IsMatch(args.LineText, @"\b(Then)\s*\S+", RegexOptions.IgnoreCase))
|
||||
return;
|
||||
//start of operator block
|
||||
if (Regex.IsMatch(args.LineText, @"^\s*(If|While|For|Do|Try|With|Using|Select)\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
args.ShiftNextLines = args.TabLength;
|
||||
return;
|
||||
}
|
||||
|
||||
//Statements else, elseif, case etc
|
||||
if (Regex.IsMatch(args.LineText, @"^\s*(Else|ElseIf|Case|Catch|Finally)\b", RegexOptions.IgnoreCase))
|
||||
{
|
||||
args.Shift = -args.TabLength;
|
||||
return;
|
||||
}
|
||||
|
||||
//Char _
|
||||
if (args.PrevLineText.TrimEnd().EndsWith("_"))
|
||||
{
|
||||
args.Shift = args.TabLength;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void CSharpAutoIndentNeeded(object sender, AutoIndentEventArgs args)
|
||||
{
|
||||
//block {}
|
||||
if (Regex.IsMatch(args.LineText, @"^[^""']*\{.*\}[^""']*$"))
|
||||
return;
|
||||
//start of block {}
|
||||
if (Regex.IsMatch(args.LineText, @"^[^""']*\{"))
|
||||
{
|
||||
args.ShiftNextLines = args.TabLength;
|
||||
return;
|
||||
}
|
||||
//end of block {}
|
||||
if (Regex.IsMatch(args.LineText, @"}[^""']*$"))
|
||||
{
|
||||
args.Shift = -args.TabLength;
|
||||
args.ShiftNextLines = -args.TabLength;
|
||||
return;
|
||||
}
|
||||
//label
|
||||
if (Regex.IsMatch(args.LineText, @"^\s*\w+\s*:\s*($|//)") &&
|
||||
!Regex.IsMatch(args.LineText, @"^\s*default\s*:"))
|
||||
{
|
||||
args.Shift = -args.TabLength;
|
||||
return;
|
||||
}
|
||||
//some statements: case, default
|
||||
if (Regex.IsMatch(args.LineText, @"^\s*(case|default)\b.*:\s*($|//)"))
|
||||
{
|
||||
args.Shift = -args.TabLength/2;
|
||||
return;
|
||||
}
|
||||
//is unclosed operator in previous line ?
|
||||
if (Regex.IsMatch(args.PrevLineText, @"^\s*(if|for|foreach|while|[\}\s]*else)\b[^{]*$"))
|
||||
if (!Regex.IsMatch(args.PrevLineText, @"(;\s*$)|(;\s*//)"))//operator is unclosed
|
||||
{
|
||||
args.Shift = args.TabLength;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static SyntaxDescriptor ParseXmlDescription(XmlDocument doc)
|
||||
{
|
||||
SyntaxDescriptor desc = new SyntaxDescriptor();
|
||||
XmlNode brackets = doc.SelectSingleNode("doc/brackets");
|
||||
if (brackets != null)
|
||||
{
|
||||
if (brackets.Attributes["left"] == null || brackets.Attributes["right"] == null ||
|
||||
brackets.Attributes["left"].Value == "" || brackets.Attributes["right"].Value == "")
|
||||
{
|
||||
desc.leftBracket = '\x0';
|
||||
desc.rightBracket = '\x0';
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.leftBracket = brackets.Attributes["left"].Value[0];
|
||||
desc.rightBracket = brackets.Attributes["right"].Value[0];
|
||||
}
|
||||
|
||||
if (brackets.Attributes["left2"] == null || brackets.Attributes["right2"] == null ||
|
||||
brackets.Attributes["left2"].Value == "" || brackets.Attributes["right2"].Value == "")
|
||||
{
|
||||
desc.leftBracket2 = '\x0';
|
||||
desc.rightBracket2 = '\x0';
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.leftBracket2 = brackets.Attributes["left2"].Value[0];
|
||||
desc.rightBracket2 = brackets.Attributes["right2"].Value[0];
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, Style> styleByName = new Dictionary<string, Style>();
|
||||
|
||||
foreach (XmlNode style in doc.SelectNodes("doc/style"))
|
||||
{
|
||||
var s = ParseStyle(style);
|
||||
styleByName[style.Attributes["name"].Value] = s;
|
||||
desc.styles.Add(s);
|
||||
}
|
||||
foreach (XmlNode rule in doc.SelectNodes("doc/rule"))
|
||||
desc.rules.Add(ParseRule(rule, styleByName));
|
||||
foreach (XmlNode folding in doc.SelectNodes("doc/folding"))
|
||||
desc.foldings.Add(ParseFolding(folding));
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
private static FoldingDesc ParseFolding(XmlNode foldingNode)
|
||||
{
|
||||
FoldingDesc folding = new FoldingDesc();
|
||||
//regex
|
||||
folding.startMarkerRegex = foldingNode.Attributes["start"].Value;
|
||||
folding.finishMarkerRegex = foldingNode.Attributes["finish"].Value;
|
||||
//options
|
||||
var optionsA = foldingNode.Attributes["options"];
|
||||
if (optionsA != null)
|
||||
folding.options = (RegexOptions)Enum.Parse(typeof(RegexOptions), optionsA.Value);
|
||||
|
||||
return folding;
|
||||
}
|
||||
|
||||
private static RuleDesc ParseRule(XmlNode ruleNode, Dictionary<string, Style> styles)
|
||||
{
|
||||
RuleDesc rule = new RuleDesc();
|
||||
rule.regex = ruleNode.InnerText;
|
||||
//
|
||||
var styleA = ruleNode.Attributes["style"];
|
||||
var optionsA = ruleNode.Attributes["options"];
|
||||
//Style
|
||||
if (styleA == null)
|
||||
throw new Exception("Rule must contain style name.");
|
||||
if(!styles.ContainsKey(styleA.Value))
|
||||
throw new Exception("Style '"+styleA.Value+"' is not found.");
|
||||
rule.style = styles[styleA.Value];
|
||||
//options
|
||||
if (optionsA != null)
|
||||
rule.options = (RegexOptions)Enum.Parse(typeof(RegexOptions), optionsA.Value);
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
private static Style ParseStyle(XmlNode styleNode)
|
||||
{
|
||||
var typeA = styleNode.Attributes["type"];
|
||||
var colorA = styleNode.Attributes["color"];
|
||||
var backColorA = styleNode.Attributes["backColor"];
|
||||
var fontStyleA = styleNode.Attributes["fontStyle"];
|
||||
var nameA = styleNode.Attributes["name"];
|
||||
//colors
|
||||
SolidBrush foreBrush = null;
|
||||
if (colorA != null)
|
||||
foreBrush = new SolidBrush(ParseColor(colorA.Value));
|
||||
SolidBrush backBrush = null;
|
||||
if (backColorA != null)
|
||||
backBrush = new SolidBrush(ParseColor(backColorA.Value));
|
||||
//fontStyle
|
||||
FontStyle fontStyle = FontStyle.Regular;
|
||||
if (fontStyleA != null)
|
||||
fontStyle = (FontStyle)Enum.Parse(typeof(FontStyle), fontStyleA.Value);
|
||||
|
||||
return new TextStyle(foreBrush, backBrush, fontStyle);
|
||||
}
|
||||
|
||||
private static Color ParseColor(string s)
|
||||
{
|
||||
if (s.StartsWith("#"))
|
||||
{
|
||||
if(s.Length<=7)
|
||||
return Color.FromArgb(255, Color.FromArgb(Int32.Parse(s.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier)));
|
||||
else
|
||||
return Color.FromArgb(Int32.Parse(s.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier));
|
||||
}
|
||||
else
|
||||
return Color.FromName(s);
|
||||
}
|
||||
|
||||
public void HighlightSyntax(SyntaxDescriptor desc, Range range)
|
||||
{
|
||||
//set style order
|
||||
range.tb.ClearStylesBuffer();
|
||||
for(int i=0;i<desc.styles.Count;i++)
|
||||
range.tb.Styles[i] = desc.styles[i];
|
||||
//brackets
|
||||
range.tb.LeftBracket = desc.leftBracket;
|
||||
range.tb.RightBracket = desc.rightBracket;
|
||||
range.tb.LeftBracket2 = desc.leftBracket2;
|
||||
range.tb.RightBracket2 = desc.rightBracket2;
|
||||
//clear styles of range
|
||||
range.ClearStyle(desc.styles.ToArray());
|
||||
//highlight syntax
|
||||
foreach (var rule in desc.rules)
|
||||
range.SetStyle(rule.style, rule.regex, rule.options);
|
||||
//clear folding
|
||||
range.ClearFoldingMarkers();
|
||||
//folding markers
|
||||
foreach (var folding in desc.foldings)
|
||||
range.SetFoldingMarkers(folding.startMarkerRegex, folding.finishMarkerRegex, folding.options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights C# code
|
||||
/// </summary>
|
||||
/// <param name="range"></param>
|
||||
public virtual void CSharpSyntaxHighlight(Range range)
|
||||
{
|
||||
range.tb.CommentPrefix = "//";
|
||||
range.tb.LeftBracket = '(';
|
||||
range.tb.RightBracket = ')';
|
||||
range.tb.LeftBracket2 = '\x0';
|
||||
range.tb.RightBracket2 = '\x0';
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BlueStyle, BoldStyle, GrayStyle, MagentaStyle, GreenStyle, BrownStyle);
|
||||
//string highlighting
|
||||
range.SetStyle(BrownStyle, @""".*?""|'.+?'");
|
||||
//comment highlighting
|
||||
range.SetStyle(GreenStyle, @"//.*$", RegexOptions.Multiline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(/\*.*)", RegexOptions.Singleline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(.*\*/)", RegexOptions.Singleline | RegexOptions.RightToLeft);
|
||||
//number highlighting
|
||||
range.SetStyle(MagentaStyle, @"\b\d+[\.]?\d*([eE]\-?\d+)?[lLdDfF]?\b|\b0x[a-fA-F\d]+\b");
|
||||
//attribute highlighting
|
||||
range.SetStyle(GrayStyle, @"^\s*(?<range>\[.+?\])\s*$", RegexOptions.Multiline);
|
||||
//class name highlighting
|
||||
range.SetStyle(BoldStyle, @"\b(class|struct|enum|interface)\s+(?<range>\w+?)\b");
|
||||
//keyword highlighting
|
||||
range.SetStyle(BlueStyle, @"\b(abstract|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b|#region\b|#endregion\b");
|
||||
|
||||
//clear folding markers
|
||||
range.ClearFoldingMarkers();
|
||||
//set folding markers
|
||||
range.SetFoldingMarkers("{", "}");//allow to collapse brackets block
|
||||
range.SetFoldingMarkers(@"#region\b", @"#endregion\b");//allow to collapse #region blocks
|
||||
range.SetFoldingMarkers(@"/\*", @"\*/");//allow to collapse comment block
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights VB code
|
||||
/// </summary>
|
||||
/// <param name="range"></param>
|
||||
public virtual void VBSyntaxHighlight(Range range)
|
||||
{
|
||||
range.tb.CommentPrefix = "'";
|
||||
range.tb.LeftBracket = '(';
|
||||
range.tb.RightBracket = ')';
|
||||
range.tb.LeftBracket2 = '\x0';
|
||||
range.tb.RightBracket2 = '\x0';
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BrownStyle, GreenStyle, MagentaStyle, BoldStyle, BlueStyle);
|
||||
//string highlighting
|
||||
range.SetStyle(BrownStyle, @""".*?""");
|
||||
//comment highlighting
|
||||
range.SetStyle(GreenStyle, @"'.*$", RegexOptions.Multiline);
|
||||
//number highlighting
|
||||
range.SetStyle(MagentaStyle, @"\b\d+[\.]?\d*([eE]\-?\d+)?\b");
|
||||
//class name highlighting
|
||||
range.SetStyle(BoldStyle, @"\b(Class|Structure|Enum|Interface)[ ]+(?<range>\w+?)\b", RegexOptions.IgnoreCase);
|
||||
//keyword highlighting
|
||||
range.SetStyle(BlueStyle, @"\b(AddHandler|AddressOf|Alias|And|AndAlso|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|Continue|CSByte|CShort|CSng|CStr|CType|CUInt|CULng|CUShort|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|False|Finally|For|Friend|Function|Get|GetType|GetXMLNamespace|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|Narrowing|New|Next|Not|Nothing|NotInheritable|NotOverridable|Object|Of|On|Operator|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|REM|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|True|Try|TryCast|TypeOf|UInteger|ULong|UShort|Using|Variant|Wend|When|While|Widening|With|WithEvents|WriteOnly|Xor|Region)\b|(#Const|#Else|#ElseIf|#End|#If|#Region)\b", RegexOptions.IgnoreCase);
|
||||
|
||||
//clear folding markers
|
||||
range.ClearFoldingMarkers();
|
||||
//set folding markers
|
||||
range.SetFoldingMarkers(@"#Region\b", @"#End\s+Region\b", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers(@"\b(Class|Property|Enum|Structure|Interface)[ \t]+\S+", @"\bEnd (Class|Property|Enum|Structure|Interface)\b", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers(@"^\s*(?<range>While)[ \t]+\S+", @"^\s*(?<range>End While)\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers(@"\b(Sub|Function)[ \t]+[^\s']+", @"\bEnd (Sub|Function)\b", RegexOptions.IgnoreCase);//this declared separately because Sub and Function can be unclosed
|
||||
range.SetFoldingMarkers(@"(\r|\n|^)[ \t]*(?<range>Get|Set)[ \t]*(\r|\n|$)", @"\bEnd (Get|Set)\b", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers(@"^\s*(?<range>For|For\s+Each)\b", @"^\s*(?<range>Next)\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers(@"^\s*(?<range>Do)\b", @"^\s*(?<range>Loop)\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights HTML code
|
||||
/// </summary>
|
||||
/// <param name="range"></param>
|
||||
public virtual void HTMLSyntaxHighlight(Range range)
|
||||
{
|
||||
range.tb.CommentPrefix = null;
|
||||
range.tb.LeftBracket = '<';
|
||||
range.tb.RightBracket = '>';
|
||||
range.tb.LeftBracket2 = '(';
|
||||
range.tb.RightBracket2 = ')';
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BlueStyle, MaroonStyle, RedStyle);
|
||||
//tag brackets highlighting
|
||||
range.SetStyle(BlueStyle, @"<|/>|</|>");
|
||||
//tag name
|
||||
range.SetStyle(MaroonStyle, @"<(?<range>[!\w]+)");
|
||||
//end of tag
|
||||
range.SetStyle(MaroonStyle, @"</(?<range>\w+)>");
|
||||
//attributes
|
||||
range.SetStyle(RedStyle, @"(?<range>\S+?)='[^']*'|(?<range>\S+)=""[^""]*""|(?<range>\S+)=\S+");
|
||||
//attribute values
|
||||
range.SetStyle(BlueStyle, @"\S+?=(?<range>'[^']*')|\S+=(?<range>""[^""]*"")|\S+=(?<range>\S+)");
|
||||
|
||||
//clear folding markers
|
||||
range.ClearFoldingMarkers();
|
||||
//set folding markers
|
||||
range.SetFoldingMarkers("<head", "</head>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<body", "</body>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<table", "</table>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<form", "</form>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<div", "</div>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<script", "</script>", RegexOptions.IgnoreCase);
|
||||
range.SetFoldingMarkers("<tr", "</tr>", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights SQL code
|
||||
/// </summary>
|
||||
/// <param name="range"></param>
|
||||
public virtual void SQLSyntaxHighlight(Range range)
|
||||
{
|
||||
range.tb.CommentPrefix = "--";
|
||||
range.tb.LeftBracket = '(';
|
||||
range.tb.RightBracket = ')';
|
||||
range.tb.LeftBracket2 = '\x0';
|
||||
range.tb.RightBracket2 = '\x0';
|
||||
//clear style of changed range
|
||||
range.ClearStyle(RedStyle, MagentaStyle, GreenStyle, BlueBoldStyle, BlueStyle, MaroonStyle);
|
||||
//string highlighting
|
||||
range.SetStyle(RedStyle, @""".*?""|'.+?'");
|
||||
//number highlighting
|
||||
range.SetStyle(MagentaStyle, @"\b\d+[\.]?\d*([eE]\-?\d+)?\b");
|
||||
//comment highlighting
|
||||
range.SetStyle(GreenStyle, @"--.*$", RegexOptions.Multiline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(/\*.*)", RegexOptions.Singleline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(.*\*/)", RegexOptions.Singleline | RegexOptions.RightToLeft);
|
||||
//var highlighting
|
||||
range.SetStyle(MaroonStyle, @"@[a-zA-Z_\d]*\b");
|
||||
//statements
|
||||
range.SetStyle(BlueBoldStyle, @"\b(ALTER APPLICATION ROLE|ALTER ASSEMBLY|ALTER ASYMMETRIC KEY|ALTER AUTHORIZATION|ALTER BROKER PRIORITY|ALTER CERTIFICATE|ALTER CREDENTIAL|ALTER CRYPTOGRAPHIC PROVIDER|ALTER DATABASE|ALTER DATABASE AUDIT SPECIFICATION|ALTER DATABASE ENCRYPTION KEY|ALTER ENDPOINT|ALTER EVENT SESSION|ALTER FULLTEXT CATALOG|ALTER FULLTEXT INDEX|ALTER FULLTEXT STOPLIST|ALTER FUNCTION|ALTER INDEX|ALTER LOGIN|ALTER MASTER KEY|ALTER MESSAGE TYPE|ALTER PARTITION FUNCTION|ALTER PARTITION SCHEME|ALTER PROCEDURE|ALTER QUEUE|ALTER REMOTE SERVICE BINDING|ALTER RESOURCE GOVERNOR|ALTER RESOURCE POOL|ALTER ROLE|ALTER ROUTE|ALTER SCHEMA|ALTER SERVER AUDIT|ALTER SERVER AUDIT SPECIFICATION|ALTER SERVICE|ALTER SERVICE MASTER KEY|ALTER SYMMETRIC KEY|ALTER TABLE|ALTER TRIGGER|ALTER USER|ALTER VIEW|ALTER WORKLOAD GROUP|ALTER XML SCHEMA COLLECTION|BULK INSERT|CREATE AGGREGATE|CREATE APPLICATION ROLE|CREATE ASSEMBLY|CREATE ASYMMETRIC KEY|CREATE BROKER PRIORITY|CREATE CERTIFICATE|CREATE CONTRACT|CREATE CREDENTIAL|CREATE CRYPTOGRAPHIC PROVIDER|CREATE DATABASE|CREATE DATABASE AUDIT SPECIFICATION|CREATE DATABASE ENCRYPTION KEY|CREATE DEFAULT|CREATE ENDPOINT|CREATE EVENT NOTIFICATION|CREATE EVENT SESSION|CREATE FULLTEXT CATALOG|CREATE FULLTEXT INDEX|CREATE FULLTEXT STOPLIST|CREATE FUNCTION|CREATE INDEX|CREATE LOGIN|CREATE MASTER KEY|CREATE MESSAGE TYPE|CREATE PARTITION FUNCTION|CREATE PARTITION SCHEME|CREATE PROCEDURE|CREATE QUEUE|CREATE REMOTE SERVICE BINDING|CREATE RESOURCE POOL|CREATE ROLE|CREATE ROUTE|CREATE RULE|CREATE SCHEMA|CREATE SERVER AUDIT|CREATE SERVER AUDIT SPECIFICATION|CREATE SERVICE|CREATE SPATIAL INDEX|CREATE STATISTICS|CREATE SYMMETRIC KEY|CREATE SYNONYM|CREATE TABLE|CREATE TRIGGER|CREATE TYPE|CREATE USER|CREATE VIEW|CREATE WORKLOAD GROUP|CREATE XML INDEX|CREATE XML SCHEMA COLLECTION|DELETE|DISABLE TRIGGER|DROP AGGREGATE|DROP APPLICATION ROLE|DROP ASSEMBLY|DROP ASYMMETRIC KEY|DROP BROKER PRIORITY|DROP CERTIFICATE|DROP CONTRACT|DROP CREDENTIAL|DROP CRYPTOGRAPHIC PROVIDER|DROP DATABASE|DROP DATABASE AUDIT SPECIFICATION|DROP DATABASE ENCRYPTION KEY|DROP DEFAULT|DROP ENDPOINT|DROP EVENT NOTIFICATION|DROP EVENT SESSION|DROP FULLTEXT CATALOG|DROP FULLTEXT INDEX|DROP FULLTEXT STOPLIST|DROP FUNCTION|DROP INDEX|DROP LOGIN|DROP MASTER KEY|DROP MESSAGE TYPE|DROP PARTITION FUNCTION|DROP PARTITION SCHEME|DROP PROCEDURE|DROP QUEUE|DROP REMOTE SERVICE BINDING|DROP RESOURCE POOL|DROP ROLE|DROP ROUTE|DROP RULE|DROP SCHEMA|DROP SERVER AUDIT|DROP SERVER AUDIT SPECIFICATION|DROP SERVICE|DROP SIGNATURE|DROP STATISTICS|DROP SYMMETRIC KEY|DROP SYNONYM|DROP TABLE|DROP TRIGGER|DROP TYPE|DROP USER|DROP VIEW|DROP WORKLOAD GROUP|DROP XML SCHEMA COLLECTION|ENABLE TRIGGER|EXEC|EXECUTE|FROM|INSERT|MERGE|OPTION|OUTPUT|SELECT|TOP|TRUNCATE TABLE|UPDATE|UPDATE STATISTICS|WHERE|WITH)\b", RegexOptions.IgnoreCase);
|
||||
//key words
|
||||
range.SetStyle(BlueStyle, @"\b(ADD|ALL|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BY|CASCADE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTINUE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXISTS|EXIT|EXTERNAL|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IN|INDEX|INNER|INTERSECT|INTO|IS|JOIN|KEY|KILL|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|OF|OFF|OFFSETS|ON|OPEN|OR|ORDER|OUTER|OVER|PERCENT|PIVOT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVERT|REVOKE|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SECURITYAUDIT|SET|SHUTDOWN|SOME|STATISTICS|TABLE|TABLESAMPLE|TEXTSIZE|THEN|TO|TRAN|TRANSACTION|TRIGGER|TSEQUAL|UNION|UNIQUE|UNPIVOT|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHILE|WRITETEXT)\b", RegexOptions.IgnoreCase);
|
||||
//functions
|
||||
range.SetStyle(MaroonStyle, @"(@@CONNECTIONS|@@CPU_BUSY|@@CURSOR_ROWS|@@DATEFIRST|@@DATEFIRST|@@DBTS|@@ERROR|@@FETCH_STATUS|@@IDENTITY|@@IDLE|@@IO_BUSY|@@LANGID|@@LANGUAGE|@@LOCK_TIMEOUT|@@MAX_CONNECTIONS|@@MAX_PRECISION|@@NESTLEVEL|@@OPTIONS|@@PACKET_ERRORS|@@PROCID|@@REMSERVER|@@ROWCOUNT|@@SERVERNAME|@@SERVICENAME|@@SPID|@@TEXTSIZE|@@TRANCOUNT|@@VERSION)\b|\b(ABS|ACOS|APP_NAME|ASCII|ASIN|ASSEMBLYPROPERTY|AsymKey_ID|ASYMKEY_ID|asymkeyproperty|ASYMKEYPROPERTY|ATAN|ATN2|AVG|CASE|CAST|CEILING|Cert_ID|Cert_ID|CertProperty|CHAR|CHARINDEX|CHECKSUM_AGG|COALESCE|COL_LENGTH|COL_NAME|COLLATIONPROPERTY|COLLATIONPROPERTY|COLUMNPROPERTY|COLUMNS_UPDATED|COLUMNS_UPDATED|CONTAINSTABLE|CONVERT|COS|COT|COUNT|COUNT_BIG|CRYPT_GEN_RANDOM|CURRENT_TIMESTAMP|CURRENT_TIMESTAMP|CURRENT_USER|CURRENT_USER|CURSOR_STATUS|DATABASE_PRINCIPAL_ID|DATABASE_PRINCIPAL_ID|DATABASEPROPERTY|DATABASEPROPERTYEX|DATALENGTH|DATALENGTH|DATEADD|DATEDIFF|DATENAME|DATEPART|DAY|DB_ID|DB_NAME|DECRYPTBYASYMKEY|DECRYPTBYCERT|DECRYPTBYKEY|DECRYPTBYKEYAUTOASYMKEY|DECRYPTBYKEYAUTOCERT|DECRYPTBYPASSPHRASE|DEGREES|DENSE_RANK|DIFFERENCE|ENCRYPTBYASYMKEY|ENCRYPTBYCERT|ENCRYPTBYKEY|ENCRYPTBYPASSPHRASE|ERROR_LINE|ERROR_MESSAGE|ERROR_NUMBER|ERROR_PROCEDURE|ERROR_SEVERITY|ERROR_STATE|EVENTDATA|EXP|FILE_ID|FILE_IDEX|FILE_NAME|FILEGROUP_ID|FILEGROUP_NAME|FILEGROUPPROPERTY|FILEPROPERTY|FLOOR|fn_helpcollations|fn_listextendedproperty|fn_servershareddrives|fn_virtualfilestats|fn_virtualfilestats|FORMATMESSAGE|FREETEXTTABLE|FULLTEXTCATALOGPROPERTY|FULLTEXTSERVICEPROPERTY|GETANSINULL|GETDATE|GETUTCDATE|GROUPING|HAS_PERMS_BY_NAME|HOST_ID|HOST_NAME|IDENT_CURRENT|IDENT_CURRENT|IDENT_INCR|IDENT_INCR|IDENT_SEED|IDENTITY\(|INDEX_COL|INDEXKEY_PROPERTY|INDEXPROPERTY|IS_MEMBER|IS_OBJECTSIGNED|IS_SRVROLEMEMBER|ISDATE|ISDATE|ISNULL|ISNUMERIC|Key_GUID|Key_GUID|Key_ID|Key_ID|KEY_NAME|KEY_NAME|LEFT|LEN|LOG|LOG10|LOWER|LTRIM|MAX|MIN|MONTH|NCHAR|NEWID|NTILE|NULLIF|OBJECT_DEFINITION|OBJECT_ID|OBJECT_NAME|OBJECT_SCHEMA_NAME|OBJECTPROPERTY|OBJECTPROPERTYEX|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|ORIGINAL_LOGIN|ORIGINAL_LOGIN|PARSENAME|PATINDEX|PATINDEX|PERMISSIONS|PI|POWER|PUBLISHINGSERVERNAME|PWDCOMPARE|PWDENCRYPT|QUOTENAME|RADIANS|RAND|RANK|REPLACE|REPLICATE|REVERSE|RIGHT|ROUND|ROW_NUMBER|ROWCOUNT_BIG|RTRIM|SCHEMA_ID|SCHEMA_ID|SCHEMA_NAME|SCHEMA_NAME|SCOPE_IDENTITY|SERVERPROPERTY|SESSION_USER|SESSION_USER|SESSIONPROPERTY|SETUSER|SIGN|SignByAsymKey|SignByCert|SIN|SOUNDEX|SPACE|SQL_VARIANT_PROPERTY|SQRT|SQUARE|STATS_DATE|STDEV|STDEVP|STR|STUFF|SUBSTRING|SUM|SUSER_ID|SUSER_NAME|SUSER_SID|SUSER_SNAME|SWITCHOFFSET|SYMKEYPROPERTY|symkeyproperty|sys\.dm_db_index_physical_stats|sys\.fn_builtin_permissions|sys\.fn_my_permissions|SYSDATETIME|SYSDATETIMEOFFSET|SYSTEM_USER|SYSTEM_USER|SYSUTCDATETIME|TAN|TERTIARY_WEIGHTS|TEXTPTR|TODATETIMEOFFSET|TRIGGER_NESTLEVEL|TYPE_ID|TYPE_NAME|TYPEPROPERTY|UNICODE|UPDATE\(|UPPER|USER_ID|USER_NAME|USER_NAME|VAR|VARP|VerifySignedByAsymKey|VerifySignedByCert|XACT_STATE|YEAR)\b", RegexOptions.IgnoreCase);
|
||||
|
||||
//clear folding markers
|
||||
range.ClearFoldingMarkers();
|
||||
//set folding markers
|
||||
range.SetFoldingMarkers(@"\bBEGIN\b", @"\bEND\b", RegexOptions.IgnoreCase);//allow to collapse BEGIN..END blocks
|
||||
range.SetFoldingMarkers(@"/\*", @"\*/");//allow to collapse comment block
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Highlights PHP code
|
||||
/// </summary>
|
||||
/// <param name="range"></param>
|
||||
public virtual void PHPSyntaxHighlight(Range range)
|
||||
{
|
||||
range.tb.CommentPrefix = "#";
|
||||
range.tb.LeftBracket = '(';
|
||||
range.tb.RightBracket = ')';
|
||||
range.tb.LeftBracket2 = '\x0';
|
||||
range.tb.RightBracket2 = '\x0';
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BlueStyle, GrayStyle, MagentaStyle, GreenStyle, RedStyle, MaroonStyle);
|
||||
//string highlighting
|
||||
range.SetStyle(RedStyle, @""".*?""|'.+?'");
|
||||
//number highlighting
|
||||
range.SetStyle(RedStyle, @"\b\d+[\.]?\d*\b");
|
||||
//comment highlighting
|
||||
range.SetStyle(GreenStyle, @"(//|#).*$", RegexOptions.Multiline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(/\*.*)", RegexOptions.Singleline);
|
||||
range.SetStyle(GreenStyle, @"(/\*.*?\*/)|(.*\*/)", RegexOptions.Singleline | RegexOptions.RightToLeft);
|
||||
//var highlighting
|
||||
range.SetStyle(MaroonStyle, @"\$[a-zA-Z_\d]*\b");
|
||||
//keyword highlighting
|
||||
range.SetStyle(MagentaStyle, @"\b(die|echo|empty|exit|eval|include|include_once|isset|list|require|require_once|return|print|unset)\b");
|
||||
range.SetStyle(BlueStyle, @"\b(abstract|and|array|as|break|case|catch|cfunction|class|clone|const|continue|declare|default|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|final|for|foreach|function|global|goto|if|implements|instanceof|interface|namespace|new|or|private|protected|public|static|switch|throw|try|use|var|while|xor)\b");
|
||||
range.SetStyle(GrayStyle, @"__CLASS__|__DIR__|__FILE__|__LINE__|__FUNCTION__|__METHOD__|__NAMESPACE__");
|
||||
|
||||
//clear folding markers
|
||||
range.ClearFoldingMarkers();
|
||||
//set folding markers
|
||||
range.SetFoldingMarkers("{", "}");//allow to collapse brackets block
|
||||
range.SetFoldingMarkers(@"/\*", @"\*/");//allow to collapse comment block
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var desc in descByXMLfileNames.Values)
|
||||
desc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Language
|
||||
/// </summary>
|
||||
public enum Language
|
||||
{
|
||||
Custom, CSharp, VB, HTML, SQL, PHP
|
||||
}
|
||||
}
|
||||
338
FastColoredTextBox/TextSource.cs
Normal file
338
FastColoredTextBox/TextSource.cs
Normal file
@@ -0,0 +1,338 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains the source text (chars and styles).
|
||||
/// It stores a text lines, the manager of commands, undo/redo stack, styles.
|
||||
/// </summary>
|
||||
public class TextSource: IList<Line>, IDisposable
|
||||
{
|
||||
readonly protected List<Line> lines = new List<Line>();
|
||||
protected LinesAccessor linesAccessor;
|
||||
int lastLineUniqueId;
|
||||
public CommandManager Manager { get; set; }
|
||||
FastColoredTextBox currentTB;
|
||||
/// <summary>
|
||||
/// Styles
|
||||
/// </summary>
|
||||
public readonly Style[] Styles;
|
||||
/// <summary>
|
||||
/// Occurs when line was inserted/added
|
||||
/// </summary>
|
||||
public event EventHandler<LineInsertedEventArgs> LineInserted;
|
||||
/// <summary>
|
||||
/// Occurs when line was removed
|
||||
/// </summary>
|
||||
public event EventHandler<LineRemovedEventArgs> LineRemoved;
|
||||
/// <summary>
|
||||
/// Occurs when text was changed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> TextChanged;
|
||||
/// <summary>
|
||||
/// Occurs when recalc is needed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> RecalcNeeded;
|
||||
/// <summary>
|
||||
/// Occurs when recalc wordwrap is needed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> RecalcWordWrap;
|
||||
/// <summary>
|
||||
/// Occurs before text changing
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangingEventArgs> TextChanging;
|
||||
/// <summary>
|
||||
/// Occurs after CurrentTB was changed
|
||||
/// </summary>
|
||||
public event EventHandler CurrentTBChanged;
|
||||
/// <summary>
|
||||
/// Current focused FastColoredTextBox
|
||||
/// </summary>
|
||||
public FastColoredTextBox CurrentTB {
|
||||
get { return currentTB; }
|
||||
set {
|
||||
if (currentTB == value)
|
||||
return;
|
||||
currentTB = value;
|
||||
OnCurrentTBChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClearIsChanged()
|
||||
{
|
||||
foreach(var line in lines)
|
||||
line.IsChanged = false;
|
||||
}
|
||||
|
||||
public virtual Line CreateLine()
|
||||
{
|
||||
return new Line(GenerateUniqueLineId());
|
||||
}
|
||||
|
||||
private void OnCurrentTBChanged()
|
||||
{
|
||||
if (CurrentTBChanged != null)
|
||||
CurrentTBChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default text style
|
||||
/// This style is using when no one other TextStyle is not defined in Char.style
|
||||
/// </summary>
|
||||
public TextStyle DefaultStyle { get; set; }
|
||||
|
||||
public TextSource(FastColoredTextBox currentTB)
|
||||
{
|
||||
this.CurrentTB = currentTB;
|
||||
linesAccessor = new LinesAccessor(this);
|
||||
Manager = new CommandManager(this);
|
||||
|
||||
if (Enum.GetUnderlyingType(typeof(StyleIndex)) == typeof(UInt32))
|
||||
Styles = new Style[32];
|
||||
else
|
||||
Styles = new Style[16];
|
||||
|
||||
InitDefaultStyle();
|
||||
}
|
||||
|
||||
public virtual void InitDefaultStyle()
|
||||
{
|
||||
DefaultStyle = new TextStyle(null, null, FontStyle.Regular);
|
||||
}
|
||||
|
||||
public virtual Line this[int i]
|
||||
{
|
||||
get{
|
||||
return lines[i];
|
||||
}
|
||||
set {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsLineLoaded(int iLine)
|
||||
{
|
||||
return lines[iLine] != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text lines
|
||||
/// </summary>
|
||||
public virtual IList<string> GetLines()
|
||||
{
|
||||
return linesAccessor;
|
||||
}
|
||||
|
||||
public IEnumerator<Line> GetEnumerator()
|
||||
{
|
||||
return lines.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return (lines as IEnumerator);
|
||||
}
|
||||
|
||||
public virtual int BinarySearch(Line item, IComparer<Line> comparer)
|
||||
{
|
||||
return lines.BinarySearch(item, comparer);
|
||||
}
|
||||
|
||||
public virtual int GenerateUniqueLineId()
|
||||
{
|
||||
return lastLineUniqueId++;
|
||||
}
|
||||
|
||||
public virtual void InsertLine(int index, Line line)
|
||||
{
|
||||
lines.Insert(index, line);
|
||||
OnLineInserted(index);
|
||||
}
|
||||
|
||||
public virtual void OnLineInserted(int index)
|
||||
{
|
||||
OnLineInserted(index, 1);
|
||||
}
|
||||
|
||||
public virtual void OnLineInserted(int index, int count)
|
||||
{
|
||||
if (LineInserted != null)
|
||||
LineInserted(this, new LineInsertedEventArgs(index, count));
|
||||
}
|
||||
|
||||
public virtual void RemoveLine(int index)
|
||||
{
|
||||
RemoveLine(index, 1);
|
||||
}
|
||||
|
||||
public virtual bool IsNeedBuildRemovedLineIds
|
||||
{
|
||||
get { return LineRemoved != null; }
|
||||
}
|
||||
|
||||
public virtual void RemoveLine(int index, int count)
|
||||
{
|
||||
List<int> removedLineIds = new List<int>();
|
||||
//
|
||||
if (count > 0)
|
||||
if (IsNeedBuildRemovedLineIds)
|
||||
for (int i = 0; i < count; i++)
|
||||
removedLineIds.Add(this[index + i].UniqueId);
|
||||
//
|
||||
lines.RemoveRange(index, count);
|
||||
|
||||
OnLineRemoved(index, count, removedLineIds);
|
||||
}
|
||||
|
||||
public virtual void OnLineRemoved(int index, int count, List<int> removedLineIds)
|
||||
{
|
||||
if (count > 0)
|
||||
if (LineRemoved != null)
|
||||
LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));
|
||||
}
|
||||
|
||||
public virtual void OnTextChanged(int fromLine, int toLine)
|
||||
{
|
||||
if (TextChanged != null)
|
||||
TextChanged(this, new TextChangedEventArgs(Math.Min(fromLine, toLine), Math.Max(fromLine, toLine) ));
|
||||
}
|
||||
|
||||
public class TextChangedEventArgs : EventArgs
|
||||
{
|
||||
public int iFromLine;
|
||||
public int iToLine;
|
||||
|
||||
public TextChangedEventArgs(int iFromLine, int iToLine)
|
||||
{
|
||||
this.iFromLine = iFromLine;
|
||||
this.iToLine = iToLine;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int IndexOf(Line item)
|
||||
{
|
||||
return lines.IndexOf(item);
|
||||
}
|
||||
|
||||
public virtual void Insert(int index, Line item)
|
||||
{
|
||||
InsertLine(index, item);
|
||||
}
|
||||
|
||||
public virtual void RemoveAt(int index)
|
||||
{
|
||||
RemoveLine(index);
|
||||
}
|
||||
|
||||
public virtual void Add(Line item)
|
||||
{
|
||||
InsertLine(Count, item);
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
RemoveLine(0, Count);
|
||||
}
|
||||
|
||||
public virtual bool Contains(Line item)
|
||||
{
|
||||
return lines.Contains(item);
|
||||
}
|
||||
|
||||
public virtual void CopyTo(Line[] array, int arrayIndex)
|
||||
{
|
||||
lines.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lines count
|
||||
/// </summary>
|
||||
public virtual int Count
|
||||
{
|
||||
get { return lines.Count; }
|
||||
}
|
||||
|
||||
public virtual bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual bool Remove(Line item)
|
||||
{
|
||||
int i = IndexOf(item);
|
||||
if (i >= 0)
|
||||
{
|
||||
RemoveLine(i);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void NeedRecalc(TextChangedEventArgs args)
|
||||
{
|
||||
if (RecalcNeeded != null)
|
||||
RecalcNeeded(this, args);
|
||||
}
|
||||
|
||||
public virtual void OnRecalcWordWrap(TextChangedEventArgs args)
|
||||
{
|
||||
if (RecalcWordWrap != null)
|
||||
RecalcWordWrap(this, args);
|
||||
}
|
||||
|
||||
public virtual void OnTextChanging()
|
||||
{
|
||||
string temp = null;
|
||||
OnTextChanging(ref temp);
|
||||
}
|
||||
|
||||
public virtual void OnTextChanging(ref string text)
|
||||
{
|
||||
if (TextChanging != null)
|
||||
{
|
||||
var args = new TextChangingEventArgs() { InsertingText = text };
|
||||
TextChanging(this, args);
|
||||
text = args.InsertingText;
|
||||
if (args.Cancel)
|
||||
text = string.Empty;
|
||||
};
|
||||
}
|
||||
|
||||
public virtual int GetLineLength(int i)
|
||||
{
|
||||
return lines[i].Count;
|
||||
}
|
||||
|
||||
public virtual bool LineHasFoldingStartMarker(int iLine)
|
||||
{
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);
|
||||
}
|
||||
|
||||
public virtual bool LineHasFoldingEndMarker(int iLine)
|
||||
{
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
public virtual void SaveToFile(string fileName, Encoding enc)
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(fileName, false, enc))
|
||||
{
|
||||
for (int i = 0; i < Count - 1;i++ )
|
||||
sw.WriteLine(lines[i].Text);
|
||||
|
||||
sw.Write(lines[Count-1].Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
FastColoredTextBox/TypeDescriptor.cs
Normal file
96
FastColoredTextBox/TypeDescriptor.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
///
|
||||
/// These classes are required for correct data binding to Text property of FastColoredTextbox
|
||||
///
|
||||
class FCTBDescriptionProvider : TypeDescriptionProvider
|
||||
{
|
||||
public FCTBDescriptionProvider(Type type)
|
||||
: base(GetDefaultTypeProvider(type))
|
||||
{
|
||||
}
|
||||
|
||||
private static TypeDescriptionProvider GetDefaultTypeProvider(Type type)
|
||||
{
|
||||
return TypeDescriptor.GetProvider(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
|
||||
{
|
||||
ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
|
||||
return new FCTBTypeDescriptor(defaultDescriptor, instance);
|
||||
}
|
||||
}
|
||||
|
||||
class FCTBTypeDescriptor : CustomTypeDescriptor
|
||||
{
|
||||
ICustomTypeDescriptor parent;
|
||||
object instance;
|
||||
|
||||
public FCTBTypeDescriptor(ICustomTypeDescriptor parent, object instance)
|
||||
: base(parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public override string GetComponentName()
|
||||
{
|
||||
var ctrl = (instance as Control);
|
||||
return ctrl == null ? null : ctrl.Name;
|
||||
}
|
||||
|
||||
public override EventDescriptorCollection GetEvents()
|
||||
{
|
||||
var coll = base.GetEvents();
|
||||
var list = new EventDescriptor[coll.Count];
|
||||
|
||||
for (int i = 0; i < coll.Count; i++)
|
||||
if (coll[i].Name == "TextChanged")//instead of TextChanged slip BindingTextChanged for binding
|
||||
list[i] = new FooTextChangedDescriptor(coll[i]);
|
||||
else
|
||||
list[i] = coll[i];
|
||||
|
||||
return new EventDescriptorCollection(list);
|
||||
}
|
||||
}
|
||||
|
||||
class FooTextChangedDescriptor : EventDescriptor
|
||||
{
|
||||
public FooTextChangedDescriptor(MemberDescriptor desc)
|
||||
: base(desc)
|
||||
{
|
||||
}
|
||||
|
||||
public override void AddEventHandler(object component, Delegate value)
|
||||
{
|
||||
(component as FastColoredTextBox).BindingTextChanged += value as EventHandler;
|
||||
}
|
||||
|
||||
public override Type ComponentType
|
||||
{
|
||||
get { return typeof(FastColoredTextBox); }
|
||||
}
|
||||
|
||||
public override Type EventType
|
||||
{
|
||||
get { return typeof(EventHandler); }
|
||||
}
|
||||
|
||||
public override bool IsMulticast
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void RemoveEventHandler(object component, Delegate value)
|
||||
{
|
||||
(component as FastColoredTextBox).BindingTextChanged -= value as EventHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
FastColoredTextBox/UnfocusablePanel.cs
Normal file
41
FastColoredTextBox/UnfocusablePanel.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
[System.ComponentModel.ToolboxItem(false)]
|
||||
public class UnfocusablePanel : UserControl
|
||||
{
|
||||
public Color BackColor2 { get; set; }
|
||||
public Color BorderColor { get; set; }
|
||||
public new string Text { get; set; }
|
||||
public StringAlignment TextAlignment { get; set; }
|
||||
|
||||
public UnfocusablePanel()
|
||||
{
|
||||
SetStyle(ControlStyles.Selectable, false);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
using (var brush = new LinearGradientBrush(ClientRectangle, BackColor2, BackColor, 90))
|
||||
e.Graphics.FillRectangle(brush, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
|
||||
using(var pen = new Pen(BorderColor))
|
||||
e.Graphics.DrawRectangle(pen, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
StringFormat sf = new StringFormat();
|
||||
sf.Alignment = TextAlignment;
|
||||
sf.LineAlignment = StringAlignment.Center;
|
||||
using(var brush = new SolidBrush(ForeColor))
|
||||
e.Graphics.DrawString(Text, Font, brush, new RectangleF(1, 1, ClientSize.Width - 2, ClientSize.Height - 2), sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
FastColoredTextBox/VisualMarker.cs
Normal file
106
FastColoredTextBox/VisualMarker.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class VisualMarker
|
||||
{
|
||||
public readonly Rectangle rectangle;
|
||||
|
||||
public VisualMarker(Rectangle rectangle)
|
||||
{
|
||||
this.rectangle = rectangle;
|
||||
}
|
||||
|
||||
public virtual void Draw(Graphics gr, Pen pen)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Cursor Cursor
|
||||
{
|
||||
get { return Cursors.Hand; }
|
||||
}
|
||||
}
|
||||
|
||||
public class CollapseFoldingMarker: VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public CollapseFoldingMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)
|
||||
{
|
||||
//draw minus
|
||||
gr.FillRectangle(backgroundBrush, rectangle);
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2, rectangle.Top + rectangle.Height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpandFoldingMarker : VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public ExpandFoldingMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)
|
||||
{
|
||||
//draw plus
|
||||
gr.FillRectangle(backgroundBrush, rectangle);
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2, rectangle.Top + rectangle.Height / 2);
|
||||
gr.DrawLine(forePen, rectangle.Left + rectangle.Width / 2, rectangle.Top + 2, rectangle.Left + rectangle.Width / 2, rectangle.Bottom - 2);
|
||||
}
|
||||
}
|
||||
|
||||
public class FoldedAreaMarker : VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public FoldedAreaMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Pen pen)
|
||||
{
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
public class StyleVisualMarker : VisualMarker
|
||||
{
|
||||
public Style Style{get;private set;}
|
||||
|
||||
public StyleVisualMarker(Rectangle rectangle, Style style)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.Style = style;
|
||||
}
|
||||
}
|
||||
|
||||
public class VisualMarkerEventArgs : MouseEventArgs
|
||||
{
|
||||
public Style Style { get; private set; }
|
||||
public StyleVisualMarker Marker { get; private set; }
|
||||
|
||||
public VisualMarkerEventArgs(Style style, StyleVisualMarker marker, MouseEventArgs args)
|
||||
: base(args.Button, args.Clicks, args.X, args.Y, args.Delta)
|
||||
{
|
||||
this.Style = style;
|
||||
this.Marker = marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user