diff --git a/Terminal.Gui/Application/Application.Initialization.cs b/Terminal.Gui/Application/Application.Initialization.cs index a971850e3..16b7b83d4 100644 --- a/Terminal.Gui/Application/Application.Initialization.cs +++ b/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: diff --git a/Terminal.Gui/Application/Application.Keyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs index e8d698286..703a84982 100644 --- a/Terminal.Gui/Application/Application.Keyboard.cs +++ b/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 ()) { diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 202b66044..3b4c9d9f7 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/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 - - /// Holds the stack of TopLevel views. - - // 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 _topLevels = new (); - - /// The object used for the application on startup () - /// The top. - public static Toplevel? Top { get; private set; } - - /// - /// The current object. This is updated in enters and leaves to - /// point to the current - /// . - /// - /// - /// Only relevant in scenarios where is . - /// - /// The current. - 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 - /// Invoked when the terminal's size changed. The new size of the terminal is provided. - /// - /// Event handlers can set to to prevent - /// from changing it's size to match the new terminal size. - /// - public static event EventHandler SizeChanging; - - /// - /// Called when the application's size changes. Sets the size of all s and fires the - /// event. - /// - /// The new size. - /// if the size was changed. - 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 - /// /// Gets a string representation of the Application as rendered by . /// diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index 617dfa7fc..32d8f8a89 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -6,7 +6,7 @@ namespace Terminal.Gui; /// /// /// -/// Toplevels can run as modal (popup) views, started by calling +/// Toplevel views can run as modal (popup) views, started by calling /// . They return control to the caller when /// has been called (which sets the /// property to false). @@ -14,7 +14,7 @@ namespace Terminal.Gui; /// /// A Toplevel is created when an application initializes Terminal.Gui by calling . /// The application Toplevel can be accessed via . Additional Toplevels can be created -/// and run (e.g. s. To run a Toplevel, create the and call +/// and run (e.g. s). To run a Toplevel, create the and call /// . /// /// @@ -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 (); + //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 (); - } - } - } - } + //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 before the redraws for the first /// time. /// + /// + /// Overrides must call base.OnLoaded() to ensure any Toplevel subviews are initialized properly and the event is raised. + /// public virtual void OnLoaded () { IsLoaded = true;