|
//
// ___ _____ ___ ___ __ __
// / __|_ _/ _ \| _ \ \/ |
// \__ \ | || (_) | / |\/| |
// |___/ |_| \___/|_|_\_| |_|
//
// Storm.TextEditor.dll
// ��������������������
// Storm.TabControl.dll was created under the LGPL
// license. Some of the code was created from scratch,
// some was not. Code not created from scratch was
// based on the DotNetFireball framework and evolved
// from that.
//
// What I mostly did in this library was that I
// cleaned up the code, structured it, documentated
// it and added new features.
//
// Although it might not sound like it, it was very
// hard and took a long (pretty much a shitload)
// time. Why? Well, this was* some of the crappiest,
// most unstructured, undocumentated, ugly code I've
// ever seen. It would actually have taken me less
// time to create it from scratch, but I figured that
// out too late. Figuring out what the code actually
// did and then documentating it was (mostly) a
// day-long process. Well, I hope you enjoy some of
// my hard work. /rant
//
// Of course some/most of it is made from scratch by me.
// *Yes, was. It isn't now. :) Some of the naming
// conventions might still seem a little bit off though.
//
// What is Storm?
// ��������������
// Storm is a set of dynamic link libraries used in
// Theodor "Vestras" Storm Kristensen's application
// "Moonlite".
//
//
// Thanks:
// �������
// - The DotNetFireball team for creating and publishing
// DotNetFireball which I based some of my code on.
//
//
// Copyright (c) Theodor "Vestras" Storm Kristensen 2009
// �����������������������������������������������������
//
namespace Storm.TextEditor.Interacting
{
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Design;
using System.Diagnostics.SymbolStore;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Windows.Forms;
using Storm.TextEditor;
using Storm.TextEditor.Controls;
using Storm.TextEditor.Controls.Core;
using Storm.TextEditor.Controls.Core.Globalization;
using Storm.TextEditor.Controls.Core.Timers;
using Storm.TextEditor.Controls.IntelliMouse;
using Storm.TextEditor.Document;
using Storm.TextEditor.Document.Exporters;
using Storm.TextEditor.Forms;
using Storm.TextEditor.Interacting;
using Storm.TextEditor.Painting;
using Storm.TextEditor.Parsing;
using Storm.TextEditor.Parsing.Base;
using Storm.TextEditor.Parsing.Classes;
using Storm.TextEditor.Parsing.Language;
using Storm.TextEditor.Preset;
using Storm.TextEditor.Preset.Painting;
using Storm.TextEditor.Preset.TextDraw;
using Storm.TextEditor.Printing;
using Storm.TextEditor.Utilities;
using Storm.TextEditor.Win32;
/// <summary>
/// A class used for defining selection in a TextEditor.
/// </summary>
public class Selection
{
#region Members
// Basic members.
private TextRange _bounds;
private TextEditorBase _control;
/// <summary>
/// Event fired when the selection has changed.
/// </summary>
public event EventHandler Change = null;
#endregion
#region Properties
/// <summary>
/// Gets or sets the currently selected text. If some text is already selected, overwrites that text.
/// </summary>
public String Text
{
get
{
if (!IsValid)
return "";
else
return _control.Document.GetRange(LogicalBounds);
}
set
{
if (Text == value) return;
// Bug fix.
string tmp = value.Replace(Environment.NewLine, "\n");
tmp = tmp.Replace("\n", Environment.NewLine);
value = tmp;
TextPoint oCaretPos = _control.Caret.Position;
int nCaretX = oCaretPos.X;
int nCaretY = oCaretPos.Y;
_control.Document.StartUndoCapture();
DeleteSelection();
_control.Document.InsertText(value, oCaretPos.X, oCaretPos.Y);
SelLength = value.Length;
if (nCaretX != oCaretPos.X || nCaretY != oCaretPos.Y)
_control.Caret.Position = new TextPoint(Bounds.LastColumn, Bounds.LastRow);
_control.Document.EndUndoCapture();
_control.Document.InvokeChange();
}
}
/// <summary>
/// Returns the normalized positions of the selection.
/// Swapping start and end values if the selection is reversed.
/// </summary>
public TextRange LogicalBounds
{
get
{
TextRange r = new TextRange();
if (Bounds.FirstRow < Bounds.LastRow)
return Bounds;
else if (Bounds.FirstRow == Bounds.LastRow &&
Bounds.FirstColumn < Bounds.LastColumn)
return Bounds;
else
{
r.FirstColumn = Bounds.LastColumn;
r.FirstRow = Bounds.LastRow;
r.LastColumn = Bounds.FirstColumn;
r.LastRow = Bounds.FirstRow;
return r;
}
}
}
/// <summary>
/// Gets whether the current selection contains one or more characters.
/// </summary>
public bool IsValid
{
get
{
return (LogicalBounds.FirstColumn != LogicalBounds.LastColumn ||
LogicalBounds.FirstRow != LogicalBounds.LastRow);
}
}
/// <summary>
/// Gets or sets the length of the selection.
/// </summary>
public int SelLength
{
get
{
TextPoint p1 = new TextPoint(Bounds.FirstColumn, Bounds.FirstRow);
TextPoint p2 = new TextPoint(Bounds.LastColumn, Bounds.LastRow);
int i1 = _control.Document.PointToIntPos(p1);
int i2 = _control.Document.PointToIntPos(p2);
return i2 - i1;
}
set { SelEnd = SelStart + value; }
}
/// <summary>
/// Gets or sets the current selection end index. (SelStart + SelLength basically)
/// </summary>
public int SelEnd
{
get
{
TextPoint p = new TextPoint(Bounds.LastColumn, Bounds.LastRow);
return _control.Document.PointToIntPos(p);
}
set
{
TextPoint p = _control.Document.IntPosToPoint(value);
Bounds.LastColumn = p.X;
Bounds.LastRow = p.Y;
}
}
/// <summary>
/// Gets or sets the current selection start index.
/// </summary>
public int SelStart
{
get
{
TextPoint p = new TextPoint(Bounds.FirstColumn, Bounds.FirstRow);
return _control.Document.PointToIntPos(p);
}
set
{
TextPoint p = _control.Document.IntPosToPoint(value);
Bounds.FirstColumn = p.X;
Bounds.FirstRow = p.Y;
}
}
/// <summary>
/// Gets or sets the logical selection start index.
/// </summary>
public int LogicalSelStart
{
get
{
TextPoint p = new TextPoint(LogicalBounds.FirstColumn, LogicalBounds.FirstRow);
return _control.Document.PointToIntPos(p);
}
set
{
TextPoint p = _control.Document.IntPosToPoint(value);
Bounds.FirstColumn = p.X;
Bounds.FirstRow = p.Y;
}
}
/// <summary>
/// Gets or sets the selection bounds as a TextRange.
/// </summary>
public TextRange Bounds
{
get { return _bounds; }
set
{
if (_bounds != null)
_bounds.Change -= new EventHandler(Bounds_Change);
_bounds = value;
_bounds.Change += new EventHandler(Bounds_Change);
OnChange();
}
}
#endregion
#region EventHandlers
private void Bounds_Change(object s, EventArgs e)
{ OnChange(); }
private void PositionChange(object s, EventArgs e)
{ OnChange(); }
private void OnChange()
{
if (Change != null)
Change(this, null);
}
#endregion
#region Methods
/// <summary>
/// Increases the level of indentation at the current selection by one.
/// </summary>
public void Indent()
{
if (!IsValid)
return;
Row xtr = null;
UndoBlockCollection ActionGroup = new UndoBlockCollection();
for (int i = LogicalBounds.FirstRow; i <= LogicalBounds.LastRow; i++)
{
xtr = _control.Document[i];
UndoBlock b = new UndoBlock();
b.Action = UndoAction.InsertRange;
if (_control.KeepTabs == true)
{
xtr.Text = "\t" + xtr.Text;
b.Text = "\t";
}
else
{
string indent = new string(' ', _control.TabSpaces);
xtr.Text = indent + xtr.Text;
b.Text = indent;
}
b.Position.X = 0;
b.Position.Y = i;
ActionGroup.Add(b);
}
if (ActionGroup.Count > 0)
_control.Document.AddToUndoList(ActionGroup);
Bounds = LogicalBounds;
Bounds.FirstColumn = 0;
Bounds.LastColumn = xtr.Text.Length;
_control.Caret.Position.X = LogicalBounds.LastColumn;
_control.Caret.Position.Y = LogicalBounds.LastRow;
}
/// <summary>
/// Decreases the level of indentation at the current selection by one.
/// </summary>
public void Outdent()
{
if (!IsValid)
return;
Row xtr = null;
UndoBlockCollection ActionGroup = new UndoBlockCollection();
for (int i = LogicalBounds.FirstRow; i <= LogicalBounds.LastRow; i++)
{
xtr = _control.Document[i];
UndoBlock b = new UndoBlock();
b.Action = UndoAction.DeleteRange;
b.Position.X = 0;
b.Position.Y = i;
ActionGroup.Add(b);
string s = xtr.Text;
if (s.StartsWith("\t"))
{
b.Text = s.Substring(0, 1);
s = s.Substring(1);
}
if (s.StartsWith(new string(' ', _control.TabSpaces)))
{
b.Text = s.Substring(0, _control.TabSpaces);
s = s.Substring(_control.TabSpaces);
}
xtr.Text = s;
}
if (ActionGroup.Count > 0)
_control.Document.AddToUndoList(ActionGroup);
Bounds = LogicalBounds;
Bounds.FirstColumn = 0;
Bounds.LastColumn = xtr.Text.Length;
_control.Caret.Position.X = LogicalBounds.LastColumn;
_control.Caret.Position.Y = LogicalBounds.LastRow;
}
/// <summary>
/// Adds a string to the current selection.
/// </summary>
/// <param name="pattern">The string that will be added to the selection.</param>
public void Indent(string pattern)
{
if (!IsValid)
return;
Row xtr = null;
UndoBlockCollection ActionGroup = new UndoBlockCollection();
for (int i = LogicalBounds.FirstRow; i <= LogicalBounds.LastRow; i++)
{
xtr = _control.Document[i];
xtr.Text = pattern + xtr.Text;
UndoBlock b = new UndoBlock();
b.Action = UndoAction.InsertRange;
b.Text = pattern;
b.Position.X = 0;
b.Position.Y = i;
ActionGroup.Add(b);
}
if (ActionGroup.Count > 0)
_control.Document.AddToUndoList(ActionGroup);
Bounds = LogicalBounds;
Bounds.FirstColumn = 0;
Bounds.LastColumn = xtr.Text.Length;
_control.Caret.Position.X = LogicalBounds.LastColumn;
_control.Caret.Position.Y = LogicalBounds.LastRow;
}
/// <summary>
/// Adds a string to the current selection.
/// </summary>
/// <param name="pattern">The string that will be added to the selection.</param>
public void Outdent(string pattern)
{
if (!IsValid)
return;
Row xtr = null;
UndoBlockCollection ActionGroup = new UndoBlockCollection();
for (int i = LogicalBounds.FirstRow; i <= LogicalBounds.LastRow; i++)
{
xtr = _control.Document[i];
UndoBlock b = new UndoBlock();
b.Action = UndoAction.DeleteRange;
b.Position.X = 0;
b.Position.Y = i;
ActionGroup.Add(b);
string s = xtr.Text;
if (s.StartsWith(pattern))
{
b.Text = s.Substring(0, pattern.Length);
s = s.Substring(pattern.Length);
}
xtr.Text = s;
}
if (ActionGroup.Count > 0)
_control.Document.AddToUndoList(ActionGroup);
Bounds = LogicalBounds;
Bounds.FirstColumn = 0;
Bounds.LastColumn = xtr.Text.Length;
_control.Caret.Position.X = LogicalBounds.LastColumn;
_control.Caret.Position.Y = LogicalBounds.LastRow;
}
/// <summary>
/// Delete the active selection.
/// <seealso cref="ClearSelection"/>
/// </summary>
public void DeleteSelection()
{
TextRange r = LogicalBounds;
int x = r.FirstColumn;
int y = r.FirstRow;
_control.Document.DeleteRange(r);
_control.Caret.Position.X = x;
_control.Caret.Position.Y = y;
ClearSelection();
_control.ScrollIntoView();
}
/// <summary>
/// Clear the active selection.
/// <seealso cref="DeleteSelection"/>
/// </summary>
public void ClearSelection()
{
Bounds.FirstColumn = _control.Caret.Position.X;
Bounds.FirstRow = _control.Caret.Position.Y;
Bounds.LastColumn = _control.Caret.Position.X;
Bounds.LastRow = _control.Caret.Position.Y;
}
/// <summary>
/// Sets the bounds of the selection to the Caret start and end positions.
/// </summary>
public void MakeSelection()
{
Bounds.LastColumn = _control.Caret.Position.X;
Bounds.LastRow = _control.Caret.Position.Y;
}
/// <summary>
/// Selects all text in the TextEditor.
/// </summary>
public void SelectAll()
{
Bounds.FirstColumn = 0;
Bounds.FirstRow = 0;
Bounds.LastColumn = _control.Document[_control.Document.Count - 1].Text.Length;
Bounds.LastRow = _control.Document.Count - 1;
_control.Caret.Position.X = Bounds.LastColumn;
_control.Caret.Position.Y = Bounds.LastRow;
_control.ScrollIntoView();
}
#endregion
/// <summary>
/// Initializes the Selection.
/// </summary>
public Selection(TextEditorBase control)
{
_control = control;
Bounds = new TextRange();
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.