From 7a712ad96aad619a52aaf4f79e16dde1a574d61e Mon Sep 17 00:00:00 2001 From: Tig Date: Thu, 27 Jun 2024 12:40:26 -0700 Subject: [PATCH] Accept now uses HandledEventARgs vs. Cancel --- Terminal.Gui/View/View.cs | 8 +- Terminal.Gui/Views/ComboBox.cs | 2 +- Terminal.Gui/Views/TextView.cs | 21 +++- UICatalog/Scenarios/Bars.cs | 4 +- UICatalog/Scenarios/Buttons.cs | 4 +- UICatalog/Scenarios/CharacterMap.cs | 6 +- UICatalog/Scenarios/GraphViewExample.cs | 2 +- UICatalog/Scenarios/Shortcuts.cs | 4 +- UICatalog/Scenarios/Sliders.cs | 2 +- UnitTests/View/ViewTests.cs | 8 +- UnitTests/Views/ButtonTests.cs | 6 +- UnitTests/Views/CheckBoxTests.cs | 6 +- UnitTests/Views/LabelTests.cs | 2 +- UnitTests/Views/ListViewTests.cs | 8 +- UnitTests/Views/RadioGroupTests.cs | 4 +- UnitTests/Views/TextFieldTests.cs | 22 ++-- UnitTests/Views/TextViewTests.cs | 150 ++++++++++++++++++++++++ UnitTests/Views/TreeViewTests.cs | 16 +-- 18 files changed, 219 insertions(+), 56 deletions(-) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index bcf9ec022..df7f242d2 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -109,10 +109,10 @@ public partial class View : Responder, ISupportInitializeNotification { /// /// Cancelable event fired when the command is invoked. Set - /// + /// /// to cancel the event. /// - public event EventHandler Accept; + public event EventHandler Accept; /// Gets or sets arbitrary data for the view. /// This property is not used internally. @@ -156,10 +156,10 @@ public partial class View : Responder, ISupportInitializeNotification /// protected bool? OnAccept () { - var args = new CancelEventArgs (); + var args = new HandledEventArgs (); Accept?.Invoke (this, args); - return Accept is null ? null : args.Cancel; + return Accept is null ? null : args.Handled; } #region Constructors and Initialization diff --git a/Terminal.Gui/Views/ComboBox.cs b/Terminal.Gui/Views/ComboBox.cs index a5d3ed4a2..17ef47651 100644 --- a/Terminal.Gui/Views/ComboBox.cs +++ b/Terminal.Gui/Views/ComboBox.cs @@ -658,7 +658,7 @@ public class ComboBox : View } // Tell TextField to handle Accept Command (Enter) - void Search_Accept (object sender, CancelEventArgs e) { e.Cancel = true; } + void Search_Accept (object sender, HandledEventArgs e) { e.Handled = true; } private void Search_Changed (object sender, StateEventArgs e) { diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index d9c67cf14..3b5e5f11a 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -2523,10 +2523,21 @@ public class TextView : View KeyBindings.Add ((KeyCode)ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu); } + // BUGBUG: AllowsReturn is mis-named. It should be EnterKeyAccepts. /// - /// Gets or sets a value indicating whether pressing ENTER in a creates a new line of text - /// in the view or activates the default button for the Toplevel. + /// Gets or sets whether pressing ENTER in a creates a new line of text + /// in the view or invokes the event. /// + /// + /// + /// Setting this property alters . + /// If is set to , then is also set to `true` and + /// vice-versa. + /// + /// + /// If is set to , then gets set to . + /// + /// public bool AllowsReturn { get => _allowsReturn; @@ -2536,12 +2547,14 @@ public class TextView : View if (_allowsReturn && !_multiline) { + // BUGBUG: Seting properties should not have side-effects like this. Multiline and AllowsReturn should be independent. Multiline = true; } if (!_allowsReturn && _multiline) { Multiline = false; + // BUGBUG: Seting properties should not have side-effects like this. Multiline and AlowsTab should be independent. AllowsTab = false; } @@ -6050,13 +6063,13 @@ public class TextView : View Paste (); } - private bool ProcessReturn () + private bool? ProcessReturn () { ResetColumnTrack (); if (!AllowsReturn || _isReadOnly) { - return false; + return OnAccept (); } SetWrapModel (); diff --git a/UICatalog/Scenarios/Bars.cs b/UICatalog/Scenarios/Bars.cs index eff3ba294..995e55ceb 100644 --- a/UICatalog/Scenarios/Bars.cs +++ b/UICatalog/Scenarios/Bars.cs @@ -193,7 +193,7 @@ public class Bars : Scenario { eventSource.Add ($"Accept: {sh!.SuperView.Id} {sh!.CommandView.Text}"); eventLog.MoveDown (); - args.Cancel = true; + args.Handled = true; }; } } @@ -453,7 +453,7 @@ public class Bars : Scenario { button1.Visible = !button1.Visible; button1.Enabled = button1.Visible; - e.Cancel = false; + e.Handled = false; }; bar.Add (new Label diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index 018352177..12c7b2469 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -486,12 +486,12 @@ public class Buttons : Scenario return; - void OnDownButtonOnAccept (object s, CancelEventArgs e) + void OnDownButtonOnAccept (object s, HandledEventArgs e) { InvokeCommand (Command.ScrollDown); } - void OnUpButtonOnAccept (object s, CancelEventArgs e) + void OnUpButtonOnAccept (object s, HandledEventArgs e) { InvokeCommand (Command.ScrollUp); } diff --git a/UICatalog/Scenarios/CharacterMap.cs b/UICatalog/Scenarios/CharacterMap.cs index 9387ed835..c310bdbb0 100644 --- a/UICatalog/Scenarios/CharacterMap.cs +++ b/UICatalog/Scenarios/CharacterMap.cs @@ -82,12 +82,12 @@ public class CharacterMap : Scenario #else jumpEdit.Accept += JumpEditOnAccept; - void JumpEditOnAccept (object sender, CancelEventArgs e) + void JumpEditOnAccept (object sender, HandledEventArgs e) { JumpEdit_TextChanged (sender, new (jumpEdit.Text, jumpEdit.Text)); // Cancel the event to prevent ENTER from being handled elsewhere - e.Cancel = true; + e.Handled = true; } #endif _categoryList = new () { X = Pos.Right (_charMap), Y = Pos.Bottom (jumpLabel), Height = Dim.Fill () }; @@ -483,7 +483,7 @@ internal class CharMap : View WantContinuousButtonPressed = true, CanFocus = false }; - up.Accept += (sender, args) => { args.Cancel = ScrollVertical (-1) == true; }; + up.Accept += (sender, args) => { args.Handled = ScrollVertical (-1) == true; }; var down = new Button { diff --git a/UICatalog/Scenarios/GraphViewExample.cs b/UICatalog/Scenarios/GraphViewExample.cs index 754a8aa10..462bcabd8 100644 --- a/UICatalog/Scenarios/GraphViewExample.cs +++ b/UICatalog/Scenarios/GraphViewExample.cs @@ -196,7 +196,7 @@ public class GraphViewExample : Scenario Application.Shutdown (); } - private void DiagShortcut_Accept (object sender, CancelEventArgs e) + private void DiagShortcut_Accept (object sender, HandledEventArgs e) { ToggleDiagnostics (); diff --git a/UICatalog/Scenarios/Shortcuts.cs b/UICatalog/Scenarios/Shortcuts.cs index 093ddebe9..ce8a6e30b 100644 --- a/UICatalog/Scenarios/Shortcuts.cs +++ b/UICatalog/Scenarios/Shortcuts.cs @@ -361,7 +361,7 @@ public class Shortcuts : Scenario { eventSource.Add ($"Accept: {shortcut!.CommandView.Text}"); eventLog.MoveDown (); - args.Cancel = true; + args.Handled = true; }; shortcut.CommandView.Accept += (o, args) => @@ -375,7 +375,7 @@ public class Shortcuts : Scenario //((CheckBox)vShortcut5.CommandView).OnToggled (); } - private void Button_Clicked (object sender, CancelEventArgs e) + private void Button_Clicked (object sender, HandledEventArgs e) { //e.Cancel = true; MessageBox.Query ("Hi", $"You clicked {sender}"); diff --git a/UICatalog/Scenarios/Sliders.cs b/UICatalog/Scenarios/Sliders.cs index 2a2892915..1b0d21031 100644 --- a/UICatalog/Scenarios/Sliders.cs +++ b/UICatalog/Scenarios/Sliders.cs @@ -599,7 +599,7 @@ public class Sliders : Scenario { eventSource.Add ($"Accept: {string.Join(",", slider.GetSetOptions ())}"); eventLog.MoveDown (); - args.Cancel = true; + args.Handled = true; }; slider.OptionsChanged += (o, args) => { diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs index d3ed65961..4044507f1 100644 --- a/UnitTests/View/ViewTests.cs +++ b/UnitTests/View/ViewTests.cs @@ -1198,7 +1198,7 @@ At 0,0 return; - void ViewOnAccept (object sender, CancelEventArgs e) { accepted = true; } + void ViewOnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -1215,10 +1215,10 @@ At 0,0 return; - void ViewOnAccept (object sender, CancelEventArgs e) + void ViewOnAccept (object sender, HandledEventArgs e) { acceptInvoked = true; - e.Cancel = true; + e.Handled = true; } } @@ -1235,7 +1235,7 @@ At 0,0 return; - void ViewOnAccept (object sender, CancelEventArgs e) { accepted = true; } + void ViewOnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] diff --git a/UnitTests/Views/ButtonTests.cs b/UnitTests/Views/ButtonTests.cs index 03f0dcba0..4ef86d387 100644 --- a/UnitTests/Views/ButtonTests.cs +++ b/UnitTests/Views/ButtonTests.cs @@ -484,7 +484,7 @@ public class ButtonTests (ITestOutputHelper output) return; - void ButtonOnAccept (object sender, CancelEventArgs e) { accepted = true; } + void ButtonOnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -503,10 +503,10 @@ public class ButtonTests (ITestOutputHelper output) return; - void ButtonAccept (object sender, CancelEventArgs e) + void ButtonAccept (object sender, HandledEventArgs e) { acceptInvoked = true; - e.Cancel = true; + e.Handled = true; } } diff --git a/UnitTests/Views/CheckBoxTests.cs b/UnitTests/Views/CheckBoxTests.cs index 5c2459812..d87b30972 100644 --- a/UnitTests/Views/CheckBoxTests.cs +++ b/UnitTests/Views/CheckBoxTests.cs @@ -229,10 +229,10 @@ public class CheckBoxTests (ITestOutputHelper output) return; - void ViewOnAccept (object sender, CancelEventArgs e) + void ViewOnAccept (object sender, HandledEventArgs e) { acceptInvoked = true; - e.Cancel = true; + e.Handled = true; } } @@ -469,7 +469,7 @@ public class CheckBoxTests (ITestOutputHelper output) return; - void CheckBoxOnAccept (object sender, CancelEventArgs e) { accepted = true; } + void CheckBoxOnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Theory] diff --git a/UnitTests/Views/LabelTests.cs b/UnitTests/Views/LabelTests.cs index f6267e24b..24a19c77d 100644 --- a/UnitTests/Views/LabelTests.cs +++ b/UnitTests/Views/LabelTests.cs @@ -81,7 +81,7 @@ public class LabelTests (ITestOutputHelper output) return; - void LabelOnAccept (object sender, CancelEventArgs e) { accepted = true; } + void LabelOnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] diff --git a/UnitTests/Views/ListViewTests.cs b/UnitTests/Views/ListViewTests.cs index 5f157a81d..2682fb677 100644 --- a/UnitTests/Views/ListViewTests.cs +++ b/UnitTests/Views/ListViewTests.cs @@ -420,7 +420,7 @@ Item 6", return; - void OnAccept (object sender, CancelEventArgs e) { accepted = true; } + void OnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -451,7 +451,7 @@ Item 6", selectedValue = e.Value.ToString (); } - void Accept (object sender, CancelEventArgs e) { accepted = true; } + void Accept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -482,10 +482,10 @@ Item 6", selectedValue = e.Value.ToString (); } - void Accept (object sender, CancelEventArgs e) + void Accept (object sender, HandledEventArgs e) { accepted = true; - e.Cancel = true; + e.Handled = true; } } diff --git a/UnitTests/Views/RadioGroupTests.cs b/UnitTests/Views/RadioGroupTests.cs index 4ddf68321..75aab7b18 100644 --- a/UnitTests/Views/RadioGroupTests.cs +++ b/UnitTests/Views/RadioGroupTests.cs @@ -189,7 +189,7 @@ public class RadioGroupTests (ITestOutputHelper output) return; - void OnAccept (object sender, CancelEventArgs e) { accepted = true; } + void OnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -205,7 +205,7 @@ public class RadioGroupTests (ITestOutputHelper output) return; - void OnAccept (object sender, CancelEventArgs e) { accepted = true; } + void OnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] diff --git a/UnitTests/Views/TextFieldTests.cs b/UnitTests/Views/TextFieldTests.cs index 41756ed69..1ad2ad9c6 100644 --- a/UnitTests/Views/TextFieldTests.cs +++ b/UnitTests/Views/TextFieldTests.cs @@ -771,7 +771,7 @@ public class TextFieldTests (ITestOutputHelper output) return; - void OnAccept (object sender, CancelEventArgs e) { accepted = true; } + void OnAccept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -786,13 +786,13 @@ public class TextFieldTests (ITestOutputHelper output) return; - void Accept (object sender, CancelEventArgs e) { accepted = true; } + void Accept (object sender, HandledEventArgs e) { accepted = true; } } [Theory] [InlineData (false, 0)] [InlineData (true, 1)] - public void Accept_Handler_Cancel_Prevents_Default_Button_Accept (bool cancelAccept, int expectedButtonAccepts) + public void Accept_Handler_Handled_Prevents_Default_Button_Accept (bool handleAccept, int expectedButtonAccepts) { var superView = new Window (); var tf = new TextField (); @@ -823,13 +823,13 @@ public class TextFieldTests (ITestOutputHelper output) return; - void TextFieldAccept (object sender, CancelEventArgs e) + void TextFieldAccept (object sender, HandledEventArgs e) { textFieldAccept++; - e.Cancel = cancelAccept; + e.Handled = handleAccept; } - void ButtonAccept (object sender, CancelEventArgs e) + void ButtonAccept (object sender, HandledEventArgs e) { buttonAccept++; } @@ -862,7 +862,7 @@ public class TextFieldTests (ITestOutputHelper output) return; - void ButtonAccept (object sender, CancelEventArgs e) + void ButtonAccept (object sender, HandledEventArgs e) { buttonAccept++; } @@ -879,23 +879,23 @@ public class TextFieldTests (ITestOutputHelper output) //var superAcceptedInvoked = false; var tfAcceptedInvoked = false; - var cancel = false; + var handle = false; view.Accept += TextViewAccept; Assert.True (view.InvokeCommand (Command.Accept)); Assert.True (tfAcceptedInvoked); tfAcceptedInvoked = false; - cancel = true; + handle = true; view.Accept += TextViewAccept; Assert.False (view.InvokeCommand (Command.Accept)); Assert.True (tfAcceptedInvoked); return; - void TextViewAccept (object sender, CancelEventArgs e) + void TextViewAccept (object sender, HandledEventArgs e) { tfAcceptedInvoked = true; - e.Cancel = cancel; + e.Handled = handle; } } diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs index 479a8112a..f65f7e902 100644 --- a/UnitTests/Views/TextViewTests.cs +++ b/UnitTests/Views/TextViewTests.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -9130,4 +9131,153 @@ line. _textView.Text = Encoding.Unicode.GetString (ms); } } + + + [Fact] + public void HotKey_Command_SetsFocus () + { + var view = new TextView (); + + view.CanFocus = true; + Assert.False (view.HasFocus); + view.InvokeCommand (Command.HotKey); + Assert.True (view.HasFocus); + } + + [Fact] + public void HotKey_Command_Does_Not_Accept () + { + var view = new TextView (); + var accepted = false; + view.Accept += OnAccept; + view.InvokeCommand (Command.HotKey); + + Assert.False (accepted); + + return; + + void OnAccept (object sender, HandledEventArgs e) { accepted = true; } + } + + [Fact] + public void Accept_Command_Fires_Accept () + { + var view = new TextView (); + + var accepted = false; + view.Accept += Accept; + view.InvokeCommand (Command.Accept); + Assert.True (accepted); + + return; + + void Accept (object sender, HandledEventArgs e) { accepted = true; } + } + + + [Theory] + [InlineData(false, 1)] + [InlineData (true, 0)] + public void Enter_Key_Fires_Accept (bool multiline, int expectedAccepts) + { + var view = new TextView () + { + Multiline = multiline, + }; + + int accepted = 0; + view.Accept += Accept; + view.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedAccepts, accepted); + + return; + + void Accept (object sender, HandledEventArgs e) { accepted++;} + } + + [Theory, InlineData (false, false, 0), InlineData (false, true, 1), InlineData (true, false, 0), InlineData (true, true, 0)] + public void Accept_Handler_Handled_Prevents_Default_Button_Accept (bool multiline, bool handleAccept, int expectedButtonAccepts) + { + var superView = new Window (); + var tv = new TextView () + { + Multiline = multiline + }; + var button = new Button () + { + IsDefault = true, + }; + + superView.Add (tv, button); + + var buttonAccept = 0; + button.Accept += ButtonAccept; + + var textViewAccept = 0; + tv.Accept += TextViewAccept; + + tv.SetFocus (); + Assert.True (tv.HasFocus); + + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (1, textViewAccept); + Assert.Equal (expectedButtonAccepts, buttonAccept); + + button.SetFocus (); + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (1, textViewAccept); + Assert.Equal (expectedButtonAccepts + 1, buttonAccept); + + return; + + void TextViewAccept (object sender, HandledEventArgs e) + { + textViewAccept++; + e.Handled = handleAccept; + } + + void ButtonAccept (object sender, HandledEventArgs e) + { + buttonAccept++; + } + } + + [Theory] + [InlineData (true, 0)] + [InlineData (false, 1)] + public void Accept_No_Handler_Enables_Default_Button_Accept (bool multiline, int expectedButtonAccept) + { + var superView = new Window (); + var tv = new TextView () + { + Multiline = multiline + }; + var button = new Button () + { + IsDefault = true, + }; + + superView.Add (tv, button); + + var buttonAccept = 0; + button.Accept += ButtonAccept; + + tv.SetFocus (); + Assert.True (tv.HasFocus); + + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedButtonAccept, buttonAccept); + + button.SetFocus (); + superView.NewKeyDownEvent (Key.Enter); + Assert.Equal (expectedButtonAccept + 1, buttonAccept); + + return; + + void ButtonAccept (object sender, HandledEventArgs e) + { + buttonAccept++; + } + } + } diff --git a/UnitTests/Views/TreeViewTests.cs b/UnitTests/Views/TreeViewTests.cs index 7efdd58b9..11d85acdb 100644 --- a/UnitTests/Views/TreeViewTests.cs +++ b/UnitTests/Views/TreeViewTests.cs @@ -1338,13 +1338,13 @@ oot two var treeView = new TreeView (); var accepted = false; - treeView.Accept += OnAccept; - treeView.InvokeCommand (Command.HotKey); +treeView.Accept += OnAccept; +treeView.InvokeCommand (Command.HotKey); - Assert.False (accepted); +Assert.False (accepted); - return; - void OnAccept (object sender, CancelEventArgs e) { accepted = true; } +return; +void OnAccept (object sender, HandledEventArgs e) { accepted = true; } } @@ -1375,7 +1375,7 @@ oot two activated = true; selectedObject = e.ActivatedObject; } - void Accept (object sender, CancelEventArgs e) { accepted = true; } + void Accept (object sender, HandledEventArgs e) { accepted = true; } } [Fact] @@ -1404,10 +1404,10 @@ oot two selectedObject = e.ActivatedObject; } - void Accept (object sender, CancelEventArgs e) + void Accept (object sender, HandledEventArgs e) { accepted = true; - e.Cancel = true; + e.Handled = true; } } }