From 74aedd25bf178d509d1c85222bd05aa2f513ee62 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 6 Aug 2023 23:46:47 +0100 Subject: [PATCH] Fixes #2789. StatusItem should have a disabled attribute if it can't execute. --- Terminal.Gui/Views/StatusBar.cs | 46 +++++++++++++++++++++++++++---- UnitTests/Views/StatusBarTests.cs | 41 ++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/Terminal.Gui/Views/StatusBar.cs b/Terminal.Gui/Views/StatusBar.cs index 5d3ec65f1..152ba68fc 100644 --- a/Terminal.Gui/Views/StatusBar.cs +++ b/Terminal.Gui/Views/StatusBar.cs @@ -27,11 +27,13 @@ namespace Terminal.Gui { /// Shortcut to activate the . /// Title for the . /// Action to invoke when the is activated. - public StatusItem (Key shortcut, ustring title, Action action) + /// Function to determine if the action can currently be executed. + public StatusItem (Key shortcut, ustring title, Action action, Func canExecute = null) { Title = title ?? ""; Shortcut = shortcut; Action = action; + CanExecute = canExecute; } /// @@ -54,7 +56,22 @@ namespace Terminal.Gui { /// Gets or sets the action to be invoked when the statusbar item is triggered /// /// Action to invoke. - public Action Action { get; } + public Action Action { get; set; } + + /// + /// Gets or sets the action to be invoked to determine if the can be triggered. + /// If returns the status item will be enabled. Otherwise, it will be disabled. + /// + /// Function to determine if the action is can be executed or not. + public Func CanExecute { get; set; } + + /// + /// Returns if the status item is enabled. This method is a wrapper around . + /// + public bool IsEnabled () + { + return CanExecute == null ? true : CanExecute (); + } /// /// Gets or sets arbitrary data for the status item. @@ -116,6 +133,17 @@ namespace Terminal.Gui { return result; } + Attribute DetermineColorSchemeFor (StatusItem item) + { + if (item != null) { + if (item.IsEnabled ()) { + return GetNormalColor (); + } + return ColorScheme.Disabled; + } + return GetNormalColor (); + } + /// public override void Redraw (Rect bounds) { @@ -129,9 +157,12 @@ namespace Terminal.Gui { Driver.SetAttribute (scheme); for (int i = 0; i < Items.Length; i++) { var title = Items [i].Title.ToString (); + Driver.SetAttribute (DetermineColorSchemeFor (Items [i])); for (int n = 0; n < Items [i].Title.RuneCount; n++) { if (title [n] == '~') { - scheme = ToggleScheme (scheme); + if (Items [i].IsEnabled ()) { + scheme = ToggleScheme (scheme); + } continue; } Driver.AddRune (title [n]); @@ -149,7 +180,9 @@ namespace Terminal.Gui { { foreach (var item in Items) { if (kb.Key == item.Shortcut) { - Run (item.Action); + if (item.IsEnabled ()) { + Run (item.Action); + } return true; } } @@ -165,7 +198,10 @@ namespace Terminal.Gui { int pos = 1; for (int i = 0; i < Items.Length; i++) { if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i].Title)) { - Run (Items [i].Action); + var item = Items [i]; + if (item.IsEnabled ()) { + Run (item.Action); + } break; } pos += GetItemTitleLength (Items [i].Title) + 3; diff --git a/UnitTests/Views/StatusBarTests.cs b/UnitTests/Views/StatusBarTests.cs index 89540d607..f713f3106 100644 --- a/UnitTests/Views/StatusBarTests.cs +++ b/UnitTests/Views/StatusBarTests.cs @@ -18,12 +18,13 @@ namespace Terminal.Gui.ViewTests { Assert.Equal (Key.CtrlMask | Key.Q, si.Shortcut); Assert.Equal ("~^Q~ Quit", si.Title); Assert.Null (si.Action); + Assert.True (si.IsEnabled ()); si = new StatusItem (Key.CtrlMask | Key.Q, "~^Q~ Quit", () => { }); Assert.NotNull (si.Action); } [Fact] - public void StatusBar_Contructor_Default () + public void StatusBar_Constructor_Default () { var sb = new StatusBar (); @@ -155,5 +156,43 @@ CTRL-O Open {Application.Driver.VLine} CTRL-Q Quit Assert.Equal ("~^A~ Save As", sb.Items [1].Title); Assert.Equal ("~^Q~ Quit", sb.Items [^1].Title); } + + [Fact, AutoInitShutdown] + public void CanExecute_ProcessHotKey () + { + Window win = null; + var statusBar = new StatusBar (new StatusItem [] { + new StatusItem (Key.CtrlMask | Key.N, "~^N~ New", New, CanExecuteNew), + new StatusItem (Key.CtrlMask | Key.C, "~^C~ Close", Close, CanExecuteClose) + }); + var top = Application.Top; + top.Add (statusBar); + + bool CanExecuteNew () => win == null; + + void New () + { + win = new Window (); + } + + bool CanExecuteClose () => win != null; + + void Close () + { + win = null; + } + + Application.Begin (top); + + Assert.Null (win); + Assert.True (CanExecuteNew ()); + Assert.False (CanExecuteClose ()); + + Assert.True (top.ProcessHotKey (new KeyEvent (Key.N | Key.CtrlMask, new KeyModifiers () { Alt = true }))); + Application.MainLoop.MainIteration (); + Assert.NotNull (win); + Assert.False (CanExecuteNew ()); + Assert.True (CanExecuteClose ()); + } } }