Browse Source

Toplevel cleanup

Tig 1 year ago
parent
commit
250050c8a2

+ 0 - 1
Terminal.Gui/Application/Application.Initialization.cs

@@ -40,7 +40,6 @@ public static partial class Application // Initialization (Init/Shutdown)
     internal static bool _initialized;
     internal static int _mainThreadId = -1;
 
-
     // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop.
     //
     // Called from:

+ 3 - 0
Terminal.Gui/Application/Application.Keyboard.cs

@@ -25,6 +25,7 @@ public static partial class Application // Keyboard handling
 
     private static void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
     {
+        // TODO: The fact Top has it's own AlternateForwardKey and events is needlessly complex. Remove it.
         foreach (Toplevel top in _topLevels.ToArray ())
         {
             top.OnAlternateForwardKeyChanged (e);
@@ -52,6 +53,7 @@ public static partial class Application // Keyboard handling
 
     private static void OnAlternateBackwardKeyChanged (KeyChangedEventArgs oldKey)
     {
+        // TODO: The fact Top has it's own AlternateBackwardKey and events is needlessly complex. Remove it.
         foreach (Toplevel top in _topLevels.ToArray ())
         {
             top.OnAlternateBackwardKeyChanged (oldKey);
@@ -79,6 +81,7 @@ public static partial class Application // Keyboard handling
 
     private static void OnQuitKeyChanged (KeyChangedEventArgs e)
     {
+        // TODO: The fact Top has it's own QuitKey and events is needlessly complex. Remove it.
         // Duplicate the list so if it changes during enumeration we're safe
         foreach (Toplevel top in _topLevels.ToArray ())
         {

+ 0 - 218
Terminal.Gui/Application/Application.cs

@@ -137,232 +137,14 @@ public static partial class Application
         SynchronizationContext.SetSynchronizationContext (null);
     }
 
-    // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
-    // This field is set in `End` in this case so that `Begin` correctly sets `Top`.
-
-    // TODO: Determine if this is really needed. The only code that calls WakeUp I can find
-    // is ProgressBarStyles, and it's not clear it needs to.
-
-    #region Toplevel handling
-
-    /// <summary>Holds the stack of TopLevel views.</summary>
-
-    // BUGBUG: Technically, this is not the full lst of TopLevels. There be dragons here, e.g. see how Toplevel.Id is used. What
-    // about TopLevels that are just a SubView of another View?
-    internal static readonly Stack<Toplevel> _topLevels = new ();
-
-    /// <summary>The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Application.Top"/>)</summary>
-    /// <value>The top.</value>
-    public static Toplevel? Top { get; private set; }
-
-    /// <summary>
-    ///     The current <see cref="Toplevel"/> object. This is updated in <see cref="Application.Begin"/> enters and leaves to
-    ///     point to the current
-    ///     <see cref="Toplevel"/> .
-    /// </summary>
-    /// <remarks>
-    ///     Only relevant in scenarios where <see cref="Toplevel.IsOverlappedContainer"/> is <see langword="true"/>.
-    /// </remarks>
-    /// <value>The current.</value>
-    public static Toplevel? Current { get; private set; }
-
-    private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel topLevel)
-    {
-        if (!topLevel.Running
-            || (topLevel == Current && topLevel.Visible)
-            || OverlappedTop == null
-            || _topLevels.Peek ().Modal)
-        {
-            return;
-        }
-
-        foreach (Toplevel? top in _topLevels.Reverse ())
-        {
-            if (top.Modal && top != Current)
-            {
-                MoveCurrent (top);
-
-                return;
-            }
-        }
-
-        if (!topLevel.Visible && topLevel == Current)
-        {
-            OverlappedMoveNext ();
-        }
-    }
-
 #nullable enable
-    private static Toplevel? FindDeepestTop (Toplevel start, in Point location)
-    {
-        if (!start.Frame.Contains (location))
-        {
-            return null;
-        }
-
-        if (_topLevels is { Count: > 0 })
-        {
-            int rx = location.X - start.Frame.X;
-            int ry = location.Y - start.Frame.Y;
-
-            foreach (Toplevel? t in _topLevels)
-            {
-                if (t != Current)
-                {
-                    if (t != start && t.Visible && t.Frame.Contains (rx, ry))
-                    {
-                        start = t;
-
-                        break;
-                    }
-                }
-            }
-        }
-
-        return start;
-    }
 #nullable restore
 
-    private static View FindTopFromView (View view)
-    {
-        View top = view?.SuperView is { } && view?.SuperView != Top
-                       ? view.SuperView
-                       : view;
-
-        while (top?.SuperView is { } && top?.SuperView != Top)
-        {
-            top = top.SuperView;
-        }
-
-        return top;
-    }
-
 #nullable enable
 
     // Only return true if the Current has changed.
-    private static bool MoveCurrent (Toplevel top)
-    {
-        // The Current is modal and the top is not modal Toplevel then
-        // the Current must be moved above the first not modal Toplevel.
-        if (OverlappedTop is { }
-            && top != OverlappedTop
-            && top != Current
-            && Current?.Modal == true
-            && !_topLevels.Peek ().Modal)
-        {
-            lock (_topLevels)
-            {
-                _topLevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
-            }
-
-            var index = 0;
-            Toplevel? [] savedToplevels = _topLevels.ToArray ();
-
-            foreach (Toplevel? t in savedToplevels)
-            {
-                if (!t!.Modal && t != Current && t != top && t != savedToplevels [index])
-                {
-                    lock (_topLevels)
-                    {
-                        _topLevels.MoveTo (top, index, new ToplevelEqualityComparer ());
-                    }
-                }
-
-                index++;
-            }
-
-            return false;
-        }
-
-        // The Current and the top are both not running Toplevel then
-        // the top must be moved above the first not running Toplevel.
-        if (OverlappedTop is { }
-            && top != OverlappedTop
-            && top != Current
-            && Current?.Running == false
-            && top?.Running == false)
-        {
-            lock (_topLevels)
-            {
-                _topLevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
-            }
-
-            var index = 0;
-
-            foreach (Toplevel? t in _topLevels.ToArray ())
-            {
-                if (!t.Running && t != Current && index > 0)
-                {
-                    lock (_topLevels)
-                    {
-                        _topLevels.MoveTo (top, index - 1, new ToplevelEqualityComparer ());
-                    }
-                }
-
-                index++;
-            }
-
-            return false;
-        }
-
-        if ((OverlappedTop is { } && top?.Modal == true && _topLevels.Peek () != top)
-            || (OverlappedTop is { } && Current != OverlappedTop && Current?.Modal == false && top == OverlappedTop)
-            || (OverlappedTop is { } && Current?.Modal == false && top != Current)
-            || (OverlappedTop is { } && Current?.Modal == true && top == OverlappedTop))
-        {
-            lock (_topLevels)
-            {
-                _topLevels.MoveTo (top, 0, new ToplevelEqualityComparer ());
-                Current = top;
-            }
-        }
-
-        return true;
-    }
 #nullable restore
 
-    /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
-    /// <remarks>
-    ///     Event handlers can set <see cref="SizeChangedEventArgs.Cancel"/> to <see langword="true"/> to prevent
-    ///     <see cref="Application"/> from changing it's size to match the new terminal size.
-    /// </remarks>
-    public static event EventHandler<SizeChangedEventArgs> SizeChanging;
-
-    /// <summary>
-    ///     Called when the application's size changes. Sets the size of all <see cref="Toplevel"/>s and fires the
-    ///     <see cref="SizeChanging"/> event.
-    /// </summary>
-    /// <param name="args">The new size.</param>
-    /// <returns><see lanword="true"/>if the size was changed.</returns>
-    public static bool OnSizeChanging (SizeChangedEventArgs args)
-    {
-        SizeChanging?.Invoke (null, args);
-
-        if (args.Cancel || args.Size is null)
-        {
-            return false;
-        }
-
-        foreach (Toplevel t in _topLevels)
-        {
-            t.SetRelativeLayout (args.Size.Value);
-            t.LayoutSubviews ();
-            t.PositionToplevels ();
-            t.OnSizeChanging (new (args.Size));
-
-            if (PositionCursor (t))
-            {
-                Driver.UpdateCursor ();
-            }
-        }
-
-        Refresh ();
-
-        return true;
-    }
-
-    #endregion Toplevel handling
-
     /// <summary>
     ///     Gets a string representation of the Application as rendered by <see cref="Driver"/>.
     /// </summary>

+ 26 - 31
Terminal.Gui/Views/Toplevel.cs

@@ -6,7 +6,7 @@ namespace Terminal.Gui;
 /// </summary>
 /// <remarks>
 ///     <para>
-///         Toplevels can run as modal (popup) views, started by calling
+///         Toplevel views can run as modal (popup) views, started by calling
 ///         <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>. They return control to the caller when
 ///         <see cref="Application.RequestStop(Toplevel)"/> has been called (which sets the <see cref="Toplevel.Running"/>
 ///         property to <c>false</c>).
@@ -14,7 +14,7 @@ namespace Terminal.Gui;
 ///     <para>
 ///         A Toplevel is created when an application initializes Terminal.Gui by calling <see cref="Application.Init"/>.
 ///         The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional Toplevels can be created
-///         and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and call
+///         and run (e.g. <see cref="Dialog"/>s). To run a Toplevel, create the <see cref="Toplevel"/> and call
 ///         <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>.
 ///     </para>
 /// </remarks>
@@ -259,32 +259,30 @@ public partial class Toplevel : View
             return;
         }
 
-        if (NeedsDisplay || SubViewNeedsDisplay || LayoutNeeded)
+        if (NeedsDisplay || SubViewNeedsDisplay /*|| LayoutNeeded*/)
         {
-            //Driver.SetAttribute (GetNormalColor ());
-            // TODO: It's bad practice for views to always clear. Defeats the purpose of clipping etc...
             Clear ();
-            LayoutSubviews ();
-            PositionToplevels ();
-
-            if (this == Application.OverlappedTop)
-            {
-                foreach (Toplevel top in Application.OverlappedChildren.AsEnumerable ().Reverse ())
-                {
-                    if (top.Frame.IntersectsWith (Viewport))
-                    {
-                        if (top != this && !top.IsCurrentTop && !OutsideTopFrame (top) && top.Visible)
-                        {
-                            top.SetNeedsLayout ();
-                            top.SetNeedsDisplay (top.Viewport);
-                            top.Draw ();
-                            top.OnRenderLineCanvas ();
-                        }
-                    }
-                }
-            }
+            //LayoutSubviews ();
+            //PositionToplevels ();
+
+            //if (this == Application.OverlappedTop)
+            //{
+            //    foreach (Toplevel top in Application.OverlappedChildren.AsEnumerable ().Reverse ())
+            //    {
+            //        if (top.Frame.IntersectsWith (Viewport))
+            //        {
+            //            if (top != this && !top.IsCurrentTop && !OutsideTopFrame (top) && top.Visible)
+            //            {
+            //                top.SetNeedsLayout ();
+            //                top.SetNeedsDisplay (top.Viewport);
+            //                top.Draw ();
+            //                top.OnRenderLineCanvas ();
+            //            }
+            //        }
+            //    }
+            //}
 
-            // This should not be here, but in base
+            // BUGBUG: This appears to be a hack to get ScrollBarViews to render correctly.
             foreach (View view in Subviews)
             {
                 if (view.Frame.IntersectsWith (Viewport) && !OutsideTopFrame (this))
@@ -296,12 +294,6 @@ public partial class Toplevel : View
             }
 
             base.OnDrawContent (viewport);
-
-            // This is causing the menus drawn incorrectly if UseSubMenusSingleFrame is true
-            //if (this.MenuBar is { } && this.MenuBar.IsMenuOpen && this.MenuBar.openMenu is { }) {
-            //	// TODO: Hack until we can get compositing working right.
-            //	this.MenuBar.openMenu.Redraw (this.MenuBar.openMenu.Viewport);
-            //}
         }
     }
 
@@ -315,6 +307,9 @@ public partial class Toplevel : View
     ///     Called from <see cref="Application.Begin(Toplevel)"/> before the <see cref="Toplevel"/> redraws for the first
     ///     time.
     /// </summary>
+    /// <remarks>
+    ///     Overrides must call base.OnLoaded() to ensure any Toplevel subviews are initialized properly and the <see cref="Loaded"/> event is raised.
+    /// </remarks>
     public virtual void OnLoaded ()
     {
         IsLoaded = true;