Browse Source

Changed Button Text property to use override instead of new. (#1622)

* Changed Button Text property to use override instead of new.

* Fixing HotKey behavior.
BDisp 3 years ago
parent
commit
4281030361
3 changed files with 130 additions and 35 deletions
  1. 2 2
      Terminal.Gui/Core/View.cs
  2. 70 23
      Terminal.Gui/Views/Button.cs
  3. 58 10
      UnitTests/ButtonTests.cs

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

@@ -186,12 +186,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Gets or sets the HotKey defined for this view. A user pressing HotKey on the keyboard while this view has focus will cause the Clicked event to fire.
 		/// </summary>
-		public Key HotKey { get => textFormatter.HotKey; set => textFormatter.HotKey = value; }
+		public virtual Key HotKey { get => textFormatter.HotKey; set => textFormatter.HotKey = value; }
 
 		/// <summary>
 		/// Gets or sets the specifier character for the hotkey (e.g. '_'). Set to '\xffff' to disable hotkey support for this View instance. The default is '\xffff'. 
 		/// </summary>
-		public Rune HotKeySpecifier { get => textFormatter.HotKeySpecifier; set => textFormatter.HotKeySpecifier = value; }
+		public virtual Rune HotKeySpecifier { get => textFormatter.HotKeySpecifier; set => textFormatter.HotKeySpecifier = value; }
 
 		/// <summary>
 		/// This is the global setting that can be used as a global shortcut to invoke an action if provided.

+ 70 - 23
Terminal.Gui/Views/Button.cs

@@ -33,6 +33,7 @@ namespace Terminal.Gui {
 	public class Button : View {
 		ustring text;
 		bool is_default;
+		TextFormatter textFormatter = new TextFormatter ();
 
 		/// <summary>
 		///   Initializes a new instance of <see cref="Button"/> using <see cref="LayoutStyle.Computed"/> layout.
@@ -96,6 +97,8 @@ namespace Terminal.Gui {
 		Rune _rightBracket;
 		Rune _leftDefault;
 		Rune _rightDefault;
+		private Key hotKey = Key.Null;
+		private Rune hotKeySpecifier;
 
 		void Initialize (ustring text, bool is_default)
 		{
@@ -113,8 +116,6 @@ namespace Terminal.Gui {
 			this.text = text ?? string.Empty;
 			Update ();
 
-			HotKeyChanged += Button_HotKeyChanged;
-
 			// Things this view knows how to do
 			AddCommand (Command.Accept, () => AcceptKey ());
 
@@ -126,27 +127,17 @@ namespace Terminal.Gui {
 			}
 		}
 
-		private void Button_HotKeyChanged (Key obj)
-		{
-			if (HotKey != Key.Null) {
-				if (ContainsKeyBinding (obj)) {
-					ReplaceKeyBinding (Key.Space | obj, Key.Space | HotKey);
-				} else {
-					AddKeyBinding (Key.Space | HotKey, Command.Accept);
-				}
-			}
-		}
-
-		/// <summary>
-		///   The text displayed by this <see cref="Button"/>.
-		/// </summary>
-		public new ustring Text {
+		/// <inheritdoc/>>
+		public override ustring Text {
 			get {
 				return text;
 			}
-
 			set {
 				text = value;
+				TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk);
+				if (hotKey != hk) {
+					HotKey = hk;
+				}
 				Update ();
 			}
 		}
@@ -163,14 +154,51 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <inheritdoc/>
+		public override Key HotKey {
+			get => hotKey;
+			set {
+				if (hotKey != value) {
+					var v = value == Key.Unknown ? Key.Null : value;
+					if (ContainsKeyBinding (Key.Space | hotKey)) {
+						if (v == Key.Null) {
+							ClearKeybinding (Key.Space | hotKey);
+						} else {
+							ReplaceKeyBinding (Key.Space | hotKey, Key.Space | v);
+						}
+					} else if (v != Key.Null) {
+						AddKeyBinding (Key.Space | v, Command.Accept);
+					}
+					hotKey = v;
+				}
+			}
+		}
+
+		/// <inheritdoc/>
+		public override Rune HotKeySpecifier {
+			get => hotKeySpecifier;
+			set {
+				hotKeySpecifier = textFormatter.HotKeySpecifier = value;
+			}
+		}
+
+		/// <inheritdoc/>
+		public override bool AutoSize {
+			get => base.AutoSize;
+			set {
+				base.AutoSize = value;
+				Update ();
+			}
+		}
+
 		internal void Update ()
 		{
 			if (IsDefault)
-				base.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket);
+				textFormatter.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket);
 			else
-				base.Text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
+				textFormatter.Text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket);
 
-			int w = base.Text.RuneCount - (base.Text.Contains (HotKeySpecifier) ? 1 : 0);
+			int w = textFormatter.Text.RuneCount - (textFormatter.Text.Contains (HotKeySpecifier) ? 1 : 0);
 			GetCurrentWidth (out int cWidth);
 			var canSetWidth = SetWidth (w, out int rWidth);
 			if (canSetWidth && (cWidth < rWidth || AutoSize)) {
@@ -194,6 +222,25 @@ namespace Terminal.Gui {
 			SetNeedsDisplay ();
 		}
 
+		/// <inheritdoc/>
+		public override void Redraw (Rect bounds)
+		{
+			if (ColorScheme != null) {
+				Driver.SetAttribute (HasFocus ? ColorScheme.Focus : ColorScheme.Normal);
+			}
+
+			if (Border != null) {
+				Border.DrawContent (this);
+			}
+
+			if (!ustring.IsNullOrEmpty (textFormatter.Text)) {
+				Clear ();
+				textFormatter.NeedsFormat = true;
+				textFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
+					HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled);
+			}
+		}
+
 		///<inheritdoc/>
 		public override bool ProcessHotKey (KeyEvent kb)
 		{
@@ -294,8 +341,8 @@ namespace Terminal.Gui {
 		public override void PositionCursor ()
 		{
 			if (HotKey == Key.Unknown && text != "") {
-				for (int i = 0; i < base.Text.RuneCount; i++) {
-					if (base.Text [i] == text [0]) {
+				for (int i = 0; i < textFormatter.Text.RuneCount; i++) {
+					if (textFormatter.Text [i] == text [0]) {
 						Move (i, 0);
 						return;
 					}

+ 58 - 10
UnitTests/ButtonTests.cs

@@ -7,12 +7,14 @@ using Xunit;
 
 namespace Terminal.Gui.Views {
 	public class ButtonTests {
-		[Fact]
+		[Fact, AutoInitShutdown]
 		public void Constructors_Defaults ()
 		{
 			var btn = new Button ();
 			Assert.Equal (string.Empty, btn.Text);
-			Assert.Equal ("[  ]", btn.GetType ().BaseType.GetProperty ("Text").GetValue (btn).ToString ());
+			Application.Top.Add (btn);
+			btn.Redraw (btn.Bounds);
+			Assert.Equal ("[  ]", GetContents (btn.Bounds.Width));
 			Assert.False (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
@@ -22,23 +24,36 @@ namespace Terminal.Gui.Views {
 
 			btn = new Button ("Test", true);
 			Assert.Equal ("Test", btn.Text);
-			Assert.Equal ("[< Test >]", btn.GetType ().BaseType.GetProperty ("Text").GetValue (btn).ToString ());
+			Application.Top.Add (btn);
+			btn.Redraw (btn.Bounds);
+			Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width));
 			Assert.True (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
 			Assert.True (btn.CanFocus);
 			Assert.Equal (new Rect (0, 0, 10, 1), btn.Frame);
-			Assert.Equal (Key.Null, btn.HotKey);
+			Assert.Equal (Key.T, btn.HotKey);
 
 			btn = new Button (3, 4, "Test", true);
 			Assert.Equal ("Test", btn.Text);
-			Assert.Equal ("[< Test >]", btn.GetType ().BaseType.GetProperty ("Text").GetValue (btn).ToString ());
+			Application.Top.Add (btn);
+			btn.Redraw (btn.Bounds);
+			Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width));
 			Assert.True (btn.IsDefault);
 			Assert.Equal (TextAlignment.Centered, btn.TextAlignment);
 			Assert.Equal ('_', btn.HotKeySpecifier);
 			Assert.True (btn.CanFocus);
 			Assert.Equal (new Rect (3, 4, 10, 1), btn.Frame);
-			Assert.Equal (Key.Null, btn.HotKey);
+			Assert.Equal (Key.T, btn.HotKey);
+		}
+
+		private string GetContents (int width)
+		{
+			string output = "";
+			for (int i = 0; i < width; i++) {
+				output += (char)Application.Driver.Contents [0, i, 0];
+			}
+			return output;
 		}
 
 		[Fact]
@@ -75,9 +90,15 @@ namespace Terminal.Gui.Views {
 			clicked = false;
 			Assert.True (btn.ProcessKey (new KeyEvent ((Key)'t', new KeyModifiers ())));
 			Assert.True (clicked);
+			clicked = false;
+			Assert.True (btn.ProcessKey (new KeyEvent (Key.Space | btn.HotKey, new KeyModifiers ())));
+			Assert.True (clicked);
+			btn.Text = "Te_st";
+			clicked = false;
+			Assert.True (btn.ProcessKey (new KeyEvent (Key.Space | btn.HotKey, new KeyModifiers ())));
+			Assert.True (clicked);
 		}
 
-
 		[Fact]
 		[AutoInitShutdown]
 		public void ChangeHotKey ()
@@ -114,18 +135,18 @@ namespace Terminal.Gui.Views {
 			btn.Clicked += () => pressed++;
 
 			// The Button class supports the Accept command
-			Assert.Contains(Command.Accept,btn.GetSupportedCommands ());
+			Assert.Contains (Command.Accept, btn.GetSupportedCommands ());
 
 			Application.Top.Add (btn);
 			Application.Begin (Application.Top);
 
 			// default keybinding is Enter which results in keypress
-			Application.Driver.SendKeys ('\n',ConsoleKey.Enter,false,false,false);
+			Application.Driver.SendKeys ('\n', ConsoleKey.Enter, false, false, false);
 			Assert.Equal (1, pressed);
 
 			// remove the default keybinding (Enter)
 			btn.ClearKeybinding (Command.Accept);
-			
+
 			// After clearing the default keystroke the Enter button no longer does anything for the Button
 			Application.Driver.SendKeys ('\n', ConsoleKey.Enter, false, false, false);
 			Assert.Equal (1, pressed);
@@ -137,5 +158,32 @@ namespace Terminal.Gui.Views {
 			Application.Driver.SendKeys ('b', ConsoleKey.B, false, false, false);
 			Assert.Equal (2, pressed);
 		}
+
+		[Fact]
+		public void TestAssignTextToButton ()
+		{
+			View b = new Button ();
+			b.Text = "heya";
+			Assert.Equal ("heya", b.Text);
+
+			// with cast
+			Assert.Equal ("heya", ((Button)b).Text);
+		}
+
+		[Fact]
+		public void Setting_Empty_Text_Sets_HoKey_To_KeyNull ()
+		{
+			var btn = new Button ("Test");
+			Assert.Equal ("Test", btn.Text);
+			Assert.Equal (Key.T, btn.HotKey);
+
+			btn.Text = string.Empty;
+			Assert.Equal ("", btn.Text);
+			Assert.Equal (Key.Null, btn.HotKey);
+
+			btn.Text = "Te_st";
+			Assert.Equal ("Te_st", btn.Text);
+			Assert.Equal (Key.S, btn.HotKey);
+		}
 	}
 }