(e.Count);
for (int i = 0; i < e.Count; i++)
temp.Add(new LineInfo(-1) { VisibleState = newState });
lineInfos.InsertRange(e.Index, temp);
OnLineInserted(e.Index, e.Count);
}
///
/// Navigates forward (by Line.LastVisit property)
///
public bool NavigateForward()
{
DateTime min = DateTime.Now;
int iLine = -1;
for (int i = 0; i < LinesCount; i++)
if (lines.IsLineLoaded(i))
if (lines[i].LastVisit > lastNavigatedDateTime && lines[i].LastVisit < min)
{
min = lines[i].LastVisit;
iLine = i;
}
if (iLine >= 0)
{
Navigate(iLine);
return true;
}
else
return false;
}
///
/// Navigates backward (by Line.LastVisit property)
///
public bool NavigateBackward()
{
var max = new DateTime();
int iLine = -1;
for (int i = 0; i < LinesCount; i++)
if (lines.IsLineLoaded(i))
if (lines[i].LastVisit < lastNavigatedDateTime && lines[i].LastVisit > max)
{
max = lines[i].LastVisit;
iLine = i;
}
if (iLine >= 0)
{
Navigate(iLine);
return true;
}
else
return false;
}
///
/// Navigates to defined line, without Line.LastVisit reseting
///
public void Navigate(int iLine)
{
if (iLine >= LinesCount) return;
lastNavigatedDateTime = lines[iLine].LastVisit;
Selection.Start = new Place(0, iLine);
DoSelectionVisible();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
m_hImc = ImmGetContext(Handle);
}
private void timer2_Tick(object sender, EventArgs e)
{
timer2.Enabled = false;
if (needRiseTextChangedDelayed)
{
needRiseTextChangedDelayed = false;
if (delayedTextChangedRange == null)
return;
delayedTextChangedRange = Range.GetIntersectionWith(delayedTextChangedRange);
delayedTextChangedRange.Expand();
OnTextChangedDelayed(delayedTextChangedRange);
delayedTextChangedRange = null;
}
}
public void AddVisualMarker(VisualMarker marker)
{
visibleMarkers.Add(marker);
}
private void timer_Tick(object sender, EventArgs e)
{
timer.Enabled = false;
if (needRiseSelectionChangedDelayed)
{
needRiseSelectionChangedDelayed = false;
OnSelectionChangedDelayed();
}
if (needRiseVisibleRangeChangedDelayed)
{
needRiseVisibleRangeChangedDelayed = false;
OnVisibleRangeChangedDelayed();
}
}
public virtual void OnTextChangedDelayed(Range changedRange)
{
if (TextChangedDelayed != null)
TextChangedDelayed(this, new TextChangedEventArgs(changedRange));
}
public virtual void OnSelectionChangedDelayed()
{
RecalcScrollByOneLine(Selection.Start.iLine);
//highlight brackets
ClearBracketsPositions();
if (LeftBracket != '\x0' && RightBracket != '\x0')
HighlightBrackets(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition);
if (LeftBracket2 != '\x0' && RightBracket2 != '\x0')
HighlightBrackets(LeftBracket2, RightBracket2, ref leftBracketPosition2, ref rightBracketPosition2);
//remember last visit time
if (Selection.IsEmpty && Selection.Start.iLine < LinesCount)
{
if (lastNavigatedDateTime != lines[Selection.Start.iLine].LastVisit)
{
lines[Selection.Start.iLine].LastVisit = DateTime.Now;
lastNavigatedDateTime = lines[Selection.Start.iLine].LastVisit;
}
}
if (SelectionChangedDelayed != null)
SelectionChangedDelayed(this, new EventArgs());
}
public virtual void OnVisibleRangeChangedDelayed()
{
if (VisibleRangeChangedDelayed != null)
VisibleRangeChangedDelayed(this, new EventArgs());
}
private void ResetTimer(Timer timer)
{
timer.Stop();
if (IsHandleCreated)
timer.Start();
}
///
/// Adds new style
///
/// Layer index of this style
public int AddStyle(Style style)
{
if (style == null) return -1;
int i = GetStyleIndex(style);
if (i >= 0)
return i;
for (i = Styles.Length - 1; i >= 0; i--)
if (Styles[i] != null)
break;
i++;
if (i >= Styles.Length)
throw new Exception("Maximum count of Styles is exceeded");
Styles[i] = style;
return i;
}
///
/// Shows find dialog
///
public void ShowFindDialog()
{
ShowFindDialog(null);
}
///
/// Shows find dialog
///
public void ShowFindDialog(string findText)
{
if (findForm == null)
findForm = new FindForm(this);
if (findText != null)
findForm.tbFind.Text = findText;
else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)
findForm.tbFind.Text = Selection.Text;
findForm.tbFind.SelectAll();
findForm.Show();
}
///
/// Shows replace dialog
///
public void ShowReplaceDialog()
{
ShowReplaceDialog(null);
}
///
/// Shows replace dialog
///
public void ShowReplaceDialog(string findText)
{
if (ReadOnly)
return;
if (replaceForm == null)
replaceForm = new ReplaceForm(this);
if (findText != null)
replaceForm.tbFind.Text = findText;
else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)
replaceForm.tbFind.Text = Selection.Text;
replaceForm.tbFind.SelectAll();
replaceForm.Show();
}
///
/// Gets length of given line
///
/// Line index
/// Length of line
public int GetLineLength(int iLine)
{
if (iLine < 0 || iLine >= lines.Count)
throw new ArgumentOutOfRangeException("Line index out of range");
return lines[iLine].Count;
}
///
/// Get range of line
///
/// Line index
public Range GetLine(int iLine)
{
if (iLine < 0 || iLine >= lines.Count)
throw new ArgumentOutOfRangeException("Line index out of range");
var sel = new Range(this);
sel.Start = new Place(0, iLine);
sel.End = new Place(lines[iLine].Count, iLine);
return sel;
}
///
/// Copy selected text into Clipboard
///
public void Copy()
{
if (Selection.IsEmpty)
Selection.Expand();
if (!Selection.IsEmpty)
{
var exp = new ExportToHTML();
exp.UseBr = false;
exp.UseNbsp = false;
exp.UseStyleTag = true;
string html = "" + exp.GetHtml(Selection.Clone()) + "
";
var data = new DataObject();
data.SetData(DataFormats.UnicodeText, true, Selection.Text);
data.SetData(DataFormats.Html, PrepareHtmlForClipboard(html));
//
var thread = new Thread(() => Clipboard.SetDataObject(data, true));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
}
public static MemoryStream PrepareHtmlForClipboard(string html)
{
Encoding enc = Encoding.UTF8;
string begin = "Version:0.9\r\nStartHTML:{0:000000}\r\nEndHTML:{1:000000}"
+ "\r\nStartFragment:{2:000000}\r\nEndFragment:{3:000000}\r\n";
string html_begin = "\r\n\r\n"
+ "\r\n"
+ "HTML clipboard\r\n\r\n\r\n"
+ "";
string html_end = "\r\n\r\n\r\n";
string begin_sample = String.Format(begin, 0, 0, 0, 0);
int count_begin = enc.GetByteCount(begin_sample);
int count_html_begin = enc.GetByteCount(html_begin);
int count_html = enc.GetByteCount(html);
int count_html_end = enc.GetByteCount(html_end);
string html_total = String.Format(
begin
, count_begin
, count_begin + count_html_begin + count_html + count_html_end
, count_begin + count_html_begin
, count_begin + count_html_begin + count_html
) + html_begin + html + html_end;
return new MemoryStream(enc.GetBytes(html_total));
}
///
/// Cut selected text into Clipboard
///
public void Cut()
{
if (!Selection.IsEmpty)
{
Copy();
ClearSelected();
}
else
{
Copy();
//remove current line
if (Selection.Start.iLine >= 0 && Selection.Start.iLine < LinesCount)
{
var iLine = Selection.Start.iLine;
RemoveLines(new List() { iLine });
Selection.Start = new Place(0, Math.Max(0, Math.Min(iLine, LinesCount - 1)));
}
}
}
///
/// Paste text from clipboard into selection position
///
public void Paste()
{
string text = null;
var thread = new Thread(() =>
{
if (Clipboard.ContainsText())
text = Clipboard.GetText();
}
);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
if (text != null)
InsertText(text.TrimStart());
}
///
/// Select all chars of text
///
public void SelectAll()
{
Selection.SelectAll();
}
///
/// Move caret to end of text
///
public void GoEnd()
{
if (lines.Count > 0)
Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);
else
Selection.Start = new Place(0, 0);
DoCaretVisible();
}
///
/// Move caret to first position
///
public void GoHome()
{
Selection.Start = new Place(0, 0);
DoCaretVisible();
//VerticalScroll.Value = 0;
//HorizontalScroll.Value = 0;
}
///
/// Clear text, styles, history, caches
///
public void Clear()
{
Selection.BeginUpdate();
try
{
Selection.SelectAll();
ClearSelected();
lines.Manager.ClearHistory();
Invalidate();
}
finally
{
Selection.EndUpdate();
}
}
///
/// Clear buffer of styles
///
public void ClearStylesBuffer()
{
for (int i = 0; i < Styles.Length; i++)
Styles[i] = null;
}
///
/// Clear style of all text
///
public void ClearStyle(StyleIndex styleIndex)
{
foreach (Line line in lines)
line.ClearStyle(styleIndex);
for (int i = 0; i < lineInfos.Count; i++)
SetVisibleState(i, VisibleState.Visible);
Invalidate();
}
///
/// Clears undo and redo stacks
///
public void ClearUndo()
{
lines.Manager.ClearHistory();
}
///
/// Insert text into current selection position
///
///
public void InsertText(string text, bool jumpToCaret = true)
{
if (text == null)
return;
lines.Manager.BeginAutoUndoCommands();
try
{
if (!Selection.IsEmpty)
lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
//insert virtual spaces
if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) && VirtualSpace)
InsertVirtualSpaces();
lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));
if (updating <= 0 && jumpToCaret)
DoCaretVisible();
}
finally
{
lines.Manager.EndAutoUndoCommands();
}
//
Invalidate();
}
///
/// Insert text into current selection position (with predefined style)
///
///
public void InsertText(string text, Style style, bool jumpToCaret = true)
{
if (text == null)
return;
//remember last caret position
Place last = Selection.Start;
//insert text
InsertText(text, jumpToCaret);
//get range
var range = new Range(this, last, Selection.Start);
//set style for range
range.SetStyle(style);
}
///
/// Append string to end of the Text
///
///
public void AppendText(string text)
{
if (text == null)
return;
Selection.ColumnSelectionMode = false;
Place oldStart = Selection.Start;
Place oldEnd = Selection.End;
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
try
{
if (lines.Count > 0)
Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);
else
Selection.Start = new Place(0, 0);
lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));
}
finally
{
lines.Manager.EndAutoUndoCommands();
Selection.Start = oldStart;
Selection.End = oldEnd;
Selection.EndUpdate();
}
//
Invalidate();
}
///
/// Returns index of the style in Styles
/// -1 otherwise
///
///
/// Index of the style in Styles
public int GetStyleIndex(Style style)
{
return Array.IndexOf(Styles, style);
}
///
/// Returns StyleIndex mask of given styles
///
///
/// StyleIndex mask of given styles
public StyleIndex GetStyleIndexMask(Style[] styles)
{
StyleIndex mask = StyleIndex.None;
foreach (Style style in styles)
{
int i = GetStyleIndex(style);
if (i >= 0)
mask |= Range.ToStyleIndex(i);
}
return mask;
}
internal int GetOrSetStyleLayerIndex(Style style)
{
int i = GetStyleIndex(style);
if (i < 0)
i = AddStyle(style);
return i;
}
public static SizeF GetCharSize(Font font, char c)
{
Size sz2 = TextRenderer.MeasureText("<" + c.ToString() + ">", font);
Size sz3 = TextRenderer.MeasureText("<>", font);
return new SizeF(sz2.Width - sz3.Width + 1, /*sz2.Height*/font.Height);
}
[DllImport("Imm32.dll")]
public static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("Imm32.dll")]
public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
if (m.WParam.ToInt32() != SB_ENDSCROLL)
Invalidate();
base.WndProc(ref m);
if (ImeAllowed)
if (m.Msg == WM_IME_SETCONTEXT && m.WParam.ToInt32() == 1)
{
ImmAssociateContext(Handle, m_hImc);
}
}
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
OnVisibleRangeChanged();
//
if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
VerticalScroll.Value = se.NewValue;
if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)
HorizontalScroll.Value = se.NewValue;
UpdateScrollbars();
Invalidate();
}
private void InsertChar(char c)
{
lines.Manager.BeginAutoUndoCommands();
try
{
if (!Selection.IsEmpty)
lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
//insert virtual spaces
if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) && VirtualSpace)
InsertVirtualSpaces();
//insert char
lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, c));
}
finally
{
lines.Manager.EndAutoUndoCommands();
}
Invalidate();
}
private void InsertVirtualSpaces()
{
var lineLength = GetLineLength(Selection.Start.iLine);
var count = Selection.Start.iChar - lineLength;
Selection.BeginUpdate();
try
{
Selection.Start = new Place(lineLength, Selection.Start.iLine);
lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new string(' ', count)));
}
finally
{
Selection.EndUpdate();
}
}
///
/// Deletes selected chars
///
public void ClearSelected()
{
if (!Selection.IsEmpty)
{
lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
Invalidate();
}
}
///
/// Deletes current line(s)
///
public void ClearCurrentLine()
{
Selection.Expand();
lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
if (Selection.Start.iLine == 0)
if (!Selection.GoRightThroughFolded()) return;
if (Selection.Start.iLine > 0)
lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, '\b')); //backspace
Invalidate();
}
private void Recalc()
{
if (!needRecalc)
return;
#if debug
var sw = Stopwatch.StartNew();
#endif
needRecalc = false;
//calc min left indent
LeftIndent = LeftPadding;
long maxLineNumber = LinesCount + lineNumberStartValue - 1;
int charsForLineNumber = 2 + (maxLineNumber > 0 ? (int)Math.Log10(maxLineNumber) : 0);
if (Created)
{
if (ShowLineNumbers)
LeftIndent += charsForLineNumber * CharWidth + minLeftIndent + 1;
}
else
needRecalc = true;
//calc max line length and count of wordWrapLines
wordWrapLinesCount = 0;
maxLineLength = RecalcMaxLineLength();
//adjust AutoScrollMinSize
int minWidth;
CalcMinAutosizeWidth(out minWidth, ref maxLineLength);
AutoScrollMinSize = new Size(minWidth, wordWrapLinesCount * CharHeight + Paddings.Top + Paddings.Bottom);
#if debug
sw.Stop();
Debug.WriteLine("Recalc: " + sw.ElapsedMilliseconds);
#endif
}
void CalcMinAutosizeWidth(out int minWidth, ref int maxLineLength)
{
//adjust AutoScrollMinSize
minWidth = LeftIndent + (maxLineLength) * CharWidth + 2 + Paddings.Left + Paddings.Right;
if (wordWrap)
switch (WordWrapMode)
{
case WordWrapMode.WordWrapControlWidth:
case WordWrapMode.CharWrapControlWidth:
maxLineLength = Math.Min(maxLineLength, (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) / CharWidth);
minWidth = 0;
break;
case WordWrapMode.WordWrapPreferredWidth:
case WordWrapMode.CharWrapPreferredWidth:
maxLineLength = Math.Min(maxLineLength, PreferredLineWidth);
minWidth = LeftIndent + PreferredLineWidth * CharWidth + 2 + Paddings.Left + Paddings.Right;
break;
}
}
private void RecalcScrollByOneLine(int iLine)
{
if (iLine >= lines.Count)
return;
int maxLineLength = lines[iLine].Count;
if (this.maxLineLength < maxLineLength && !WordWrap)
this.maxLineLength = maxLineLength;
int minWidth;
CalcMinAutosizeWidth(out minWidth, ref maxLineLength);
if (AutoScrollMinSize.Width < minWidth)
AutoScrollMinSize = new Size(minWidth, AutoScrollMinSize.Height);
}
private int RecalcMaxLineLength()
{
int maxLineLength = 0;
TextSource lines = this.lines;
int count = lines.Count;
int charHeight = CharHeight;
int topIndent = Paddings.Top;
for (int i = 0; i < count; i++)
{
int lineLength = lines.GetLineLength(i);
LineInfo lineInfo = lineInfos[i];
if (lineLength > maxLineLength && lineInfo.VisibleState == VisibleState.Visible)
maxLineLength = lineLength;
lineInfo.startY = wordWrapLinesCount * charHeight + topIndent;
wordWrapLinesCount += lineInfo.WordWrapStringsCount;
lineInfos[i] = lineInfo;
}
return maxLineLength;
}
private int GetMaxLineWordWrapedWidth()
{
if (wordWrap)
switch (wordWrapMode)
{
case WordWrapMode.WordWrapControlWidth:
case WordWrapMode.CharWrapControlWidth:
return ClientSize.Width;
case WordWrapMode.WordWrapPreferredWidth:
case WordWrapMode.CharWrapPreferredWidth:
return LeftIndent + PreferredLineWidth * CharWidth + 2 + Paddings.Left + Paddings.Right;
}
return int.MaxValue;
}
private void RecalcWordWrap(int fromLine, int toLine)
{
int maxCharsPerLine = 0;
bool charWrap = false;
switch (WordWrapMode)
{
case WordWrapMode.WordWrapControlWidth:
maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) / CharWidth;
break;
case WordWrapMode.CharWrapControlWidth:
maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) / CharWidth;
charWrap = true;
break;
case WordWrapMode.WordWrapPreferredWidth:
maxCharsPerLine = PreferredLineWidth;
break;
case WordWrapMode.CharWrapPreferredWidth:
maxCharsPerLine = PreferredLineWidth;
charWrap = true;
break;
}
for (int iLine = fromLine; iLine <= toLine; iLine++)
if (lines.IsLineLoaded(iLine))
{
if (!wordWrap)
lineInfos[iLine].CutOffPositions.Clear();
else
{
LineInfo li = lineInfos[iLine];
li.CalcCutOffs(maxCharsPerLine, ImeAllowed, charWrap, lines[iLine]);
lineInfos[iLine] = li;
}
}
needRecalc = true;
}
protected override void OnClientSizeChanged(EventArgs e)
{
base.OnClientSizeChanged(e);
if (WordWrap)
{
RecalcWordWrap(0, lines.Count - 1);
Invalidate();
}
OnVisibleRangeChanged();
}
///
/// Scroll control for display defined rectangle
///
///
private void DoVisibleRectangle(Rectangle rect)
{
int oldV = VerticalScroll.Value;
int v = VerticalScroll.Value;
int h = HorizontalScroll.Value;
if (rect.Bottom > ClientRectangle.Height)
v += rect.Bottom - ClientRectangle.Height;
else if (rect.Top < 0)
v += rect.Top;
if (rect.Right > ClientRectangle.Width)
h += rect.Right - ClientRectangle.Width;
else if (rect.Left < LeftIndent)
h += rect.Left - LeftIndent;
//
if (!Multiline)
v = 0;
//
v = Math.Max(0, v);
h = Math.Max(0, h);
//
try
{
if (VerticalScroll.Visible || !ShowScrollBars)
VerticalScroll.Value = v;
if (HorizontalScroll.Visible || !ShowScrollBars)
HorizontalScroll.Value = h;
}
catch (ArgumentOutOfRangeException)
{
;
}
UpdateScrollbars();
//
if (oldV != VerticalScroll.Value)
OnVisibleRangeChanged();
}
///
/// Updates scrollbar position after Value changed
///
public void UpdateScrollbars()
{
if (ShowScrollBars)
{
//some magic for update scrolls
base.AutoScrollMinSize -= new Size(1, 0);
base.AutoScrollMinSize += new Size(1, 0);
}
}
///
/// Scroll control for display caret
///
public void DoCaretVisible()
{
Invalidate();
Recalc();
Point car = PlaceToPoint(Selection.Start);
car.Offset(-CharWidth, 0);
DoVisibleRectangle(new Rectangle(car, new Size(2 * CharWidth, 2 * CharHeight)));
}
///
/// Scroll control left
///
public void ScrollLeft()
{
Invalidate();
HorizontalScroll.Value = 0;
AutoScrollMinSize -= new Size(1, 0);
AutoScrollMinSize += new Size(1, 0);
}
///
/// Scroll control for display selection area
///
public void DoSelectionVisible()
{
if (lineInfos[Selection.End.iLine].VisibleState != VisibleState.Visible)
ExpandBlock(Selection.End.iLine);
if (lineInfos[Selection.Start.iLine].VisibleState != VisibleState.Visible)
ExpandBlock(Selection.Start.iLine);
Recalc();
DoVisibleRectangle(new Rectangle(PlaceToPoint(new Place(0, Selection.End.iLine)),
new Size(2 * CharWidth, 2 * CharHeight)));
Point car = PlaceToPoint(Selection.Start);
Point car2 = PlaceToPoint(Selection.End);
car.Offset(-CharWidth, -ClientSize.Height / 2);
DoVisibleRectangle(new Rectangle(car, new Size(Math.Abs(car2.X - car.X), ClientSize.Height)));//Math.Abs(car2.Y-car.Y) + 2 * CharHeight
Invalidate();
}
///
/// Scroll control for display given range
///
public void DoRangeVisible(Range range)
{
range = range.Clone();
range.Normalize();
range.End = new Place(range.End.iChar, Math.Min(range.End.iLine, range.Start.iLine + ClientSize.Height / CharHeight));
if (lineInfos[range.End.iLine].VisibleState != VisibleState.Visible)
ExpandBlock(range.End.iLine);
if (lineInfos[range.Start.iLine].VisibleState != VisibleState.Visible)
ExpandBlock(range.Start.iLine);
Recalc();
DoVisibleRectangle(new Rectangle(PlaceToPoint(new Place(0, range.Start.iLine)), new Size(2 * CharWidth, (1 + range.End.iLine - range.Start.iLine) * CharHeight)));
Invalidate();
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (e.KeyCode == Keys.ShiftKey)
lastModifiers &= ~Keys.Shift;
if (e.KeyCode == Keys.Alt)
lastModifiers &= ~Keys.Alt;
if (e.KeyCode == Keys.ControlKey)
lastModifiers &= ~Keys.Control;
}
private const Keys AltShift = Keys.Alt | Keys.Shift;
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (Focused)
lastModifiers = e.Modifiers;
handledChar = false;
if (e.Handled)
{
handledChar = true;
return;
}
switch (e.KeyCode)
{
case Keys.G:
if (e.Modifiers == Keys.Control)
ShowGoToDialog();
break;
case Keys.F:
if (e.Modifiers == Keys.Control)
ShowFindDialog();
break;
case Keys.F3:
if (e.Modifiers == Keys.None)
if (findForm == null || findForm.tbFind.Text == "")
ShowFindDialog();
else
findForm.FindNext(findForm.tbFind.Text);
break;
case Keys.H:
if (e.Modifiers == Keys.Control)
ShowReplaceDialog();
break;
case Keys.C:
if (e.Modifiers == Keys.Control)
Copy();
if (e.Modifiers == (Keys.Control | Keys.Shift))
CommentSelected();
break;
case Keys.X:
if (e.Modifiers == Keys.Control && !ReadOnly)
Cut();
break;
case Keys.V:
if (e.Modifiers == Keys.Control && !ReadOnly)
Paste();
break;
case Keys.A:
if (e.Modifiers == Keys.Control)
Selection.SelectAll();
break;
case Keys.Z:
if (e.Modifiers == Keys.Control && !ReadOnly)
Undo();
break;
case Keys.R:
if (e.Modifiers == Keys.Control && !ReadOnly)
Redo();
break;
case Keys.U:
if (e.Modifiers == (Keys.Control | Keys.Shift))
LowerCase();
if (e.Modifiers == Keys.Control)
UpperCase();
break;
case Keys.Tab:
if (e.Modifiers == Keys.Shift && !ReadOnly)
DecreaseIndent();
break;
case Keys.OemMinus:
if (e.Modifiers == Keys.Control)
NavigateBackward();
if (e.Modifiers == (Keys.Control | Keys.Shift))
NavigateForward();
break;
case Keys.Back:
if (ReadOnly) break;
if (e.Modifiers == Keys.Alt)
Undo();
else
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
if (OnKeyPressing('\b')) //KeyPress event processed key
break;
if (!Selection.IsEmpty)
ClearSelected();
else
InsertChar('\b');
OnKeyPressed('\b');
}
else
if (e.Modifiers == Keys.Control)
{
if (OnKeyPressing('\b')) //KeyPress event processed key
break;
if (!Selection.IsEmpty)
ClearSelected();
Selection.GoWordLeft(true);
ClearSelected();
OnKeyPressed('\b');
}
break;
case Keys.Insert:
if (e.Modifiers == Keys.None)
{
if (!ReadOnly)
isReplaceMode = !isReplaceMode;
}
else
if (e.Modifiers == Keys.Control)
{
Copy();
}
else
if (e.Modifiers == Keys.Shift)
{
if (!ReadOnly)
Paste();
}
break;
case Keys.Delete:
if (ReadOnly) break;
if (e.Modifiers == Keys.None)
{
if (OnKeyPressing((char)0xff)) //KeyPress event processed key
break;
if (!Selection.IsEmpty)
ClearSelected();
else
{
//if line contains only spaces then delete line
if (this[Selection.Start.iLine].StartSpacesCount == this[Selection.Start.iLine].Count)
RemoveSpacesAfterCaret();
if (Selection.GoRightThroughFolded())
{
int iLine = Selection.Start.iLine;
InsertChar('\b');
//if removed \n then trim spaces
if (iLine != Selection.Start.iLine && AutoIndent)
if (Selection.Start.iChar > 0)
RemoveSpacesAfterCaret();
}
}
OnKeyPressed((char)0xff);
}
else
if (e.Modifiers == Keys.Control)
{
if (OnKeyPressing((char)0xff)) //KeyPress event processed key
break;
if (!Selection.IsEmpty)
ClearSelected();
else
{
Selection.GoWordRight(true);
ClearSelected();
}
OnKeyPressed((char)0xff);
}
else
if (e.Modifiers == Keys.Shift)
{
if (OnKeyPressing((char)0xff)) //KeyPress event processed key
break;
Cut();
OnKeyPressed((char)0xff);
}
break;
case Keys.Space:
if (ReadOnly) break;
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
if (OnKeyPressing(' ')) //KeyPress event processed key
break;
if (!Selection.IsEmpty)
ClearSelected();
//replace mode? select forward char
if (IsReplaceMode)
{
Selection.GoRight(true);
Selection.Inverse();
}
InsertChar(' ');
OnKeyPressed(' ');
}
break;
case Keys.Left:
if (e.Modifiers == Keys.Control || e.Modifiers == (Keys.Control | Keys.Shift))
Selection.GoWordLeft(e.Shift);
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
Selection.GoLeft(e.Shift);
if (e.Modifiers == AltShift)
{
CheckAndChangeSelectionType();
if (Selection.ColumnSelectionMode)
Selection.GoLeft_ColumnSelectionMode();
}
break;
case Keys.Right:
if (e.Modifiers == Keys.Control || e.Modifiers == (Keys.Control | Keys.Shift))
Selection.GoWordRight(e.Shift);
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
Selection.GoRight(e.Shift);
if (e.Modifiers == AltShift)
{
CheckAndChangeSelectionType();
if (Selection.ColumnSelectionMode)
Selection.GoRight_ColumnSelectionMode();
}
break;
case Keys.Up:
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
Selection.GoUp(e.Shift);
ScrollLeft();
}
if (e.Modifiers == AltShift)
{
CheckAndChangeSelectionType();
if (Selection.ColumnSelectionMode)
Selection.GoUp_ColumnSelectionMode();
}
if (e.Modifiers == Keys.Alt)
{
if (!ReadOnly && !Selection.ColumnSelectionMode)
MoveSelectedLinesUp();
}
break;
case Keys.Down:
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
Selection.GoDown(e.Shift);
ScrollLeft();
}
else
if (e.Modifiers == AltShift)
{
CheckAndChangeSelectionType();
if (Selection.ColumnSelectionMode)
Selection.GoDown_ColumnSelectionMode();
}
if (e.Modifiers == Keys.Alt)
{
if (!ReadOnly && !Selection.ColumnSelectionMode)
MoveSelectedLinesDown();
}
break;
case Keys.PageUp:
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
Selection.GoPageUp(e.Shift);
ScrollLeft();
}
break;
case Keys.PageDown:
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
Selection.GoPageDown(e.Shift);
ScrollLeft();
}
break;
case Keys.Home:
if (e.Modifiers == Keys.Control || e.Modifiers == (Keys.Control | Keys.Shift))
Selection.GoFirst(e.Shift);
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
{
GoHome(e.Shift);
ScrollLeft();
}
break;
case Keys.End:
if (e.Modifiers == Keys.Control || e.Modifiers == (Keys.Control | Keys.Shift))
Selection.GoLast(e.Shift);
if (e.Modifiers == Keys.None || e.Modifiers == Keys.Shift)
Selection.GoEnd(e.Shift);
break;
case Keys.Alt:
return;
default:
if ((e.Modifiers & Keys.Control) != 0)
return;
if ((e.Modifiers & Keys.Alt) != 0)
{
if ((Control.MouseButtons & MouseButtons.Left) != 0)
CheckAndChangeSelectionType();
return;
}
if (e.KeyCode == Keys.ShiftKey)
return;
break;
}
e.Handled = true;
DoCaretVisible();
Invalidate();
}
///
/// Moves selected lines down
///
public virtual void MoveSelectedLinesDown()
{
var prevSelection = Selection.Clone();
Selection.Expand();
var iLine = Selection.Start.iLine;
if (Selection.End.iLine >= LinesCount - 1)
{
Selection = prevSelection;
return;
}
var text = SelectedText;
var temp = new List();
for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)
temp.Add(i);
RemoveLines(temp);
Selection.Start = new Place(GetLineLength(iLine), iLine);
SelectedText = "\n" + text;
Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine + 1);
Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine + 1);
}
///
/// Moves selected lines up
///
public virtual void MoveSelectedLinesUp()
{
var prevSelection = Selection.Clone();
Selection.Expand();
var iLine = Selection.Start.iLine;
if (iLine == 0)
{
Selection = prevSelection;
return;
}
var text = SelectedText;
var temp = new List();
for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)
temp.Add(i);
RemoveLines(temp);
Selection.Start = new Place(0, iLine - 1);
SelectedText = text + "\n";
Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine - 1);
Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine - 1);
}
private void GoHome(bool shift)
{
Selection.BeginUpdate();
try
{
int iLine = Selection.Start.iLine;
int spaces = this[iLine].StartSpacesCount;
if (Selection.Start.iChar <= spaces)
Selection.GoHome(shift);
else
{
Selection.GoHome(shift);
for (int i = 0; i < spaces; i++)
Selection.GoRight(shift);
}
}
finally
{
Selection.EndUpdate();
}
}
///
/// Convert selected text to upper case
///
public void UpperCase()
{
Range old = Selection.Clone();
SelectedText = SelectedText.ToUpper();
Selection.Start = old.Start;
Selection.End = old.End;
}
///
/// Convert selected text to lower case
///
public void LowerCase()
{
Range old = Selection.Clone();
SelectedText = SelectedText.ToLower();
Selection.Start = old.Start;
Selection.End = old.End;
}
///
/// Insert/remove comment prefix into selected lines
///
public void CommentSelected()
{
CommentSelected(CommentPrefix);
}
///
/// Insert/remove comment prefix into selected lines
///
public void CommentSelected(string commentPrefix)
{
if (string.IsNullOrEmpty(commentPrefix))
return;
Selection.Normalize();
bool isCommented = lines[Selection.Start.iLine].Text.TrimStart().StartsWith(commentPrefix);
if (isCommented)
RemoveLinePrefix(commentPrefix);
else
InsertLinePrefix(commentPrefix);
}
/*
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
bool proc = ProcessKeyPress('\r');
if (proc)
{
base.OnKeyDown(new KeyEventArgs(Keys.Enter));
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}*/
public void OnKeyPressing(KeyPressEventArgs args)
{
if (KeyPressing != null)
KeyPressing(this, args);
}
private bool OnKeyPressing(char c)
{
var args = new KeyPressEventArgs(c);
OnKeyPressing(args);
return args.Handled;
}
public void OnKeyPressed(char c)
{
var args = new KeyPressEventArgs(c);
if (KeyPressed != null)
KeyPressed(this, args);
}
/*
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
ProcessKeyPress(e.KeyChar);
}*/
protected override bool ProcessMnemonic(char charCode)
{
if (Focused)
return ProcessKeyPress(charCode) || base.ProcessMnemonic(charCode);
else
return false;
}
private bool ProcessKeyPress(char c)
{
if (handledChar)
return true;
if (c == ' ')
return true;
if (c == '\b' && (lastModifiers & Keys.Alt) != 0)
return true;
if (char.IsControl(c) && c != '\r' && c != '\t')
return false;
if (ReadOnly || !Enabled)
return false;
if (lastModifiers != Keys.None &&
lastModifiers != Keys.Shift &&
lastModifiers != (Keys.Control | Keys.Alt) && //ALT+CTRL is special chars (AltGr)
lastModifiers != (Keys.Shift | Keys.Control | Keys.Alt) && //SHIFT + ALT + CTRL is special chars (AltGr)
(lastModifiers != (Keys.Alt) || char.IsLetterOrDigit(c)) //may be ALT+LetterOrDigit is mnemonic code
)
return false; //do not process Ctrl+? and Alt+? keys
char sourceC = c;
if (OnKeyPressing(sourceC)) //KeyPress event processed key
return true;
if (c == '\r' && !AcceptsReturn)
return false;
//tab?
if (c == '\t')
{
if (!AcceptsTab)
return false;
if (Selection.Start.iLine == Selection.End.iLine)
{
ClearSelected();
//insert tab as spaces
int spaces = TabLength - (Selection.Start.iChar % TabLength);
//replace mode? select forward chars
if (IsReplaceMode)
{
for (int i = 0; i < spaces; i++)
Selection.GoRight(true);
Selection.Inverse();
}
InsertText(new String(' ', spaces));
}
else
if ((lastModifiers & Keys.Shift) == 0)
IncreaseIndent();
}
else
{
//replace \r on \n
if (c == '\r')
c = '\n';
//replace mode? select forward char
if (IsReplaceMode)
{
Selection.GoRight(true);
Selection.Inverse();
}
//insert char
InsertChar(c);
//do autoindent
if (c == '\n' || AutoIndentExistingLines)
DoAutoIndentIfNeed();
}
DoCaretVisible();
Invalidate();
OnKeyPressed(sourceC);
return true;
}
private void DoAutoIndentIfNeed()
{
if (Selection.ColumnSelectionMode)
return;
if (AutoIndent)
{
DoCaretVisible();
int needSpaces = CalcAutoIndent(Selection.Start.iLine);
if (this[Selection.Start.iLine].AutoIndentSpacesNeededCount != needSpaces)
{
DoAutoIndent(Selection.Start.iLine);
this[Selection.Start.iLine].AutoIndentSpacesNeededCount = needSpaces;
}
}
}
private void RemoveSpacesAfterCaret()
{
if (!Selection.IsEmpty)
return;
Place end = Selection.Start;
while (Selection.CharAfterStart == ' ')
Selection.GoRight(true);
ClearSelected();
}
///
/// Inserts autoindent's spaces in the line
///
public virtual void DoAutoIndent(int iLine)
{
if (Selection.ColumnSelectionMode)
return;
Place oldStart = Selection.Start;
//
int needSpaces = CalcAutoIndent(iLine);
//
int spaces = lines[iLine].StartSpacesCount;
int needToInsert = needSpaces - spaces;
if (needToInsert < 0)
needToInsert = -Math.Min(-needToInsert, spaces);
//insert start spaces
if (needToInsert == 0)
return;
Selection.Start = new Place(0, iLine);
if (needToInsert > 0)
InsertText(new String(' ', needToInsert));
else
{
Selection.Start = new Place(0, iLine);
Selection.End = new Place(-needToInsert, iLine);
ClearSelected();
}
Selection.Start = new Place(Math.Min(lines[iLine].Count, Math.Max(0, oldStart.iChar + needToInsert)), iLine);
}
///
/// Returns needed start space count for the line
///
public virtual int CalcAutoIndent(int iLine)
{
if (iLine < 0 || iLine >= LinesCount) return 0;
EventHandler calculator = AutoIndentNeeded;
if (calculator == null)
if (Language != Language.Custom && SyntaxHighlighter != null)
calculator = SyntaxHighlighter.AutoIndentNeeded;
else
calculator = CalcAutoIndentShiftByCodeFolding;
int needSpaces = 0;
var stack = new Stack();
//calc indent for previous lines, find stable line
int i;
for (i = iLine - 1; i >= 0; i--)
{
var args = new AutoIndentEventArgs(i, lines[i].Text, i > 0 ? lines[i - 1].Text : "", TabLength);
calculator(this, args);
stack.Push(args);
if (args.Shift == 0 && args.LineText.Trim() != "")
break;
}
int indent = lines[i >= 0 ? i : 0].StartSpacesCount;
while (stack.Count != 0)
indent += stack.Pop().ShiftNextLines;
//clalc shift for current line
var a = new AutoIndentEventArgs(iLine, lines[iLine].Text, iLine > 0 ? lines[iLine - 1].Text : "", TabLength);
calculator(this, a);
needSpaces = indent + a.Shift;
return needSpaces;
}
internal virtual void CalcAutoIndentShiftByCodeFolding(object sender, AutoIndentEventArgs args)
{
//inset TAB after start folding marker
if (string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&
!string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))
{
args.ShiftNextLines = TabLength;
return;
}
//remove TAB before end folding marker
if (!string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&
string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))
{
args.Shift = -TabLength;
args.ShiftNextLines = -TabLength;
return;
}
}
private int GetMinStartSpacesCount(int fromLine, int toLine)
{
if (fromLine > toLine)
return 0;
int result = int.MaxValue;
for (int i = fromLine; i <= toLine; i++)
{
int count = lines[i].StartSpacesCount;
if (count < result)
result = count;
}
return result;
}
///
/// Undo last operation
///
public void Undo()
{
lines.Manager.Undo();
DoCaretVisible();
Invalidate();
}
///
/// Redo
///
public void Redo()
{
lines.Manager.Redo();
DoCaretVisible();
Invalidate();
}
protected override bool IsInputKey(Keys keyData)
{
if (keyData == Keys.Tab && !AcceptsTab)
return false;
if (keyData == Keys.Enter && !AcceptsReturn)
return false;
if ((keyData & Keys.Alt) == Keys.None)
{
Keys keys = keyData & Keys.KeyCode;
if (keys == Keys.Return)
return true;
}
if ((keyData & Keys.Alt) != Keys.Alt)
{
switch ((keyData & Keys.KeyCode))
{
case Keys.Prior:
case Keys.Next:
case Keys.End:
case Keys.Home:
case Keys.Left:
case Keys.Right:
case Keys.Up:
case Keys.Down:
return true;
case Keys.Escape:
return false;
case Keys.Tab:
return (keyData & Keys.Control) == Keys.None;
}
}
return base.IsInputKey(keyData);
}
[DllImport("User32.dll")]
private static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);
[DllImport("User32.dll")]
private static extern bool SetCaretPos(int x, int y);
[DllImport("User32.dll")]
private static extern bool DestroyCaret();
[DllImport("User32.dll")]
private static extern bool ShowCaret(IntPtr hWnd);
[DllImport("User32.dll")]
private static extern bool HideCaret(IntPtr hWnd);
protected override void OnPaintBackground(PaintEventArgs e)
{
if (BackBrush == null)
base.OnPaintBackground(e);
else
e.Graphics.FillRectangle(BackBrush, ClientRectangle);
}
///
/// Draw control
///
protected override void OnPaint(PaintEventArgs e)
{
if (needRecalc)
Recalc();
if (needRecalcFoldingLines)
RecalcFoldingLines();
#if debug
var sw = Stopwatch.StartNew();
#endif
visibleMarkers.Clear();
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//FCTBRenderingHints.SetGridFitTextHint(e.Graphics);
//
var servicePen = new Pen(ServiceLinesColor);
Brush changedLineBrush = new SolidBrush(ChangedLineColor);
Brush indentBrush = new SolidBrush(IndentBackColor);
Brush paddingBrush = new SolidBrush(PaddingBackColor);
Brush currentLineBrush = new SolidBrush(Color.FromArgb(CurrentLineColor.A == 255 ? 50 : CurrentLineColor.A, CurrentLineColor));
//draw padding area
//top
e.Graphics.FillRectangle(paddingBrush, 0, -VerticalScroll.Value, ClientSize.Width, Math.Max(0, Paddings.Top - 1));
//bottom
var bottomPaddingStartY = wordWrapLinesCount * charHeight + Paddings.Top;
e.Graphics.FillRectangle(paddingBrush, 0, bottomPaddingStartY - VerticalScroll.Value, ClientSize.Width, ClientSize.Height);
//right
var rightPaddingStartX = LeftIndent + maxLineLength * CharWidth + Paddings.Left + 1;
e.Graphics.FillRectangle(paddingBrush, rightPaddingStartX - HorizontalScroll.Value, 0, ClientSize.Width, ClientSize.Height);
//left
e.Graphics.FillRectangle(paddingBrush, LeftIndentLine, 0, LeftIndent - LeftIndentLine - 1, ClientSize.Height);
if (HorizontalScroll.Value <= Paddings.Left)
e.Graphics.FillRectangle(paddingBrush, LeftIndent - HorizontalScroll.Value - 2, 0, Math.Max(0, Paddings.Left - 1), ClientSize.Height);
var leftTextIndent = Math.Max(LeftIndent, LeftIndent + Paddings.Left - HorizontalScroll.Value);
var textWidth = rightPaddingStartX - HorizontalScroll.Value - leftTextIndent;
//draw indent area
e.Graphics.FillRectangle(indentBrush, 0, 0, LeftIndentLine, ClientSize.Height);
if (LeftIndent > minLeftIndent)
e.Graphics.DrawLine(servicePen, LeftIndentLine, 0, LeftIndentLine, ClientSize.Height);
//draw preferred line width
if (PreferredLineWidth > 0)
e.Graphics.DrawLine(servicePen,
new Point(LeftIndent + Paddings.Left + PreferredLineWidth * CharWidth - HorizontalScroll.Value + 1, 0),
new Point(LeftIndent + Paddings.Left + PreferredLineWidth * CharWidth - HorizontalScroll.Value + 1, Height));
//
int firstChar = (Math.Max(0, HorizontalScroll.Value - Paddings.Left)) / CharWidth;
int lastChar = (HorizontalScroll.Value + ClientSize.Width) / CharWidth;
//draw chars
int startLine = YtoLineIndex(VerticalScroll.Value);
int iLine;
for (iLine = startLine; iLine < lines.Count; iLine++)
{
Line line = lines[iLine];
LineInfo lineInfo = lineInfos[iLine];
//
if (lineInfo.startY > VerticalScroll.Value + ClientSize.Height)
break;
if (lineInfo.startY + lineInfo.WordWrapStringsCount * CharHeight < VerticalScroll.Value)
continue;
if (lineInfo.VisibleState == VisibleState.Hidden)
continue;
int y = lineInfo.startY - VerticalScroll.Value;
//
e.Graphics.SmoothingMode = SmoothingMode.None;
//draw line background
if (lineInfo.VisibleState == VisibleState.Visible)
if (line.BackgroundBrush != null)
e.Graphics.FillRectangle(line.BackgroundBrush,
new Rectangle(leftTextIndent, y, textWidth,
CharHeight * lineInfo.WordWrapStringsCount));
//draw current line background
if (CurrentLineColor != Color.Transparent && iLine == Selection.Start.iLine)
if (Selection.IsEmpty)
e.Graphics.FillRectangle(currentLineBrush, new Rectangle(leftTextIndent, y, textWidth, CharHeight));
//draw changed line marker
if (ChangedLineColor != Color.Transparent && line.IsChanged)
e.Graphics.FillRectangle(changedLineBrush,
new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight + 1));
//
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//OnPaint event
if (lineInfo.VisibleState == VisibleState.Visible)
OnPaintLine(new PaintLineEventArgs(iLine,
new Rectangle(LeftIndent, y, Width,
CharHeight * lineInfo.WordWrapStringsCount),
e.Graphics, e.ClipRectangle));
//draw line number
if (ShowLineNumbers)
using (var lineNumberBrush = new SolidBrush(LineNumberColor))
e.Graphics.DrawString((iLine + lineNumberStartValue).ToString(), Font, lineNumberBrush,
new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight),
new StringFormat(StringFormatFlags.DirectionRightToLeft));
//create markers
if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)
visibleMarkers.Add(new ExpandFoldingMarker(iLine,
new Rectangle(LeftIndentLine - 4, y + CharHeight / 2 - 3, 8,
8)));
if (!string.IsNullOrEmpty(line.FoldingStartMarker) && lineInfo.VisibleState == VisibleState.Visible &&
string.IsNullOrEmpty(line.FoldingEndMarker))
visibleMarkers.Add(new CollapseFoldingMarker(iLine,
new Rectangle(LeftIndentLine - 4, y + CharHeight / 2 - 3,
8, 8)));
if (lineInfo.VisibleState == VisibleState.Visible && !string.IsNullOrEmpty(line.FoldingEndMarker) &&
string.IsNullOrEmpty(line.FoldingStartMarker))
e.Graphics.DrawLine(servicePen, LeftIndentLine, y + CharHeight * lineInfo.WordWrapStringsCount - 1,
LeftIndentLine + 4, y + CharHeight * lineInfo.WordWrapStringsCount - 1);
//draw wordwrap strings of line
for (int iWordWrapLine = 0; iWordWrapLine < lineInfo.WordWrapStringsCount; iWordWrapLine++)
{
y = lineInfo.startY + iWordWrapLine * CharHeight - VerticalScroll.Value;
//draw chars
DrawLineChars(e, firstChar, lastChar, iLine, iWordWrapLine, LeftIndent + Paddings.Left - HorizontalScroll.Value, y);
}
}
var endLine = iLine - 1;
//draw folding lines
if (ShowFoldingLines)
DrawFoldingLines(e, startLine, endLine);
//draw column selection
if (Selection.ColumnSelectionMode)
if (SelectionStyle.BackgroundBrush is SolidBrush)
{
var color = ((SolidBrush)SelectionStyle.BackgroundBrush).Color;
var p1 = PlaceToPoint(Selection.Start);
var p2 = PlaceToPoint(Selection.End);
using (var pen = new Pen(color))
e.Graphics.DrawRectangle(pen, Rectangle.FromLTRB(Math.Min(p1.X, p2.X) - 1, Math.Min(p1.Y, p2.Y), Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y) + CharHeight));
}
//draw brackets highlighting
if (BracketsStyle != null && leftBracketPosition != null && rightBracketPosition != null)
{
BracketsStyle.Draw(e.Graphics, PlaceToPoint(leftBracketPosition.Start), leftBracketPosition);
BracketsStyle.Draw(e.Graphics, PlaceToPoint(rightBracketPosition.Start), rightBracketPosition);
}
if (BracketsStyle2 != null && leftBracketPosition2 != null && rightBracketPosition2 != null)
{
BracketsStyle2.Draw(e.Graphics, PlaceToPoint(leftBracketPosition2.Start), leftBracketPosition2);
BracketsStyle2.Draw(e.Graphics, PlaceToPoint(rightBracketPosition2.Start), rightBracketPosition2);
}
//
e.Graphics.SmoothingMode = SmoothingMode.None;
//draw folding indicator
if ((startFoldingLine >= 0 || endFoldingLine >= 0) && Selection.Start == Selection.End)
if (endFoldingLine < lineInfos.Count)
{
//folding indicator
int startFoldingY = (startFoldingLine >= 0 ? lineInfos[startFoldingLine].startY : 0) -
VerticalScroll.Value + CharHeight / 2;
int endFoldingY = (endFoldingLine >= 0
? lineInfos[endFoldingLine].startY +
(lineInfos[endFoldingLine].WordWrapStringsCount - 1) * CharHeight
: (WordWrapLinesCount + 1) * CharHeight) - VerticalScroll.Value + CharHeight;
using (var indicatorPen = new Pen(Color.FromArgb(100, FoldingIndicatorColor), 4))
e.Graphics.DrawLine(indicatorPen, LeftIndent - 5, startFoldingY, LeftIndent - 5, endFoldingY);
}
//draw markers
foreach (VisualMarker m in visibleMarkers)
m.Draw(e.Graphics, servicePen);
//draw caret
Point car = PlaceToPoint(Selection.Start);
if ((Focused || IsDragDrop) && car.X >= LeftIndent && CaretVisible)
{
int carWidth = IsReplaceMode ? CharWidth : 1;
CreateCaret(Handle, 0, carWidth, CharHeight + 1);
SetCaretPos(car.X, car.Y);
ShowCaret(Handle);
//using (Pen pen = new Pen(CaretColor))
// e.Graphics.DrawLine(pen, car.X, car.Y, car.X, car.Y + CharHeight);
}
else
HideCaret(Handle);
//draw disabled mask
if (!Enabled)
using (var brush = new SolidBrush(DisabledColor))
e.Graphics.FillRectangle(brush, ClientRectangle);
//dispose resources
servicePen.Dispose();
changedLineBrush.Dispose();
indentBrush.Dispose();
currentLineBrush.Dispose();
paddingBrush.Dispose();
//
#if debug
Debug.WriteLine("OnPaint: "+ sw.ElapsedMilliseconds);
#endif
//
base.OnPaint(e);
}
protected virtual void DrawFoldingLines(PaintEventArgs e, int startLine, int endLine)
{
e.Graphics.SmoothingMode = SmoothingMode.None;
using (var pen = new Pen(Color.FromArgb(200, ServiceLinesColor)) { DashStyle = DashStyle.Dot })
foreach (var iLine in foldingPairs)
if (iLine.Key < endLine && iLine.Value > startLine)
{
var line = lines[iLine.Key];
var y = lineInfos[iLine.Key].startY - VerticalScroll.Value + CharHeight;
y += y % 2;
int y2;
if (iLine.Value >= LinesCount)
y2 = lineInfos[LinesCount - 1].startY + CharHeight - VerticalScroll.Value;
else
if (lineInfos[iLine.Value].VisibleState == VisibleState.Visible)
{
var d = 0;
var spaceCount = line.StartSpacesCount;
if (lines[iLine.Value].Count <= spaceCount || lines[iLine.Value][spaceCount].c == ' ')
d = CharHeight;
y2 = lineInfos[iLine.Value].startY - VerticalScroll.Value + d;
}
else
continue;
var x = LeftIndent + Paddings.Left + line.StartSpacesCount * CharWidth - HorizontalScroll.Value;
if (x >= LeftIndent + Paddings.Left)
e.Graphics.DrawLine(pen, x, y >= 0 ? y : 0, x, y2 < ClientSize.Height ? y2 : ClientSize.Height);
}
}
///
/// Color of selected area
///
[DefaultValue(typeof(Color), "Blue")]
[Description("Color of selected area.")]
public virtual Color SelectionColor
{
get
{
return selectionColor;
}
set
{
selectionColor = value;
if (selectionColor.A == 255)
selectionColor = Color.FromArgb(50, selectionColor);
SelectionStyle = new SelectionStyle(new SolidBrush(selectionColor));
Invalidate();
}
}
private void DrawLineChars(PaintEventArgs e, int firstChar, int lastChar, int iLine, int iWordWrapLine, int x, int y)
{
Line line = lines[iLine];
LineInfo lineInfo = lineInfos[iLine];
int from = lineInfo.GetWordWrapStringStartPosition(iWordWrapLine);
int to = lineInfo.GetWordWrapStringFinishPosition(iWordWrapLine, line);
int startX = x;
if (startX < LeftIndent)
firstChar++;
lastChar = Math.Min(to - from, lastChar);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//folded block ?
if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)
{
//rendering by FoldedBlockStyle
FoldedBlockStyle.Draw(e.Graphics, new Point(startX + firstChar * CharWidth, y),
new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine));
}
else
{
//render by custom styles
StyleIndex currentStyleIndex = StyleIndex.None;
int iLastFlushedChar = firstChar - 1;
for (int iChar = firstChar; iChar <= lastChar; iChar++)
{
StyleIndex style = line[from + iChar].style;
if (currentStyleIndex != style)
{
FlushRendering(e.Graphics, currentStyleIndex,
new Point(startX + (iLastFlushedChar + 1) * CharWidth, y),
new Range(this, from + iLastFlushedChar + 1, iLine, from + iChar, iLine));
iLastFlushedChar = iChar - 1;
currentStyleIndex = style;
}
}
FlushRendering(e.Graphics, currentStyleIndex, new Point(startX + (iLastFlushedChar + 1) * CharWidth, y),
new Range(this, from + iLastFlushedChar + 1, iLine, from + lastChar + 1, iLine));
}
//draw selection
if (!Selection.IsEmpty && lastChar >= firstChar)
{
e.Graphics.SmoothingMode = SmoothingMode.None;
var textRange = new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine);
textRange = Selection.GetIntersectionWith(textRange);
if (textRange != null && SelectionStyle != null)
{
SelectionStyle.Draw(e.Graphics, new Point(startX + (textRange.Start.iChar - from) * CharWidth, y),
textRange);
}
}
}
private void FlushRendering(Graphics gr, StyleIndex styleIndex, Point pos, Range range)
{
if (range.End > range.Start)
{
int mask = 1;
bool hasTextStyle = false;
for (int i = 0; i < Styles.Length; i++)
{
if (Styles[i] != null && ((int)styleIndex & mask) != 0)
{
Style style = Styles[i];
bool isTextStyle = style is TextStyle;
if (!hasTextStyle || !isTextStyle || AllowSeveralTextStyleDrawing)
//cancelling secondary rendering by TextStyle
style.Draw(gr, pos, range); //rendering
hasTextStyle |= isTextStyle;
}
mask = mask << 1;
}
//draw by default renderer
if (!hasTextStyle)
DefaultStyle.Draw(gr, pos, range);
}
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
mouseIsDrag = false;
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
isLineSelect = false;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
VisualMarker marker = FindVisualMarkerForPoint(e.Location);
//click on marker
if (marker != null)
{
mouseIsDrag = false;
OnMarkerClick(e, marker);
return;
}
mouseIsDrag = true;
isLineSelect = e.Location.X < LeftIndentLine;
//
CheckAndChangeSelectionType();
//
//click on text
Place oldEnd = Selection.End;
Selection.BeginUpdate();
if (isLineSelect)
{
//select whole line
var iLine = PointToPlaceSimple(e.Location).iLine;
lineSelectFrom = iLine;
Selection.Start = new Place(0, iLine);
Selection.End = new Place(GetLineLength(iLine), iLine);
}
else
{
if (Selection.ColumnSelectionMode)
{
Selection.Start = PointToPlaceSimple(e.Location);
Selection.ColumnSelectionMode = true;
}
else
{
if (VirtualSpace)
Selection.Start = PointToPlaceSimple(e.Location);
else
Selection.Start = PointToPlace(e.Location);
}
if ((lastModifiers & Keys.Shift) != 0)
Selection.End = oldEnd;
}
Selection.EndUpdate();
Invalidate();
return;
}
}
private void CheckAndChangeSelectionType()
{
//change selection type to ColumnSelectionMode
if ((Control.ModifierKeys & Keys.Alt) != 0 && !WordWrap)
{
Selection.ColumnSelectionMode = true;
}
else
//change selection type to Range
{
Selection.ColumnSelectionMode = false;
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
Invalidate();
base.OnMouseWheel(e);
OnVisibleRangeChanged();
}
Cursor defaultCursor;
public override Cursor Cursor
{
get
{
return base.Cursor;
}
set
{
defaultCursor = value;
base.Cursor = value;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left && mouseIsDrag)
{
Place place;
if (Selection.ColumnSelectionMode || VirtualSpace)
place = PointToPlaceSimple(e.Location);
else
place = PointToPlace(e.Location);
if (isLineSelect)
{
Selection.BeginUpdate();
var iLine = place.iLine;
if (iLine < lineSelectFrom)
{
Selection.Start = new Place(0, iLine);
Selection.End = new Place(GetLineLength(lineSelectFrom), lineSelectFrom);
}
else
{
Selection.Start = new Place(GetLineLength(iLine), iLine);
Selection.End = new Place(0, lineSelectFrom);
}
Selection.EndUpdate();
DoCaretVisible();
HorizontalScroll.Value = 0;
UpdateScrollbars();
Invalidate();
}
else
if (place != Selection.Start)
{
Place oldEnd = Selection.End;
Selection.BeginUpdate();
if (Selection.ColumnSelectionMode)
{
Selection.Start = place;
Selection.ColumnSelectionMode = true;
}
else
Selection.Start = place;
Selection.End = oldEnd;
Selection.EndUpdate();
DoCaretVisible();
Invalidate();
return;
}
}
VisualMarker marker = FindVisualMarkerForPoint(e.Location);
if (marker != null)
base.Cursor = marker.Cursor;
else
{
if (e.Location.X < LeftIndentLine || isLineSelect)
base.Cursor = Cursors.Arrow;
else
base.Cursor = defaultCursor;
}
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e);
VisualMarker m = FindVisualMarkerForPoint(e.Location);
if (m != null)
{
OnMarkerDoubleClick(m);
return;
}
Place p = PointToPlace(e.Location);
int fromX = p.iChar;
int toX = p.iChar;
for (int i = p.iChar; i < lines[p.iLine].Count; i++)
{
char c = lines[p.iLine][i].c;
if (char.IsLetterOrDigit(c) || c == '_')
toX = i + 1;
else
break;
}
for (int i = p.iChar - 1; i >= 0; i--)
{
char c = lines[p.iLine][i].c;
if (char.IsLetterOrDigit(c) || c == '_')
fromX = i;
else
break;
}
Selection.Start = new Place(toX, p.iLine);
Selection.End = new Place(fromX, p.iLine);
Invalidate();
}
private int YtoLineIndex(int y)
{
int i = lineInfos.BinarySearch(new LineInfo(-10), new LineYComparer(y));
i = i < 0 ? -i - 2 : i;
if (i < 0) return 0;
if (i > lines.Count - 1) return lines.Count - 1;
return i;
}
///
/// Gets nearest line and char position from coordinates
///
/// Point
/// Line and char position
public Place PointToPlace(Point point)
{
#if debug
var sw = Stopwatch.StartNew();
#endif
point.Offset(HorizontalScroll.Value, VerticalScroll.Value);
point.Offset(-LeftIndent - Paddings.Left, 0);
int iLine = YtoLineIndex(point.Y);
int y = 0;
for (; iLine < lines.Count; iLine++)
{
y = lineInfos[iLine].startY + lineInfos[iLine].WordWrapStringsCount * CharHeight;
if (y > point.Y && lineInfos[iLine].VisibleState == VisibleState.Visible)
break;
}
if (iLine >= lines.Count)
iLine = lines.Count - 1;
if (lineInfos[iLine].VisibleState != VisibleState.Visible)
iLine = FindPrevVisibleLine(iLine);
//
int iWordWrapLine = lineInfos[iLine].WordWrapStringsCount;
do
{
iWordWrapLine--;
y -= CharHeight;
} while (y > point.Y);
if (iWordWrapLine < 0) iWordWrapLine = 0;
//
int start = lineInfos[iLine].GetWordWrapStringStartPosition(iWordWrapLine);
int finish = lineInfos[iLine].GetWordWrapStringFinishPosition(iWordWrapLine, lines[iLine]);
var x = (int)Math.Round((float)point.X / CharWidth);
x = x < 0 ? start : start + x;
if (x > finish)
x = finish + 1;
if (x > lines[iLine].Count)
x = lines[iLine].Count;
#if debug
Debug.WriteLine("PointToPlace: " + sw.ElapsedMilliseconds);
#endif
return new Place(x, iLine);
}
private Place PointToPlaceSimple(Point point)
{
point.Offset(HorizontalScroll.Value, VerticalScroll.Value);
point.Offset(-LeftIndent - Paddings.Left, 0);
int iLine = YtoLineIndex(point.Y);
var x = (int)Math.Round((float)point.X / CharWidth);
if (x < 0) x = 0;
return new Place(x, iLine);
}
///
/// Gets nearest absolute text position for given point
///
/// Point
/// Position
public int PointToPosition(Point point)
{
return PlaceToPosition(PointToPlace(point));
}
///
/// Fires TextChanging event
///
public virtual void OnTextChanging(ref string text)
{
ClearBracketsPositions();
if (TextChanging != null)
{
var args = new TextChangingEventArgs { InsertingText = text };
TextChanging(this, args);
text = args.InsertingText;
if (args.Cancel)
text = string.Empty;
}
}
public virtual void OnTextChanging()
{
string temp = null;
OnTextChanging(ref temp);
}
///
/// Fires TextChanged event
///
public virtual void OnTextChanged()
{
var r = new Range(this);
r.SelectAll();
OnTextChanged(new TextChangedEventArgs(r));
}
///
/// Fires TextChanged event
///
public virtual void OnTextChanged(int fromLine, int toLine)
{
var r = new Range(this);
r.Start = new Place(0, Math.Min(fromLine, toLine));
r.End = new Place(lines[Math.Max(fromLine, toLine)].Count, Math.Max(fromLine, toLine));
OnTextChanged(new TextChangedEventArgs(r));
}
///
/// Fires TextChanged event
///
public virtual void OnTextChanged(Range r)
{
OnTextChanged(new TextChangedEventArgs(r));
}
public void BeginUpdate()
{
if (updating == 0)
updatingRange = null;
updating++;
}
public void EndUpdate()
{
updating--;
if (updating == 0 && updatingRange != null)
{
updatingRange.Expand();
OnTextChanged(updatingRange);
}
}
///
/// Fires TextChanged event
///
protected virtual void OnTextChanged(TextChangedEventArgs args)
{
//
args.ChangedRange.Normalize();
//
if (updating > 0)
{
if (updatingRange == null)
updatingRange = args.ChangedRange.Clone();
else
{
if (updatingRange.Start.iLine > args.ChangedRange.Start.iLine)
updatingRange.Start = new Place(0, args.ChangedRange.Start.iLine);
if (updatingRange.End.iLine < args.ChangedRange.End.iLine)
updatingRange.End = new Place(lines[args.ChangedRange.End.iLine].Count,
args.ChangedRange.End.iLine);
updatingRange = updatingRange.GetIntersectionWith(Range);
}
return;
}
//
#if debug
var sw = Stopwatch.StartNew();
#endif
IsChanged = true;
TextVersion++;
MarkLinesAsChanged(args.ChangedRange);
//
if (wordWrap)
RecalcWordWrap(args.ChangedRange.Start.iLine, args.ChangedRange.End.iLine);
//
base.OnTextChanged(args);
//dalayed event stuffs
if (delayedTextChangedRange == null)
delayedTextChangedRange = args.ChangedRange.Clone();
else
delayedTextChangedRange = delayedTextChangedRange.GetUnionWith(args.ChangedRange);
needRiseTextChangedDelayed = true;
ResetTimer(timer2);
//
OnSyntaxHighlight(args);
//
if (TextChanged != null)
TextChanged(this, args);
//
if (BindingTextChanged != null)
BindingTextChanged(this, EventArgs.Empty);
//
base.OnTextChanged(EventArgs.Empty);
//
#if debug
Debug.WriteLine("OnTextChanged: " + sw.ElapsedMilliseconds);
#endif
OnVisibleRangeChanged();
}
private void MarkLinesAsChanged(Range range)
{
for (int iLine = range.Start.iLine; iLine <= range.End.iLine; iLine++)
if (iLine >= 0 && iLine < lines.Count)
lines[iLine].IsChanged = true;
}
///
/// Fires SelectionCnaged event
///
public virtual void OnSelectionChanged()
{
#if debug
var sw = Stopwatch.StartNew();
#endif
//find folding markers for highlighting
if (HighlightFoldingIndicator)
HighlightFoldings();
//
needRiseSelectionChangedDelayed = true;
ResetTimer(timer);
if (SelectionChanged != null)
SelectionChanged(this, new EventArgs());
#if debug
Debug.WriteLine("OnSelectionChanged: "+ sw.ElapsedMilliseconds);
#endif
}
//find folding markers for highlighting
private void HighlightFoldings()
{
if (LinesCount == 0)
return;
//
int prevStartFoldingLine = startFoldingLine;
int prevEndFoldingLine = endFoldingLine;
//
startFoldingLine = -1;
endFoldingLine = -1;
//
string marker = null;
int counter = 0;
for (int i = Selection.Start.iLine; i >= Math.Max(Selection.Start.iLine - maxLinesForFolding, 0); i--)
{
bool hasStartMarker = lines.LineHasFoldingStartMarker(i);
bool hasEndMarker = lines.LineHasFoldingEndMarker(i);
if (hasEndMarker && hasStartMarker)
continue;
if (hasStartMarker)
{
counter--;
if (counter == -1) //found start folding
{
startFoldingLine = i;
marker = lines[i].FoldingStartMarker;
break;
}
}
if (hasEndMarker && i != Selection.Start.iLine)
counter++;
}
if (startFoldingLine >= 0)
{
//find end of block
endFoldingLine = FindEndOfFoldingBlock(startFoldingLine, maxLinesForFolding);
if (endFoldingLine == startFoldingLine)
endFoldingLine = -1;
}
if (startFoldingLine != prevStartFoldingLine || endFoldingLine != prevEndFoldingLine)
OnFoldingHighlightChanged();
}
protected virtual void OnFoldingHighlightChanged()
{
if (FoldingHighlightChanged != null)
FoldingHighlightChanged(this, EventArgs.Empty);
}
protected override void OnGotFocus(EventArgs e)
{
SetAsCurrentTB();
base.OnGotFocus(e);
//Invalidate(new Rectangle(PlaceToPoint(Selection.Start), new Size(2, CharHeight+1)));
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
//Invalidate(new Rectangle(PlaceToPoint(Selection.Start), new Size(2, CharHeight+1)));
Invalidate();
}
///
/// Gets absolute text position from line and char position
///
/// Line and char position
/// Point of char
public int PlaceToPosition(Place point)
{
if (point.iLine < 0 || point.iLine >= lines.Count ||
point.iChar >= lines[point.iLine].Count + Environment.NewLine.Length)
return -1;
int result = 0;
for (int i = 0; i < point.iLine; i++)
result += lines[i].Count + Environment.NewLine.Length;
result += point.iChar;
return result;
}
///
/// Gets line and char position from absolute text position
///
///
///
public Place PositionToPlace(int pos)
{
if (pos < 0)
return new Place(0, 0);
for (int i = 0; i < lines.Count; i++)
{
int lineLength = lines[i].Count + Environment.NewLine.Length;
if (pos < lines[i].Count)
return new Place(pos, i);
if (pos < lineLength)
return new Place(lines[i].Count, i);
pos -= lineLength;
}
if (lines.Count > 0)
return new Place(lines[lines.Count - 1].Count, lines.Count - 1);
else
return new Place(0, 0);
//throw new ArgumentOutOfRangeException("Position out of range");
}
///
/// Gets absolute char position from char position
///
public Point PositionToPoint(int pos)
{
return PlaceToPoint(PositionToPlace(pos));
}
///
/// Gets point for given line and char position
///
/// Line and char position
/// Coordiantes
public Point PlaceToPoint(Place place)
{
if (place.iLine >= lineInfos.Count)
return new Point();
int y = lineInfos[place.iLine].startY;
//
int iWordWrapIndex = lineInfos[place.iLine].GetWordWrapStringIndex(place.iChar);
y += iWordWrapIndex * CharHeight;
int x = (place.iChar - lineInfos[place.iLine].GetWordWrapStringStartPosition(iWordWrapIndex)) * CharWidth;
//
y = y - VerticalScroll.Value;
x = LeftIndent + Paddings.Left + x - HorizontalScroll.Value;
return new Point(x, y);
}
///
/// Get range of text
///
/// Absolute start position
/// Absolute finish position
/// Range
public Range GetRange(int fromPos, int toPos)
{
var sel = new Range(this);
sel.Start = PositionToPlace(fromPos);
sel.End = PositionToPlace(toPos);
return sel;
}
///
/// Get range of text
///
/// Line and char position
/// Line and char position
/// Range
public Range GetRange(Place fromPlace, Place toPlace)
{
return new Range(this, fromPlace, toPlace);
}
///
/// Finds ranges for given regex pattern
///
/// Regex pattern
/// Enumeration of ranges
public IEnumerable GetRanges(string regexPattern)
{
var range = new Range(this);
range.SelectAll();
//
foreach (Range r in range.GetRanges(regexPattern, RegexOptions.None))
yield return r;
}
///
/// Finds ranges for given regex pattern
///
/// Regex pattern
/// Enumeration of ranges
public IEnumerable GetRanges(string regexPattern, RegexOptions options)
{
var range = new Range(this);
range.SelectAll();
//
foreach (Range r in range.GetRanges(regexPattern, options))
yield return r;
}
///
/// Get text of given line
///
/// Line index
/// Text
public string GetLineText(int iLine)
{
if (iLine < 0 || iLine >= lines.Count)
throw new ArgumentOutOfRangeException("Line index out of range");
var sb = new StringBuilder(lines[iLine].Count);
foreach (Char c in lines[iLine])
sb.Append(c.c);
return sb.ToString();
}
///
/// Exapnds folded block
///
/// Start line
public void ExpandFoldedBlock(int iLine)
{
if (iLine < 0 || iLine >= lines.Count)
throw new ArgumentOutOfRangeException("Line index out of range");
//find all hidden lines afetr iLine
int end = iLine;
for (; end < LinesCount - 1; end++)
{
if (lineInfos[end + 1].VisibleState != VisibleState.Hidden)
break;
}
ExpandBlock(iLine, end);
}
///
/// Expand collapsed block
///
public void ExpandBlock(int fromLine, int toLine)
{
int from = Math.Min(fromLine, toLine);
int to = Math.Max(fromLine, toLine);
for (int i = from; i <= to; i++)
SetVisibleState(i, VisibleState.Visible);
needRecalc = true;
Invalidate();
}
///
/// Expand collapsed block
///
/// Any line inside collapsed block
public void ExpandBlock(int iLine)
{
if (lineInfos[iLine].VisibleState == VisibleState.Visible)
return;
for (int i = iLine; i < LinesCount; i++)
if (lineInfos[i].VisibleState == VisibleState.Visible)
break;
else
{
SetVisibleState(i, VisibleState.Visible);
needRecalc = true;
}
for (int i = iLine - 1; i >= 0; i--)
if (lineInfos[i].VisibleState == VisibleState.Visible)
break;
else
{
SetVisibleState(i, VisibleState.Visible);
needRecalc = true;
}
Invalidate();
}
///
/// Collapses all folding blocks
///
public void CollapseAllFoldingBlocks()
{
for (int i = 0; i < LinesCount; i++)
if (lines.LineHasFoldingStartMarker(i))
{
int iFinish = FindEndOfFoldingBlock(i);
if (iFinish >= 0)
{
CollapseBlock(i, iFinish);
i = iFinish;
}
}
OnVisibleRangeChanged();
}
///
/// Exapnds all folded blocks
///
///
public void ExpandAllFoldingBlocks()
{
for (int i = 0; i < LinesCount; i++)
SetVisibleState(i, VisibleState.Visible);
OnVisibleRangeChanged();
Invalidate();
}
///
/// Collapses folding block
///
/// Start folding line
public void CollapseFoldingBlock(int iLine)
{
if (iLine < 0 || iLine >= lines.Count)
throw new ArgumentOutOfRangeException("Line index out of range");
if (string.IsNullOrEmpty(lines[iLine].FoldingStartMarker))
throw new ArgumentOutOfRangeException("This line is not folding start line");
//find end of block
int i = FindEndOfFoldingBlock(iLine);
//collapse
if (i >= 0)
CollapseBlock(iLine, i);
}
private int FindEndOfFoldingBlock(int iStartLine)
{
return FindEndOfFoldingBlock(iStartLine, int.MaxValue);
}
protected virtual int FindEndOfFoldingBlock(int iStartLine, int maxLines)
{
//find end of block
int counter = 0;
int i;
string marker = lines[iStartLine].FoldingStartMarker;
Stack stack = new Stack();
switch (FindEndOfFoldingBlockStrategy)
{
case FindEndOfFoldingBlockStrategy.Strategy1:
for (i = iStartLine /*+1*/; i < LinesCount; i++)
{
if (lines.LineHasFoldingStartMarker(i))
stack.Push(lines[i].FoldingStartMarker);
if (lines.LineHasFoldingEndMarker(i))
{
var m = lines[i].FoldingEndMarker;
while (stack.Count > 0 && stack.Pop() != m) ;
if (stack.Count == 0)
return i;
}
maxLines--;
if (maxLines < 0)
return i;
}
break;
case FindEndOfFoldingBlockStrategy.Strategy2:
for (i = iStartLine /*+1*/; i < LinesCount; i++)
{
if (lines.LineHasFoldingEndMarker(i))
{
var m = lines[i].FoldingEndMarker;
while (stack.Count > 0 && stack.Pop() != m) ;
if (stack.Count == 0)
return i;
}
if (lines.LineHasFoldingStartMarker(i))
stack.Push(lines[i].FoldingStartMarker);
maxLines--;
if (maxLines < 0)
return i;
}
break;
}
//return -1;
return LinesCount - 1;
}
///
/// Start foilding marker for the line
///
public string GetLineFoldingStartMarker(int iLine)
{
if (lines.LineHasFoldingStartMarker(iLine))
return lines[iLine].FoldingStartMarker;
return null;
}
///
/// End foilding marker for the line
///
public string GetLineFoldingEndMarker(int iLine)
{
if (lines.LineHasFoldingEndMarker(iLine))
return lines[iLine].FoldingEndMarker;
return null;
}
protected Dictionary foldingPairs = new Dictionary();
protected virtual void RecalcFoldingLines()
{
if (!needRecalcFoldingLines)
return;
needRecalcFoldingLines = false;
if (!ShowFoldingLines)
return;
foldingPairs.Clear();
//
var range = VisibleRange;
var startLine = Math.Max(range.Start.iLine - maxLinesForFolding, 0);
var endLine = Math.Min(range.End.iLine + maxLinesForFolding, Math.Max(range.End.iLine, LinesCount - 1));
var stack = new Stack();
for (int i = startLine; i <= endLine; i++)
{
bool hasStartMarker = lines.LineHasFoldingStartMarker(i);
bool hasEndMarker = lines.LineHasFoldingEndMarker(i);
if (hasEndMarker && hasStartMarker)
continue;
if (hasStartMarker)
{
stack.Push(i);
}
if (hasEndMarker)
{
var m = lines[i].FoldingEndMarker;
while (stack.Count > 0)
{
var iStartLine = stack.Pop();
foldingPairs[iStartLine] = i;
if (m == lines[iStartLine].FoldingStartMarker)
break;
}
}
}
while (stack.Count > 0)
foldingPairs[stack.Pop()] = endLine + 1;
}
///
/// Collapse text block
///
public void CollapseBlock(int fromLine, int toLine)
{
int from = Math.Min(fromLine, toLine);
int to = Math.Max(fromLine, toLine);
if (from == to)
return;
//find first non empty line
for (; from <= to; from++)
{
if (GetLineText(from).Trim().Length > 0)
{
//hide lines
for (int i = from + 1; i <= to; i++)
SetVisibleState(i, VisibleState.Hidden);
SetVisibleState(from, VisibleState.StartOfHiddenBlock);
Invalidate();
break;
}
}
//Move caret outside
from = Math.Min(fromLine, toLine);
to = Math.Max(fromLine, toLine);
int newLine = FindNextVisibleLine(to);
if (newLine == to)
newLine = FindPrevVisibleLine(from);
Selection.Start = new Place(0, newLine);
//
needRecalc = true;
Invalidate();
}
internal int FindNextVisibleLine(int iLine)
{
if (iLine >= lines.Count - 1) return iLine;
int old = iLine;
do
iLine++; while (iLine < lines.Count - 1 && lineInfos[iLine].VisibleState != VisibleState.Visible);
if (lineInfos[iLine].VisibleState != VisibleState.Visible)
return old;
else
return iLine;
}
internal int FindPrevVisibleLine(int iLine)
{
if (iLine <= 0) return iLine;
int old = iLine;
do
iLine--; while (iLine > 0 && lineInfos[iLine].VisibleState != VisibleState.Visible);
if (lineInfos[iLine].VisibleState != VisibleState.Visible)
return old;
else
return iLine;
}
private VisualMarker FindVisualMarkerForPoint(Point p)
{
foreach (VisualMarker m in visibleMarkers)
if (m.rectangle.Contains(p))
return m;
return null;
}
///
/// Insert TAB into front of seletcted lines
///
public void IncreaseIndent()
{
if (Selection.IsEmpty)
return;
Range old = Selection.Clone();
int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
BeginUpdate();
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
for (int i = from; i <= to; i++)
{
if (lines[i].Count == 0) continue;
Selection.Start = new Place(0, i);
lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new String(' ', TabLength)));
}
lines.Manager.EndAutoUndoCommands();
Selection.Start = new Place(0, from);
Selection.End = new Place(lines[to].Count, to);
needRecalc = true;
Selection.EndUpdate();
EndUpdate();
Invalidate();
}
///
/// Remove TAB from front of seletcted lines
///
public void DecreaseIndent()
{
if (Selection.IsEmpty)
return;
Range old = Selection.Clone();
int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
BeginUpdate();
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
for (int i = from; i <= to; i++)
{
Selection.Start = new Place(0, i);
Selection.End = new Place(Math.Min(lines[i].Count, TabLength), i);
if (Selection.Text.Trim() == "")
ClearSelected();
}
lines.Manager.EndAutoUndoCommands();
Selection.Start = new Place(0, from);
Selection.End = new Place(lines[to].Count, to);
needRecalc = true;
EndUpdate();
Selection.EndUpdate();
}
///
/// Insert autoindents into selected lines
///
public void DoAutoIndent()
{
if (Selection.ColumnSelectionMode)
return;
Range r = Selection.Clone();
r.Normalize();
//
BeginUpdate();
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
//
for (int i = r.Start.iLine; i <= r.End.iLine; i++)
DoAutoIndent(i);
//
lines.Manager.EndAutoUndoCommands();
Selection.Start = r.Start;
Selection.End = r.End;
Selection.Expand();
//
Selection.EndUpdate();
EndUpdate();
}
///
/// Insert prefix into front of seletcted lines
///
public void InsertLinePrefix(string prefix)
{
Range old = Selection.Clone();
int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
BeginUpdate();
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
int spaces = GetMinStartSpacesCount(from, to);
for (int i = from; i <= to; i++)
{
Selection.Start = new Place(spaces, i);
lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, prefix));
}
Selection.Start = new Place(0, from);
Selection.End = new Place(lines[to].Count, to);
needRecalc = true;
lines.Manager.EndAutoUndoCommands();
Selection.EndUpdate();
EndUpdate();
Invalidate();
}
///
/// Remove prefix from front of seletcted lines
///
public void RemoveLinePrefix(string prefix)
{
Range old = Selection.Clone();
int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
BeginUpdate();
Selection.BeginUpdate();
lines.Manager.BeginAutoUndoCommands();
for (int i = from; i <= to; i++)
{
string text = lines[i].Text;
string trimmedText = text.TrimStart();
if (trimmedText.StartsWith(prefix))
{
int spaces = text.Length - trimmedText.Length;
Selection.Start = new Place(spaces, i);
Selection.End = new Place(spaces + prefix.Length, i);
ClearSelected();
}
}
Selection.Start = new Place(0, from);
Selection.End = new Place(lines[to].Count, to);
needRecalc = true;
lines.Manager.EndAutoUndoCommands();
Selection.EndUpdate();
EndUpdate();
}
///
/// Begins AutoUndo block.
/// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.
///
public void BeginAutoUndo()
{
lines.Manager.BeginAutoUndoCommands();
}
///
/// Ends AutoUndo block.
/// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.
///
public void EndAutoUndo()
{
lines.Manager.EndAutoUndoCommands();
}
public virtual void OnVisualMarkerClick(MouseEventArgs args, StyleVisualMarker marker)
{
if (VisualMarkerClick != null)
VisualMarkerClick(this, new VisualMarkerEventArgs(marker.Style, marker, args));
}
protected virtual void OnMarkerClick(MouseEventArgs args, VisualMarker marker)
{
if (marker is StyleVisualMarker)
{
OnVisualMarkerClick(args, marker as StyleVisualMarker);
return;
}
if (marker is CollapseFoldingMarker)
{
CollapseFoldingBlock((marker as CollapseFoldingMarker).iLine);
OnVisibleRangeChanged();
Invalidate();
return;
}
if (marker is ExpandFoldingMarker)
{
ExpandFoldedBlock((marker as ExpandFoldingMarker).iLine);
OnVisibleRangeChanged();
Invalidate();
return;
}
if (marker is FoldedAreaMarker)
{
//select folded block
int iStart = (marker as FoldedAreaMarker).iLine;
int iEnd = FindEndOfFoldingBlock(iStart);
if (iEnd < 0)
return;
Selection.BeginUpdate();
Selection.Start = new Place(0, iStart);
Selection.End = new Place(lines[iEnd].Count, iEnd);
Selection.EndUpdate();
Invalidate();
return;
}
}
protected virtual void OnMarkerDoubleClick(VisualMarker marker)
{
if (marker is FoldedAreaMarker)
{
ExpandFoldedBlock((marker as FoldedAreaMarker).iLine);
Invalidate();
return;
}
}
private void ClearBracketsPositions()
{
leftBracketPosition = null;
rightBracketPosition = null;
leftBracketPosition2 = null;
rightBracketPosition2 = null;
}
private void HighlightBrackets(char LeftBracket, char RightBracket, ref Range leftBracketPosition,
ref Range rightBracketPosition)
{
if (!Selection.IsEmpty)
return;
if (LinesCount == 0)
return;
//
Range oldLeftBracketPosition = leftBracketPosition;
Range oldRightBracketPosition = rightBracketPosition;
Range range = Selection.Clone(); //need clone because we will move caret
int counter = 0;
int maxIterations = maxBracketSearchIterations;
while (range.GoLeftThroughFolded()) //move caret left
{
if (range.CharAfterStart == LeftBracket) counter++;
if (range.CharAfterStart == RightBracket) counter--;
if (counter == 1)
{
//highlighting
range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
leftBracketPosition = range;
break;
}
//
maxIterations--;
if (maxIterations <= 0) break;
}
//
range = Selection.Clone(); //need clone because we will move caret
counter = 0;
maxIterations = maxBracketSearchIterations;
do
{
if (range.CharAfterStart == LeftBracket) counter++;
if (range.CharAfterStart == RightBracket) counter--;
if (counter == -1)
{
//highlighting
range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
rightBracketPosition = range;
break;
}
//
maxIterations--;
if (maxIterations <= 0) break;
} while (range.GoRightThroughFolded()); //move caret right
if (oldLeftBracketPosition != leftBracketPosition ||
oldRightBracketPosition != rightBracketPosition)
Invalidate();
}
public virtual void OnSyntaxHighlight(TextChangedEventArgs args)
{
#if debug
Stopwatch sw = Stopwatch.StartNew();
#endif
Range range;
switch (HighlightingRangeType)
{
case HighlightingRangeType.VisibleRange:
range = VisibleRange.GetUnionWith(args.ChangedRange);
break;
case HighlightingRangeType.AllTextRange:
range = Range;
break;
default:
range = args.ChangedRange;
break;
}
if (SyntaxHighlighter != null)
{
if (Language == Language.Custom && !string.IsNullOrEmpty(DescriptionFile))
SyntaxHighlighter.HighlightSyntax(DescriptionFile, range);
else
SyntaxHighlighter.HighlightSyntax(Language, range);
}
#if debug
Debug.WriteLine("OnSyntaxHighlight: "+ sw.ElapsedMilliseconds);
#endif
}
private void InitializeComponent()
{
SuspendLayout();
//
// FastColoredTextBox
//
Name = "FastColoredTextBox";
ResumeLayout(false);
}
///
/// Prints range of text
///
public virtual void Print(Range range, PrintDialogSettings settings)
{
//prepare export with wordwrapping
var exporter = new ExportToHTML();
exporter.UseBr = true;
exporter.UseForwardNbsp = true;
exporter.UseNbsp = true;
exporter.UseStyleTag = false;
exporter.IncludeLineNumbers = settings.IncludeLineNumbers;
if (range == null)
range = this.Range;
if (range.Text == string.Empty)
return;
//change visible range
visibleRange = range;
try
{
//call handlers for VisibleRange
if (VisibleRangeChanged != null)
VisibleRangeChanged(this, new EventArgs());
if (VisibleRangeChangedDelayed != null)
VisibleRangeChangedDelayed(this, new EventArgs());
}
finally
{
//restore visible range
visibleRange = null;
}
//generate HTML
var HTML = exporter.GetHtml(range);
HTML = "" + PrepareHtmlText(settings.Title) + "" + HTML + SelectHTMLRangeScript();
var tempFile = Path.GetTempPath() + "fctb.html";
File.WriteAllText(tempFile, HTML);
//clear wb page setup settings
SetPageSetupSettings(settings);
//create wb
var wb = new WebBrowser();
wb.Tag = settings;
wb.Visible = false;
wb.Location = new Point(-1000, -1000);
wb.Parent = this;
wb.StatusTextChanged += new EventHandler(wb_StatusTextChanged);
wb.Navigate(tempFile);
}
protected virtual string PrepareHtmlText(string s)
{
return s.Replace("<", "<").Replace(">", ">").Replace("&", "&");
}
void wb_StatusTextChanged(object sender, EventArgs e)
{
var wb = sender as WebBrowser;
if (wb.StatusText.Contains("#print"))
{
var settings = wb.Tag as PrintDialogSettings;
try
{
//show print dialog
if (settings.ShowPrintPreviewDialog)
wb.ShowPrintPreviewDialog();
else
{
if (settings.ShowPageSetupDialog)
wb.ShowPageSetupDialog();
if (settings.ShowPrintDialog)
wb.ShowPrintDialog();
else
wb.Print();
}
}
finally
{
//destroy webbrowser
wb.Parent = null;
wb.Dispose();
}
}
}
///
/// Prints all text
///
public void Print(PrintDialogSettings settings)
{
Print(Range, settings);
}
///
/// Prints all text, without any dialog windows
///
public void Print()
{
Print(Range,
new PrintDialogSettings
{ ShowPageSetupDialog = false, ShowPrintDialog = false, ShowPrintPreviewDialog = false });
}
private string SelectHTMLRangeScript()
{
var sel = Selection.Clone();
sel.Normalize();
var start = PlaceToPosition(sel.Start) - sel.Start.iLine;
var len = sel.Text.Length - (sel.End.iLine - sel.Start.iLine);
return string.Format(
@"", start, len);
}
private static void SetPageSetupSettings(PrintDialogSettings settings)
{
var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Internet Explorer\PageSetup", true);
if (key != null)
{
key.SetValue("footer", settings.Footer);
key.SetValue("header", settings.Header);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (SyntaxHighlighter != null)
SyntaxHighlighter.Dispose();
timer.Dispose();
timer2.Dispose();
if (findForm != null)
findForm.Dispose();
if (replaceForm != null)
replaceForm.Dispose();
if (Font != null)
Font.Dispose();
if (TextSource != null)
TextSource.Dispose();
}
}
protected virtual void OnPaintLine(PaintLineEventArgs e)
{
if (PaintLine != null)
PaintLine(this, e);
}
internal void OnLineInserted(int index)
{
OnLineInserted(index, 1);
}
internal void OnLineInserted(int index, int count)
{
if (LineInserted != null)
LineInserted(this, new LineInsertedEventArgs(index, count));
}
internal void OnLineRemoved(int index, int count, List removedLineIds)
{
if (count > 0)
if (LineRemoved != null)
LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));
}
///
/// Open file binding mode
///
///
///
public void OpenBindingFile(string fileName, Encoding enc)
{
try
{
var fts = new FileTextSource(this);
InitTextSource(fts);
fts.OpenFile(fileName, enc);
IsChanged = false;
OnVisibleRangeChanged();
}
catch
{
InitTextSource(CreateTextSource());
lines.InsertLine(0, TextSource.CreateLine());
IsChanged = false;
throw;
}
}
///
/// Close file binding mode
///
public void CloseBindingFile()
{
if (lines is FileTextSource)
{
var fts = lines as FileTextSource;
fts.CloseFile();
InitTextSource(CreateTextSource());
lines.InsertLine(0, TextSource.CreateLine());
IsChanged = false;
Invalidate();
}
}
///
/// Save text to the file
///
///
///
public void SaveToFile(string fileName, Encoding enc)
{
lines.SaveToFile(fileName, enc);
IsChanged = false;
OnVisibleRangeChanged();
}
///
/// Set VisibleState of line
///
public void SetVisibleState(int iLine, VisibleState state)
{
LineInfo li = lineInfos[iLine];
li.VisibleState = state;
lineInfos[iLine] = li;
needRecalc = true;
}
///
/// Returns VisibleState of the line
///
public VisibleState GetVisibleState(int iLine)
{
return lineInfos[iLine].VisibleState;
}
///
/// Shows Goto dialog form
///
public void ShowGoToDialog()
{
var form = new GoToForm();
form.TotalLineCount = LinesCount;
form.SelectedLineNumber = Selection.Start.iLine + 1;
if (form.ShowDialog() == DialogResult.OK)
{
int line = Math.Min(LinesCount - 1, Math.Max(0, form.SelectedLineNumber - 1));
Selection = new Range(this, 0, line, 0, line);
DoSelectionVisible();
}
}
///
/// Occurs when undo/redo stack is changed
///
public void OnUndoRedoStateChanged()
{
if (UndoRedoStateChanged != null)
UndoRedoStateChanged(this, EventArgs.Empty);
}
///
/// Search lines by regex pattern
///
public List FindLines(string searchPattern, RegexOptions options)
{
List iLines = new List();
foreach (var r in Range.GetRangesByLines(searchPattern, options))
iLines.Add(r.Start.iLine);
return iLines;
}
///
/// Removes given lines
///
public void RemoveLines(List iLines)
{
TextSource.Manager.ExecuteCommand(new RemoveLinesCommand(TextSource, iLines));
if (iLines.Count > 0)
IsChanged = true;
if (LinesCount == 0)
Text = "";
NeedRecalc();
Invalidate();
}
#region Drag and drop
private bool IsDragDrop { get; set; }
protected override void OnDragEnter(DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
{
e.Effect = DragDropEffects.Copy;
IsDragDrop = true;
}
base.OnDragEnter(e);
}
protected override void OnDragDrop(DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
{
if (ParentForm != null)
ParentForm.Activate();
Focus();
var p = PointToClient(new Point(e.X, e.Y));
Selection.Start = PointToPlace(p);
InsertText(e.Data.GetData(DataFormats.Text).ToString());
IsDragDrop = false;
}
base.OnDragDrop(e);
}
protected override void OnDragOver(DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
{
var p = PointToClient(new Point(e.X, e.Y));
Selection.Start = PointToPlace(p);
Invalidate();
}
base.OnDragOver(e);
}
protected override void OnDragLeave(EventArgs e)
{
IsDragDrop = false;
base.OnDragLeave(e);
}
#endregion
#region Nested type: LineYComparer
private class LineYComparer : IComparer
{
private readonly int Y;
public LineYComparer(int Y)
{
this.Y = Y;
}
#region IComparer Members
public int Compare(LineInfo x, LineInfo y)
{
if (x.startY == -10)
return -y.startY.CompareTo(Y);
else
return x.startY.CompareTo(Y);
}
#endregion
}
#endregion
}
public class PaintLineEventArgs : PaintEventArgs
{
public PaintLineEventArgs(int iLine, Rectangle rect, Graphics gr, Rectangle clipRect) : base(gr, clipRect)
{
LineIndex = iLine;
LineRect = rect;
}
public int LineIndex { get; private set; }
public Rectangle LineRect { get; private set; }
}
public class LineInsertedEventArgs : EventArgs
{
public LineInsertedEventArgs(int index, int count)
{
Index = index;
Count = count;
}
///
/// Inserted line index
///
public int Index { get; private set; }
///
/// Count of inserted lines
///
public int Count { get; private set; }
}
public class LineRemovedEventArgs : EventArgs
{
public LineRemovedEventArgs(int index, int count, List removedLineIds)
{
Index = index;
Count = count;
RemovedLineUniqueIds = removedLineIds;
}
///
/// Removed line index
///
public int Index { get; private set; }
///
/// Count of removed lines
///
public int Count { get; private set; }
///
/// UniqueIds of removed lines
///
public List RemovedLineUniqueIds { get; private set; }
}
///
/// TextChanged event argument
///
public class TextChangedEventArgs : EventArgs
{
///
/// Constructor
///
public TextChangedEventArgs(Range changedRange)
{
ChangedRange = changedRange;
}
///
/// This range contains changed area of text
///
public Range ChangedRange { get; set; }
}
public class TextChangingEventArgs : EventArgs
{
public string InsertingText { get; set; }
///
/// Set to true if you want to cancel text inserting
///
public bool Cancel { get; set; }
}
public enum WordWrapMode
{
///
/// Word wrapping by control width
///
WordWrapControlWidth,
///
/// Word wrapping by preferred line width (PreferredLineWidth)
///
WordWrapPreferredWidth,
///
/// Char wrapping by control width
///
CharWrapControlWidth,
///
/// Char wrapping by preferred line width (PreferredLineWidth)
///
CharWrapPreferredWidth
}
public class PrintDialogSettings
{
public bool ShowPageSetupDialog { get; set; }
public bool ShowPrintDialog { get; set; }
public bool ShowPrintPreviewDialog { get; set; }
///
/// Title of page. If you want to print Title on the page, insert code &w in Footer or Header.
///
public string Title { get; set; }
///
/// Footer of page.
/// Here you can use special codes: &w (Window title), &D, &d (Date), &t(), &4 (Time), &p (Current page number), &P (Total number of pages), && (A single ampersand), &b (Right justify text, Center text. If &b occurs once, then anything after the &b is right justified. If &b occurs twice, then anything between the two &b is centered, and anything after the second &b is right justified).
/// More detailed see here
///
public string Footer { get; set; }
///
/// Header of page
/// Here you can use special codes: &w (Window title), &D, &d (Date), &t(), &4 (Time), &p (Current page number), &P (Total number of pages), && (A single ampersand), &b (Right justify text, Center text. If &b occurs once, then anything after the &b is right justified. If &b occurs twice, then anything between the two &b is centered, and anything after the second &b is right justified).
/// More detailed see here
///
public string Header { get; set; }
///
/// Prints line numbers
///
public bool IncludeLineNumbers { get; set; }
public PrintDialogSettings()
{
ShowPrintPreviewDialog = true;
Title = "";
Footer = "";
Header = "";
Footer = "";
Header = "";
}
}
public class AutoIndentEventArgs : EventArgs
{
public AutoIndentEventArgs(int iLine, string lineText, string prevLineText, int tabLength)
{
this.iLine = iLine;
LineText = lineText;
PrevLineText = prevLineText;
TabLength = tabLength;
}
public int iLine { get; internal set; }
public int TabLength { get; internal set; }
public string LineText { get; internal set; }
public string PrevLineText { get; internal set; }
///
/// Additional spaces count for this line, relative to previous line
///
public int Shift { get; set; }
///
/// Additional spaces count for next line, relative to previous line
///
public int ShiftNextLines { get; set; }
}
///
/// Type of highlighting
///
public enum HighlightingRangeType
{
///
/// Highlight only changed range of text. Highest performance.
///
ChangedRange,
///
/// Highlight visible range of text. Middle performance.
///
VisibleRange,
///
/// Highlight all (visible and invisible) text. Lowest performance.
///
AllTextRange
}
///
/// Strategy of search of end of folding block
///
public enum FindEndOfFoldingBlockStrategy
{
Strategy1,
Strategy2
}
}