Fixes #1179. TextView does not copy to the clipboard on deleting. (#1180)

* Fixes #1133. Flaw in LayoutSubviews/TopologicalSort.

* Toplevel can't be used on Pos/Dim but only his subviews. Was not caught before because the LayoutSubviews  method never gone so deep before.

* Fixed the error that is triggered when the Pos/Dim is the current Application.Top.

* Application.Top is the only exception in the TopologicalSort method check.

* Fixes #1179. TextView does not copy to the clipboard on deleting.

* Added Button DoubleClick and fixed WordForward/WordBackward issues.

* Prevents a negative height.

* Fixes the enter key line feed.

* Fixes #1187. Prevents WordBackward throwing an exception if point is greater than the text length.

* Fixes #1189. Prevents negative index.

* Fixes #1193. A  non auto size default Button now preserves his width and thus the text alignment now work.

* Fixing the Width and Height checks of the Dim class with AutoSize dependence.

* Fixes #1197. Prevents width negative value if added directly to the Application.Top

* Fixes #1199. Normalize views constructors and did some typo fixing.

* Fixing the Application.Top Pos/Dim settings.

* Always uses inverted color for selected text to avoid same colors.

* Prevents throw an exception if the clipboard content is null.

* Added Find and Replace (next/previous). Replace All and Select All. A non modal dialog box.

* Keeps tracking the selected replaced text.

* Fixes #1202. CheckBox now deals with a functional '_' underscore hotkey.

* The selected text should be maintained when losing focus.

* Fixes an extra line on page down.

* Fixes the WordBackward if it text has more than one whitespaces or when has only one digit or letter.

* Fixes WordForward/WordBackward on text with more than one whitespace or with only one digit or letter.

* Forgot to replace the hacking.

* Added unit tests for the TextField view. Fixed some more bugs.

* Redraw should only show the selected text if it is focused.

* Fixes cursor position on double click and ensures the setting of the selected text.

* Added match whole word checking.

* Added missing parameters documentation.

* Ensures the SelectedLength property to be always with positive value.

* Fixes the WordBackward when at the end of the text has a character between two whitespace.

* Added unit tests to the TextView, Used property and fixed some more bugs.

* Fixed Used to only show if it has focus.

* Fixed ReplaceAll and prevents Debug.Assert from showing.
This commit is contained in:
BDisp
2021-04-13 21:37:13 +01:00
committed by GitHub
parent 5bd8be83ca
commit e784765094
12 changed files with 2046 additions and 112 deletions

View File

@@ -36,7 +36,7 @@ namespace Terminal.Gui {
return 0;
}
class PosFactor : Pos {
internal class PosFactor : Pos {
float factor;
public PosFactor (float n)
@@ -82,7 +82,7 @@ namespace Terminal.Gui {
static PosAnchorEnd endNoMargin;
class PosAnchorEnd : Pos {
internal class PosAnchorEnd : Pos {
int n;
public PosAnchorEnd (int n)
@@ -205,8 +205,8 @@ namespace Terminal.Gui {
return new PosAbsolute (n);
}
class PosCombine : Pos {
Pos left, right;
internal class PosCombine : Pos {
internal Pos left, right;
bool add;
public PosCombine (bool add, Pos left, Pos right)
{
@@ -500,7 +500,7 @@ namespace Terminal.Gui {
}
internal class DimCombine : Dim {
Dim left, right;
internal Dim left, right;
bool add;
public DimCombine (bool add, Dim left, Dim right)
{

View File

@@ -625,7 +625,8 @@ namespace Terminal.Gui {
Application.Driver?.AddRune (rune);
}
col += Rune.ColumnWidth (rune);
if (idx + 1 < runes.Length && col + Rune.ColumnWidth (runes [idx + 1]) > bounds.Width) {
if (idx + 1 > - 1 && idx + 1 < runes.Length && col
+ Rune.ColumnWidth (runes [idx + 1]) > bounds.Width) {
break;
}
}

View File

@@ -370,7 +370,7 @@ namespace Terminal.Gui {
l = SuperView.Frame.Width;
}
nx = nx + top.Frame.Width > l ? Math.Max (l - top.Frame.Width, 0) : nx;
SetWidth (top.Frame.Width, out int rWidth);
SetWidth (top.Frame.Width, out int rWidth, out _);
if (rWidth < 0 && nx >= top.Frame.X) {
nx = Math.Max (top.Frame.Right - 2, 0);
}
@@ -399,7 +399,7 @@ namespace Terminal.Gui {
}
ny = Math.Min (ny, l);
ny = ny + top.Frame.Height > l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
SetHeight (top.Frame.Height, out int rHeight);
SetHeight (top.Frame.Height, out int rHeight, out _);
if (rHeight < 0 && ny >= top.Frame.Y) {
ny = Math.Max (top.Frame.Bottom - 2, 0);
}

View File

@@ -1753,7 +1753,7 @@ namespace Terminal.Gui {
var result = new List<View> ();
// Set of all nodes with no incoming edges
var S = new HashSet<View> (nodes.Where (n => edges.All (e => e.To.Equals (n) == false)));
var S = new HashSet<View> (nodes.Where (n => edges.All (e => !e.To.Equals (n))));
while (S.Any ()) {
// remove a node n from S
@@ -1772,15 +1772,15 @@ namespace Terminal.Gui {
edges.Remove (e);
// if m has no other incoming edges then
if (edges.All (me => me.To.Equals (m) == false) && m != this?.SuperView) {
if (edges.All (me => !me.To.Equals (m)) && m != this?.SuperView) {
// insert m into S
S.Add (m);
}
}
}
if (edges.Any ()) {
if (!object.ReferenceEquals (edges.First ().From, edges.First ().To)) {
if (edges.Any () && edges.First ().From != Application.Top) {
if (!ReferenceEquals (edges.First ().From, edges.First ().To)) {
throw new InvalidOperationException ($"TopologicalSort (for Pos/Dim) cannot find {edges.First ().From}. Did you forget to add it to {this}?");
} else {
throw new InvalidOperationException ("TopologicalSort encountered a recursive cycle in the relative Pos/Dim in the views of " + this);
@@ -1863,20 +1863,60 @@ namespace Terminal.Gui {
var nodes = new HashSet<View> ();
var edges = new HashSet<(View, View)> ();
foreach (var v in InternalSubviews) {
nodes.Add (v);
if (v.LayoutStyle == LayoutStyle.Computed) {
if (v.X is Pos.PosView vX)
edges.Add ((vX.Target, v));
if (v.Y is Pos.PosView vY)
edges.Add ((vY.Target, v));
if (v.Width is Dim.DimView vWidth)
edges.Add ((vWidth.Target, v));
if (v.Height is Dim.DimView vHeight)
edges.Add ((vHeight.Target, v));
void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
{
if (pos is Pos.PosView pv) {
if (pv.Target != this) {
nEdges.Add ((pv.Target, from));
}
foreach (var v in from.InternalSubviews) {
CollectAll (v, ref nNodes, ref nEdges);
}
return;
}
if (pos is Pos.PosCombine pc) {
foreach (var v in from.InternalSubviews) {
CollectPos (pc.left, from, ref nNodes, ref nEdges);
CollectPos (pc.right, from, ref nNodes, ref nEdges);
}
}
}
void CollectDim (Dim dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
{
if (dim is Dim.DimView dv) {
if (dv.Target != this) {
nEdges.Add ((dv.Target, from));
}
foreach (var v in from.InternalSubviews) {
CollectAll (v, ref nNodes, ref nEdges);
}
return;
}
if (dim is Dim.DimCombine dc) {
foreach (var v in from.InternalSubviews) {
CollectDim (dc.left, from, ref nNodes, ref nEdges);
CollectDim (dc.right, from, ref nNodes, ref nEdges);
}
}
}
void CollectAll (View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
{
foreach (var v in from.InternalSubviews) {
nNodes.Add (v);
if (v.layoutStyle != LayoutStyle.Computed) {
continue;
}
CollectPos (v.X, v, ref nNodes, ref nEdges);
CollectPos (v.Y, v, ref nNodes, ref nEdges);
CollectDim (v.Width, v, ref nNodes, ref nEdges);
CollectDim (v.Height, v, ref nNodes, ref nEdges);
}
}
CollectAll (this, ref nodes, ref edges);
var ordered = TopologicalSort (nodes, edges);
foreach (var v in ordered) {
@@ -1886,7 +1926,6 @@ namespace Terminal.Gui {
v.LayoutSubviews ();
v.LayoutNeeded = false;
}
if (SuperView == Application.Top && LayoutNeeded && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
@@ -2154,14 +2193,17 @@ namespace Terminal.Gui {
/// </summary>
/// <param name="desiredWidth">The desired width.</param>
/// <param name="resultWidth">The real result width.</param>
/// <param name="currentWidth">The real current width.</param>
/// <returns>True if the width can be directly assigned, false otherwise.</returns>
public bool SetWidth (int desiredWidth, out int resultWidth)
public bool SetWidth (int desiredWidth, out int resultWidth, out int currentWidth)
{
int w = desiredWidth;
currentWidth = Width != null ? Width.Anchor (0) : 0;
bool canSetWidth;
if (Width is Dim.DimCombine || Width is Dim.DimView || Width is Dim.DimFill) {
// It's a Dim.DimCombine and so can't be assigned. Let it have it's width anchored.
w = Width.Anchor (w);
currentWidth = Width.Anchor (w);
canSetWidth = false;
} else if (Width is Dim.DimFactor factor) {
// Tries to get the SuperView width otherwise the view width.
@@ -2170,6 +2212,7 @@ namespace Terminal.Gui {
sw -= Frame.X;
}
w = Width.Anchor (sw);
currentWidth = Width.Anchor (sw);
canSetWidth = false;
} else {
canSetWidth = true;
@@ -2184,14 +2227,17 @@ namespace Terminal.Gui {
/// </summary>
/// <param name="desiredHeight">The desired height.</param>
/// <param name="resultHeight">The real result height.</param>
/// <param name="currentHeight">The real current height.</param>
/// <returns>True if the height can be directly assigned, false otherwise.</returns>
public bool SetHeight (int desiredHeight, out int resultHeight)
public bool SetHeight (int desiredHeight, out int resultHeight, out int currentHeight)
{
int h = desiredHeight;
currentHeight = Height != null ? Height.Anchor (0) : 0;
bool canSetHeight;
if (Height is Dim.DimCombine || Height is Dim.DimView || Height is Dim.DimFill) {
// It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
h = Height.Anchor (h);
currentHeight = Height.Anchor (h);
canSetHeight = false;
} else if (Height is Dim.DimFactor factor) {
// Tries to get the SuperView height otherwise the view height.
@@ -2200,6 +2246,7 @@ namespace Terminal.Gui {
sh -= Frame.Y;
}
h = Height.Anchor (sh);
currentHeight = Height.Anchor (sh);
canSetHeight = false;
} else {
canSetHeight = true;

View File

@@ -146,10 +146,13 @@ namespace Terminal.Gui {
base.Text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
int w = base.Text.RuneCount - (base.Text.Contains (HotKeySpecifier) ? 1 : 0);
if (SetWidth (w, out int rWidth)) {
var canSetWidth = SetWidth (w, out int rWidth, out int cWidth);
if (canSetWidth && (cWidth < rWidth || AutoSize)) {
Width = rWidth;
w = rWidth;
} else if (!canSetWidth || !AutoSize) {
w = cWidth;
}
w = rWidth;
var layout = LayoutStyle;
bool layoutChanged = false;
if (!(Height is Dim.DimAbsolute)) {

View File

@@ -279,6 +279,184 @@ namespace Terminal.Gui {
}
return col;
}
(Point startPointToFind, Point currentPointToFind, bool found) toFind;
internal (Point current, bool found) FindNextText (ustring text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
{
if (text == null || lines.Count == 0) {
gaveFullTurn = false;
return (Point.Empty, false);
}
if (toFind.found) {
toFind.currentPointToFind.X++;
}
var foundPos = GetFoundNextTextPoint (text, lines.Count, matchCase, matchWholeWord, toFind.currentPointToFind);
if (!foundPos.found && toFind.currentPointToFind != toFind.startPointToFind) {
foundPos = GetFoundNextTextPoint (text, toFind.startPointToFind.Y + 1, matchCase, matchWholeWord, Point.Empty);
}
gaveFullTurn = ApplyToFind (foundPos);
return foundPos;
}
internal (Point current, bool found) FindPreviousText (ustring text, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false)
{
if (text == null || lines.Count == 0) {
gaveFullTurn = false;
return (Point.Empty, false);
}
if (toFind.found) {
toFind.currentPointToFind.X++;
}
var foundPos = GetFoundPreviousTextPoint (text, toFind.currentPointToFind.Y, matchCase, matchWholeWord, toFind.currentPointToFind);
if (!foundPos.found && toFind.currentPointToFind != toFind.startPointToFind) {
foundPos = GetFoundPreviousTextPoint (text, lines.Count - 1, matchCase, matchWholeWord,
new Point (lines [lines.Count - 1].Count, lines.Count));
}
gaveFullTurn = ApplyToFind (foundPos);
return foundPos;
}
internal (Point current, bool found) ReplaceAllText (ustring text, bool matchCase = false, bool matchWholeWord = false, ustring textToReplace = null)
{
bool found = false;
Point pos = Point.Empty;
for (int i = 0; i < lines.Count; i++) {
var x = lines [i];
var txt = ustring.Make (x).ToString ();
if (!matchCase) {
txt = txt.ToUpper ();
}
var matchText = !matchCase ? text.ToUpper ().ToString () : text.ToString ();
var col = txt.IndexOf (matchText);
if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
continue;
}
if (col > -1) {
if (!found) {
found = true;
}
pos = new Point (col, i);
lines [i] = ReplaceText (x, textToReplace, matchText, col).ToRuneList ();
i--;
}
}
return (pos, found);
}
ustring ReplaceText (List<Rune> source, ustring textToReplace, string matchText, int col)
{
var origTxt = ustring.Make (source);
(int _, int len) = TextModel.DisplaySize (source, 0, col, false);
(var _, var len2) = TextModel.DisplaySize (source, col, col + matchText.Length, false);
(var _, var len3) = TextModel.DisplaySize (source, col + matchText.Length, origTxt.RuneCount, false);
return origTxt [0, len] +
textToReplace.ToString () +
origTxt [len + len2, len + len2 + len3];
}
bool ApplyToFind ((Point current, bool found) foundPos)
{
bool gaveFullTurn = false;
if (foundPos.found) {
toFind.currentPointToFind = foundPos.current;
if (toFind.found && toFind.currentPointToFind == toFind.startPointToFind) {
gaveFullTurn = true;
}
if (!toFind.found) {
toFind.startPointToFind = toFind.currentPointToFind = foundPos.current;
toFind.found = foundPos.found;
}
}
return gaveFullTurn;
}
(Point current, bool found) GetFoundNextTextPoint (ustring text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
{
for (int i = start.Y; i < linesCount; i++) {
var x = lines [i];
var txt = ustring.Make (x).ToString ();
if (!matchCase) {
txt = txt.ToUpper ();
}
var matchText = !matchCase ? text.ToUpper ().ToString () : text.ToString ();
var col = txt.IndexOf (matchText, Math.Min (start.X, txt.Length));
if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
continue;
}
if (col > -1 && ((i == start.Y && col >= start.X)
|| i > start.Y)
&& txt.Contains (matchText)) {
return (new Point (col, i), true);
} else if (col == -1 && start.X > 0) {
start.X = 0;
}
}
return (Point.Empty, false);
}
(Point current, bool found) GetFoundPreviousTextPoint (ustring text, int linesCount, bool matchCase, bool matchWholeWord, Point start)
{
for (int i = linesCount; i >= 0; i--) {
var x = lines [i];
var txt = ustring.Make (x).ToString ();
if (!matchCase) {
txt = txt.ToUpper ();
}
if (start.Y != i) {
start.X = Math.Max (x.Count - 1, 0);
}
var matchText = !matchCase ? text.ToUpper ().ToString () : text.ToString ();
var col = txt.LastIndexOf (matchText, start.X);
if (col > -1 && matchWholeWord && !MatchWholeWord (txt, matchText, col)) {
continue;
}
if (col > -1 && ((i == linesCount && col <= start.X)
|| i < start.Y)
&& txt.Contains (matchText)) {
return (new Point (col, i), true);
}
}
return (Point.Empty, false);
}
bool MatchWholeWord (string source, string matchText, int index = 0)
{
if (string.IsNullOrEmpty (source) || string.IsNullOrEmpty (matchText)) {
return false;
}
var txt = matchText.Trim ();
var start = index > 0 ? index - 1 : 0;
var end = index + txt.Length;
if ((start == 0 || Rune.IsWhiteSpace (source [start]))
&& (end == source.Length || Rune.IsWhiteSpace (source [end]))) {
return true;
}
return false;
}
/// <summary>
/// Redefine column and line tracking.
/// </summary>
/// <param name="point">Contains the column and line.</param>
internal void ResetContinuousFind (Point point)
{
toFind.startPointToFind = toFind.currentPointToFind = point;
toFind.found = false;
}
}
class WordWrapManager {
@@ -645,9 +823,9 @@ namespace Terminal.Gui {
int currentColumn;
int selectionStartColumn, selectionStartRow;
bool selecting;
//bool used;
bool wordWrap;
WordWrapManager wrapManager;
bool continuousFind;
/// <summary>
/// Raised when the <see cref="Text"/> of the <see cref="TextView"/> changes.
@@ -671,7 +849,7 @@ namespace Terminal.Gui {
/// </remarks>
public TextView (Rect frame) : base (frame)
{
CanFocus = true;
Initialize ();
}
/// <summary>
@@ -680,9 +858,21 @@ namespace Terminal.Gui {
/// </summary>
public TextView () : base ()
{
CanFocus = true;
Initialize ();
}
void Initialize ()
{
CanFocus = true;
Used = true;
}
/// <summary>
/// Tracks whether the text view should be considered "used", that is, that the user has moved in the entry,
/// so new input should be appended at the cursor position, rather than clearing the entry
/// </summary>
public bool Used { get; set; }
void ResetPosition ()
{
topRow = leftColumn = currentRow = currentColumn = 0;
@@ -763,6 +953,79 @@ namespace Terminal.Gui {
/// </summary>
public int Lines => model.Count;
/// <summary>
/// Sets or gets the current cursor position.
/// </summary>
public Point CursorPosition {
get => new Point (currentColumn, currentRow);
set {
var line = model.GetLine (Math.Max (Math.Min (value.Y, model.Count - 1), 0));
currentColumn = value.X < 0 ? 0 : value.X > line.Count ? line.Count : value.X;
currentRow = value.Y < 0 ? 0 : value.Y > model.Count - 1
? Math.Max (model.Count - 1, 0) : value.Y;
SetNeedsDisplay ();
Adjust ();
}
}
/// <summary>
/// Start column position of the selected text.
/// </summary>
public int SelectionStartColumn {
get => selectionStartColumn;
set {
var line = model.GetLine (currentRow);
selectionStartColumn = value < 0 ? 0 : value > line.Count ? line.Count : value;
selecting = true;
SetNeedsDisplay ();
Adjust ();
}
}
/// <summary>
/// Start row position of the selected text.
/// </summary>
public int SelectionStartRow {
get => selectionStartRow;
set {
selectionStartRow = value < 0 ? 0 : value > model.Count - 1
? Math.Max (model.Count - 1, 0) : value;
selecting = true;
SetNeedsDisplay ();
Adjust ();
}
}
/// <summary>
/// The selected text.
/// </summary>
public ustring SelectedText {
get {
if (!selecting || (model.Count == 1 && model.GetLine (0).Count == 0)) {
return ustring.Empty;
}
SetWrapModel ();
var sel = GetRegion ();
UpdateWrapModel ();
Adjust ();
return sel;
}
}
/// <summary>
/// Length of the selected text.
/// </summary>
public int SelectedLength => GetSelectedLength ();
/// <summary>
/// Get or sets the selecting.
/// </summary>
public bool Selecting {
get => selecting;
set => selecting = value;
}
/// <summary>
/// Allows word wrap the to fit the available container width.
/// </summary>
@@ -796,6 +1059,11 @@ namespace Terminal.Gui {
/// </summary>
public int RightOffset { get; set; }
int GetSelectedLength ()
{
return SelectedText.Length;
}
CursorVisibility savedCursorVisibility = CursorVisibility.Default;
void SaveCursorVisibility ()
@@ -884,7 +1152,7 @@ namespace Terminal.Gui {
var col = 0;
if (line.Count > 0) {
retreat = Math.Max (SpecialRune (line [Math.Min (Math.Max (currentColumn - leftColumn - 1, 0), line.Count - 1)])
? 1 : 0, 0);
? 1 : 0, 0);
for (int idx = leftColumn < 0 ? 0 : leftColumn; idx < line.Count; idx++) {
if (idx == currentColumn)
break;
@@ -892,7 +1160,7 @@ namespace Terminal.Gui {
col += cols - 1;
}
}
var ccol = currentColumn - leftColumn - retreat + col;
var ccol = currentColumn - leftColumn + retreat + col;
if (leftColumn <= currentColumn && ccol < Frame.Width
&& topRow <= currentRow && currentRow - topRow < Frame.Height) {
ResetCursorVisibility ();
@@ -921,6 +1189,11 @@ namespace Terminal.Gui {
Driver.SetAttribute (ColorScheme.Focus);
}
void ColorUsed ()
{
Driver.SetAttribute (ColorScheme.HotFocus);
}
bool isReadOnly = false;
/// <summary>
@@ -1050,6 +1323,145 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
}
/// <summary>
/// Select all text.
/// </summary>
public void SelectAll ()
{
if (model.Count == 0) {
return;
}
StartSelecting ();
selectionStartColumn = 0;
selectionStartRow = 0;
currentColumn = model.GetLine (model.Count - 1).Count;
currentRow = model.Count - 1;
SetNeedsDisplay ();
}
/// <summary>
/// Find the next text based on the match case with the option to replace it.
/// </summary>
/// <param name="textToFind">The text to find.</param>
/// <param name="gaveFullTurn"><c>true</c>If all the text was forward searched.<c>false</c>otherwise.</param>
/// <param name="matchCase">The match case setting.</param>
/// <param name="matchWholeWord">The match whole word setting.</param>
/// <param name="textToReplace">The text to replace.</param>
/// <param name="replace"><c>true</c>If is replacing.<c>false</c>otherwise.</param>
/// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
public bool FindNextText (ustring textToFind, out bool gaveFullTurn, bool matchCase = false,
bool matchWholeWord = false, ustring textToReplace = null, bool replace = false)
{
if (model.Count == 0) {
gaveFullTurn = false;
return false;
}
SetWrapModel ();
ResetContinuousFind ();
var foundPos = model.FindNextText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
return SetFoundText (textToFind, foundPos, textToReplace, replace);
}
/// <summary>
/// Find the previous text based on the match case with the option to replace it.
/// </summary>
/// <param name="textToFind">The text to find.</param>
/// <param name="gaveFullTurn"><c>true</c>If all the text was backward searched.<c>false</c>otherwise.</param>
/// <param name="matchCase">The match case setting.</param>
/// <param name="matchWholeWord">The match whole word setting.</param>
/// <param name="textToReplace">The text to replace.</param>
/// <param name="replace"><c>true</c>If the text was found.<c>false</c>otherwise.</param>
/// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
public bool FindPreviousText (ustring textToFind, out bool gaveFullTurn, bool matchCase = false,
bool matchWholeWord = false, ustring textToReplace = null, bool replace = false)
{
if (model.Count == 0) {
gaveFullTurn = false;
return false;
}
SetWrapModel ();
ResetContinuousFind ();
var foundPos = model.FindPreviousText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
return SetFoundText (textToFind, foundPos, textToReplace, replace);
}
/// <summary>
/// Reset the flag to stop continuous find.
/// </summary>
public void FindTextChanged ()
{
continuousFind = false;
}
/// <summary>
/// Replaces all the text based on the match case.
/// </summary>
/// <param name="textToFind">The text to find.</param>
/// <param name="matchCase">The match case setting.</param>
/// <param name="matchWholeWord">The match whole word setting.</param>
/// <param name="textToReplace">The text to replace.</param>
/// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
public bool ReplaceAllText (ustring textToFind, bool matchCase = false, bool matchWholeWord = false,
ustring textToReplace = null)
{
if (isReadOnly || model.Count == 0) {
return false;
}
SetWrapModel ();
ResetContinuousFind ();
var foundPos = model.ReplaceAllText (textToFind, matchCase, matchWholeWord, textToReplace);
return SetFoundText (textToFind, foundPos, textToReplace, false, true);
}
bool SetFoundText (ustring text, (Point current, bool found) foundPos,
ustring textToReplace = null, bool replace = false, bool replaceAll = false)
{
if (foundPos.found) {
StartSelecting ();
selectionStartColumn = foundPos.current.X;
selectionStartRow = foundPos.current.Y;
if (!replaceAll) {
currentColumn = selectionStartColumn + text.RuneCount;
} else {
currentColumn = selectionStartColumn + textToReplace.RuneCount;
}
currentRow = foundPos.current.Y;
if (!isReadOnly && replace) {
Adjust ();
ClearSelectedRegion ();
InsertText (textToReplace);
StartSelecting ();
selectionStartColumn = currentColumn - textToReplace.RuneCount;
} else {
UpdateWrapModel ();
SetNeedsDisplay ();
Adjust ();
}
continuousFind = true;
return foundPos.found;
}
UpdateWrapModel ();
continuousFind = false;
return foundPos.found;
}
void ResetContinuousFind ()
{
if (!continuousFind) {
var col = selecting ? selectionStartColumn : currentColumn;
var row = selecting ? selectionStartRow : currentRow;
model.ResetContinuousFind (new Point (col, row));
}
}
/// <summary>
/// Restore from original model.
/// </summary>
@@ -1088,7 +1500,7 @@ namespace Terminal.Gui {
ColorNormal ();
int bottom = bounds.Bottom;
int right = bounds.Right + 1;
int right = bounds.Right;
for (int row = bounds.Top; row < bottom; row++) {
int textLine = topRow + row;
if (textLine >= model.Count) {
@@ -1111,14 +1523,27 @@ namespace Terminal.Gui {
var cols = Rune.ColumnWidth (rune);
if (lineCol < line.Count && selecting && PointInSelection (idx + leftColumn, row + topRow)) {
ColorSelection ();
} else if (lineCol == currentColumn && textLine == currentRow && !selecting && !Used
&& HasFocus && lineCol < lineRuneCount) {
ColorUsed ();
} else {
ColorNormal ();
}
if (!SpecialRune (rune)) {
AddRune (col, row, rune);
} else {
col++;
}
col = TextModel.SetCol (col, bounds.Right, cols);
if (idx + 1 < lineRuneCount && col + Rune.ColumnWidth (line [idx + 1]) > right) {
break;
} else if (idx == lineRuneCount - 1) {
ColorNormal ();
for (int i = col; i < right; i++) {
Driver.AddRune (' ');
}
}
}
}
PositionCursor ();
@@ -1156,9 +1581,21 @@ namespace Terminal.Gui {
void Insert (Rune rune)
{
var line = GetCurrentLine ();
line.Insert (Math.Min (currentColumn, line.Count), rune);
if (Used) {
line.Insert (Math.Min (currentColumn, line.Count), rune);
} else {
if (currentColumn < line.Count) {
line.RemoveAt (currentColumn);
}
line.Insert (Math.Min (currentColumn, line.Count), rune);
}
if (wordWrap) {
wrapNeeded = wrapManager.Insert (currentRow, currentColumn, rune);
if (Used) {
wrapNeeded = wrapManager.Insert (currentRow, currentColumn, rune);
} else {
wrapNeeded = wrapManager.RemoveAt (currentRow, currentColumn);
wrapNeeded = wrapManager.Insert (currentRow, currentColumn, rune);
}
if (wrapNeeded) {
SetNeedsDisplay ();
}
@@ -1211,7 +1648,7 @@ namespace Terminal.Gui {
if (wordWrap) {
SetNeedsDisplay ();
} else {
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, currentRow - topRow + 1));
SetNeedsDisplay (new Rect (0, currentRow - topRow, Frame.Width, Math.Max (currentRow - topRow + 1, 0)));
}
return;
}
@@ -1348,9 +1785,35 @@ namespace Terminal.Gui {
case Key.P | Key.CtrlMask:
case Key.CursorUp:
lastWasKill = false;
continuousFind = false;
break;
case Key.K | Key.CtrlMask:
break;
case Key.F | Key.CtrlMask:
case Key.B | Key.CtrlMask:
case (Key)((int)'B' + Key.AltMask):
case Key.A | Key.CtrlMask:
case Key.E | Key.CtrlMask:
case Key.CursorRight:
case Key.CursorLeft:
case Key.CursorRight | Key.CtrlMask:
case Key.CursorLeft | Key.CtrlMask:
case Key.CursorRight | Key.ShiftMask:
case Key.CursorLeft | Key.ShiftMask:
case Key.CursorRight | Key.CtrlMask | Key.ShiftMask:
case Key.CursorLeft | Key.CtrlMask | Key.ShiftMask:
case Key.Home:
case Key.Home | Key.CtrlMask:
case Key.Home | Key.ShiftMask:
case Key.Home | Key.CtrlMask | Key.ShiftMask:
case Key.End:
case Key.End | Key.CtrlMask:
case Key.End | Key.ShiftMask:
case Key.End | Key.CtrlMask | Key.ShiftMask:
lastWasKill = false;
columnTrack = -1;
continuousFind = false;
break;
default:
lastWasKill = false;
columnTrack = -1;
@@ -1371,7 +1834,9 @@ namespace Terminal.Gui {
if (currentRow < model.Count) {
if (columnTrack == -1)
columnTrack = currentColumn;
currentRow = (currentRow + nPageDnShift) > model.Count ? model.Count : currentRow + nPageDnShift;
currentRow = (currentRow + nPageDnShift) > model.Count
? model.Count > 0 ? model.Count - 1 : 0
: currentRow + nPageDnShift;
if (topRow < currentRow - nPageDnShift) {
topRow = currentRow >= model.Count ? currentRow - nPageDnShift : topRow + nPageDnShift;
SetNeedsDisplay ();
@@ -1478,7 +1943,7 @@ namespace Terminal.Gui {
if (isReadOnly)
break;
if (selecting) {
Cut ();
ClearSelectedRegion ();
return true;
}
if (currentColumn > 0) {
@@ -1533,7 +1998,7 @@ namespace Terminal.Gui {
if (isReadOnly)
break;
if (selecting) {
Cut ();
ClearSelectedRegion ();
return true;
}
currentLine = GetCurrentLine ();
@@ -1733,6 +2198,15 @@ namespace Terminal.Gui {
MoveHome ();
break;
case Key.T | Key.CtrlMask:
SelectAll ();
break;
case Key.InsertChar:
Used = !Used;
SetNeedsDisplay ();
break;
default:
// Ignore control characters and other special keys
if (kb.Key < Key.Space || kb.Key > Key.CharMask)
@@ -1741,13 +2215,18 @@ namespace Terminal.Gui {
if (isReadOnly)
return true;
if (selecting) {
Cut ();
ClearSelectedRegion ();
}
Insert ((uint)kb.Key);
currentColumn++;
if (currentColumn >= leftColumn + Frame.Width) {
leftColumn++;
SetNeedsDisplay ();
if (Used) {
Insert ((uint)kb.Key);
currentColumn++;
if (currentColumn >= leftColumn + Frame.Width) {
leftColumn++;
SetNeedsDisplay ();
}
} else {
Insert ((uint)kb.Key);
currentColumn++;
}
break;
}
@@ -1838,6 +2317,17 @@ namespace Terminal.Gui {
selecting = false;
}
void ClearSelectedRegion ()
{
SetWrapModel ();
if (!isReadOnly) {
ClearRegion ();
}
UpdateWrapModel ();
selecting = false;
DoNeededAction ();
}
void MoveUp ()
{
if (currentRow > 0) {
@@ -1895,7 +2385,11 @@ namespace Terminal.Gui {
Rune RuneAt (int col, int row)
{
var line = model.GetLine (row);
return line [col > line.Count - 1 ? line.Count - 1 : col];
if (line.Count > 0) {
return line [col > line.Count - 1 ? line.Count - 1 : col];
} else {
return 0;
}
}
/// <summary>
@@ -1927,6 +2421,9 @@ namespace Terminal.Gui {
if (col + 1 < line.Count) {
col++;
rune = line [col];
if (col + 1 == line.Count) {
col++;
}
return true;
}
while (row + 1 < model.Count) {
@@ -1975,27 +2472,45 @@ namespace Terminal.Gui {
try {
var rune = RuneAt (col, row);
var srow = row;
if (Rune.IsPunctuation (rune) || Rune.IsWhiteSpace (rune)) {
while (MoveNext (ref col, ref row, out rune)) {
if (Rune.IsLetterOrDigit (rune))
break;
}
if (row != fromRow && Rune.IsLetterOrDigit (rune)) {
return (col, row);
}
while (MoveNext (ref col, ref row, out rune)) {
if (!Rune.IsLetterOrDigit (rune))
break;
}
} else {
while (MoveNext (ref col, ref row, out rune)) {
if (!Rune.IsLetterOrDigit (rune))
break;
void ProcMoveNext (ref int nCol, ref int nRow, Rune nRune)
{
if (Rune.IsSymbol (nRune) || Rune.IsWhiteSpace (nRune)) {
while (MoveNext (ref nCol, ref nRow, out nRune)) {
if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune))
return;
}
if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune))) {
return;
}
while (MoveNext (ref nCol, ref nRow, out nRune)) {
if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune))
break;
}
} else {
if (!MoveNext (ref nCol, ref nRow, out nRune)) {
return;
}
var line = model.GetLine (fromRow);
if ((nRow != fromRow && fromCol < line.Count)
|| (nRow == fromRow && nCol == line.Count - 1)) {
nCol = line.Count;
nRow = fromRow;
return;
} else if (nRow != fromRow && fromCol == line.Count) {
line = model.GetLine (nRow);
if (Rune.IsLetterOrDigit (line [nCol]) || Rune.IsPunctuation (line [nCol])) {
return;
}
}
ProcMoveNext (ref nCol, ref nRow, nRune);
}
}
ProcMoveNext (ref col, ref row, rune);
if (fromCol != col || fromRow != row)
return (col + 1, row);
return (col, row);
return null;
} catch (Exception) {
return null;
@@ -2011,36 +2526,54 @@ namespace Terminal.Gui {
var row = fromRow;
try {
var rune = RuneAt (col, row);
int lastValidCol = Rune.IsLetterOrDigit (rune) || Rune.IsPunctuation (rune) ? col : -1;
if (Rune.IsPunctuation (rune) || Rune.IsSymbol (rune) || Rune.IsWhiteSpace (rune)) {
while (MovePrev (ref col, ref row, out rune)) {
if (Rune.IsLetterOrDigit (rune))
break;
}
int lastValidCol = -1;
while (MovePrev (ref col, ref row, out rune)) {
if (col == 0 && Rune.IsLetterOrDigit (rune)) {
return (col, row);
} else if (col == 0 && !Rune.IsLetterOrDigit (rune) && lastValidCol > -1) {
col = lastValidCol;
return (col, row);
void ProcMovePrev (ref int nCol, ref int nRow, Rune nRune)
{
if (Rune.IsSymbol (nRune) || Rune.IsWhiteSpace (nRune)) {
while (MovePrev (ref nCol, ref nRow, out nRune)) {
if (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune)) {
lastValidCol = nCol;
break;
}
}
if (!Rune.IsLetterOrDigit (rune)) {
break;
if (nRow != fromRow && (Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune))) {
return;
}
lastValidCol = Rune.IsLetterOrDigit (rune) ? col : -1;
}
} else {
while (MovePrev (ref col, ref row, out rune)) {
if (!Rune.IsLetterOrDigit (rune))
break;
while (MovePrev (ref nCol, ref nRow, out nRune)) {
if (!Rune.IsLetterOrDigit (nRune) && !Rune.IsPunctuation (nRune))
break;
lastValidCol = nCol;
}
if (lastValidCol > -1) {
nCol = lastValidCol;
}
} else {
if (!MovePrev (ref nCol, ref nRow, out nRune)) {
return;
}
var line = model.GetLine (nRow);
if (nCol == 0 && nRow == fromRow && (Rune.IsLetterOrDigit (line [0]) || Rune.IsPunctuation (line [0]))) {
return;
}
lastValidCol = Rune.IsLetterOrDigit (nRune) || Rune.IsPunctuation (nRune) ? nCol : lastValidCol;
if (lastValidCol > -1 && (Rune.IsSymbol (nRune) || Rune.IsWhiteSpace (nRune))) {
nCol = lastValidCol;
return;
}
if (fromRow != nRow) {
nCol = line.Count;
return;
}
ProcMovePrev (ref nCol, ref nRow, nRune);
}
}
if (fromCol != col && fromRow == row) {
return (col == 0 ? col : col + 1, row);
} else if (fromCol != col && fromRow != row) {
return (col + 1, row);
}
ProcMovePrev (ref col, ref row, rune);
if (fromCol != col || fromRow != row)
return (col, row);
return null;
} catch (Exception) {
return null;
@@ -2054,7 +2587,9 @@ namespace Terminal.Gui {
&& !ev.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition)
&& !ev.Flags.HasFlag (MouseFlags.Button1Released)
&& !ev.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ButtonShift)
&& !ev.Flags.HasFlag (MouseFlags.WheeledDown) && !ev.Flags.HasFlag (MouseFlags.WheeledUp)) {
&& !ev.Flags.HasFlag (MouseFlags.WheeledDown) && !ev.Flags.HasFlag (MouseFlags.WheeledUp)
&& !ev.Flags.HasFlag (MouseFlags.Button1DoubleClicked)
&& !ev.Flags.HasFlag (MouseFlags.Button1DoubleClicked | MouseFlags.ButtonShift)) {
return false;
}
@@ -2066,6 +2601,8 @@ namespace Terminal.Gui {
SetFocus ();
}
continuousFind = false;
if (ev.Flags == MouseFlags.Button1Clicked) {
if (shiftSelecting) {
shiftSelecting = false;
@@ -2143,6 +2680,40 @@ namespace Terminal.Gui {
}
} else if (ev.Flags.HasFlag (MouseFlags.Button1Released)) {
Application.UngrabMouse ();
} else if (ev.Flags.HasFlag (MouseFlags.Button1DoubleClicked)) {
if (ev.Flags.HasFlag (MouseFlags.ButtonShift)) {
if (!selecting) {
StartSelecting ();
}
} else if (selecting) {
StopSelecting ();
}
ProcessMouseClick (ev, out List<Rune> line);
(int col, int row)? newPos = null;
if (currentColumn > 0 && line [currentColumn - 1] != ' ') {
newPos = WordBackward (currentColumn, currentRow);
if (newPos.HasValue) {
currentColumn = newPos.Value.col;
currentRow = newPos.Value.row;
}
}
if (!selecting) {
StartSelecting ();
}
if (currentRow < selectionStartRow || currentRow == selectionStartRow && currentColumn < selectionStartColumn) {
if (currentColumn > 0 && line [currentColumn - 1] != ' ') {
newPos = WordBackward (currentColumn, currentRow);
}
} else {
newPos = WordForward (currentColumn, currentRow);
}
if (newPos != null && newPos.HasValue) {
currentColumn = newPos.Value.col;
currentRow = newPos.Value.row;
}
PositionCursor ();
lastWasKill = false;
columnTrack = currentColumn;
}
return true;

View File

@@ -93,13 +93,8 @@ namespace UICatalog {
};
frame.Add (numButtonsEdit);
void Top_Loaded ()
{
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit)
+ Dim.Height (numButtonsEdit) + 2;
Top.Loaded -= Top_Loaded;
}
Top.Loaded += Top_Loaded;
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit)
+ Dim.Height (numButtonsEdit) + 2;
label = new Label ("Button Pressed:") {
X = Pos.Center (),

View File

@@ -15,6 +15,11 @@ namespace UICatalog {
private bool _saved = true;
private ScrollBarView _scrollBar;
private byte [] _originalText;
private string _textToFind;
private string _textToReplace;
private bool _matchCase;
private bool _matchWholeWord;
Window winDialog;
public override void Init (Toplevel top, ColorScheme colorScheme)
{
@@ -36,7 +41,17 @@ namespace UICatalog {
new MenuBarItem ("_Edit", new MenuItem [] {
new MenuItem ("_Copy", "", () => Copy(),null,null, Key.CtrlMask | Key.C),
new MenuItem ("C_ut", "", () => Cut(),null,null, Key.CtrlMask | Key.W),
new MenuItem ("_Paste", "", () => Paste(),null,null, Key.CtrlMask | Key.Y)
new MenuItem ("_Paste", "", () => Paste(),null,null, Key.CtrlMask | Key.Y),
null,
new MenuItem ("_Find", "", () => Find(),null,null, Key.CtrlMask | Key.S),
new MenuItem ("Find _Next", "", () => FindNext(),null,null, Key.CtrlMask | Key.ShiftMask | Key.S),
new MenuItem ("Find P_revious", "", () => FindPrevious(),null,null, Key.CtrlMask | Key.ShiftMask | Key.AltMask | Key.S),
new MenuItem ("_Replace", "", () => Replace(),null,null, Key.CtrlMask | Key.R),
new MenuItem ("Replace Ne_xt", "", () => ReplaceNext(),null,null, Key.CtrlMask | Key.ShiftMask | Key.R),
new MenuItem ("Replace Pre_vious", "", () => ReplacePrevious(),null,null, Key.CtrlMask | Key.ShiftMask | Key.AltMask | Key.R),
new MenuItem ("Replace _All", "", () => ReplaceAll(),null,null, Key.CtrlMask | Key.ShiftMask | Key.AltMask | Key.A),
null,
new MenuItem ("_Select All", "", () => SelectAll(),null,null, Key.CtrlMask | Key.T)
}),
new MenuBarItem ("_ScrollBarView", CreateKeepChecked ()),
new MenuBarItem ("_Cursor", new MenuItem [] {
@@ -115,6 +130,20 @@ namespace UICatalog {
_scrollBar.LayoutSubviews ();
_scrollBar.Refresh ();
};
Win.KeyPress += (e) => {
if (winDialog != null && (e.KeyEvent.Key == Key.Esc
|| e.KeyEvent.Key.HasFlag (Key.Q | Key.CtrlMask))) {
DisposeWinDialog ();
}
};
}
private void DisposeWinDialog ()
{
winDialog.Dispose ();
Win.Remove (winDialog);
winDialog = null;
}
public override void Setup ()
@@ -166,6 +195,91 @@ namespace UICatalog {
}
}
private void SelectAll ()
{
_textView.SelectAll ();
}
private void Find ()
{
CreateFindReplace ();
}
private void FindNext ()
{
ContinueFind ();
}
private void FindPrevious ()
{
ContinueFind (false);
}
private void ContinueFind (bool next = true, bool replace = false)
{
if (!replace && string.IsNullOrEmpty (_textToFind)) {
Find ();
return;
} else if (replace && (string.IsNullOrEmpty (_textToFind)
|| (winDialog == null && string.IsNullOrEmpty (_textToReplace)))) {
Replace ();
return;
}
bool found;
bool gaveFullTurn;
if (next) {
if (!replace) {
found = _textView.FindNextText (_textToFind, out gaveFullTurn, _matchCase, _matchWholeWord);
} else {
found = _textView.FindNextText (_textToFind, out gaveFullTurn, _matchCase, _matchWholeWord,
_textToReplace, true);
}
} else {
if (!replace) {
found = _textView.FindPreviousText (_textToFind, out gaveFullTurn, _matchCase, _matchWholeWord);
} else {
found = _textView.FindPreviousText (_textToFind, out gaveFullTurn, _matchCase, _matchWholeWord,
_textToReplace, true);
}
}
if (!found) {
MessageBox.Query ("Find", $"The following specified text was not found: '{_textToFind}'", "Ok");
} else if (gaveFullTurn) {
MessageBox.Query ("Find", $"No more occurrences were found for the following specified text: '{_textToFind}'", "Ok");
}
}
private void Replace ()
{
CreateFindReplace (false);
}
private void ReplaceNext ()
{
ContinueFind (true, true);
}
private void ReplacePrevious ()
{
ContinueFind (false, true);
}
private void ReplaceAll ()
{
if (string.IsNullOrEmpty (_textToFind) || (string.IsNullOrEmpty (_textToReplace) && winDialog == null)) {
Replace ();
return;
}
if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace)) {
MessageBox.Query ("Replace All", $"All occurrences were replaced for the following specified text: '{_textToReplace}'", "Ok");
} else {
MessageBox.Query ("Replace All", $"None of the following specified text was found: '{_textToFind}'", "Ok");
}
}
private void SetCursor (CursorVisibility visibility)
{
_textView.DesiredCursorVisibility = visibility;
@@ -307,6 +421,259 @@ namespace UICatalog {
return new MenuItem [] { item };
}
private void CreateFindReplace (bool isFind = true)
{
winDialog = new Window (isFind ? "Find" : "Replace") {
X = Win.Bounds.Width / 2 - 30,
Y = Win.Bounds.Height / 2 - 10,
ColorScheme = Colors.Menu
};
var tabView = new TabView () {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
tabView.AddTab (new Tab ("Find", FindTab ()), isFind);
var replace = ReplaceTab ();
tabView.AddTab (new Tab ("Replace", replace), !isFind);
tabView.SelectedTabChanged += (s, e) => tabView.SelectedTab.View.FocusFirst ();
winDialog.Add (tabView);
Win.Add (winDialog);
winDialog.Width = replace.Width + 4;
winDialog.Height = replace.Height + 4;
winDialog.SuperView.BringSubviewToFront (winDialog);
winDialog.SetFocus ();
}
private void SetFindText ()
{
_textToFind = !_textView.SelectedText.IsEmpty
? _textView.SelectedText.ToString ()
: string.IsNullOrEmpty (_textToFind) ? "" : _textToFind;
_textToReplace = string.IsNullOrEmpty (_textToReplace) ? "" : _textToReplace;
}
private View FindTab ()
{
var d = new View () {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
d.DrawContent += (e) => {
foreach (var v in d.Subviews) {
v.SetNeedsDisplay ();
}
};
var lblWidth = "Replace:".Length;
var label = new Label (0, 1, "Find:") {
Width = lblWidth,
TextAlignment = TextAlignment.Right,
LayoutStyle = LayoutStyle.Computed
};
d.Add (label);
SetFindText ();
var txtToFind = new TextField (_textToFind) {
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 20
};
txtToFind.Enter += (_) => txtToFind.Text = _textToFind;
d.Add (txtToFind);
var btnFindNext = new Button ("Find _Next") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (label),
Width = 20,
CanFocus = !txtToFind.Text.IsEmpty,
TextAlignment = TextAlignment.Centered,
IsDefault = true
};
btnFindNext.Clicked += () => FindNext ();
d.Add (btnFindNext);
var btnFindPrevious = new Button ("Find _Previous") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (btnFindNext) + 1,
Width = 20,
CanFocus = !txtToFind.Text.IsEmpty,
TextAlignment = TextAlignment.Centered
};
btnFindPrevious.Clicked += () => FindPrevious ();
d.Add (btnFindPrevious);
txtToFind.TextChanged += (e) => {
_textToFind = txtToFind.Text.ToString ();
_textView.FindTextChanged ();
btnFindNext.CanFocus = !txtToFind.Text.IsEmpty;
btnFindPrevious.CanFocus = !txtToFind.Text.IsEmpty;
};
var btnCancel = new Button ("Cancel") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (btnFindPrevious) + 2,
Width = 20,
TextAlignment = TextAlignment.Centered
};
btnCancel.Clicked += () => {
DisposeWinDialog ();
};
d.Add (btnCancel);
var ckbMatchCase = new CheckBox ("Match c_ase") {
X = 0,
Y = Pos.Top (txtToFind) + 2,
Checked = _matchCase
};
ckbMatchCase.Toggled += (e) => _matchCase = ckbMatchCase.Checked;
d.Add (ckbMatchCase);
var ckbMatchWholeWord = new CheckBox ("Match _whole word") {
X = 0,
Y = Pos.Top (ckbMatchCase) + 1,
Checked = _matchWholeWord
};
ckbMatchWholeWord.Toggled += (e) => _matchWholeWord = ckbMatchWholeWord.Checked;
d.Add (ckbMatchWholeWord);
d.Width = label.Width + txtToFind.Width + btnFindNext.Width + 2;
d.Height = btnFindNext.Height + btnFindPrevious.Height + btnCancel.Height + 4;
return d;
}
private View ReplaceTab ()
{
var d = new View () {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
d.DrawContent += (e) => {
foreach (var v in d.Subviews) {
v.SetNeedsDisplay ();
}
};
var lblWidth = "Replace:".Length;
var label = new Label (0, 1, "Find:") {
Width = lblWidth,
TextAlignment = TextAlignment.Right,
LayoutStyle = LayoutStyle.Computed
};
d.Add (label);
SetFindText ();
var txtToFind = new TextField (_textToFind) {
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 20
};
txtToFind.Enter += (_) => txtToFind.Text = _textToFind;
d.Add (txtToFind);
var btnFindNext = new Button ("Replace _Next") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (label),
Width = 20,
CanFocus = !txtToFind.Text.IsEmpty,
TextAlignment = TextAlignment.Centered,
IsDefault = true
};
btnFindNext.Clicked += () => ReplaceNext ();
d.Add (btnFindNext);
label = new Label ("Replace:") {
X = Pos.Left (label),
Y = Pos.Top (label) + 1,
Width = lblWidth,
TextAlignment = TextAlignment.Right
};
d.Add (label);
SetFindText ();
var txtToReplace = new TextField (_textToReplace) {
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = 20
};
txtToReplace.TextChanged += (e) => _textToReplace = txtToReplace.Text.ToString ();
d.Add (txtToReplace);
var btnFindPrevious = new Button ("Replace _Previous") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (btnFindNext) + 1,
Width = 20,
CanFocus = !txtToFind.Text.IsEmpty,
TextAlignment = TextAlignment.Centered
};
btnFindPrevious.Clicked += () => ReplacePrevious ();
d.Add (btnFindPrevious);
var btnReplaceAll = new Button ("Replace _All") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (btnFindPrevious) + 1,
Width = 20,
CanFocus = !txtToFind.Text.IsEmpty,
TextAlignment = TextAlignment.Centered
};
btnReplaceAll.Clicked += () => ReplaceAll ();
d.Add (btnReplaceAll);
txtToFind.TextChanged += (e) => {
_textToFind = txtToFind.Text.ToString ();
_textView.FindTextChanged ();
btnFindNext.CanFocus = !txtToFind.Text.IsEmpty;
btnFindPrevious.CanFocus = !txtToFind.Text.IsEmpty;
btnReplaceAll.CanFocus = !txtToFind.Text.IsEmpty;
};
var btnCancel = new Button ("Cancel") {
X = Pos.Right (txtToFind) + 1,
Y = Pos.Top (btnReplaceAll) + 1,
Width = 20,
TextAlignment = TextAlignment.Centered
};
btnCancel.Clicked += () => {
DisposeWinDialog ();
};
d.Add (btnCancel);
var ckbMatchCase = new CheckBox ("Match c_ase") {
X = 0,
Y = Pos.Top (txtToFind) + 2,
Checked = _matchCase
};
ckbMatchCase.Toggled += (e) => _matchCase = ckbMatchCase.Checked;
d.Add (ckbMatchCase);
var ckbMatchWholeWord = new CheckBox ("Match _whole word") {
X = 0,
Y = Pos.Top (ckbMatchCase) + 1,
Checked = _matchWholeWord
};
ckbMatchWholeWord.Toggled += (e) => _matchWholeWord = ckbMatchWholeWord.Checked;
d.Add (ckbMatchWholeWord);
d.Width = lblWidth + txtToFind.Width + btnFindNext.Width + 2;
d.Height = btnFindNext.Height + btnFindPrevious.Height + btnCancel.Height + 4;
return d;
}
public override void Run ()
{
base.Run ();

View File

@@ -140,13 +140,8 @@ namespace UICatalog {
};
frame.Add (styleRadioGroup);
void Top_Loaded ()
{
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + Dim.Height (messageEdit)
+ Dim.Height (numButtonsEdit) + Dim.Height (defaultButtonEdit) + Dim.Height (styleRadioGroup) + 2;
Top.Loaded -= Top_Loaded;
}
Top.Loaded += Top_Loaded;
frame.Height = Dim.Height (widthEdit) + Dim.Height (heightEdit) + Dim.Height (titleEdit) + Dim.Height (messageEdit)
+ Dim.Height (numButtonsEdit) + Dim.Height(defaultButtonEdit) + Dim.Height (styleRadioGroup) + 2;
label = new Label ("Button Pressed:") {
X = Pos.Center (),

View File

@@ -483,6 +483,10 @@ namespace Terminal.Gui {
Assert.Equal (1, v3.Frame.Height); // 1 because is Dim.DimAbsolute
v4.Text = "Button4";
v4.AutoSize = false;
Assert.Equal ("Dim.Absolute(50)", v4.Width.ToString ());
Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ());
v4.AutoSize = true;
Assert.Equal ("Dim.Absolute(11)", v4.Width.ToString ());
Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ());
Assert.Equal (11, v4.Frame.Width); // 11 is the text length and because is Dim.DimAbsolute
@@ -507,6 +511,84 @@ namespace Terminal.Gui {
Application.Shutdown ();
}
// TODO: Test operators
// DONE: Test operators
[Fact]
public void DimCombine_Do_Not_Throws ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
var w = new Window ("w") {
Width = Dim.Width (t) - 2,
Height = Dim.Height (t) - 2
};
var f = new FrameView ("f");
var v1 = new View ("v1") {
Width = Dim.Width (w) - 2,
Height = Dim.Height (w) - 2
};
var v2 = new View ("v2") {
Width = Dim.Width (v1) - 2,
Height = Dim.Height (v1) - 2
};
f.Add (v1, v2);
w.Add (f);
t.Add (w);
f.Width = Dim.Width (t) - Dim.Width (v2);
f.Height = Dim.Height (t) - Dim.Height (v2);
t.Ready += () => {
Assert.Equal (80, t.Frame.Width);
Assert.Equal (25, t.Frame.Height);
Assert.Equal (78, w.Frame.Width);
Assert.Equal (23, w.Frame.Height);
Assert.Equal (6, f.Frame.Width);
Assert.Equal (6, f.Frame.Height);
Assert.Equal (76, v1.Frame.Width);
Assert.Equal (21, v1.Frame.Height);
Assert.Equal (74, v2.Frame.Width);
Assert.Equal (19, v2.Frame.Height);
};
Application.Iteration += () => Application.RequestStop ();
Application.Run ();
Application.Shutdown ();
}
[Fact]
public void PosCombine_Will_Throws ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
var w = new Window ("w") {
Width = Dim.Width (t) - 2,
Height = Dim.Height (t) - 2
};
var f = new FrameView ("f");
var v1 = new View ("v1") {
Width = Dim.Width (w) - 2,
Height = Dim.Height (w) - 2
};
var v2 = new View ("v2") {
Width = Dim.Width (v1) - 2,
Height = Dim.Height (v1) - 2
};
f.Add (v1); // v2 not added
w.Add (f);
t.Add (w);
f.Width = Dim.Width (t) - Dim.Width (v2);
f.Height = Dim.Height (t) - Dim.Height (v2);
Assert.Throws<InvalidOperationException> (() => Application.Run ());
Application.Shutdown ();
}
}
}

View File

@@ -79,7 +79,7 @@ namespace Terminal.Gui {
Assert.Equal (pos1, pos2);
}
[Fact]
[Fact]
public void SetSide_Null_Throws ()
{
var pos = Pos.Left (null);
@@ -91,7 +91,7 @@ namespace Terminal.Gui {
pos = Pos.Top (null);
Assert.Throws<NullReferenceException> (() => pos.ToString ());
pos = Pos.Y(null);
pos = Pos.Y (null);
Assert.Throws<NullReferenceException> (() => pos.ToString ());
pos = Pos.Bottom (null);
@@ -112,7 +112,7 @@ namespace Terminal.Gui {
string side; // used in format string
var testRect = Rect.Empty;
var testInt = 0;
Pos pos;
Pos pos;
// Pos.Left
side = "x";
@@ -456,9 +456,85 @@ namespace Terminal.Gui {
Application.Shutdown ();
}
// TODO: Test PosCombine
// DONE: Test PosCombine
// DONE: Test operators
[Fact]
public void PosCombine_Do_Not_Throws ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
// TODO: Test operators
var w = new Window ("w") {
X = Pos.Left (t) + 2,
Y = Pos.Top (t) + 2
};
var f = new FrameView ("f");
var v1 = new View ("v1") {
X = Pos.Left (w) + 2,
Y = Pos.Top (w) + 2
};
var v2 = new View ("v2") {
X = Pos.Left (v1) + 2,
Y = Pos.Top (v1) + 2
};
f.Add (v1, v2);
w.Add (f);
t.Add (w);
f.X = Pos.X (t) + Pos.X (v2) - Pos.X (v1);
f.Y = Pos.Y (t) + Pos.Y (v2) - Pos.Y (v1);
t.Ready += () => {
Assert.Equal (0, t.Frame.X);
Assert.Equal (0, t.Frame.Y);
Assert.Equal (2, w.Frame.X);
Assert.Equal (2, w.Frame.Y);
Assert.Equal (2, f.Frame.X);
Assert.Equal (2, f.Frame.Y);
Assert.Equal (4, v1.Frame.X);
Assert.Equal (4, v1.Frame.Y);
Assert.Equal (6, v2.Frame.X);
Assert.Equal (6, v2.Frame.Y);
};
Application.Iteration += () => Application.RequestStop ();
Application.Run ();
Application.Shutdown ();
}
[Fact]
public void PosCombine_Will_Throws ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
var w = new Window ("w") {
X = Pos.Left (t) + 2,
Y = Pos.Top (t) + 2
};
var f = new FrameView ("f");
var v1 = new View ("v1") {
X = Pos.Left (w) + 2,
Y = Pos.Top (w) + 2
};
var v2 = new View ("v2") {
X = Pos.Left (v1) + 2,
Y = Pos.Top (v1) + 2
};
f.Add (v1); // v2 not added
w.Add (f);
t.Add (w);
f.X = Pos.X (v2) - Pos.X (v1);
f.Y = Pos.Y (v2) - Pos.Y (v1);
Assert.Throws<InvalidOperationException> (() => Application.Run ());
Application.Shutdown ();
}
}
}

797
UnitTests/TextViewTests.cs Normal file
View File

@@ -0,0 +1,797 @@
using Xunit;
namespace Terminal.Gui {
public class TextViewTests {
private TextView _textView;
public TextViewTests ()
{
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
// 1 2 3
// 01234567890123456789012345678901=32 (Length)
var txt = "TAB to jump between text fields.";
var buff = new byte [txt.Length];
for (int i = 0; i < txt.Length; i++) {
buff [i] = (byte)txt [i];
}
var ms = new System.IO.MemoryStream (buff).ToArray ();
_textView = new TextView () { Width = 30, Height = 10 };
_textView.Text = ms;
}
[Fact]
public void Changing_Selection_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
{
_textView.SelectionStartColumn = 2;
_textView.SelectionStartRow = 0;
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (2, _textView.SelectedLength);
Assert.Equal ("TA", _textView.SelectedText);
_textView.CursorPosition = new Point (20, 0);
Assert.Equal (2, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (18, _textView.SelectedLength);
Assert.Equal ("B to jump between ", _textView.SelectedText);
}
[Fact]
public void Selection_With_Value_Less_Than_Zero_Changes_To_Zero ()
{
_textView.SelectionStartColumn = -2;
_textView.SelectionStartRow = -2;
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void Selection_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
{
_textView.CursorPosition = new Point (2, 0);
_textView.SelectionStartColumn = 33;
_textView.SelectionStartRow = 1;
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (30, _textView.SelectedLength);
Assert.Equal ("B to jump between text fields.", _textView.SelectedText);
}
[Fact]
public void Selection_With_Empty_Text ()
{
_textView = new TextView ();
_textView.CursorPosition = new Point (2, 0);
_textView.SelectionStartColumn = 33;
_textView.SelectionStartRow = 1;
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void Selection_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
{
_textView.CursorPosition = new Point (33, 2);
_textView.SelectionStartColumn = 33;
_textView.SelectionStartRow = 33;
Assert.Equal (32, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
{
_textView.CursorPosition = new Point (-1, -1);
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
{
_textView.CursorPosition = new Point (33, 1);
Assert.Equal (32, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void WordForward_With_No_Selection ()
{
_textView.CursorPosition = new Point (0, 0);
var iteration = 0;
while (_textView.CursorPosition.X < _textView.Text.Length) {
_textView.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (4, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 1:
Assert.Equal (7, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 3:
Assert.Equal (20, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 4:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 5:
Assert.Equal (32, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordBackward_With_No_Selection ()
{
_textView.CursorPosition = new Point (_textView.Text.Length, 0);
var iteration = 0;
while (_textView.CursorPosition.X > 0) {
_textView.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 1:
Assert.Equal (20, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 3:
Assert.Equal (7, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 4:
Assert.Equal (4, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 5:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordForward_With_Selection ()
{
_textView.CursorPosition = new Point (0, 0);
_textView.SelectionStartColumn = 0;
_textView.SelectionStartRow = 0;
var iteration = 0;
while (_textView.CursorPosition.X < _textView.Text.Length) {
_textView.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (4, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (4, _textView.SelectedLength);
Assert.Equal ("TAB ", _textView.SelectedText);
break;
case 1:
Assert.Equal (7, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (7, _textView.SelectedLength);
Assert.Equal ("TAB to ", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (12, _textView.SelectedLength);
Assert.Equal ("TAB to jump ", _textView.SelectedText);
break;
case 3:
Assert.Equal (20, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (20, _textView.SelectedLength);
Assert.Equal ("TAB to jump between ", _textView.SelectedText);
break;
case 4:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (25, _textView.SelectedLength);
Assert.Equal ("TAB to jump between text ", _textView.SelectedText);
break;
case 5:
Assert.Equal (32, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (32, _textView.SelectedLength);
Assert.Equal ("TAB to jump between text fields.", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordBackward_With_Selection ()
{
_textView.CursorPosition = new Point (_textView.Text.Length, 0);
_textView.SelectionStartColumn = _textView.Text.Length;
_textView.SelectionStartRow = 0;
var iteration = 0;
while (_textView.CursorPosition.X > 0) {
_textView.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (7, _textView.SelectedLength);
Assert.Equal ("fields.", _textView.SelectedText);
break;
case 1:
Assert.Equal (20, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (12, _textView.SelectedLength);
Assert.Equal ("text fields.", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (20, _textView.SelectedLength);
Assert.Equal ("between text fields.", _textView.SelectedText);
break;
case 3:
Assert.Equal (7, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (25, _textView.SelectedLength);
Assert.Equal ("jump between text fields.", _textView.SelectedText);
break;
case 4:
Assert.Equal (4, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (28, _textView.SelectedLength);
Assert.Equal ("to jump between text fields.", _textView.SelectedText);
break;
case 5:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (32, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (32, _textView.SelectedLength);
Assert.Equal ("TAB to jump between text fields.", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
{
_textView.CursorPosition = new Point (10, 0);
_textView.SelectionStartColumn = 10;
_textView.SelectionStartRow = 0;
var iteration = 0;
while (_textView.CursorPosition.X < _textView.Text.Length) {
_textView.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (2, _textView.SelectedLength);
Assert.Equal ("p ", _textView.SelectedText);
break;
case 1:
Assert.Equal (20, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (10, _textView.SelectedLength);
Assert.Equal ("p between ", _textView.SelectedText);
break;
case 2:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (15, _textView.SelectedLength);
Assert.Equal ("p between text ", _textView.SelectedText);
break;
case 3:
Assert.Equal (32, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (22, _textView.SelectedLength);
Assert.Equal ("p between text fields.", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
{
_textView.CursorPosition = new Point (10, 0);
_textView.SelectionStartColumn = 10;
_textView.SelectionStartRow = 0;
var iteration = 0;
while (_textView.CursorPosition.X > 0) {
_textView.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (7, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (3, _textView.SelectedLength);
Assert.Equal ("jum", _textView.SelectedText);
break;
case 1:
Assert.Equal (4, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (6, _textView.SelectedLength);
Assert.Equal ("to jum", _textView.SelectedText);
break;
case 2:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (10, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (10, _textView.SelectedLength);
Assert.Equal ("TAB to jum", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
{
// 1 2 3 4 5
// 0123456789012345678901234567890123456789012345678901234=55 (Length)
_textView.Text = "TAB t o jump b etween t ext f ields .";
_textView.CursorPosition = new Point (0, 0);
var iteration = 0;
while (_textView.CursorPosition.X < _textView.Text.Length) {
_textView.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (6, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 1:
Assert.Equal (9, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 2:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 3:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 4:
Assert.Equal (28, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 5:
Assert.Equal (38, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 6:
Assert.Equal (40, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 7:
Assert.Equal (46, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 8:
Assert.Equal (48, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 9:
Assert.Equal (55, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
{
// 1 2 3 4 5
// 0123456789012345678901234567890123456789012345678901234=55 (Length)
_textView.Text = "TAB t o jump b etween t ext f ields .";
_textView.CursorPosition = new Point (_textView.Text.Length, 0);
var iteration = 0;
while (_textView.CursorPosition.X > 0) {
_textView.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask, new KeyModifiers ()));
switch (iteration) {
case 0:
Assert.Equal (54, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 1:
Assert.Equal (48, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 2:
Assert.Equal (46, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 3:
Assert.Equal (40, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 4:
Assert.Equal (38, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 5:
Assert.Equal (28, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 6:
Assert.Equal (25, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 7:
Assert.Equal (12, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 8:
Assert.Equal (9, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 9:
Assert.Equal (6, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
case 10:
Assert.Equal (0, _textView.CursorPosition.X);
Assert.Equal (0, _textView.CursorPosition.Y);
Assert.Equal (0, _textView.SelectionStartColumn);
Assert.Equal (0, _textView.SelectionStartRow);
Assert.Equal (0, _textView.SelectedLength);
Assert.Equal ("", _textView.SelectedText);
break;
}
iteration++;
}
}
[Fact]
public void Copy_Or_Cut_Null_If_No_Selection ()
{
_textView.SelectionStartColumn = 0;
_textView.SelectionStartRow = 0;
_textView.Copy ();
Assert.Equal ("", _textView.SelectedText);
_textView.Cut ();
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
{
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.CursorPosition = new Point (24, 0);
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
_textView.Cut ();
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void Copy_Or_Cut_And_Paste_With_Selection ()
{
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.CursorPosition = new Point (24, 0);
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.Paste ();
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.Cut ();
_textView.Paste ();
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
}
[Fact]
public void Copy_Or_Cut_And_Paste_With_No_Selection ()
{
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.CursorPosition = new Point (24, 0);
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.SelectionStartColumn = 0;
_textView.SelectionStartRow = 0;
Assert.True (_textView.Selecting);
_textView.Selecting = false;
_textView.Paste ();
Assert.Equal ("TAB to jump between texttext fields.", _textView.Text);
_textView.SelectionStartColumn = 24;
_textView.SelectionStartRow = 0;
_textView.Cut ();
Assert.Equal ("", _textView.SelectedText);
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.SelectionStartColumn = 0;
_textView.SelectionStartRow = 0;
Assert.True (_textView.Selecting);
_textView.Selecting = false;
_textView.Paste ();
Assert.Equal ("TAB to jump between texttext fields.", _textView.Text);
}
[Fact]
public void Cut_Not_Allowed_If_ReadOnly_Is_True ()
{
_textView.ReadOnly = true;
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.CursorPosition = new Point (24, 0);
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
_textView.Cut (); // Selecting is set to false after Cut.
Assert.Equal ("", _textView.SelectedText);
_textView.ReadOnly = false;
Assert.False (_textView.Selecting);
_textView.Selecting = true; // Needed to set Selecting to true.
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
_textView.Cut ();
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void Paste_Always_Clear_The_SelectedText ()
{
_textView.SelectionStartColumn = 20;
_textView.SelectionStartRow = 0;
_textView.CursorPosition = new Point (24, 0);
_textView.Copy ();
Assert.Equal ("text", _textView.SelectedText);
_textView.Paste ();
Assert.Equal ("", _textView.SelectedText);
}
[Fact]
public void TextChanged_Event ()
{
_textView.TextChanged += () => {
if (_textView.Text == "changing") {
Assert.Equal ("changing", _textView.Text);
_textView.Text = "changed";
}
};
_textView.Text = "changing";
Assert.Equal ("changed", _textView.Text);
}
[Fact]
public void Used_Is_True_By_Default ()
{
_textView.CursorPosition = new Point (10, 0);
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
Assert.Equal ("TAB to jumup between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
Assert.Equal ("TAB to jumusp between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
Assert.Equal ("TAB to jumusep between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
Assert.Equal ("TAB to jumusedp between text fields.", _textView.Text);
}
[Fact]
public void Used_Is_False ()
{
_textView.Used = false;
_textView.CursorPosition = new Point (10, 0);
Assert.Equal ("TAB to jump between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
Assert.Equal ("TAB to jumu between text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
Assert.Equal ("TAB to jumusbetween text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
Assert.Equal ("TAB to jumuseetween text fields.", _textView.Text);
_textView.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
Assert.Equal ("TAB to jumusedtween text fields.", _textView.Text);
}
}
}