Tig 11 ماه پیش
والد
کامیت
d625921b43

+ 32 - 30
Terminal.Gui/View/View.Navigation.cs

@@ -14,7 +14,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         If there is no next/previous view, the focus is set to the view itself.
+    ///         If there is no next/previous view to advance to, the focus is set to the view itself.
     ///     </para>
     /// </remarks>
     /// <param name="direction"></param>
@@ -37,17 +37,19 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return true;
         }
 
-        // AdvanceFocus did not advance
-        View [] index = GetSubviewFocusChain (direction, behavior);
+        // AdvanceFocus did not advance - do we wrap, or move up to the superview?
 
-        if (index.Length == 0)
+        View [] focusChain = GetSubviewFocusChain (direction, behavior);
+
+        if (focusChain.Length == 0)
         {
             return false;
         }
 
+        // Special case TabGroup
         if (behavior == TabBehavior.TabGroup)
         {
-            if (direction == NavigationDirection.Forward && focused == index [^1] && SuperView is null)
+            if (direction == NavigationDirection.Forward && focused == focusChain [^1] && SuperView is null)
             {
                 // We're at the top of the focus chain. Go back down the focus chain and focus the first TabGroup
                 View [] views = GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
@@ -66,7 +68,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 }
             }
 
-            if (direction == NavigationDirection.Backward && focused == index [0])
+            if (direction == NavigationDirection.Backward && focused == focusChain [0])
             {
                 // We're at the bottom of the focus chain
                 View [] views = GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
@@ -86,38 +88,38 @@ public partial class View // Focus and cross-view navigation management (TabStop
             }
         }
 
-        int focusedIndex = index.IndexOf (Focused); // Will return -1 if Focused can't be found or is null
-        int next = 0;
+        int focusedIndex = focusChain.IndexOf (Focused); // Will return -1 if Focused can't be found or is null
+        var next = 0; // Assume we wrap to start of the focus chain
 
-        if (focusedIndex < index.Length - 1)
+        if (focusedIndex < focusChain.Length - 1)
         {
             // We're moving w/in the subviews
             next = focusedIndex + 1;
         }
         else
         {
-            // We're moving beyond the last subview
-
             // Determine if focus should remain in this focus chain, or move to the superview's focus chain
-
-            // If we are TabStop and our SuperView has at least one other TabStop subview, move to the SuperView's chain
-            if (TabStop == TabBehavior.TabStop && SuperView is { } && SuperView.GetSubviewFocusChain (direction, behavior).Length > 1)
-            {
-                return false;
-            }
-
-            // TabGroup is special-cased. 
-            if (focused?.TabStop == TabBehavior.TabGroup)
+            if (SuperView is { })
             {
-                if (SuperView?.GetSubviewFocusChain (direction, TabBehavior.TabGroup)?.Length > 0)
+                // If we are TabStop, and we have at least one other focusable peer, move to the SuperView's chain
+                if (TabStop == TabBehavior.TabStop && SuperView is { } && SuperView.GetSubviewFocusChain (direction, behavior).Length > 1)
                 {
-                    // Our superview has a TabGroup subview; signal we couldn't move so we nav out to it
                     return false;
                 }
+
+                // TabGroup is special-cased. 
+                if (focused?.TabStop == TabBehavior.TabGroup)
+                {
+                    if (SuperView?.GetSubviewFocusChain (direction, TabBehavior.TabGroup)?.Length > 0)
+                    {
+                        // Our superview has a TabGroup subview; signal we couldn't move so we nav out to it
+                        return false;
+                    }
+                }
             }
         }
 
-        View view = index [next];
+        View view = focusChain [next];
 
         if (view.HasFocus)
         {
@@ -259,7 +261,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
     {
         if (Focused is null && _subviews?.Count > 0)
         {
-            if (_previouslyMostFocused is { } /* && (behavior is null || _previouslyMostFocused.TabStop == behavior)*/)
+            if (_previouslyMostFocused is { })
             {
                 return _previouslyMostFocused.SetFocus ();
             }
@@ -355,6 +357,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
         return focusSet;
     }
 
+    /// <summary>
+    ///     Caches the most focused subview when this view is losing focus. This is used by <see cref="RestoreFocus"/>.
+    /// </summary>
+    private View? _previouslyMostFocused;
+
     /// <summary>
     ///     INTERNAL: Called when focus is going to change to this view. This method is called by <see cref="SetFocus"/> and
     ///     other methods that
@@ -625,7 +632,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         if (SuperView is { })
         {
-            SuperView._previouslyMostFocused = focusedPeer;
+            //SuperView._previouslyMostFocused = focusedPeer;
         }
 
         // Post-conditions - prove correctness
@@ -637,11 +644,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
         SetNeedsDisplay ();
     }
 
-    /// <summary>
-    ///     Caches the most focused subview when this view is losing focus. This is used by <see cref="RestoreFocus"/>.
-    /// </summary>
-    private View? _previouslyMostFocused;
-
     private void NotifyFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedVew)
     {
         // Call the virtual method

+ 24 - 5
Terminal.Gui/Views/ColorPicker.cs

@@ -64,6 +64,7 @@ public class ColorPicker : View
                     Width = textFieldWidth
                 };
                 tfValue.HasFocusChanged += UpdateSingleBarValueFromTextField;
+                tfValue.Accept += (s, _)=>UpdateSingleBarValueFromTextField(s);
                 _textFields.Add (bar, tfValue);
             }
 
@@ -153,6 +154,7 @@ public class ColorPicker : View
         _tfName.Autocomplete = auto;
 
         _tfName.HasFocusChanged += UpdateValueFromName;
+        _tfName.Accept += (_s, _) => UpdateValueFromName ();
     }
 
     private void CreateTextField ()
@@ -182,6 +184,7 @@ public class ColorPicker : View
         Add (_tfHex);
 
         _tfHex.HasFocusChanged += UpdateValueFromTextField;
+        _tfHex.Accept += (_,_)=> UpdateValueFromTextField();
     }
 
     private void DisposeOldViews ()
@@ -192,7 +195,6 @@ public class ColorPicker : View
 
             if (_textFields.TryGetValue (bar, out TextField? tf))
             {
-                tf.HasFocusChanged -= UpdateSingleBarValueFromTextField;
                 Remove (tf);
                 tf.Dispose ();
             }
@@ -214,7 +216,6 @@ public class ColorPicker : View
         if (_tfHex != null)
         {
             Remove (_tfHex);
-            _tfHex.HasFocusChanged -= UpdateValueFromTextField;
             _tfHex.Dispose ();
             _tfHex = null;
         }
@@ -229,7 +230,6 @@ public class ColorPicker : View
         if (_tfName != null)
         {
             Remove (_tfName);
-            _tfName.HasFocusChanged -= UpdateValueFromName;
             _tfName.Dispose ();
             _tfName = null;
         }
@@ -279,11 +279,18 @@ public class ColorPicker : View
 
     private void UpdateSingleBarValueFromTextField (object? sender, HasFocusEventArgs e)
     {
+        // if the new value of Focused is true then it is an enter event so ignore
         if (e.NewValue)
         {
             return;
         }
 
+        // it is a leave event so update
+        UpdateSingleBarValueFromTextField (sender);
+    }
+    private void UpdateSingleBarValueFromTextField (object? sender)
+    {
+
         foreach (KeyValuePair<IColorBar, TextField> kvp in _textFields)
         {
             if (kvp.Value == sender)
@@ -296,13 +303,19 @@ public class ColorPicker : View
         }
     }
 
-    private void UpdateValueFromName (object? sender, HasFocusEventArgs e)
+    private void UpdateValueFromName (object sender, HasFocusEventArgs e)
     {
+        // if the new value of Focused is true then it is an enter event so ignore
         if (e.NewValue)
         {
             return;
         }
 
+        // it is a leave event so update
+        UpdateValueFromName();
+    }
+    private void UpdateValueFromName ()
+    {
         if (_tfName == null)
         {
             return;
@@ -321,11 +334,17 @@ public class ColorPicker : View
 
     private void UpdateValueFromTextField (object? sender, HasFocusEventArgs e)
     {
-            if (e.NewValue)
+        // if the new value of Focused is true then it is an enter event so ignore
+        if (e.NewValue)
         {
             return;
         }
 
+        // it is a leave event so update
+        UpdateValueFromTextField ();
+    }
+    private void UpdateValueFromTextField ()
+    {
         if (_tfHex == null)
         {
             return;

+ 4 - 0
Terminal.Gui/Views/DatePicker.cs

@@ -192,6 +192,7 @@ public class DatePicker : View
 
         _calendar = new TableView
         {
+            Id = "_calendar",
             X = 0,
             Y = Pos.Bottom (_dateLabel),
             Height = 11,
@@ -206,6 +207,7 @@ public class DatePicker : View
 
         _dateField = new DateField (DateTime.Now)
         {
+            Id = "_dateField",
             X = Pos.Right (_dateLabel),
             Y = 0,
             Width = Dim.Width (_calendar) - Dim.Width (_dateLabel),
@@ -215,6 +217,7 @@ public class DatePicker : View
 
         _previousMonthButton = new Button
         {
+            Id = "_previousMonthButton",
             X = Pos.Center () - 2,
             Y = Pos.Bottom (_calendar) - 1,
             Width = 2,
@@ -234,6 +237,7 @@ public class DatePicker : View
 
         _nextMonthButton = new Button
         {
+            Id = "_nextMonthButton",
             X = Pos.Right (_previousMonthButton) + 2,
             Y = Pos.Bottom (_calendar) - 1,
             Width = 2,

+ 5 - 8
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -351,14 +351,11 @@ public class Wizard : Dialog
 
         UpdateButtonsAndTitle ();
 
-        // Set focus to the nav buttons
-        if (BackButton.HasFocus)
-        {
-            BackButton.SetFocus ();
-        }
-        else
+
+        // Set focus on the contentview
+        if (newStep is { })
         {
-            NextFinishButton.SetFocus ();
+            newStep.Subviews.ToArray () [0].SetFocus ();
         }
 
         if (OnStepChanged (oldStep, _currentStep))
@@ -543,7 +540,7 @@ public class Wizard : Dialog
 
         SetNeedsLayout ();
         LayoutSubviews ();
-        Draw ();
+        //Draw ();
     }
 
     private void Wizard_Closing (object sender, ToplevelClosingEventArgs obj)

+ 15 - 11
Terminal.Gui/Views/Wizard/WizardStep.cs

@@ -36,8 +36,21 @@ public class WizardStep : View
     //private string title = string.Empty;
 
     // The contentView works like the ContentView in FrameView.
-    private readonly View _contentView = new () { CanFocus = true, TabStop = TabBehavior.TabStop, Id = "WizardContentView" };
-    private readonly TextView _helpTextView = new ();
+    private readonly View _contentView = new ()
+    {
+        CanFocus = true,
+        TabStop = TabBehavior.TabStop,
+        Id = "WizardStep._contentView"
+    };
+    private readonly TextView _helpTextView = new ()
+    {
+        CanFocus = true,
+        TabStop = TabBehavior.TabStop,
+        ReadOnly = true,
+        WordWrap = true,
+        AllowsTab = false,
+        Id = "WizardStep._helpTextView"
+    };
 
     /// <summary>
     ///     Initializes a new instance of the <see cref="Wizard"/> class.
@@ -49,10 +62,6 @@ public class WizardStep : View
         BorderStyle = LineStyle.None;
         base.Add (_contentView);
 
-        _helpTextView.CanFocus = true;
-        _helpTextView.TabStop = TabBehavior.NoStop;
-        _helpTextView.ReadOnly = true;
-        _helpTextView.WordWrap = true;
         base.Add (_helpTextView);
 
         // BUGBUG: v2 - Disabling scrolling for now
@@ -148,11 +157,6 @@ public class WizardStep : View
     /// <remarks></remarks>
     public override View Remove (View view)
     {
-        if (view is null)
-        {
-            return view;
-        }
-
         SetNeedsDisplay ();
         View container = view?.SuperView;
 

+ 29 - 10
UICatalog/Scenarios/Wizards.cs

@@ -26,7 +26,7 @@ public class Wizards : Scenario
         };
         win.Add (frame);
 
-        var label = new Label { X = 0, Y = 0, TextAlignment = Alignment.End, Text = "Width:" };
+        var label = new Label { X = 0, Y = 0, TextAlignment = Alignment.End, Text = "_Width:", Width = 10 };
         frame.Add (label);
 
         var widthEdit = new TextField
@@ -39,7 +39,7 @@ public class Wizards : Scenario
         };
         frame.Add (widthEdit);
 
-        label = new()
+        label = new ()
         {
             X = 0,
             Y = Pos.Bottom (label),
@@ -47,7 +47,7 @@ public class Wizards : Scenario
             Width = Dim.Width (label),
             Height = 1,
             TextAlignment = Alignment.End,
-            Text = "Height:"
+            Text = "_Height:"
         };
         frame.Add (label);
 
@@ -61,7 +61,7 @@ public class Wizards : Scenario
         };
         frame.Add (heightEdit);
 
-        label = new()
+        label = new ()
         {
             X = 0,
             Y = Pos.Bottom (label),
@@ -69,7 +69,7 @@ public class Wizards : Scenario
             Width = Dim.Width (label),
             Height = 1,
             TextAlignment = Alignment.End,
-            Text = "Title:"
+            Text = "_Title:"
         };
         frame.Add (label);
 
@@ -91,7 +91,7 @@ public class Wizards : Scenario
 
         win.Loaded += Win_Loaded;
 
-        label = new()
+        label = new ()
         {
             X = Pos.Center (), Y = Pos.AnchorEnd (1), TextAlignment = Alignment.End, Text = "Action:"
         };
@@ -105,7 +105,7 @@ public class Wizards : Scenario
 
         var showWizardButton = new Button
         {
-            X = Pos.Center (), Y = Pos.Bottom (frame) + 2, IsDefault = true, Text = "Show Wizard"
+            X = Pos.Center (), Y = Pos.Bottom (frame) + 2, IsDefault = true, Text = "_Show Wizard"
         };
 
         showWizardButton.Accept += (s, e) =>
@@ -162,6 +162,13 @@ public class Wizards : Scenario
 
                                            firstStep.HelpText =
                                                "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA.";
+
+                                           RadioGroup radioGroup = new ()
+                                           {
+                                               RadioLabels = ["_One", "_Two", "_3"]
+                                           };
+                                           firstStep.Add (radioGroup);
+
                                            wizard.AddStep (firstStep);
 
                                            // Add 2nd step
@@ -178,6 +185,13 @@ public class Wizards : Scenario
                                                Text = "Press Me to Rename Step", X = Pos.Right (buttonLbl), Y = Pos.Top (buttonLbl)
                                            };
 
+                                           RadioGroup radioGroup2 = new ()
+                                           {
+                                               RadioLabels = ["_A", "_B", "_C"],
+                                               Orientation = Orientation.Horizontal
+                                           };
+                                           secondStep.Add (radioGroup2);
+
                                            button.Accept += (s, e) =>
                                                             {
                                                                 secondStep.Title = "2nd Step";
@@ -193,7 +207,7 @@ public class Wizards : Scenario
                                            var firstNameField =
                                                new TextField { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
                                            secondStep.Add (lbl, firstNameField);
-                                           lbl = new() { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
+                                           lbl = new () { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
                                            var lastNameField = new TextField { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
                                            secondStep.Add (lbl, lastNameField);
 
@@ -214,7 +228,7 @@ public class Wizards : Scenario
                                                Width = Dim.Fill (),
                                                Height = 4,
                                                Title = "A Broken Frame (by Depeche Mode)",
-                                               TabStop = TabBehavior.TabStop
+                                               TabStop = TabBehavior.NoStop
                                            };
                                            frame.Add (new TextField { Text = "This is a TextField inside of the frame." });
                                            secondStep.Add (frame);
@@ -287,7 +301,7 @@ public class Wizards : Scenario
                                                                      }
                                                                  };
                                            fourthStep.Add (hideHelpBtn);
-                                           fourthStep.NextButtonText = "Go To Last Step";
+                                           fourthStep.NextButtonText = "_Go To Last Step";
                                            var scrollBar = new ScrollBarView (someText, true);
 
                                            scrollBar.ChangedPosition += (s, e) =>
@@ -356,4 +370,9 @@ public class Wizards : Scenario
         win.Dispose ();
         Application.Shutdown ();
     }
+
+    private void Wizard_StepChanged (object sender, StepChangeEventArgs e)
+    {
+        throw new NotImplementedException ();
+    }
 }

+ 130 - 1
UnitTests/View/Navigation/AdvanceFocusTests.cs

@@ -1,4 +1,5 @@
-using Xunit.Abstractions;
+using System.Runtime.Intrinsics;
+using Xunit.Abstractions;
 
 namespace Terminal.Gui.ViewTests;
 
@@ -72,6 +73,38 @@ public class AdvanceFocusTests ()
         r.Dispose ();
     }
 
+
+    [Fact]
+    public void AdvanceFocus_Subviews_TabStop ()
+    {
+        TabBehavior behavior = TabBehavior.TabStop;
+        var top = new View { Id = "top", CanFocus = true };
+
+        var v1 = new View { Id = "v1", CanFocus = true, TabStop = behavior };
+        var v2 = new View { Id = "v2", CanFocus = true, TabStop = behavior };
+        var v3 = new View { Id = "v3", CanFocus = false, TabStop = behavior };
+
+        top.Add (v1, v2, v3);
+
+        // Cycle through v1 & v2
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v1.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v2.HasFocus);
+
+        // Should cycle back to v1
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v1.HasFocus);
+
+        // Go backwards
+        top.AdvanceFocus (NavigationDirection.Backward, behavior);
+        Assert.True (v2.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Backward, behavior);
+        Assert.True (v1.HasFocus);
+
+        top.Dispose ();
+    }
+
     [Fact]
     public void AdvanceFocus_Compound_Subview_TabStop ()
     {
@@ -145,6 +178,102 @@ public class AdvanceFocusTests ()
         top.Dispose ();
     }
 
+
+    [Fact]
+    public void AdvanceFocus_CompoundCompound_Subview_TabStop ()
+    {
+        TabBehavior behavior = TabBehavior.TabStop;
+        var top = new View { Id = "top", CanFocus = true };
+        var topv1 = new View { Id = "topv1", CanFocus = true, TabStop = behavior };
+        var topv2 = new View { Id = "topv2", CanFocus = true, TabStop = behavior };
+        var topv3 = new View { Id = "topv3", CanFocus = false, TabStop = behavior };
+        top.Add (topv1, topv2, topv3);
+
+        var compoundSubview = new View
+        {
+            CanFocus = true,
+            Id = "compoundSubview",
+            TabStop = behavior
+        };
+        var v1 = new View { Id = "v1", CanFocus = true, TabStop = behavior };
+        var v2 = new View { Id = "v2", CanFocus = true, TabStop = behavior };
+        var v3 = new View { Id = "v3", CanFocus = false, TabStop = behavior };
+
+        compoundSubview.Add (v1, v2, v3);
+
+
+        var compoundCompoundSubview = new View
+        {
+            CanFocus = true,
+            Id = "compoundCompoundSubview",
+            TabStop = behavior
+        };
+        var v4 = new View { Id = "v4", CanFocus = true, TabStop = behavior };
+        var v5 = new View { Id = "v5", CanFocus = true, TabStop = behavior };
+        var v6 = new View { Id = "v6", CanFocus = false, TabStop = behavior };
+
+        compoundCompoundSubview.Add (v4, v5, v6);
+
+        compoundSubview.Add (compoundCompoundSubview);
+
+        top.Add (compoundSubview);
+
+        top.SetFocus ();
+        Assert.True (topv1.HasFocus);
+
+        // Cycle through topv2
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv2.HasFocus);
+
+        // Cycle v1, v2, v4, v5
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v1.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v2.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v4.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v5.HasFocus);
+
+        // Should cycle back to topv1
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv1.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv2.HasFocus);
+
+        // Add another top subview. Should cycle to it after v5
+        View otherSubview = new ()
+        {
+            CanFocus = true,
+            TabStop = behavior,
+            Id = "otherSubview"
+        };
+
+        top.Add (otherSubview);
+
+        // Adding a focusable subview causes advancefocus
+        Assert.True (otherSubview.HasFocus);
+
+        // Cycle through topv1, topv2, v1, v2, v4, v5
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv1.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv2.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+
+        // the above should have cycled to v5 since it was the previously most focused subview of compoundSubView
+        Assert.True (v5.HasFocus);
+
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (otherSubview.HasFocus);
+
+        // Should cycle back to topv1
+        top.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (topv1.HasFocus);
+
+        top.Dispose ();
+    }
+
     [Fact]
     public void AdvanceFocus_Compound_Subview_TabGroup ()
     {

+ 58 - 0
UnitTests/Views/ColorPickerTests.cs

@@ -790,6 +790,64 @@ public class ColorPickerTests
         Application.ResetState ();
     }
 
+    /// <summary>
+    /// In this version we use the Enter button to accept the typed text instead
+    /// of tabbing to the next view.
+    /// </summary>
+    [Fact]
+    [SetupFakeDriver]
+    public void ColorPicker_EnterHexFor_ColorName_AcceptVariation ()
+    {
+        var cp = GetColorPicker (ColorModel.RGB, true, true);
+        Application.Navigation = new ();
+        Application.Current = new ();
+        Application.Current.Add (cp);
+
+        cp.Draw ();
+
+        var name = GetTextField (cp, ColorPickerPart.ColorName);
+        var hex = GetTextField (cp, ColorPickerPart.Hex);
+
+        hex.SetFocus ();
+
+        Assert.True (hex.HasFocus);
+        Assert.Same (hex, cp.Focused);
+
+        hex.Text = "";
+        name.Text = "";
+
+        Assert.Empty (hex.Text);
+        Assert.Empty (name.Text);
+
+        Application.OnKeyDown ('#');
+        Assert.Empty (name.Text);
+        //7FFFD4
+
+        Assert.Equal ("#", hex.Text);
+        Application.OnKeyDown ('7');
+        Application.OnKeyDown ('F');
+        Application.OnKeyDown ('F');
+        Application.OnKeyDown ('F');
+        Application.OnKeyDown ('D');
+        Assert.Empty (name.Text);
+
+        Application.OnKeyDown ('4');
+
+        Assert.True (hex.HasFocus);
+
+        // Should stay in the hex field (because accept not tab)
+        Application.OnKeyDown (Key.Enter);
+        Assert.True (hex.HasFocus);
+        Assert.Same (hex, cp.Focused);
+
+        // But still, Color name should be recognised as a known string and populated
+        Assert.Equal ("#7FFFD4", hex.Text);
+        Assert.Equal ("Aquamarine", name.Text);
+
+        Application.Current?.Dispose ();
+        Application.ResetState ();
+    }
+
     [Fact]
     public void TestColorNames ()
     {

+ 19 - 7
UnitTests/Views/DatePickerTests.cs

@@ -71,18 +71,25 @@ public class DatePickerTests
         top.Add (datePicker);
         Application.Begin (top);
 
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_dateField"), datePicker.Focused);
+
         // Set focus to next month button
         datePicker.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_calendar"), datePicker.Focused);
         datePicker.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_previousMonthButton"), datePicker.Focused);
         datePicker.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_nextMonthButton"), datePicker.Focused);
 
         // Change month to December
         Assert.True (Application.OnKeyDown (Key.Enter));
         Assert.Equal (12, datePicker.Date.Month);
 
-        // Date should change as next month button was disabled, causing focus to advance
-        Assert.True (Application.OnKeyDown (Key.Enter));
-        Assert.Equal (11, datePicker.Date.Month);
+        // Next month button is disabled, so focus advanced to edit field
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_dateField"), datePicker.Focused);
+
+        // Pressing enter on datefield does nothing
+        Assert.False (Application.OnKeyDown (Key.Enter));
         top.Dispose ();
     }
 
@@ -98,17 +105,22 @@ public class DatePickerTests
         top.Add (datePicker);
         Application.Begin (top);
 
-        // set focus to the previous month button
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_dateField"), datePicker.Focused);
+
         datePicker.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_calendar"), datePicker.Focused);
         datePicker.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_previousMonthButton"), datePicker.Focused);
 
         // Change month to January 
         Assert.True (datePicker.NewKeyDownEvent (Key.Enter));
         Assert.Equal (1, datePicker.Date.Month);
 
-        // Previous month button is disabled, so focus advanced to edit field
-        Assert.True (datePicker.NewKeyDownEvent (Key.Enter));
-        Assert.Equal (1, datePicker.Date.Month);
+        // Next prev button is disabled, so focus advanced to edit button
+        Assert.Equal (datePicker.Subviews.First (v => v.Id == "_dateField"), datePicker.Focused);
+
+        // Pressing enter on datefield does nothing
+        Assert.False (Application.OnKeyDown (Key.Enter));
         top.Dispose ();
     }
 }