Răsfoiți Sursa

Toplevel.cs organization

Tig 1 an în urmă
părinte
comite
47010805cd
1 a modificat fișierele cu 356 adăugiri și 312 ștergeri
  1. 356 312
      Terminal.Gui/Views/Toplevel.cs

+ 356 - 312
Terminal.Gui/Views/Toplevel.cs

@@ -27,12 +27,45 @@ public partial class Toplevel : View
     /// </summary>
     public Toplevel ()
     {
+        CanFocus = true;
         Arrangement = ViewArrangement.Fixed;
         Width = Dim.Fill ();
         Height = Dim.Fill ();
 
         ColorScheme = Colors.ColorSchemes ["TopLevel"];
 
+        ConfigureKeyBindings ();
+
+        MouseClick += Toplevel_MouseClick;
+    }
+
+    // TODO: IRunnable: Re-implement - Modal means IRunnable, ViewArrangement.Overlapped where modalView.Z > allOtherViews.Max (v = v.Z).
+    /// <summary>
+    ///     Determines whether the <see cref="Toplevel"/> is modal or not. If set to <c>false</c> (the default):
+    ///     <list type="bullet">
+    ///         <item>
+    ///             <description><see cref="View.OnKeyDown"/> events will propagate keys upwards.</description>
+    ///         </item>
+    ///         <item>
+    ///             <description>The Toplevel will act as an embedded view (not a modal/pop-up).</description>
+    ///         </item>
+    ///     </list>
+    ///     If set to <c>true</c>:
+    ///     <list type="bullet">
+    ///         <item>
+    ///             <description><see cref="View.OnKeyDown"/> events will NOT propagate keys upwards.</description>
+    ///         </item>
+    ///         <item>
+    ///             <description>The Toplevel will and look like a modal (pop-up) (e.g. see <see cref="Dialog"/>.</description>
+    ///         </item>
+    ///     </list>
+    /// </summary>
+    public bool Modal { get; set; }
+
+    #region Keyboard & Mouse
+
+    private void ConfigureKeyBindings ()
+    {
         // Things this view knows how to do
         AddCommand (
                     Command.QuitToplevel,
@@ -134,107 +167,19 @@ public partial class Toplevel : View
         KeyBindings.Add (Key.I.WithCtrl, Command.NextView); // Unix
         KeyBindings.Add (Key.B.WithCtrl, Command.PreviousView); // Unix
 #endif
-        MouseClick += Toplevel_MouseClick;
-
-        CanFocus = true;
-    }
-
-    private void Toplevel_MouseClick (object sender, MouseEventEventArgs e)
-    {
-        e.Handled = InvokeCommand (Command.HotKey) == true;
     }
 
-    /// <summary>
-    ///     <see langword="true"/> if was already loaded by the <see cref="Application.Begin(Toplevel)"/>
-    ///     <see langword="false"/>, otherwise.
-    /// </summary>
-    public bool IsLoaded { get; private set; }
-
-    /// <summary>Gets or sets the menu for this Toplevel.</summary>
-    public virtual MenuBar MenuBar { get; set; }
-
-    /// <summary>
-    ///     Determines whether the <see cref="Toplevel"/> is modal or not. If set to <c>false</c> (the default):
-    ///     <list type="bullet">
-    ///         <item>
-    ///             <description><see cref="View.OnKeyDown"/> events will propagate keys upwards.</description>
-    ///         </item>
-    ///         <item>
-    ///             <description>The Toplevel will act as an embedded view (not a modal/pop-up).</description>
-    ///         </item>
-    ///     </list>
-    ///     If set to <c>true</c>:
-    ///     <list type="bullet">
-    ///         <item>
-    ///             <description><see cref="View.OnKeyDown"/> events will NOT propagate keys upwards.</description>
-    ///         </item>
-    ///         <item>
-    ///             <description>The Toplevel will and look like a modal (pop-up) (e.g. see <see cref="Dialog"/>.</description>
-    ///         </item>
-    ///     </list>
-    /// </summary>
-    public bool Modal { get; set; }
-
-    /// <summary>Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not.</summary>
-    /// <remarks>Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/> instead.</remarks>
-    public bool Running { get; set; }
-
-    /// <summary>Gets or sets the status bar for this Toplevel.</summary>
-    public virtual StatusBar StatusBar { get; set; }
-
-    /// <summary>Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/> Toplevel.</summary>
-    public event EventHandler<ToplevelEventArgs> Activate;
-
-    /// <inheritdoc/>
-    public override View Add (View view)
-    {
-        CanFocus = true;
-        AddMenuStatusBar (view);
-        return base.Add (view);
-    }
-
-    /// <summary>
-    ///     Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from by
-    ///     <see cref="Application.End(RunState)"/>.
-    /// </summary>
-    public event EventHandler AllChildClosed;
+    private void Toplevel_MouseClick (object sender, MouseEventEventArgs e) { e.Handled = InvokeCommand (Command.HotKey) == true; }
 
+    // TODO: Deprecate - No need for this at View level; having at Application is sufficient.
     /// <summary>Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.</summary>
     public event EventHandler<KeyChangedEventArgs> AlternateBackwardKeyChanged;
 
+    // TODO: Deprecate - No need for this at View level; having at Application is sufficient.
     /// <summary>Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.</summary>
     public event EventHandler<KeyChangedEventArgs> AlternateForwardKeyChanged;
 
-    /// <summary>
-    ///     Invoked when a child of the Toplevel <see cref="RunState"/> is closed by
-    ///     <see cref="Application.End(RunState)"/>.
-    /// </summary>
-    public event EventHandler<ToplevelEventArgs> ChildClosed;
-
-    /// <summary>Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.</summary>
-    public event EventHandler<ToplevelEventArgs> ChildLoaded;
-
-    /// <summary>Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.</summary>
-    public event EventHandler<ToplevelEventArgs> ChildUnloaded;
-
-    /// <summary>Invoked when the Toplevel's <see cref="RunState"/> is closed by <see cref="Application.End(RunState)"/>.</summary>
-    public event EventHandler<ToplevelEventArgs> Closed;
-
-    /// <summary>
-    ///     Invoked when the Toplevel's <see cref="RunState"/> is being closed by
-    ///     <see cref="Application.RequestStop(Toplevel)"/>.
-    /// </summary>
-    public event EventHandler<ToplevelClosingEventArgs> Closing;
-
-    /// <summary>Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.</summary>
-    public event EventHandler<ToplevelEventArgs> Deactivate;
-
-    /// <summary>
-    ///     Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded. A Loaded event handler
-    ///     is a good place to finalize initialization before calling <see cref="Application.RunLoop(RunState)"/>.
-    /// </summary>
-    public event EventHandler Loaded;
-
+    // TODO: Deprecate - No need for this at View level; having at Application is sufficient.
     /// <summary>Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.</summary>
     /// <param name="e"></param>
     public virtual void OnAlternateBackwardKeyChanged (KeyChangedEventArgs e)
@@ -243,6 +188,7 @@ public partial class Toplevel : View
         AlternateBackwardKeyChanged?.Invoke (this, e);
     }
 
+    // TODO: Deprecate - No need for this at View level; having at Application is sufficient.
     /// <summary>Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.</summary>
     /// <param name="e"></param>
     public virtual void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
@@ -251,189 +197,171 @@ public partial class Toplevel : View
         AlternateForwardKeyChanged?.Invoke (this, e);
     }
 
-    /// <inheritdoc/>
-    public override void OnDrawContent (Rectangle viewport)
+    /// <summary>Virtual method to invoke the <see cref="QuitKeyChanged"/> event.</summary>
+    /// <param name="e"></param>
+    public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
     {
-        if (!Visible)
-        {
-            return;
-        }
+        KeyBindings.Replace (e.OldKey, e.NewKey);
+        QuitKeyChanged?.Invoke (this, e);
+    }
 
-        if (NeedsDisplay || SubViewNeedsDisplay /*|| LayoutNeeded*/)
-        {
-            Clear ();
-            //LayoutSubviews ();
-            //PositionToplevels ();
+    /// <summary>Invoked when the <see cref="Application.QuitKey"/> is changed.</summary>
+    public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
 
-            //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 ();
-            //            }
-            //        }
-            //    }
-            //}
+    #endregion
 
-            // 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))
-                {
-                    //view.SetNeedsLayout ();
-                    view.SetNeedsDisplay ();
-                    view.SetSubViewNeedsDisplay ();
-                }
-            }
+    #region Subviews
 
-            base.OnDrawContent (viewport);
-        }
-    }
+    // TODO: Deprecate - Any view can host a menubar in v2
+    /// <summary>Gets or sets the menu for this Toplevel.</summary>
+    public virtual MenuBar MenuBar { get; set; }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view) { return MostFocused?.OnEnter (view) ?? base.OnEnter (view); }
+    // TODO: Deprecate - Any view can host a statusbar in v2
+    /// <summary>Gets or sets the status bar for this Toplevel.</summary>
+    public virtual StatusBar StatusBar { get; set; }
 
     /// <inheritdoc/>
-    public override bool OnLeave (View view) { return MostFocused?.OnLeave (view) ?? base.OnLeave (view); }
-
-    /// <summary>
-    ///     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 ()
+    public override View Add (View view)
     {
-        IsLoaded = true;
-
-        foreach (Toplevel tl in Subviews.Where (v => v is Toplevel))
-        {
-            tl.OnLoaded ();
-        }
+        CanFocus = true;
+        AddMenuStatusBar (view);
 
-        Loaded?.Invoke (this, EventArgs.Empty);
+        return base.Add (view);
     }
 
-    /// <summary>Virtual method to invoke the <see cref="QuitKeyChanged"/> event.</summary>
-    /// <param name="e"></param>
-    public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
+    /// <inheritdoc/>
+    public override View Remove (View view)
     {
-        KeyBindings.Replace (e.OldKey, e.NewKey);
-        QuitKeyChanged?.Invoke (this, e);
+        if (this is Toplevel { MenuBar: { } })
+        {
+            RemoveMenuStatusBar (view);
+        }
+
+        return base.Remove (view);
     }
 
     /// <inheritdoc/>
-    public override Point? PositionCursor ()
+    public override void RemoveAll ()
     {
-        if (!IsOverlappedContainer)
+        if (this == Application.Top)
         {
-            if (Focused is null)
-            {
-                EnsureFocus ();
-            }
-
-            return null;
+            MenuBar?.Dispose ();
+            MenuBar = null;
+            StatusBar?.Dispose ();
+            StatusBar = null;
         }
 
-        // This code path only happens when the Toplevel is an Overlapped container
+        base.RemoveAll ();
+    }
 
-        if (Focused is null)
+    internal void AddMenuStatusBar (View view)
+    {
+        if (view is MenuBar)
         {
-            // TODO: this is an Overlapped hack
-            foreach (Toplevel top in Application.OverlappedChildren)
-            {
-                if (top != this && top.Visible)
-                {
-                    top.SetFocus ();
+            MenuBar = view as MenuBar;
+        }
 
-                    return null;
-                }
-            }
+        if (view is StatusBar)
+        {
+            StatusBar = view as StatusBar;
         }
+    }
 
-        var cursor2 = base.PositionCursor ();
+    internal void RemoveMenuStatusBar (View view)
+    {
+        if (view is MenuBar)
+        {
+            MenuBar?.Dispose ();
+            MenuBar = null;
+        }
 
-        return null; 
+        if (view is StatusBar)
+        {
+            StatusBar?.Dispose ();
+            StatusBar = null;
+        }
     }
 
+    // TODO: Overlapped - Rename to AllSubviewsClosed - Move to View?
     /// <summary>
-    ///     Adjusts the location and size of <paramref name="top"/> within this Toplevel. Virtual method enabling
-    ///     implementation of specific positions for inherited <see cref="Toplevel"/> views.
+    ///     Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from by
+    ///     <see cref="Application.End(RunState)"/>.
     /// </summary>
-    /// <param name="top">The Toplevel to adjust.</param>
-    public virtual void PositionToplevel (Toplevel top)
-    {
+    public event EventHandler AllChildClosed;
 
-        View superView = GetLocationEnsuringFullVisibility (
-                                              top,
-                                              top.Frame.X,
-                                              top.Frame.Y,
-                                              out int nx,
-                                              out int ny,
-                                              out StatusBar sb
-                                             );
+    // TODO: Overlapped - Rename to *Subviews* - Move to View?
+    /// <summary>
+    ///     Invoked when a child of the Toplevel <see cref="RunState"/> is closed by
+    ///     <see cref="Application.End(RunState)"/>.
+    /// </summary>
+    public event EventHandler<ToplevelEventArgs> ChildClosed;
 
-        if (superView is null)
-        {
-            return;
-        }
+    // TODO: Overlapped - Rename to *Subviews* - Move to View?
+    /// <summary>Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.</summary>
+    public event EventHandler<ToplevelEventArgs> ChildLoaded;
 
-        var layoutSubviews = false;
-        var maxWidth = 0;
+    // TODO: Overlapped - Rename to *Subviews* - Move to View?
+    /// <summary>Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.</summary>
+    public event EventHandler<ToplevelEventArgs> ChildUnloaded;
 
-        if (superView.Margin is { } && superView == top.SuperView)
-        {
-            maxWidth -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
-        }
+    #endregion
 
-        if ((superView != top || top?.SuperView is { } || (top != Application.Top && top.Modal) || (top?.SuperView is null && top.IsOverlapped))
-            && (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y))
-        {
-            if ((top.X is null || top.X is PosAbsolute) && top.Frame.X != nx)
-            {
-                top.X = nx;
-                layoutSubviews = true;
-            }
+    #region Life Cycle
 
-            if ((top.Y is null || top.Y is PosAbsolute) && top.Frame.Y != ny)
-            {
-                top.Y = ny;
-                layoutSubviews = true;
-            }
-        }
+    // TODO: IRunnable: Re-implement as a property on IRunnable
+    /// <summary>Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not.</summary>
+    /// <remarks>Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/> instead.</remarks>
+    public bool Running { get; set; }
 
-        // TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
-        if (sb != null
-            && !top.Subviews.Contains (sb)
-            && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
-            && top.Height is DimFill
-            && -top.Height.GetAnchor (0) < 1)
-        {
-            top.Height = Dim.Fill (sb.Visible ? 1 : 0);
-            layoutSubviews = true;
-        }
+    // TODO: IRunnable: Re-implement in IRunnable
+    /// <summary>
+    ///     <see langword="true"/> if was already loaded by the <see cref="Application.Begin(Toplevel)"/>
+    ///     <see langword="false"/>, otherwise.
+    /// </summary>
+    public bool IsLoaded { get; private set; }
 
-        if (superView.LayoutNeeded || layoutSubviews)
-        {
-            superView.LayoutSubviews ();
-        }
+    // TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Activating/Activate
+    /// <summary>Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/> Toplevel.</summary>
+    public event EventHandler<ToplevelEventArgs> Activate;
+
+    // TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Deactivating/Deactivate?
+    /// <summary>Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.</summary>
+    public event EventHandler<ToplevelEventArgs> Deactivate;
+
+    /// <summary>Invoked when the Toplevel's <see cref="RunState"/> is closed by <see cref="Application.End(RunState)"/>.</summary>
+    public event EventHandler<ToplevelEventArgs> Closed;
+
+    /// <summary>
+    ///     Invoked when the Toplevel's <see cref="RunState"/> is being closed by
+    ///     <see cref="Application.RequestStop(Toplevel)"/>.
+    /// </summary>
+    public event EventHandler<ToplevelClosingEventArgs> Closing;
+
+    /// <summary>
+    ///     Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded. A Loaded event handler
+    ///     is a good place to finalize initialization before calling <see cref="Application.RunLoop(RunState)"/>.
+    /// </summary>
+    public event EventHandler Loaded;
+
+    /// <summary>
+    ///     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;
 
-        if (LayoutNeeded)
+        foreach (Toplevel tl in Subviews.Where (v => v is Toplevel))
         {
-            LayoutSubviews ();
+            tl.OnLoaded ();
         }
-    }
 
-    /// <summary>Invoked when the <see cref="Application.QuitKey"/> is changed.</summary>
-    public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
+        Loaded?.Invoke (this, EventArgs.Empty);
+    }
 
     /// <summary>
     ///     Invoked when the <see cref="Toplevel"/> main loop has started it's first iteration. Subscribe to this event to
@@ -445,31 +373,6 @@ public partial class Toplevel : View
     /// </summary>
     public event EventHandler Ready;
 
-    /// <inheritdoc/>
-    public override View Remove (View view)
-    {
-        if (this is Toplevel { MenuBar: { } })
-        {
-            RemoveMenuStatusBar (view);
-        }
-
-        return base.Remove (view);
-    }
-
-    /// <inheritdoc/>
-    public override void RemoveAll ()
-    {
-        if (this == Application.Top)
-        {
-            MenuBar?.Dispose ();
-            MenuBar = null;
-            StatusBar?.Dispose ();
-            StatusBar = null;
-        }
-
-        base.RemoveAll ();
-    }
-
     /// <summary>
     ///     Stops and closes this <see cref="Toplevel"/>. If this Toplevel is the top-most Toplevel,
     ///     <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
@@ -527,37 +430,22 @@ public partial class Toplevel : View
         }
     }
 
-    /// <summary>
-    ///     Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If <paramref name="top"/> is
-    ///     the top-most Toplevel, <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to
-    ///     exit.
-    /// </summary>
-    /// <param name="top">The Toplevel to request stop.</param>
-    public virtual void RequestStop (Toplevel top) { top.RequestStop (); }
-
-    /// <summary>Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.</summary>
-    public event EventHandler<SizeChangedEventArgs> SizeChanging;
-
     /// <summary>
     ///     Invoked when the Toplevel <see cref="RunState"/> has been unloaded. A Unloaded event handler is a good place
     ///     to dispose objects after calling <see cref="Application.End(RunState)"/>.
     /// </summary>
     public event EventHandler Unloaded;
 
-    internal void AddMenuStatusBar (View view)
-    {
-        if (view is MenuBar)
-        {
-            MenuBar = view as MenuBar;
-        }
+    internal virtual void OnActivate (Toplevel deactivated) { Activate?.Invoke (this, new (deactivated)); }
 
-        if (view is StatusBar)
-        {
-            StatusBar = view as StatusBar;
-        }
-    }
+    /// <summary>
+    ///     Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If <paramref name="top"/> is
+    ///     the top-most Toplevel, <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to
+    ///     exit.
+    /// </summary>
+    /// <param name="top">The Toplevel to request stop.</param>
+    public virtual void RequestStop (Toplevel top) { top.RequestStop (); }
 
-    internal virtual void OnActivate (Toplevel deactivated) { Activate?.Invoke (this, new ToplevelEventArgs (deactivated)); }
     internal virtual void OnAllChildClosed () { AllChildClosed?.Invoke (this, EventArgs.Empty); }
 
     internal virtual void OnChildClosed (Toplevel top)
@@ -567,12 +455,12 @@ public partial class Toplevel : View
             SetSubViewNeedsDisplay ();
         }
 
-        ChildClosed?.Invoke (this, new ToplevelEventArgs (top));
+        ChildClosed?.Invoke (this, new (top));
     }
 
-    internal virtual void OnChildLoaded (Toplevel top) { ChildLoaded?.Invoke (this, new ToplevelEventArgs (top)); }
-    internal virtual void OnChildUnloaded (Toplevel top) { ChildUnloaded?.Invoke (this, new ToplevelEventArgs (top)); }
-    internal virtual void OnClosed (Toplevel top) { Closed?.Invoke (this, new ToplevelEventArgs (top)); }
+    internal virtual void OnChildLoaded (Toplevel top) { ChildLoaded?.Invoke (this, new (top)); }
+    internal virtual void OnChildUnloaded (Toplevel top) { ChildUnloaded?.Invoke (this, new (top)); }
+    internal virtual void OnClosed (Toplevel top) { Closed?.Invoke (this, new (top)); }
 
     internal virtual bool OnClosing (ToplevelClosingEventArgs ev)
     {
@@ -581,7 +469,7 @@ public partial class Toplevel : View
         return ev.Cancel;
     }
 
-    internal virtual void OnDeactivate (Toplevel activated) { Deactivate?.Invoke (this, new ToplevelEventArgs (activated)); }
+    internal virtual void OnDeactivate (Toplevel activated) { Deactivate?.Invoke (this, new (activated)); }
 
     /// <summary>
     ///     Called from <see cref="Application.RunLoop"/> after the <see cref="Toplevel"/> has entered the first iteration
@@ -597,9 +485,6 @@ public partial class Toplevel : View
         Ready?.Invoke (this, EventArgs.Empty);
     }
 
-    // TODO: Make cancelable?
-    internal virtual void OnSizeChanging (SizeChangedEventArgs size) { SizeChanging?.Invoke (this, size); }
-
     /// <summary>Called from <see cref="Application.End(RunState)"/> before the <see cref="Toplevel"/> is disposed.</summary>
     internal virtual void OnUnloaded ()
     {
@@ -611,35 +496,79 @@ public partial class Toplevel : View
         Unloaded?.Invoke (this, EventArgs.Empty);
     }
 
-    // TODO: v2 - Not sure this is needed anymore.
-    internal void PositionToplevels ()
+    private void QuitToplevel ()
     {
-        PositionToplevel (this);
-
-        foreach (View top in Subviews)
+        if (Application.OverlappedTop is { })
         {
-            if (top is Toplevel)
-            {
-                PositionToplevel ((Toplevel)top);
-            }
+            RequestStop (this);
+        }
+        else
+        {
+            Application.RequestStop ();
         }
     }
 
-    internal void RemoveMenuStatusBar (View view)
+    #endregion
+
+    #region Draw
+
+    /// <inheritdoc/>
+    public override void OnDrawContent (Rectangle viewport)
     {
-        if (view is MenuBar)
+        if (!Visible)
         {
-            MenuBar?.Dispose ();
-            MenuBar = null;
+            return;
         }
 
-        if (view is StatusBar)
+        if (NeedsDisplay || SubViewNeedsDisplay /*|| LayoutNeeded*/)
         {
-            StatusBar?.Dispose ();
-            StatusBar = null;
+            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 ();
+            //            }
+            //        }
+            //    }
+            //}
+
+            // 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))
+                {
+                    //view.SetNeedsLayout ();
+                    view.SetNeedsDisplay ();
+                    view.SetSubViewNeedsDisplay ();
+                }
+            }
+
+            base.OnDrawContent (viewport);
         }
     }
 
+    #endregion
+
+    #region Focus
+
+    /// <inheritdoc/>
+    public override bool OnEnter (View view) { return MostFocused?.OnEnter (view) ?? base.OnEnter (view); }
+
+    /// <inheritdoc/>
+    public override bool OnLeave (View view) { return MostFocused?.OnLeave (view) ?? base.OnLeave (view); }
+
     private void FocusNearestView (IEnumerable<View> views, NavigationDirection direction)
     {
         if (views is null)
@@ -785,6 +714,117 @@ public partial class Toplevel : View
         }
     }
 
+    #endregion
+
+    #region Size / Position Management
+
+    // TODO: Make cancelable?
+    internal virtual void OnSizeChanging (SizeChangedEventArgs size) { SizeChanging?.Invoke (this, size); }
+
+    /// <inheritdoc/>
+    public override Point? PositionCursor ()
+    {
+        if (!IsOverlappedContainer)
+        {
+            if (Focused is null)
+            {
+                EnsureFocus ();
+            }
+
+            return null;
+        }
+
+        // This code path only happens when the Toplevel is an Overlapped container
+
+        if (Focused is null)
+        {
+            // TODO: this is an Overlapped hack
+            foreach (Toplevel top in Application.OverlappedChildren)
+            {
+                if (top != this && top.Visible)
+                {
+                    top.SetFocus ();
+
+                    return null;
+                }
+            }
+        }
+
+        Point? cursor2 = base.PositionCursor ();
+
+        return null;
+    }
+
+    /// <summary>
+    ///     Adjusts the location and size of <paramref name="top"/> within this Toplevel. Virtual method enabling
+    ///     implementation of specific positions for inherited <see cref="Toplevel"/> views.
+    /// </summary>
+    /// <param name="top">The Toplevel to adjust.</param>
+    public virtual void PositionToplevel (Toplevel top)
+    {
+        View superView = GetLocationEnsuringFullVisibility (
+                                                            top,
+                                                            top.Frame.X,
+                                                            top.Frame.Y,
+                                                            out int nx,
+                                                            out int ny,
+                                                            out StatusBar sb
+                                                           );
+
+        if (superView is null)
+        {
+            return;
+        }
+
+        var layoutSubviews = false;
+        var maxWidth = 0;
+
+        if (superView.Margin is { } && superView == top.SuperView)
+        {
+            maxWidth -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
+        }
+
+        if ((superView != top || top?.SuperView is { } || (top != Application.Top && top.Modal) || (top?.SuperView is null && top.IsOverlapped))
+            && (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y))
+        {
+            if ((top.X is null || top.X is PosAbsolute) && top.Frame.X != nx)
+            {
+                top.X = nx;
+                layoutSubviews = true;
+            }
+
+            if ((top.Y is null || top.Y is PosAbsolute) && top.Frame.Y != ny)
+            {
+                top.Y = ny;
+                layoutSubviews = true;
+            }
+        }
+
+        // TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
+        if (sb != null
+            && !top.Subviews.Contains (sb)
+            && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
+            && top.Height is DimFill
+            && -top.Height.GetAnchor (0) < 1)
+        {
+            top.Height = Dim.Fill (sb.Visible ? 1 : 0);
+            layoutSubviews = true;
+        }
+
+        if (superView.LayoutNeeded || layoutSubviews)
+        {
+            superView.LayoutSubviews ();
+        }
+
+        if (LayoutNeeded)
+        {
+            LayoutSubviews ();
+        }
+    }
+
+    /// <summary>Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.</summary>
+    public event EventHandler<SizeChangedEventArgs> SizeChanging;
+
     private bool OutsideTopFrame (Toplevel top)
     {
         if (top.Frame.X > Driver.Cols || top.Frame.Y > Driver.Rows)
@@ -795,17 +835,21 @@ public partial class Toplevel : View
         return false;
     }
 
-    private void QuitToplevel ()
+    // TODO: v2 - Not sure this is needed anymore.
+    internal void PositionToplevels ()
     {
-        if (Application.OverlappedTop is { })
-        {
-            RequestStop (this);
-        }
-        else
+        PositionToplevel (this);
+
+        foreach (View top in Subviews)
         {
-            Application.RequestStop ();
+            if (top is Toplevel)
+            {
+                PositionToplevel ((Toplevel)top);
+            }
         }
     }
+
+    #endregion
 }
 
 /// <summary>