Explorar el Código

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

BDisp hace 4 años
padre
commit
2ea03e6b24
Se han modificado 2 ficheros con 72 adiciones y 48 borrados
  1. 1 1
      Terminal.Gui/Core/View.cs
  2. 71 47
      Terminal.Gui/Views/TextField.cs

+ 1 - 1
Terminal.Gui/Core/View.cs

@@ -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>

+ 71 - 47
Terminal.Gui/Views/TextField.cs

@@ -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 ();
 		}