Fixes #998. Added a cancelable TextChanging event to prevent the TextChanged event being called if the changing is canceled.

This commit is contained in:
BDisp
2020-11-17 17:17:32 +00:00
parent 945a456ec0
commit 2ea03e6b24
2 changed files with 72 additions and 48 deletions

View File

@@ -1908,7 +1908,7 @@ namespace Terminal.Gui {
/// <summary>
/// Used by <see cref="Text"/> to resize the view's <see cref="Bounds"/> with the <see cref="TextFormatter.Size"/>.
/// Setting <see cref="Auto"/> to true only work if the <see cref="Width"/> and <see cref="Height"/> are null or
/// Setting <see cref="AutoSize"/> to true only work if the <see cref="Width"/> and <see cref="Height"/> are null or
/// <see cref="LayoutStyle.Absolute"/> values and doesn't work with <see cref="LayoutStyle.Computed"/> layout,
/// to avoid breaking the <see cref="Pos"/> and <see cref="Dim"/> settings.
/// </summary>

View File

@@ -40,7 +40,7 @@ namespace Terminal.Gui {
/// Changed event, raised when the text has changed.
/// </summary>
/// <remarks>
/// This event is raised when the <see cref="Text"/> changes.
/// This event is raised when the <see cref="Text"/> changes.
/// </remarks>
/// <remarks>
/// The passed <see cref="EventArgs"/> is a <see cref="ustring"/> containing the old value.
@@ -156,11 +156,10 @@ namespace Terminal.Gui {
}
TextChanged?.Invoke (oldText);
if (point > text.Count)
point = Math.Max (DisplaySize (text, 0) - 1, 0);
if (point > text.Count) {
point = Math.Max (DisplaySize (text, 0).size - 1, 0);
}
// FIXME: this needs to be updated to use Rune.ColumnWidth
//first = point > Frame.Width ? point - Frame.Width : 0;
Adjust ();
SetNeedsDisplay ();
}
@@ -215,11 +214,8 @@ namespace Terminal.Gui {
int width = Frame.Width;
var tcount = text.Count;
var roc = new Attribute (Color.DarkGray, Color.Gray);
for (int idx = 0; idx < tcount; idx++) {
for (int idx = p; idx < tcount; idx++) {
var rune = text [idx];
if (idx < p) {
continue;
}
var cols = Rune.ColumnWidth (rune);
if (idx == point && HasFocus && !Used && SelectedLength == 0 && !ReadOnly) {
Driver.SetAttribute (Colors.Menu.HotFocus);
@@ -232,10 +228,13 @@ namespace Terminal.Gui {
Driver.AddRune ((Rune)(Secret ? '*' : rune));
}
col = SetCol (col, width, cols);
if (idx + 1 < tcount && col + Rune.ColumnWidth (text [idx + 1]) > width) {
break;
}
}
Driver.SetAttribute (ColorScheme.Focus);
for (int i = col; i < Frame.Width; i++) {
for (int i = col; i < width; i++) {
Driver.AddRune (' ');
}
@@ -251,20 +250,26 @@ namespace Terminal.Gui {
return col;
}
// Returns the size in a range of the string.
int DisplaySize (List<Rune> t, int start = -1, int end = -1)
// Returns the size and length in a range of the string.
(int size, int length) DisplaySize (List<Rune> t, int start = -1, int end = -1, bool checkNextRune = true)
{
if (t == null || t.Count == 0) {
return 0;
return (0, 0);
}
int size = 0;
int len = 0;
int tcount = end == -1 ? t.Count : end > t.Count ? t.Count : end;
int i = start == -1 ? 0 : start;
for (; i < tcount; i++) {
var rune = t [i];
size += Rune.ColumnWidth (rune);
len += Rune.RuneLen (rune);
if (checkNextRune && i == tcount - 1 && t.Count > tcount && Rune.ColumnWidth (t [i + 1]) > 1) {
size += Rune.ColumnWidth (t [i + 1]);
len += Rune.RuneLen (t [i + 1]);
}
}
return size;
return (size, len);
}
void Adjust ()
@@ -273,10 +278,9 @@ namespace Terminal.Gui {
if (point < first) {
first = point;
} else if (first + point - (Frame.Width + offB) == 0 ||
DisplaySize (text, first, point) >= Frame.Width + offB) {
DisplaySize (text, first, point).size >= Frame.Width + offB) {
first = Math.Max (CalculateFirst (text, first, point, Frame.Width - 1 + offB), 0);
}
SetNeedsDisplay ();
}
@@ -292,22 +296,29 @@ namespace Terminal.Gui {
int CalculateFirst (List<Rune> t, int start, int end, int width)
{
if (start + end - width >= width) {
return end - width;
if (t == null) {
return 0;
}
(var dSize, _) = DisplaySize (t, start, end);
if (dSize < width) {
return start;
}
int size = 0;
int tcount = end > width || end > t.Count - 1 ? t.Count - 1 : end;
int tcount = end > t.Count - 1 ? t.Count - 1 : end;
int col = 0;
for (int i = tcount; i > -1; i--) {
for (int i = tcount; i > start; i--) {
var rune = t [i];
var s = Rune.ColumnWidth (rune);
size += s;
if (size > width) {
col += size - width;
if (size >= dSize - width) {
col = tcount - i + start;
if (start == 0 || col == start || (point == t.Count && (point - col > width))) {
col++;
}
break;
}
}
return col + start;
return col;
}
void SetText (List<Rune> newText)
@@ -358,6 +369,7 @@ namespace Terminal.Gui {
var oldCursorPos = point;
switch (ShortcutHelper.GetModifiersKey (kb)) {
case Key.Delete:
case Key.DeleteChar:
case Key.D | Key.CtrlMask:
if (ReadOnly)
@@ -375,7 +387,6 @@ namespace Terminal.Gui {
}
break;
case Key.Delete:
case Key.Backspace:
if (ReadOnly)
return true;
@@ -405,7 +416,7 @@ namespace Terminal.Gui {
case Key.End | Key.ShiftMask:
case Key.End | Key.ShiftMask | Key.CtrlMask:
case Key.E | Key.ShiftMask | Key.CtrlMask:
if (point < text.Count) {
if (point <= text.Count) {
int x = point;
point = text.Count;
PrepareSelection (x, point - x);
@@ -438,19 +449,21 @@ namespace Terminal.Gui {
case Key.CursorLeft | Key.ShiftMask | Key.CtrlMask:
case Key.CursorUp | Key.ShiftMask | Key.CtrlMask:
if (point > 0) {
int x = start > -1 ? start : point;
int sbw = WordBackward (point);
if (sbw != -1)
point = sbw;
PrepareSelection (x, sbw - x);
int x = start > -1 && start > point ? start : point;
if (x > 0) {
int sbw = WordBackward (x);
if (sbw != -1)
point = sbw;
PrepareSelection (x, sbw - x);
}
}
break;
case Key.CursorRight | Key.ShiftMask | Key.CtrlMask:
case Key.CursorDown | Key.ShiftMask | Key.CtrlMask:
if (point < text.Count) {
int x = start > -1 ? start : point;
int sfw = WordForward (point);
int x = start > -1 && start > point ? start : point;
int sfw = WordForward (x);
if (sfw != -1)
point = sfw;
PrepareSelection (x, sfw - x);
@@ -816,12 +829,15 @@ namespace Terminal.Gui {
if (SelectedStart > -1) {
SelectedLength = x + direction <= text.Count ? x + direction - SelectedStart : text.Count - SelectedStart;
SetSelectedStartSelectedLength ();
SelectedText = length > 0 ? ustring.Make (text).ToString ().Substring (
start < 0 ? 0 : start, length > text.Count ? text.Count : length) : "";
if (first > start) {
first = start;
if (start > -1) {
SelectedText = length > 0 ? ustring.Make (text).ToString ().Substring (
start < 0 ? 0 : start, length > text.Count ? text.Count : length) : "";
if (first > start) {
first = start;
}
} else {
ClearAllSelection ();
}
point = start + length;
}
Adjust ();
}
@@ -837,6 +853,7 @@ namespace Terminal.Gui {
SelectedLength = 0;
SelectedText = "";
start = 0;
length = 0;
SetNeedsDisplay ();
}
@@ -880,11 +897,14 @@ namespace Terminal.Gui {
ustring actualText = Text;
int selStart = SelectedLength < 0 ? SelectedLength + SelectedStart : SelectedStart;
int selLength = Math.Abs (SelectedLength);
Text = actualText[0, selStart] +
actualText[selStart + selLength, actualText.RuneCount - selLength];
(var _, var len) = DisplaySize (text, 0, selStart, false);
(var _, var len2) = DisplaySize (text, selStart, selStart + selLength, false);
(var _, var len3) = DisplaySize (text, selStart + selLength, actualText.RuneCount, false);
Text = actualText[0, len] +
actualText[len + len2, len + len2 + len3];
ClearAllSelection ();
CursorPosition = selStart >= Text.RuneCount ? Text.RuneCount : selStart;
SetNeedsDisplay ();
point = selStart >= Text.RuneCount ? Text.RuneCount : selStart;
Adjust ();
}
/// <summary>
@@ -892,17 +912,21 @@ namespace Terminal.Gui {
/// </summary>
public virtual void Paste ()
{
if (ReadOnly)
if (ReadOnly) {
return;
}
SetSelectedStartSelectedLength ();
int selStart = start == -1 ? CursorPosition : start;
ustring actualText = Text;
int start = SelectedStart == -1 ? CursorPosition : SelectedStart;
(int _, int len) = DisplaySize (text, 0, selStart, false);
(var _, var len2) = DisplaySize (text, selStart, selStart + length, false);
(var _, var len3) = DisplaySize (text, selStart + length, actualText.RuneCount, false);
ustring cbTxt = Clipboard.Contents ?? "";
Text = actualText[0, start] +
Text = actualText [0, len] +
cbTxt +
actualText[start + SelectedLength, actualText.RuneCount - SelectedLength];
point = start + cbTxt.RuneCount;
SelectedLength = 0;
actualText [len + len2, len + len2 + len3];
point = selStart + cbTxt.RuneCount;
ClearAllSelection ();
SetNeedsDisplay ();
}