Browse Source

Working on ComboBox

Tig 9 months ago
parent
commit
f2d27a5d08

+ 1 - 1
Terminal.Gui/Input/Command.cs

@@ -313,4 +313,4 @@ public enum Command
     Edit,
 
     #endregion
-}
+}

+ 8 - 1
Terminal.Gui/Input/CommandContext.cs

@@ -20,11 +20,13 @@ public record struct CommandContext
     /// <param name="command"></param>
     /// <param name="key"></param>
     /// <param name="keyBinding"></param>
-    public CommandContext (Command command, Key? key, KeyBinding? keyBinding = null)
+    /// <param name="data"></param>
+    public CommandContext (Command command, Key? key, KeyBinding? keyBinding = null, object? data = null)
     {
         Command = command;
         Key = key;
         KeyBinding = keyBinding;
+        Data = data;
     }
 
     /// <summary>
@@ -41,4 +43,9 @@ public record struct CommandContext
     /// The KeyBinding that was used to invoke the <see cref="Command"/>, if any.
     /// </summary>
     public KeyBinding? KeyBinding { get; set; }
+
+    /// <summary>
+    ///     Arbitrary data.
+    /// </summary>
+    public object? Data { get; set; }
 }

+ 15 - 0
Terminal.Gui/Input/CommandEventArgs.cs

@@ -0,0 +1,15 @@
+#nullable enable
+using System.ComponentModel;
+
+namespace Terminal.Gui;
+
+/// <summary>
+///     Event arguments for <see cref="Command"/> events.
+/// </summary>
+public class CommandEventArgs : CancelEventArgs
+{
+    /// <summary>
+    ///     The context for the command.
+    /// </summary>
+    public CommandContext Context { get; init; }
+}

+ 24 - 11
Terminal.Gui/View/View.Command.cs

@@ -30,17 +30,21 @@ public partial class View // Command APIs
                     });
 
         // Space or single-click - Raise Selected
-        AddCommand (Command.Select, () =>
+        AddCommand (Command.Select, (ctx) =>
                                     {
-                                        bool? cancelled = RaiseSelected ();
-                                        if (cancelled is null or false && CanFocus)
+                                        if (RaiseSelected (ctx) is true)
+                                        {
+                                            return true;
+                                        }
+
+                                        if (CanFocus)
                                         {
                                             SetFocus ();
 
                                             return true;
                                         }
 
-                                        return cancelled is true;
+                                        return false;
                                     });
     }
 
@@ -118,13 +122,13 @@ public partial class View // Command APIs
     ///     If <see langword="true"/> the event was canceled. If <see langword="false"/> the event was raised but not canceled.
     ///     If <see langword="null"/> no event was raised.
     /// </returns>
-    protected bool? RaiseSelected ()
+    protected bool? RaiseSelected (CommandContext ctx)
     {
-        HandledEventArgs args = new ();
+        CommandEventArgs args = new () { Context = ctx };
 
         // Best practice is to invoke the virtual method first.
         // This allows derived classes to handle the event and potentially cancel it.
-        if (OnSelected (args) || args.Handled)
+        if (OnSelected (args) || args.Cancel)
         {
             return true;
         }
@@ -132,7 +136,7 @@ public partial class View // Command APIs
         // If the event is not canceled by the virtual method, raise the event to notify any external subscribers.
         Selected?.Invoke (this, args);
 
-        return Selected is null ? null : args.Handled;
+        return Selected is null ? null : args.Cancel;
     }
 
     /// <summary>
@@ -141,14 +145,14 @@ public partial class View // Command APIs
     /// </summary>
     /// <param name="args"></param>
     /// <returns><see langword="true"/> to stop processing.</returns>
-    protected virtual bool OnSelected (HandledEventArgs args) { return false; }
+    protected virtual bool OnSelected (CommandEventArgs args) { return false; }
 
     /// <summary>
     ///     Cancelable event raised when the user has selected the View or otherwise changed the state of the View. Set
     ///     <see cref="HandledEventArgs.Handled"/>
     ///     to cancel the event.
     /// </summary>
-    public event EventHandler<HandledEventArgs>? Selected;
+    public event EventHandler<CommandEventArgs>? Selected;
 
 
     // TODO: What does this event really do? "Called when the user has pressed the View's hot key or otherwise invoked the View's hot key command.???"
@@ -291,10 +295,19 @@ public partial class View // Command APIs
         if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
         {
             var context = new CommandContext (command, key, keyBinding); // Create the context here
-
             return implementation (context);
         }
 
         return null;
     }
+
+    public bool? InvokeCommand (Command command, CommandContext ctx)
+    {
+        if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
+        {
+            return implementation (ctx);
+        }
+
+        return null;
+    }
 }

+ 3 - 8
Terminal.Gui/View/View.Mouse.cs

@@ -372,7 +372,7 @@ public partial class View // Mouse APIs
 
         // Always invoke Select command on MouseClick
         // By default, this will raise Selected/OnSelected - Subclasses can override this via AddCommand (Command.Select ...).
-        args.Handled = InvokeCommand (Command.Select, null, new KeyBinding ([Command.Select], scope: KeyBindingScope.Focused, boundView: this, context: args.MouseEvent)) == true;
+        args.Handled = InvokeCommand (Command.Select, ctx: new (Command.Select, key: null, data: args.MouseEvent)) == true;
 
         return args.Handled;
     }
@@ -399,18 +399,13 @@ public partial class View // Mouse APIs
 
             if (SetPressedHighlight (HighlightStyle.None))
             {
-                // BUGBUG: If we return true here we never generate a mouse click!
                 return true;
             }
 
             // If mouse is still in bounds, generate a click
-            if (!WantContinuousButtonPressed && Viewport.Contains (mouseEvent.Position))
+            if (Viewport.Contains (mouseEvent.Position))
             {
-                var meea = new MouseEventEventArgs (mouseEvent);
-
-                // We can ignore the return value of OnMouseClick; if the click is handled
-                // meea.Handled and meea.MouseEvent.Handled will be true
-                OnMouseClick (meea);
+                return OnMouseClick (new (mouseEvent));
             }
 
             return mouseEvent.Handled = true;

+ 13 - 2
Terminal.Gui/Views/Button.cs

@@ -70,10 +70,14 @@ public class Button : View, IDesignable
         // Override default behavior of View
         AddCommand (
                     Command.HotKey,
-                    () =>
+                    (ctx) =>
                     {
                         bool cachedIsDefault = IsDefault; // Supports "Swap Default" in Buttons scenario where IsDefault changes
 
+                        if (RaiseSelected (ctx) is true)
+                        {
+                            return true;
+                        }
                         bool? handled = RaiseAccepted ();
 
                         if (handled == true)
@@ -132,7 +136,14 @@ public class Button : View, IDesignable
         }
     }
 
-    private void Button_MouseClick (object sender, MouseEventEventArgs e) { e.Handled = InvokeCommand (Command.HotKey) == true; }
+    private void Button_MouseClick (object sender, MouseEventEventArgs e)
+    {
+        if (e.Handled)
+        {
+            return;
+        }
+        e.Handled = InvokeCommand (Command.HotKey) == true;
+    }
 
     private void Button_TitleChanged (object sender, EventArgs<string> e)
     {

+ 4 - 13
Terminal.Gui/Views/CheckBox.cs

@@ -23,13 +23,13 @@ public class CheckBox : View
         CanFocus = true;
 
         // Select (Space key and single-click) - Advance state and raise Select event
-        AddCommand (Command.Select, () =>
+        AddCommand (Command.Select, (ctx) =>
                                     {
                                         bool? cancelled = AdvanceCheckState ();
 
                                         if (cancelled is null or false)
                                         {
-                                            if (RaiseSelected () == true)
+                                            if (RaiseSelected (ctx) == true)
                                             {
                                                 return true;
                                             }
@@ -42,13 +42,13 @@ public class CheckBox : View
         AddCommand (Command.Accept, () => RaiseAccepted ());
 
         // Hotkey - Advance state and raise Select event - DO NOT raise Accept
-        AddCommand (Command.HotKey, () =>
+        AddCommand (Command.HotKey, (ctx) =>
                                     {
                                         bool? cancelled = AdvanceCheckState ();
 
                                         if (cancelled is null or false)
                                         {
-                                            if (RaiseSelected () == true)
+                                            if (RaiseSelected (ctx) == true)
                                             {
                                                 return true;
                                             }
@@ -60,15 +60,6 @@ public class CheckBox : View
         TitleChanged += Checkbox_TitleChanged;
 
         HighlightStyle = DefaultHighlightStyle;
-        MouseClick += CheckBox_MouseClick;
-    }
-
-    private void CheckBox_MouseClick (object? sender, MouseEventEventArgs e)
-    {
-        if (e.MouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked))
-        {
-            e.Handled = InvokeCommand (Command.Select) is true;
-        }
     }
 
     private void Checkbox_TitleChanged (object? sender, EventArgs<string> e)

+ 17 - 3
Terminal.Gui/Views/ComboBox.cs

@@ -6,6 +6,7 @@
 //
 
 using System.Collections.ObjectModel;
+using System.ComponentModel;
 
 namespace Terminal.Gui;
 
@@ -32,6 +33,7 @@ public class ComboBox : View, IDesignable
         _listview = new ComboListView (this, HideDropdownListOnClick) { CanFocus = true, TabStop = TabBehavior.NoStop };
 
         _search.TextChanged += Search_Changed;
+        _search.Accepted += Search_Accept;
 
         _listview.Y = Pos.Bottom (_search);
         _listview.OpenSelectedItem += (sender, a) => Selected ();
@@ -383,7 +385,10 @@ public class ComboBox : View, IDesignable
     {
         if (HasItems ())
         {
-            Selected ();
+            if (Selected ())
+            {
+                //return false;
+            }
 
             return RaiseAccepted () == true;
         }
@@ -653,6 +658,12 @@ public class ComboBox : View, IDesignable
         SetSearchSet ();
     }
 
+    // Tell TextField to handle Accepted Command (Enter)
+    void Search_Accept (object sender, HandledEventArgs e)
+    {
+        e.Handled = true;
+    }
+
     private void Search_Changed (object sender, EventArgs e)
     {
         if (_source is null)
@@ -712,7 +723,7 @@ public class ComboBox : View, IDesignable
         }
     }
 
-    private void Selected ()
+    private bool Selected ()
     {
         IsShow = false;
         _listview.TabStop = TabBehavior.NoStop;
@@ -723,7 +734,7 @@ public class ComboBox : View, IDesignable
             HideList ();
             IsShow = false;
 
-            return;
+            return false;
         }
 
         SetValue (_listview.SelectedItem > -1 ? _searchSet [_listview.SelectedItem] : _text);
@@ -733,6 +744,8 @@ public class ComboBox : View, IDesignable
         Reset (true);
         HideList ();
         IsShow = false;
+
+        return true;
     }
 
     private void SetSearchSet ()
@@ -788,6 +801,7 @@ public class ComboBox : View, IDesignable
         _listview.Clear ();
         _listview.Height = CalculateHeight ();
         SuperView?.MoveSubviewToStart (this);
+        _listview.SetFocus ();
     }
 
     private bool UnixEmulation ()

+ 4 - 4
Terminal.Gui/Views/ListView.cs

@@ -154,11 +154,11 @@ public class ListView : View, IDesignable
                                     });
 
         // Select (Space key and single-click) - If markable, change mark and raise Select event
-        AddCommand (Command.Select, () =>
+        AddCommand (Command.Select, (ctx) =>
                                     {
                                         if (_allowsMarking)
                                         {
-                                            if (RaiseSelected () == true)
+                                            if (RaiseSelected (ctx) == true)
                                             {
                                                 return true;
                                             }
@@ -174,12 +174,12 @@ public class ListView : View, IDesignable
 
 
         // Hotkey - If none set, select and raise Select event. SetFocus. - DO NOT raise Accept
-        AddCommand (Command.HotKey, () =>
+        AddCommand (Command.HotKey, (ctx) =>
                                     {
                                         if (SelectedItem == -1)
                                         {
                                             SelectedItem = 0;
-                                            if (RaiseSelected () == true)
+                                            if (RaiseSelected (ctx) == true)
                                             {
                                                 return true;
 

+ 1 - 1
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -137,7 +137,7 @@ public class MenuBar : View, IDesignable
                                                   });
         AddCommand (Command.Select, ctx =>
                                     {
-                                        if (ctx.KeyBinding?.Context is MouseEvent)
+                                        if (ctx.Data is MouseEvent)
                                         {
                                             // HACK: Work around the fact that View.MouseClick always invokes Select
                                             return false;

+ 4 - 4
Terminal.Gui/Views/RadioGroup.cs

@@ -20,7 +20,7 @@ public class RadioGroup : View, IDesignable, IOrientation
         // Select (Space key or mouse click) - The default implementation sets focus. RadioGroup does not.
         AddCommand (
                     Command.Select,
-                    () =>
+                    (ctx) =>
                     {
                         bool cursorChanged = false;
                         if (SelectedItem == Cursor)
@@ -40,7 +40,7 @@ public class RadioGroup : View, IDesignable, IOrientation
 
                         if (cursorChanged || selectedItemChanged)
                         {
-                            if (RaiseSelected () == true)
+                            if (RaiseSelected (ctx) == true)
                             {
                                 return true;
                             }
@@ -83,7 +83,7 @@ public class RadioGroup : View, IDesignable, IOrientation
                                     if (selectedItemChanged)
                                     {
                                         // Doesn't matter if it's handled
-                                        RaiseSelected ();
+                                        RaiseSelected (ctx);
                                         return true;
                                     }
 
@@ -93,7 +93,7 @@ public class RadioGroup : View, IDesignable, IOrientation
 
                                 if (SelectedItem == -1 && ChangeSelectedItem (0))
                                 {
-                                    if (RaiseSelected () == true)
+                                    if (RaiseSelected (ctx) == true)
                                     {
                                         return true;
                                     }

+ 77 - 60
Terminal.Gui/Views/Shortcut.cs

@@ -1,4 +1,5 @@
 using System.ComponentModel;
+using System.Diagnostics;
 
 namespace Terminal.Gui;
 
@@ -91,7 +92,7 @@ public class Shortcut : View, IOrientation, IDesignable
     public Shortcut (Key key, string commandText, Action action, string helpText = null)
     {
         Id = "_shortcut";
-        // Disabled for now due to bugs in highlight handling and mouse clicks - HighlightStyle = HighlightStyle.Pressed;
+        // Disabled for now due to bs in highlight handling and mouse clicks - HighlightStyle = HighlightStyle.Pressed;
         CanFocus = true;
         Width = GetWidthDimAuto ();
         Height = Dim.Auto (DimAutoStyle.Content, 1);
@@ -115,11 +116,28 @@ public class Shortcut : View, IOrientation, IDesignable
                                             return true;
                                         }
 
-                                        return RaiseSelected ();
+                                        return RaiseSelected (ctx);
                                     });
 
         // Select (Space key or click) - 
-        AddCommand (Command.Select, ctx => RaiseSelected ());
+        AddCommand (Command.Select, ctx =>
+                                      {
+                                          if (ctx.Data != this)
+                                          {
+                                              ctx.Data = this;
+                                              CommandView.InvokeCommand (Command.Select, ctx);
+                                          }
+
+                                          if (RaiseSelected (ctx) is true)
+                                          {
+                                              return true;
+                                          }
+
+                                          // The default HotKey handler sets Focus
+                                          SetFocus ();
+
+                                          return DispatchAcceptCommand (ctx);
+                                      });
 
         TitleChanged += Shortcut_TitleChanged; // This needs to be set before CommandView is set
 
@@ -138,15 +156,15 @@ public class Shortcut : View, IOrientation, IDesignable
         KeyView.CanFocus = false;
         Add (KeyView);
 
-        // If the user clicks anywhere on the Shortcut...
+        //// If the user clicks anywhere on the Shortcut...
         MouseClick += Shortcut_MouseClick;
 
-        // If the user clicks on HelpView or KeyView
-        HelpView.MouseClick += HelpOrKeyView_MouseClick;
-        KeyView.MouseClick += HelpOrKeyView_MouseClick;
+        //// If the user clicks on HelpView or KeyView
+        //HelpView.MouseClick += HelpOrKeyView_MouseClick;
+        //KeyView.MouseClick += HelpOrKeyView_MouseClick;
 
-        HelpView.Selected += HelpAndKeyViewOnSelect;
-        KeyView.Selected += HelpAndKeyViewOnSelect;
+        HelpView.Selected += HelpAndKeyViewOnSelected;
+        KeyView.Selected += HelpAndKeyViewOnSelected;
 
         LayoutStarted += OnLayoutStarted;
         Initialized += OnInitialized;
@@ -193,9 +211,14 @@ public class Shortcut : View, IOrientation, IDesignable
         }
     }
 
-    private void HelpAndKeyViewOnSelect (object sender, HandledEventArgs e)
+    private void Shortcut_MouseClick (object sender, MouseEventEventArgs e)
     {
-        e.Handled = InvokeCommand (Command.Accept) == true;
+        //e.Handled = true;
+    }
+
+    private void HelpAndKeyViewOnSelected (object sender, CommandEventArgs e)
+    {
+        //e.Handled = InvokeCommand (Command.Select) == true;
     }
 
     [CanBeNull]
@@ -386,29 +409,30 @@ public class Shortcut : View, IOrientation, IDesignable
         }
     }
 
-    private void Shortcut_MouseClick (object sender, MouseEventEventArgs e)
-    {
-        // When the Shortcut is clicked, we want to invoke the Command and Set focus
-        var view = sender as View;
-
-        if (!e.Handled)
-        {
-            // If the subview (likely CommandView) didn't handle the mouse click, invoke the Select command.
-            // e.Handled = CommandView.InvokeCommand (Command.Select) == true;
-            e.Handled = InvokeCommand (Command.HotKey) == true;
-        }
-
-        //if (CanFocus)
-        //{
-        //    SetFocus ();
-        //}
-    }
-
-    private void HelpOrKeyView_MouseClick (object sender, MouseEventEventArgs e)
-    {
-        // Always eat
-        //e.Handled = true;
-    }
+    //private void Shortcut_MouseClick (object sender, MouseEventEventArgs e)
+    //{
+    //    // When the Shortcut is clicked, we want to invoke the Command and Set focus
+    //    var view = sender as View;
+
+    //    if (!e.Handled)
+    //    {
+    //        // If the subview (likely CommandView) didn't handle the mouse click, invoke the Select command.
+    //        // e.Handled = CommandView.InvokeCommand (Command.Select) == true;
+    //        e.Handled = InvokeCommand (Command.HotKey) == true;
+    //    }
+
+    //    //if (CanFocus)
+    //    //{
+    //    //    SetFocus ();
+    //    //}
+    //}
+
+    //private void HelpOrKeyView_MouseClick (object sender, MouseEventEventArgs e)
+    //{
+    //    // Always eat
+    //    e.Handled = true;
+    //    InvokeCommand (Command.HotKey);
+    //}
 
     #region IOrientation members
 
@@ -505,7 +529,8 @@ public class Shortcut : View, IOrientation, IDesignable
 
             if (_commandView is { })
             {
-                _commandView.Accepted -= CommandViewOnSelected;
+                _commandView.Selected -= CommandViewOnSelected;
+                _commandView.Accepted -= CommandViewOnAccepted;
                 Remove (_commandView);
                 _commandView?.Dispose ();
             }
@@ -531,32 +556,26 @@ public class Shortcut : View, IOrientation, IDesignable
             Title = _commandView.Text;
 
             _commandView.Selected += CommandViewOnSelected;
-
-            void CommandViewOnSelected (object sender, HandledEventArgs e)
-            {
-                // Always eat CommandView.Select
-                SetFocus ();
-                e.Handled = true;
-            }
-
-            _commandView.MouseClick += CommandViewOnMouseClick;
-
-            void CommandViewOnMouseClick (object sender, MouseEventEventArgs e)
+            void CommandViewOnSelected (object sender, CommandEventArgs e)
             {
-                if (!e.Handled)
+                if (e.Context.Data != this)
                 {
-                    // If the subview (likely CommandView) didn't handle the mouse click, invoke the Accept Command.
-                    InvokeCommand (Command.Accept);
-
-                    // Always eat the mouseclick
-                    e.Handled = true;
+                    // Forward command to ourselves
+                    InvokeCommand (Command.Select, new CommandContext (Command.Select, null, null, this));
+                    e.Cancel = true;
+                }
+                else
+                {
+                    e.Cancel = true;
                 }
-
-                // Always Setfocus and invoke Select
-                SetFocus ();
-                InvokeCommand (Command.Select);
             }
 
+            _commandView.Accepted += CommandViewOnAccepted;
+            void CommandViewOnAccepted (object sender, HandledEventArgs e)
+            {
+                // Always eat CommandView.Accept
+                e.Handled = true;
+            }
 
             SetCommandViewDefaultLayout ();
             SetHelpViewDefaultLayout ();
@@ -800,13 +819,11 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         // Invoke Select on the command view to cause it to change state if it wants to
         // If this causes CommandView to raise Accept, we eat it
-        CommandView.InvokeCommand (Command.Select);
-
         var cancel = false;
 
-        cancel = RaiseAccepted () == true;
+        cancel = RaiseAccepted () is true;
 
-        if (cancel is true)
+        if (cancel)
         {
             return true;
         }

+ 2 - 2
Terminal.Gui/Views/TableView/TableView.cs

@@ -242,11 +242,11 @@ public class TableView : View
 
         AddCommand (
                     Command.Select, // was Command.ToggleChecked
-                    () =>
+                    (ctx) =>
                     {
                         if (ToggleCurrentCellSelection () is true)
                         {
-                            return RaiseSelected () is true;
+                            return RaiseSelected (ctx) is true;
                         }
 
                         return false;

+ 2 - 0
Terminal.Gui/Views/TextField.cs

@@ -404,6 +404,8 @@ public class TextField : View
         ContextMenu.KeyChanged += ContextMenu_KeyChanged;
 
         KeyBindings.Add (ContextMenu.Key, KeyBindingScope.HotKey, Command.Context);
+
+        KeyBindings.Remove (Key.Space);
     }
 
     /// <summary>

+ 9 - 1
UICatalog/Scenarios/Shortcuts.cs

@@ -356,15 +356,23 @@ public class Shortcuts : Scenario
             {
                 shortcut.Selected += (o, args) =>
                 {
+                    if (args.Cancel)
+                    {
+                        return;
+                    }
                     eventSource.Add ($"{shortcut!.Id}.Select: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
                     eventLog.MoveDown ();
-                    //args.Handled = true;
                 };
 
                 shortcut.CommandView.Selected += (o, args) =>
                 {
+                    if (args.Cancel)
+                    {
+                        return;
+                    }
                     eventSource.Add ($"{shortcut!.Id}.CommandView.Select: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
                     eventLog.MoveDown ();
+                    args.Cancel = true;
                 };
 
                 shortcut.Accepted += (o, args) =>

+ 61 - 1
UnitTests/View/Mouse/MouseTests.cs

@@ -33,6 +33,38 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews
         Assert.Equal (expectedHasFocus, testView.HasFocus);
     }
 
+
+    [Theory]
+    [InlineData (false, false, 1)]
+    [InlineData (true, false, 1)]
+    [InlineData (true, true, 1)]
+    public void MouseClick_Raises_Selected (bool canFocus, bool setFocus, int expectedSelectedCount)
+    {
+        var superView = new View { CanFocus = true, Height = 1, Width = 15 };
+        var focusedView = new View { CanFocus = true, Width = 1, Height = 1 };
+        var testView = new View { CanFocus = canFocus, X = 4, Width = 4, Height = 1 };
+        superView.Add (focusedView, testView);
+
+        focusedView.SetFocus ();
+
+        Assert.True (superView.HasFocus);
+        Assert.True (focusedView.HasFocus);
+        Assert.False (testView.HasFocus);
+
+        if (setFocus)
+        {
+            testView.SetFocus ();
+        }
+
+        int selectedCount = 0;
+        testView.Selected += (sender, args) => selectedCount++;
+
+        testView.NewMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Clicked });
+        Assert.True (superView.HasFocus);
+        Assert.Equal (expectedSelectedCount, selectedCount);
+    }
+
+
     // TODO: Add more tests that ensure the above test works with positive adornments
 
     // Test drag to move
@@ -207,7 +239,7 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews
     [InlineData (MouseFlags.Button2Clicked)]
     [InlineData (MouseFlags.Button3Clicked)]
     [InlineData (MouseFlags.Button4Clicked)]
-    public void WantContinuousButtonPressed_True_Button_Clicked_Clicks (MouseFlags clicked)
+    public void WantContinuousButtonPressed_True_Button_Clicked_Raises_MouseClick (MouseFlags clicked)
     {
         var me = new MouseEvent ();
 
@@ -229,6 +261,34 @@ public class MouseTests (ITestOutputHelper output) : TestsAllViews
         view.Dispose ();
     }
 
+
+    [Theory]
+    [InlineData (MouseFlags.Button1Clicked)]
+    [InlineData (MouseFlags.Button2Clicked)]
+    [InlineData (MouseFlags.Button3Clicked)]
+    [InlineData (MouseFlags.Button4Clicked)]
+    public void WantContinuousButtonPressed_True_Button_Clicked_Raises_Selected (MouseFlags clicked)
+    {
+        var me = new MouseEvent ();
+
+        var view = new View ()
+        {
+            Width = 1,
+            Height = 1,
+            WantContinuousButtonPressed = true
+        };
+
+        var selectedCount = 0;
+
+        view.Selected += (s, e) => selectedCount++;
+
+        me.Flags = clicked;
+        view.NewMouseEvent (me);
+        Assert.Equal (1, selectedCount);
+
+        view.Dispose ();
+    }
+
     [Theory]
     [InlineData (MouseFlags.Button1Pressed, MouseFlags.Button1Released)]
     [InlineData (MouseFlags.Button2Pressed, MouseFlags.Button2Released)]

+ 68 - 68
UnitTests/View/ViewCommandTests.cs

@@ -15,9 +15,9 @@ public class ViewCommandTests (ITestOutputHelper output)
 
         Assert.False (view.InvokeCommand (Command.Accept)); // false means it was not handled
 
-        Assert.Equal (1, view.OnAcceptCount);
+        Assert.Equal (1, view.OnAcceptedCount);
 
-        Assert.Equal (1, view.AcceptCount);
+        Assert.Equal (1, view.AcceptedCount);
 
         Assert.False (view.HasFocus);
     }
@@ -28,12 +28,12 @@ public class ViewCommandTests (ITestOutputHelper output)
         var view = new ViewEventTester ();
         Assert.False (view.HasFocus);
 
-        view.HandleOnAccept = true;
+        view.HandleOnAccepted = true;
         Assert.True (view.InvokeCommand (Command.Accept));
 
-        Assert.Equal (1, view.OnAcceptCount);
+        Assert.Equal (1, view.OnAcceptedCount);
 
-        Assert.Equal (0, view.AcceptCount);
+        Assert.Equal (0, view.AcceptedCount);
     }
 
     [Fact]
@@ -82,40 +82,40 @@ public class ViewCommandTests (ITestOutputHelper output)
         view.Add (subview);
 
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (1, subview.OnAcceptCount);
-        Assert.Equal (1, view.OnAcceptCount);
+        Assert.Equal (1, subview.OnAcceptedCount);
+        Assert.Equal (1, view.OnAcceptedCount);
 
-        subview.HandleOnAccept = true;
+        subview.HandleOnAccepted = true;
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (2, subview.OnAcceptCount);
-        Assert.Equal (1, view.OnAcceptCount);
+        Assert.Equal (2, subview.OnAcceptedCount);
+        Assert.Equal (1, view.OnAcceptedCount);
 
-        subview.HandleOnAccept = false;
-        subview.HandleAccept = true;
+        subview.HandleOnAccepted = false;
+        subview.HandleAccepted = true;
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (3, subview.OnAcceptCount);
-        Assert.Equal (1, view.OnAcceptCount);
+        Assert.Equal (3, subview.OnAcceptedCount);
+        Assert.Equal (1, view.OnAcceptedCount);
 
         // Add a super view to test deeper hierarchy
         var superView = new ViewEventTester () { Id = "superView" };
         superView.Add (view);
 
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (4, subview.OnAcceptCount);
-        Assert.Equal (1, view.OnAcceptCount);
-        Assert.Equal (0, superView.OnAcceptCount);
+        Assert.Equal (4, subview.OnAcceptedCount);
+        Assert.Equal (1, view.OnAcceptedCount);
+        Assert.Equal (0, superView.OnAcceptedCount);
 
-        subview.HandleAccept = false;
+        subview.HandleAccepted = false;
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (5, subview.OnAcceptCount);
-        Assert.Equal (2, view.OnAcceptCount);
-        Assert.Equal (1, superView.OnAcceptCount);
+        Assert.Equal (5, subview.OnAcceptedCount);
+        Assert.Equal (2, view.OnAcceptedCount);
+        Assert.Equal (1, superView.OnAcceptedCount);
 
-        view.HandleAccept = true;
+        view.HandleAccepted = true;
         subview.InvokeCommand (Command.Accept);
-        Assert.Equal (6, subview.OnAcceptCount);
-        Assert.Equal (3, view.OnAcceptCount);
-        Assert.Equal (1, superView.OnAcceptCount);
+        Assert.Equal (6, subview.OnAcceptedCount);
+        Assert.Equal (3, view.OnAcceptedCount);
+        Assert.Equal (1, superView.OnAcceptedCount);
     }
 
     [Fact]
@@ -124,7 +124,7 @@ public class ViewCommandTests (ITestOutputHelper output)
         var view = new ViewEventTester ();
         view.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked, Position = Point.Empty, View = view });
 
-        Assert.Equal (0, view.OnAcceptCount);
+        Assert.Equal (0, view.OnAcceptedCount);
     }
 
     #endregion OnAccept/Accept tests
@@ -145,9 +145,9 @@ public class ViewCommandTests (ITestOutputHelper output)
 
         Assert.Equal (canFocus, view.InvokeCommand (Command.Select));
 
-        Assert.Equal (1, view.OnSelectCount);
+        Assert.Equal (1, view.OnSelectedCount);
 
-        Assert.Equal (1, view.SelectCount);
+        Assert.Equal (1, view.SelectedCount);
 
         Assert.Equal (canFocus, view.HasFocus);
     }
@@ -158,49 +158,49 @@ public class ViewCommandTests (ITestOutputHelper output)
         var view = new ViewEventTester ();
         Assert.False (view.HasFocus);
 
-        view.HandleOnSelect = true;
+        view.HandleOnSelected = true;
         Assert.True (view.InvokeCommand (Command.Select));
 
-        Assert.Equal (1, view.OnSelectCount);
+        Assert.Equal (1, view.OnSelectedCount);
 
-        Assert.Equal (0, view.SelectCount);
+        Assert.Equal (0, view.SelectedCount);
     }
 
     [Fact]
-    public void Select_Handle_Event_OnSelect_Returns_True ()
+    public void Select_Handle_Event_OnSelected_Returns_True ()
     {
         var view = new View ();
-        var SelectInvoked = false;
+        var SelectedInvoked = false;
 
         view.Selected += ViewOnSelect;
 
         bool? ret = view.InvokeCommand (Command.Select);
         Assert.True (ret);
-        Assert.True (SelectInvoked);
+        Assert.True (SelectedInvoked);
 
         return;
 
-        void ViewOnSelect (object sender, HandledEventArgs e)
+        void ViewOnSelect (object sender, CommandEventArgs e)
         {
-            SelectInvoked = true;
-            e.Handled = true;
+            SelectedInvoked = true;
+            e.Cancel = true;
         }
     }
 
     [Fact]
-    public void Select_Command_Invokes_Select_Event ()
+    public void Select_Command_Invokes_Selected_Event ()
     {
         var view = new View ();
-        var Selected = false;
+        var selected = false;
 
-        view.Selected += ViewOnSelect;
+        view.Selected += ViewOnSelected;
 
         view.InvokeCommand (Command.Select);
-        Assert.True (Selected);
+        Assert.True (selected);
 
         return;
 
-        void ViewOnSelect (object sender, HandledEventArgs e) { Selected = true; }
+        void ViewOnSelected (object sender, CommandEventArgs e) { selected = true; }
     }
 
     [Fact]
@@ -209,7 +209,7 @@ public class ViewCommandTests (ITestOutputHelper output)
         var view = new ViewEventTester ();
         view.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked, Position = Point.Empty, View = view });
 
-        Assert.Equal (1, view.OnSelectCount);
+        Assert.Equal (1, view.OnSelectedCount);
     }
 
     #endregion OnSelect/Select tests
@@ -237,66 +237,66 @@ public class ViewCommandTests (ITestOutputHelper output)
 
             Accepted += (s, a) =>
                       {
-                          a.Handled = HandleAccept;
-                          AcceptCount++;
+                          a.Handled = HandleAccepted;
+                          AcceptedCount++;
                       };
 
             HotKeyHandled += (s, a) =>
                              {
-                                 a.Handled = HandleHotKeyCommand;
-                                 HotKeyCommandCount++;
+                                 a.Handled = HandleHotKeyHandled;
+                                 HotKeyHandledCount++;
                              };
 
 
             Selected += (s, a) =>
                              {
-                                 a.Handled = HandleSelect;
-                                 SelectCount++;
+                                 a.Cancel = HandleSelected;
+                                 SelectedCount++;
                              };
         }
 
-        public int OnAcceptCount { get; set; }
-        public int AcceptCount { get; set; }
-        public bool HandleOnAccept { get; set; }
+        public int OnAcceptedCount { get; set; }
+        public int AcceptedCount { get; set; }
+        public bool HandleOnAccepted { get; set; }
 
         /// <inheritdoc />
         protected override bool OnAccepted (HandledEventArgs args)
         {
-            OnAcceptCount++;
+            OnAcceptedCount++;
 
-            return HandleOnAccept;
+            return HandleOnAccepted;
         }
 
-        public bool HandleAccept { get; set; }
+        public bool HandleAccepted { get; set; }
 
-        public int OnHotKeyCommandCount { get; set; }
-        public int HotKeyCommandCount { get; set; }
-        public bool HandleOnHotKeyCommand { get; set; }
+        public int OnHotKeyHandledCount { get; set; }
+        public int HotKeyHandledCount { get; set; }
+        public bool HandleOnHotKeyHandled { get; set; }
 
         /// <inheritdoc />
         protected override bool OnHotKeyHandled (HandledEventArgs args)
         {
-            OnHotKeyCommandCount++;
+            OnHotKeyHandledCount++;
 
-            return HandleOnHotKeyCommand;
+            return HandleOnHotKeyHandled;
         }
 
-        public bool HandleHotKeyCommand { get; set; }
+        public bool HandleHotKeyHandled { get; set; }
 
 
-        public int OnSelectCount { get; set; }
-        public int SelectCount { get; set; }
-        public bool HandleOnSelect { get; set; }
+        public int OnSelectedCount { get; set; }
+        public int SelectedCount { get; set; }
+        public bool HandleOnSelected { get; set; }
 
         /// <inheritdoc />
-        protected override bool OnSelected (HandledEventArgs args)
+        protected override bool OnSelected (CommandEventArgs args)
         {
-            OnSelectCount++;
+            OnSelectedCount++;
 
-            return HandleOnSelect;
+            return HandleOnSelected;
         }
 
-        public bool HandleSelect { get; set; }
+        public bool HandleSelected { get; set; }
 
     }
 }

+ 36 - 10
UnitTests/Views/ButtonTests.cs

@@ -608,21 +608,33 @@ public class ButtonTests (ITestOutputHelper output)
             WantContinuousButtonPressed = true
         };
 
-        var acceptCount = 0;
+        var selectedCount = 0;
 
-        button.Accepted += (s, e) => acceptCount++;
+        button.Selected += (s, e) => selectedCount++;
+        var acceptedCount = 0;
+        button.Accepted += (s, e) =>
+                           {
+                               acceptedCount++;
+                               e.Handled = true;
+                           };
 
+        me = new MouseEvent ();
         me.Flags = pressed;
         button.NewMouseEvent (me);
-        Assert.Equal (1, acceptCount);
+        Assert.Equal (0, selectedCount);
+        Assert.Equal (0, acceptedCount);
 
+        me = new MouseEvent ();
         me.Flags = released;
         button.NewMouseEvent (me);
-        Assert.Equal (1, acceptCount);
+        Assert.Equal (0, selectedCount);
+        Assert.Equal (0, acceptedCount);
 
+        me = new MouseEvent ();
         me.Flags = clicked;
         button.NewMouseEvent (me);
-        Assert.Equal (1, acceptCount);
+        Assert.Equal (1, selectedCount);
+        Assert.Equal (1, acceptedCount);
 
         button.Dispose ();
     }
@@ -632,7 +644,7 @@ public class ButtonTests (ITestOutputHelper output)
     [InlineData (MouseFlags.Button2Pressed, MouseFlags.Button2Released)]
     [InlineData (MouseFlags.Button3Pressed, MouseFlags.Button3Released)]
     [InlineData (MouseFlags.Button4Pressed, MouseFlags.Button4Released)]
-    public void WantContinuousButtonPressed_True_ButtonPressRelease_Accepts (MouseFlags pressed, MouseFlags released)
+    public void WantContinuousButtonPressed_True_ButtonPressRelease_Does_Not_Raise_Selected_Or_Accepted (MouseFlags pressed, MouseFlags released)
     {
         var me = new MouseEvent ();
 
@@ -643,17 +655,31 @@ public class ButtonTests (ITestOutputHelper output)
             WantContinuousButtonPressed = true
         };
 
-        var acceptCount = 0;
+        var acceptedCount = 0;
 
-        button.Accepted += (s, e) => acceptCount++;
+        button.Accepted += (s, e) =>
+                           {
+                               acceptedCount++;
+                               e.Handled = true;
+                           };
+
+        var selectedCount = 0;
+
+        button.Selected += (s, e) =>
+                           {
+                               selectedCount++;
+                               e.Cancel = true;
+                           };
 
         me.Flags = pressed;
         button.NewMouseEvent (me);
-        Assert.Equal (1, acceptCount);
+        Assert.Equal (0, acceptedCount);
+        Assert.Equal (0, selectedCount);
 
         me.Flags = released;
         button.NewMouseEvent (me);
-        Assert.Equal (1, acceptCount);
+        Assert.Equal (0, acceptedCount);
+        Assert.Equal (0, selectedCount);
 
         button.Dispose ();
     }

+ 2 - 2
UnitTests/Views/CheckBoxTests.cs

@@ -576,10 +576,10 @@ public class CheckBoxTests (ITestOutputHelper output)
 
         return;
 
-        void OnSelected (object sender, HandledEventArgs e)
+        void OnSelected (object sender, CommandEventArgs e)
         {
             checkedInvoked = true;
-            e.Handled = true;
+            e.Cancel = true;
         }
     }
 

+ 1 - 1
UnitTests/Views/ComboBoxTests.cs

@@ -837,7 +837,7 @@ Three ",
         Assert.False (opened);
 
         cb.Text = "Tw";
-        Assert.True (Application.OnKeyDown (Key.Enter));
+        Assert.False (Application.OnKeyDown (Key.Enter));
         Assert.True (opened);
         Assert.Equal ("Tw", cb.Text);
         Assert.False (cb.IsShow);

+ 23 - 22
UnitTests/Views/ShortcutTests.cs

@@ -409,10 +409,9 @@ public class ShortcutTests
     [InlineData (7, 1)]
     [InlineData (8, 1)]
     [InlineData (9, 0)]
-    [AutoInitShutdown]
-    public void MouseClick_Fires_Accept (int x, int expectedAccept)
+    public void MouseClick_Raises_Accepted (int x, int expectedAccepted)
     {
-        var current = new Toplevel ();
+        Application.Top = new Toplevel ();
 
         var shortcut = new Shortcut
         {
@@ -420,9 +419,9 @@ public class ShortcutTests
             Text = "0",
             Title = "C"
         };
-        current.Add (shortcut);
-
-        Application.Begin (current);
+        Application.Top.Add (shortcut);
+        Application.Top.SetRelativeLayout (new (100, 100));
+        Application.Top.LayoutSubviews ();
 
         var accepted = 0;
         shortcut.Accepted += (s, e) => accepted++;
@@ -434,9 +433,10 @@ public class ShortcutTests
                                       Flags = MouseFlags.Button1Clicked
                                   });
 
-        Assert.Equal (expectedAccept, accepted);
+        Assert.Equal (expectedAccepted, accepted);
 
-        current.Dispose ();
+        Application.Top.Dispose ();
+        Application.ResetState (ignoreDisposed: true);
     }
 
 
@@ -447,7 +447,7 @@ public class ShortcutTests
     [InlineData (-1, 0, 0, 0, 0)]
     [InlineData (0, 0, 1, 1, 1)] // mouseX = 0 is on the CommandView.Margin, so Shortcut will get MouseClick
     [InlineData (1, 0, 1, 1, 1)] // mouseX = 1 is on the CommandView, so CommandView will get MouseClick
-    [InlineData (2, 1, 1, 1, 1)] // mouseX = 2 is on the CommandView.Margin, so Shortcut will get MouseClick
+    [InlineData (2, 0, 1, 1, 1)] // mouseX = 2 is on the CommandView.Margin, so Shortcut will get MouseClick
     [InlineData (3, 0, 1, 1, 1)]
     [InlineData (4, 0, 1, 1, 1)]
     [InlineData (5, 0, 1, 1, 1)]
@@ -465,7 +465,7 @@ public class ShortcutTests
     //[InlineData (7, 1, 0)]
     //[InlineData (8, 1, 0)]
     //[InlineData (9, 0, 0)]
-    public void MouseClick_Default_CommandView_Raises_Accept_Select_Correctly (int mouseX, int expectedCommandViewAccept, int expectedCommandViewSelect, 
+    public void MouseClick_Default_CommandView_Raises_Accepted_Select_Correctly (int mouseX, int expectedCommandViewAccept, int expectedCommandViewSelect, 
                                                                                int expectedShortcutAccept, int expectedShortcutSelect)
     {
         Application.Top = new Toplevel ();
@@ -526,7 +526,7 @@ public class ShortcutTests
     // " C  0  A "
     [InlineData (-1, 0, 0)]
     [InlineData (0, 1, 0)]
-    [InlineData (1, 1, 1)]
+    [InlineData (1, 1, 0)]
     [InlineData (2, 1, 0)]
     [InlineData (3, 1, 0)]
     [InlineData (4, 1, 0)]
@@ -535,7 +535,7 @@ public class ShortcutTests
     [InlineData (7, 1, 0)]
     [InlineData (8, 1, 0)]
     [InlineData (9, 0, 0)]
-    public void MouseClick_Button_CommandView_Raises_Shortcut_Accept
+    public void MouseClick_Button_CommandView_Raises_Shortcut_Accepted
         (int mouseX, int expectedAccept, int expectedButtonAccept)
     {
         Application.Top = new Toplevel ();
@@ -557,15 +557,16 @@ public class ShortcutTests
         shortcut.CommandView.Accepted += (s, e) =>
         {
             buttonAccepted++;
-            // Must indicate handled
-            e.Handled = true;
         };
         Application.Top.Add (shortcut);
+        Application.Top.SetRelativeLayout (new (100, 100));
+        Application.Top.LayoutSubviews ();
 
         var accepted = 0;
-        shortcut.Accepted += (s, e) => accepted++;
-
-        //Assert.True (shortcut.HasFocus);
+        shortcut.Accepted += (s, e) =>
+                             {
+                                 accepted++;
+                             };
 
         Application.OnMouseEvent (
                                   new ()
@@ -574,8 +575,8 @@ public class ShortcutTests
                                       Flags = MouseFlags.Button1Clicked
                                   });
 
-        Assert.Equal (expectedButtonAccept, buttonAccepted);
         Assert.Equal (expectedAccept, accepted);
+        Assert.Equal (expectedButtonAccept, buttonAccepted);
 
         Application.Top.Dispose ();
         Application.ResetState (true);
@@ -586,7 +587,7 @@ public class ShortcutTests
     [InlineData (true, KeyCode.C, 1)]
     [InlineData (true, KeyCode.C | KeyCode.AltMask, 1)]
     [InlineData (true, KeyCode.Enter, 1)]
-    [InlineData (true, KeyCode.Space, 0)]
+    [InlineData (true, KeyCode.Space, 1)]
     [InlineData (true, KeyCode.F1, 0)]
     [InlineData (false, KeyCode.A, 1)]
     [InlineData (false, KeyCode.C, 1)]
@@ -626,7 +627,7 @@ public class ShortcutTests
     [InlineData (KeyCode.C, 1)]
     [InlineData (KeyCode.C | KeyCode.AltMask, 1)]
     [InlineData (KeyCode.Enter, 1)]
-    [InlineData (KeyCode.Space, 0)]
+    [InlineData (KeyCode.Space, 1)]
     [InlineData (KeyCode.F1, 0)]
     public void KeyDown_App_Scope_Invokes_Accept (KeyCode key, int expectedAccept)
     {
@@ -658,7 +659,7 @@ public class ShortcutTests
     [InlineData (true, KeyCode.C, 1)]
     [InlineData (true, KeyCode.C | KeyCode.AltMask, 1)]
     [InlineData (true, KeyCode.Enter, 1)]
-    [InlineData (true, KeyCode.Space, 0)]
+    [InlineData (true, KeyCode.Space, 1)]
     [InlineData (true, KeyCode.F1, 0)]
     [InlineData (false, KeyCode.A, 1)]
     [InlineData (false, KeyCode.C, 1)]
@@ -698,7 +699,7 @@ public class ShortcutTests
     [InlineData (true, KeyCode.C, 1)]
     [InlineData (true, KeyCode.C | KeyCode.AltMask, 1)]
     [InlineData (true, KeyCode.Enter, 1)]
-    [InlineData (true, KeyCode.Space, 0)]
+    [InlineData (true, KeyCode.Space, 1)]
     [InlineData (true, KeyCode.F1, 0)]
     [InlineData (false, KeyCode.A, 1)]
     [InlineData (false, KeyCode.C, 1)]

+ 54 - 0
UnitTests/Views/TextFieldTests.cs

@@ -516,6 +516,60 @@ public class TextFieldTests (ITestOutputHelper output)
         Assert.True (tf.IsDirty);
     }
 
+    [Fact]
+    public void Space_Does_Not_Raise_Selected ()
+    {
+        TextField tf = new ();
+
+        tf.Selected += (sender, args) => Assert.Fail ("Selected should not be raied.");
+
+        Application.Top = new Toplevel ();
+        Application.Top.Add (tf);
+        tf.SetFocus ();
+        Application.OnKeyDown (Key.Space);
+
+        Application.Top.Dispose ();
+        Application.ResetState (ignoreDisposed: true);
+    }
+
+    [Fact]
+    public void Enter_Does_Not_Raise_Selected ()
+    {
+        TextField tf = new ();
+
+        int selectedCount = 0;
+        tf.Selected += (sender, args) => selectedCount++;
+
+        Application.Top = new Toplevel ();
+        Application.Top.Add (tf);
+        tf.SetFocus ();
+        Application.OnKeyDown (Key.Enter);
+
+        Assert.Equal (0, selectedCount);
+
+        Application.Top.Dispose ();
+        Application.ResetState (ignoreDisposed: true);
+    }
+
+    [Fact]
+    public void Enter_Raises_Accepted ()
+    {
+        TextField tf = new ();
+
+        int acceptedCount = 0;
+        tf.Accepted += (sender, args) => acceptedCount++;
+
+        Application.Top = new Toplevel ();
+        Application.Top.Add (tf);
+        tf.SetFocus ();
+        Application.OnKeyDown (Key.Enter);
+
+        Assert.Equal (1, acceptedCount);
+
+        Application.Top.Dispose ();
+        Application.ResetState (ignoreDisposed: true);
+    }
+
     [Fact]
     [AutoInitShutdown (useFakeClipboard: true)]
     public void KeyBindings_Command ()

+ 1 - 1
UnitTests/Views/TreeTableSourceTests.cs

@@ -150,7 +150,7 @@ public class TreeTableSourceTests : IDisposable
     }
 
     [Fact]
-    [AutoInitShutdown]
+    [AutoInitShutdown (configLocation:ConfigurationManager.ConfigLocations.DefaultOnly)]
     public void TestTreeTableSource_CombinedWithCheckboxes ()
     {
         Toplevel top = new ();