浏览代码

Hacked in Application.Navigation.Set/GetFocused

Tig 1 年之前
父节点
当前提交
4985da476e

+ 70 - 0
Terminal.Gui/Application/ApplicationNavigation.cs

@@ -7,6 +7,7 @@ namespace Terminal.Gui;
 /// </summary>
 public class ApplicationNavigation
 {
+
     /// <summary>
     ///     Initializes a new instance of the <see cref="ApplicationNavigation"/> class.
     /// </summary>
@@ -15,6 +16,75 @@ public class ApplicationNavigation
         // TODO: Move navigation key bindings here from AddApplicationKeyBindings
     }
 
+    private View? _focused = null;
+
+    /// <summary>
+    ///     Gets the most focused <see cref="View"/> in the application, if there is one.
+    /// </summary>
+    public View? GetFocused () { return _focused; }
+
+    /// <summary>
+    ///     INTERNAL method to record the most focused <see cref="View"/> in the application.
+    /// </summary>
+    /// <remarks>
+    ///     Raises <see cref="FocusedChanged"/>.
+    /// </remarks>
+    internal void SetFocused (View? value)
+    {
+        if (_focused == value)
+        {
+            return;
+        }
+
+        _focused = value;
+
+        FocusedChanged?.Invoke (null, EventArgs.Empty);
+
+        return;
+    }
+
+    /// <summary>
+    ///     Raised when the most focused <see cref="View"/> in the application has changed.
+    /// </summary>
+    public event EventHandler<EventArgs>? FocusedChanged;
+
+
+    /// <summary>
+    ///     Gets whether <paramref name="view"/> is in the Subview hierarchy of <paramref name="start"/>.
+    /// </summary>
+    /// <param name="start"></param>
+    /// <param name="view"></param>
+    /// <returns></returns>
+    public static bool IsInHierarchy (View start, View? view)
+    {
+        if (view is null)
+        {
+            return false;
+        }
+
+        if (view == start)
+        {
+            return true;
+        }
+
+        foreach (View subView in start.Subviews)
+        {
+            if (view == subView)
+            {
+                return true;
+            }
+
+            var found = IsInHierarchy (subView, view);
+            if (found)
+            {
+                return found;
+            }
+        }
+
+        return false;
+    }
+
+
     /// <summary>
     ///     Gets the deepest focused subview of the specified <paramref name="view"/>.
     /// </summary>

+ 18 - 0
Terminal.Gui/View/View.Navigation.cs

@@ -72,6 +72,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
         {
             if (Focused.AdvanceFocus (direction, behavior))
             {
+                // TODO: Temporary hack to make Application.Navigation.FocusChanged work
+                if (Focused.Focused is null)
+                {
+                    Application.Navigation!.SetFocused (Focused);
+                }
                 return true;
             }
         }
@@ -144,6 +149,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
             SetFocus (view);
 
+            // TODO: Temporary hack to make Application.Navigation.FocusChanged work
+            if (view.Focused is null)
+            {
+                Application.Navigation!.SetFocused (view);
+            }
+
             return true;
         }
 
@@ -604,6 +615,13 @@ public partial class View // Focus and cross-view navigation management (TabStop
         {
             // If there is no SuperView, then this is a top-level view
             SetFocus (this);
+
+        }
+
+        // TODO: Temporary hack to make Application.Navigation.FocusChanged work
+        if (HasFocus && Focused.Focused is null)
+        {
+            Application.Navigation!.SetFocused (Focused);
         }
 
         // TODO: This is a temporary hack to make overlapped non-Toplevels have a zorder. See also: View.OnDrawContent.

+ 20 - 20
UICatalog/Scenarios/AdornmentsEditor.cs

@@ -34,27 +34,27 @@ public class AdornmentsEditor : View
 
         TabStop = TabBehavior.TabGroup;
 
-        Application.MouseEvent += Application_MouseEvent;
-        //ApplicationNavigation.FocusedChanged += ApplicationNavigationOnFocusedChanged;
+        //Application.MouseEvent += Application_MouseEvent;
+        Application.Navigation!.FocusedChanged += ApplicationNavigationOnFocusedChanged;
         Initialized += AdornmentsEditor_Initialized;
     }
 
-    //private void ApplicationNavigationOnFocusedChanged (object sender, EventArgs e)
-    //{
-    //    if (ApplicationNavigation.IsInHierarchy (this, ApplicationNavigation.Focused))
-    //    {
-    //        return;
-    //    }
-
-    //    if (ApplicationNavigation.Focused is Adornment adornment)
-    //    {
-    //        ViewToEdit = adornment.Parent;
-    //    }
-    //    else
-    //    {
-    //        ViewToEdit = ApplicationNavigation.Focused;
-    //    }
-    //}
+    private void ApplicationNavigationOnFocusedChanged (object sender, EventArgs e)
+    {
+        if (ApplicationNavigation.IsInHierarchy (this, Application.Navigation!.GetFocused ()))
+        {
+            return;
+        }
+
+        if (Application.Navigation!.GetFocused () is Adornment adornment)
+        {
+            ViewToEdit = adornment.Parent;
+        }
+        else
+        {
+            ViewToEdit = Application.Navigation.GetFocused ();
+        }
+    }
 
     /// <summary>
     /// Gets or sets whether the AdornmentsEditor should automatically select the View to edit when the mouse is clicked
@@ -128,7 +128,7 @@ public class AdornmentsEditor : View
         _diagPaddingCheckBox.Y = Pos.Bottom (_paddingEditor);
 
         _diagRulerCheckBox = new () { Text = "_Diagnostic Ruler" };
-        _diagRulerCheckBox.State = Diagnostics.FastHasFlags(ViewDiagnosticFlags.Ruler) ? CheckState.Checked : CheckState.UnChecked;
+        _diagRulerCheckBox.State = Diagnostics.FastHasFlags (ViewDiagnosticFlags.Ruler) ? CheckState.Checked : CheckState.UnChecked;
 
         _diagRulerCheckBox.Toggle += (s, e) =>
                                       {
@@ -192,7 +192,7 @@ public class AdornmentsEditor : View
             _borderEditor.AdornmentToEdit = _viewToEdit?.Border ?? null;
             _paddingEditor.AdornmentToEdit = _viewToEdit?.Padding ?? null;
 
-            _lblView.Text = $"{_viewToEdit?.GetType ().Name}: {_viewToEdit?.Id}"  ?? string.Empty;
+            _lblView.Text = $"{_viewToEdit?.GetType ().Name}: {_viewToEdit?.Id}" ?? string.Empty;
 
             return;
         }

+ 3 - 1
UnitTests/UICatalog/ScenarioTests.cs

@@ -40,6 +40,7 @@ public class ScenarioTests : TestsAllViews
         var initialized = false;
         var shutdown = false;
         object timeout = null;
+        int iterationCount = 0;
 
         Application.InitializedChanged += OnApplicationOnInitializedChanged;
 
@@ -106,7 +107,7 @@ public class ScenarioTests : TestsAllViews
             }
 
             Assert.Fail (
-                         $"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms. Force quit.");
+                         $"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
 
             Application.ResetState (true);
 
@@ -115,6 +116,7 @@ public class ScenarioTests : TestsAllViews
 
         void OnApplicationOnIteration (object s, IterationEventArgs a)
         {
+            iterationCount++;
             if (Application.IsInitialized)
             {
                 // Press QuitKey