Browse Source

Fixes #3090. Introduce StatusItem.HotTextSpecifier (#3093)

Andrey Akinshin 1 year ago
parent
commit
b4975f4747
2 changed files with 37 additions and 8 deletions
  1. 18 8
      Terminal.Gui/Views/StatusBar.cs
  2. 19 0
      UnitTests/Views/StatusBarTests.cs

+ 18 - 8
Terminal.Gui/Views/StatusBar.cs

@@ -16,9 +16,9 @@ namespace Terminal.Gui {
 	/// Each <see cref="StatusItem"/> has a title, a shortcut (hotkey), and an <see cref="Action"/> that will be invoked when the 
 	/// Each <see cref="StatusItem"/> has a title, a shortcut (hotkey), and an <see cref="Action"/> that will be invoked when the 
 	/// <see cref="StatusItem.Shortcut"/> is pressed.
 	/// <see cref="StatusItem.Shortcut"/> is pressed.
 	/// The <see cref="StatusItem.Shortcut"/> will be a global hotkey for the application in the current context of the screen.
 	/// The <see cref="StatusItem.Shortcut"/> will be a global hotkey for the application in the current context of the screen.
-	/// The colour of the <see cref="StatusItem.Title"/> will be changed after each ~. 
+	/// The colour of the <see cref="StatusItem.Title"/> will be changed after each ~ (can be customized using <see cref="HotTextSpecifier"/>).
 	/// A <see cref="StatusItem.Title"/> set to `~F1~ Help` will render as *F1* using <see cref="ColorScheme.HotNormal"/> and
 	/// A <see cref="StatusItem.Title"/> set to `~F1~ Help` will render as *F1* using <see cref="ColorScheme.HotNormal"/> and
-	/// *Help* as <see cref="ColorScheme.HotNormal"/>.
+	/// *Help* as <see cref="ColorScheme.Normal"/>.
 	/// </summary>
 	/// </summary>
 	public class StatusItem {
 	public class StatusItem {
 		/// <summary>
 		/// <summary>
@@ -65,6 +65,15 @@ namespace Terminal.Gui {
 		/// <value>Function to determine if the action is can be executed or not.</value>
 		/// <value>Function to determine if the action is can be executed or not.</value>
 		public Func<bool> CanExecute { get; set; }
 		public Func<bool> CanExecute { get; set; }
 
 
+		/// <summary>
+		/// Gets or sets the rune that toggles the text color between <see cref="ColorScheme.Normal"/> and <see cref="ColorScheme.HotNormal"/>.
+		/// The default value is '~'.
+		/// Therefore, '~F1~ Help' will be rendered as 'F1' using <see cref="ColorScheme.HotNormal"/> and 'Help' using <see cref="ColorScheme.Normal"/>.
+		/// In order to use '~' as part of the title (e.g., to denote the home directory as a part of the current directory),
+		/// <see cref="HotTextSpecifier"/> should be changed to a different rune.
+		/// </summary>
+		public Rune HotTextSpecifier { get; set; } = '~';
+
 		/// <summary>
 		/// <summary>
 		/// Returns <see langword="true"/> if the status item is enabled. This method is a wrapper around <see cref="CanExecute"/>.
 		/// Returns <see langword="true"/> if the status item is enabled. This method is a wrapper around <see cref="CanExecute"/>.
 		/// </summary>
 		/// </summary>
@@ -157,9 +166,10 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (scheme);
 			Driver.SetAttribute (scheme);
 			for (int i = 0; i < Items.Length; i++) {
 			for (int i = 0; i < Items.Length; i++) {
 				var title = Items [i].Title.ToString ();
 				var title = Items [i].Title.ToString ();
+				var hotTextSpecifier = Items [i].HotTextSpecifier;
 				Driver.SetAttribute (DetermineColorSchemeFor (Items [i]));
 				Driver.SetAttribute (DetermineColorSchemeFor (Items [i]));
 				for (int n = 0; n < Items [i].Title.RuneCount; n++) {
 				for (int n = 0; n < Items [i].Title.RuneCount; n++) {
-					if (title [n] == '~') {
+					if (title [n] == hotTextSpecifier) {
 						if (Items [i].IsEnabled ()) {
 						if (Items [i].IsEnabled ()) {
 							scheme = ToggleScheme (scheme);
 							scheme = ToggleScheme (scheme);
 						}
 						}
@@ -197,23 +207,23 @@ namespace Terminal.Gui {
 
 
 			int pos = 1;
 			int pos = 1;
 			for (int i = 0; i < Items.Length; i++) {
 			for (int i = 0; i < Items.Length; i++) {
-				if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i].Title)) {
+				if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i])) {
 					var item = Items [i];
 					var item = Items [i];
 					if (item.IsEnabled ()) {
 					if (item.IsEnabled ()) {
 						Run (item.Action);
 						Run (item.Action);
 					}
 					}
 					break;
 					break;
 				}
 				}
-				pos += GetItemTitleLength (Items [i].Title) + 3;
+				pos += GetItemTitleLength (Items [i]) + 3;
 			}
 			}
 			return true;
 			return true;
 		}
 		}
 
 
-		int GetItemTitleLength (ustring title)
+		int GetItemTitleLength (StatusItem item)
 		{
 		{
 			int len = 0;
 			int len = 0;
-			foreach (var ch in title) {
-				if (ch == '~')
+			foreach (var ch in item.Title) {
+				if (ch == item.HotTextSpecifier)
 					continue;
 					continue;
 				len++;
 				len++;
 			}
 			}

+ 19 - 0
UnitTests/Views/StatusBarTests.cs

@@ -128,6 +128,25 @@ CTRL-O Open {Application.Driver.VLine} CTRL-Q Quit
 			TestHelpers.AssertDriverContentsAre (expected, output);
 			TestHelpers.AssertDriverContentsAre (expected, output);
 		}
 		}
 
 
+		[Fact]
+		[AutoInitShutdown]
+		public void Redraw_Output_Custom_HotTextSpecifier ()
+		{
+			var sb = new StatusBar (new StatusItem [] {
+				new StatusItem (Key.CtrlMask | Key.T, "~CTRL-T~ _Text_", null),
+				new StatusItem (Key.CtrlMask | Key.O, "_CTRL-O_ ~/Work", null) { HotTextSpecifier = '_' },
+			});
+			Application.Top.Add (sb);
+
+			sb.Redraw (sb.Bounds);
+
+			string expected = @$"
+CTRL-T _Text_ {Application.Driver.VLine} CTRL-O ~/Work
+";
+
+			TestHelpers.AssertDriverContentsAre (expected, output);
+		}
+
 		[Fact]
 		[Fact]
 		public void AddItemAt_RemoveItem_Replacing ()
 		public void AddItemAt_RemoveItem_Replacing ()
 		{
 		{