From 2ea03e6b242eb500cdb175b0b2161960902fd3dc Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 17 Nov 2020 17:17:32 +0000 Subject: [PATCH] Fixes #998. Added a cancelable TextChanging event to prevent the TextChanged event being called if the changing is canceled. --- Terminal.Gui/Core/View.cs | 2 +- Terminal.Gui/Views/TextField.cs | 118 +++++++++++++++++++------------- 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index add994704..33b207f10 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1908,7 +1908,7 @@ namespace Terminal.Gui { /// /// Used by to resize the view's with the . - /// Setting to true only work if the and are null or + /// Setting to true only work if the and are null or /// values and doesn't work with layout, /// to avoid breaking the and settings. /// diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index 7d33fbef8..1c0a6f21f 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -40,7 +40,7 @@ namespace Terminal.Gui { /// Changed event, raised when the text has changed. /// /// - /// This event is raised when the changes. + /// This event is raised when the changes. /// /// /// The passed is a 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 t, int start = -1, int end = -1) + // Returns the size and length in a range of the string. + (int size, int length) DisplaySize (List 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 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 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 (); } /// @@ -892,17 +912,21 @@ namespace Terminal.Gui { /// 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 (); }