diff --git a/Terminal.Gui/Application/Application.Overlapped.cs b/Terminal.Gui/Application/Application.Overlapped.cs index cf9212d80..8ae645717 100644 --- a/Terminal.Gui/Application/Application.Overlapped.cs +++ b/Terminal.Gui/Application/Application.Overlapped.cs @@ -1,4 +1,6 @@ #nullable enable +using System.Reflection; + namespace Terminal.Gui; /// @@ -6,6 +8,17 @@ namespace Terminal.Gui; /// public static class ApplicationOverlapped { + + /// + /// Gets or sets if is in overlapped mode within a Toplevel container. + /// + /// + /// + public static bool IsOverlapped (Toplevel? top) + { + return ApplicationOverlapped.OverlappedTop is { } && ApplicationOverlapped.OverlappedTop != top && !top!.Modal; + } + /// /// Gets the list of the Overlapped children which are not modal from the /// . @@ -99,7 +112,7 @@ public static class ApplicationOverlapped } /// - /// Move to the next Overlapped child from the and set it as the if + /// Move to the next Overlapped child from the and set it as the if /// it is not already. /// /// @@ -262,7 +275,7 @@ public static class ApplicationOverlapped } /// - /// Given , returns the first Superview up the chain that is . + /// Given , returns the first Superview up the chain that is . /// internal static View? FindTopFromView (View? view) { @@ -284,7 +297,7 @@ public static class ApplicationOverlapped } /// - /// If the is not the then is moved to the top of + /// If the is not the then is moved to the top of /// the Toplevel stack and made Current. /// /// @@ -361,7 +374,7 @@ public static class ApplicationOverlapped { lock (Application.TopLevels) { - Application.TopLevels.MoveTo (top, 0, new ToplevelEqualityComparer ()); + Application.TopLevels.MoveTo (top!, 0, new ToplevelEqualityComparer ()); Application.Current = top; } } diff --git a/Terminal.Gui/Application/Application.Run.cs b/Terminal.Gui/Application/Application.Run.cs index 3e088c348..57097cbda 100644 --- a/Terminal.Gui/Application/Application.Run.cs +++ b/Terminal.Gui/Application/Application.Run.cs @@ -579,7 +579,7 @@ public static partial class Application // Run (Begin, Run, End, Stop) { ApplicationOverlapped.OverlappedTop?.OnDeactivate (state.Toplevel); state.Toplevel = Current; - ApplicationOverlapped.OverlappedTop?.OnActivate (state.Toplevel); + ApplicationOverlapped.OverlappedTop?.OnActivate (state.Toplevel!); Top!.SetSubViewNeedsDisplay (); Refresh (); } diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index 4e2531745..72a9bf14c 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -404,7 +404,7 @@ public partial class View int targetY, out int nx, out int ny, - out StatusBar statusBar + out StatusBar? statusBar ) { int maxDimension; diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs index d13ae0766..26fe724c8 100644 --- a/Terminal.Gui/Views/Toplevel.cs +++ b/Terminal.Gui/Views/Toplevel.cs @@ -1,3 +1,4 @@ +#nullable enable namespace Terminal.Gui; /// @@ -60,7 +61,7 @@ public partial class Toplevel : View /// public bool Modal { get; set; } - private void Toplevel_MouseClick (object sender, MouseEventEventArgs e) { e.Handled = InvokeCommand (Command.HotKey) == true; } + private void Toplevel_MouseClick (object? sender, MouseEventEventArgs e) { e.Handled = InvokeCommand (Command.HotKey) == true; } #endregion @@ -68,11 +69,11 @@ public partial class Toplevel : View // TODO: Deprecate - Any view can host a menubar in v2 /// Gets or sets the menu for this Toplevel. - public virtual MenuBar MenuBar { get; set; } + public MenuBar? MenuBar { get; set; } // TODO: Deprecate - Any view can host a statusbar in v2 /// Gets or sets the status bar for this Toplevel. - public virtual StatusBar StatusBar { get; set; } + public StatusBar? StatusBar { get; set; } /// public override View Add (View view) @@ -141,22 +142,22 @@ public partial class Toplevel : View /// Invoked when the last child of the Toplevel is closed from by /// . /// - public event EventHandler AllChildClosed; + public event EventHandler? AllChildClosed; // TODO: Overlapped - Rename to *Subviews* - Move to View? /// /// Invoked when a child of the Toplevel is closed by /// . /// - public event EventHandler ChildClosed; + public event EventHandler? ChildClosed; // TODO: Overlapped - Rename to *Subviews* - Move to View? /// Invoked when a child Toplevel's has been loaded. - public event EventHandler ChildLoaded; + public event EventHandler? ChildLoaded; // TODO: Overlapped - Rename to *Subviews* - Move to View? /// Invoked when a cjhild Toplevel's has been unloaded. - public event EventHandler ChildUnloaded; + public event EventHandler? ChildUnloaded; #endregion @@ -176,26 +177,26 @@ public partial class Toplevel : View // TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Activating/Activate /// Invoked when the Toplevel becomes the Toplevel. - public event EventHandler Activate; + public event EventHandler? Activate; // TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Deactivating/Deactivate? /// Invoked when the Toplevel ceases to be the Toplevel. - public event EventHandler Deactivate; + public event EventHandler? Deactivate; /// Invoked when the Toplevel's is closed by . - public event EventHandler Closed; + public event EventHandler? Closed; /// /// Invoked when the Toplevel's is being closed by /// . /// - public event EventHandler Closing; + public event EventHandler? Closing; /// /// Invoked when the has begun to be loaded. A Loaded event handler /// is a good place to finalize initialization before calling . /// - public event EventHandler Loaded; + public event EventHandler? Loaded; /// /// Called from before the redraws for the first @@ -209,8 +210,9 @@ public partial class Toplevel : View { IsLoaded = true; - foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) + foreach (var view in Subviews.Where (v => v is Toplevel)) { + var tl = (Toplevel)view; tl.OnLoaded (); } @@ -225,7 +227,7 @@ public partial class Toplevel : View /// on this . /// /// - public event EventHandler Ready; + public event EventHandler? Ready; /// /// Stops and closes this . If this Toplevel is the top-most Toplevel, @@ -288,7 +290,7 @@ public partial class Toplevel : View /// Invoked when the Toplevel has been unloaded. A Unloaded event handler is a good place /// to dispose objects after calling . /// - public event EventHandler Unloaded; + public event EventHandler? Unloaded; internal virtual void OnActivate (Toplevel deactivated) { Activate?.Invoke (this, new (deactivated)); } @@ -331,8 +333,9 @@ public partial class Toplevel : View /// internal virtual void OnReady () { - foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) + foreach (var view in Subviews.Where (v => v is Toplevel)) { + var tl = (Toplevel)view; tl.OnReady (); } @@ -342,8 +345,9 @@ public partial class Toplevel : View /// Called from before the is disposed. internal virtual void OnUnloaded () { - foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) + foreach (var view in Subviews.Where (v => v is Toplevel)) { + var tl = (Toplevel)view; tl.OnUnloaded (); } @@ -411,7 +415,7 @@ public partial class Toplevel : View /// public override bool OnLeave (View view) { return MostFocused?.OnLeave (view) ?? base.OnLeave (view); } - + #endregion #region Size / Position Management @@ -458,15 +462,20 @@ public partial class Toplevel : View /// implementation of specific positions for inherited views. /// /// The Toplevel to adjust. - public virtual void PositionToplevel (Toplevel top) + public virtual void PositionToplevel (Toplevel? top) { - View superView = GetLocationEnsuringFullVisibility ( + if (top is null) + { + return; + } + + View? superView = GetLocationEnsuringFullVisibility ( top, top.Frame.X, top.Frame.Y, out int nx, out int ny, - out StatusBar sb + out StatusBar? sb ); if (superView is null) @@ -482,25 +491,25 @@ public partial class Toplevel : View 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 ((superView != top || top?.SuperView is { } || (top != Application.Top && top!.Modal) || (top?.SuperView is null && ApplicationOverlapped.IsOverlapped (top))) + && (top!.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y)) { - if ((top.X is null || top.X is PosAbsolute) && top.Frame.X != nx) + if (top?.X is null or PosAbsolute && top?.Frame.X != nx) { - top.X = nx; + top!.X = nx; layoutSubviews = true; } - if ((top.Y is null || top.Y is PosAbsolute) && top.Frame.Y != ny) + if (top?.Y is null or PosAbsolute && top?.Frame.Y != ny) { - top.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) + && !top!.Subviews.Contains (sb) && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0) && top.Height is DimFill && -top.Height.GetAnchor (0) < 1) @@ -521,7 +530,7 @@ public partial class Toplevel : View } /// Invoked when the terminal has been resized. The new of the terminal is provided. - public event EventHandler SizeChanging; + public event EventHandler? SizeChanging; private bool OutsideTopFrame (Toplevel top) { @@ -560,7 +569,7 @@ public class ToplevelEqualityComparer : IEqualityComparer /// The first object of type to compare. /// The second object of type to compare. /// if the specified objects are equal; otherwise, . - public bool Equals (Toplevel x, Toplevel y) + public bool Equals (Toplevel? x, Toplevel? y) { if (y is null && x is null) { @@ -623,7 +632,7 @@ public sealed class ToplevelComparer : IComparer /// equals .Greater than zero is greater than /// . /// - public int Compare (Toplevel x, Toplevel y) + public int Compare (Toplevel? x, Toplevel? y) { if (ReferenceEquals (x, y)) { @@ -640,6 +649,6 @@ public sealed class ToplevelComparer : IComparer return 1; } - return string.Compare (x.Id, y.Id); + return string.CompareOrdinal (x.Id, y.Id); } } diff --git a/Terminal.Gui/Views/ToplevelOverlapped.cs b/Terminal.Gui/Views/ToplevelOverlapped.cs index 06dac3694..28513c4ce 100644 --- a/Terminal.Gui/Views/ToplevelOverlapped.cs +++ b/Terminal.Gui/Views/ToplevelOverlapped.cs @@ -2,9 +2,6 @@ public partial class Toplevel { - /// Gets or sets if this Toplevel is in overlapped mode within a Toplevel container. - public bool IsOverlapped => ApplicationOverlapped.OverlappedTop is { } && ApplicationOverlapped.OverlappedTop != this && !Modal; - /// Gets or sets if this Toplevel is a container for overlapped children. public bool IsOverlappedContainer { get; set; } } diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index a9014d017..86352717a 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -658,7 +658,7 @@ internal class UICatalogApp ColorScheme = Colors.ColorSchemes [_topLevelColorScheme]; - MenuBar.Menus [0].Children [0].Shortcut = (KeyCode)Application.QuitKey; + MenuBar!.Menus [0].Children [0].Shortcut = (KeyCode)Application.QuitKey; if (StatusBar is { }) { @@ -942,7 +942,7 @@ internal class UICatalogApp { MiIsMenuBorderDisabled.Checked = (bool)!MiIsMenuBorderDisabled.Checked!; - MenuBar.MenusBorderStyle = !(bool)MiIsMenuBorderDisabled.Checked + MenuBar!.MenusBorderStyle = !(bool)MiIsMenuBorderDisabled.Checked ? LineStyle.Single : LineStyle.None; }; @@ -985,7 +985,7 @@ internal class UICatalogApp MiUseSubMenusSingleFrame.Action += () => { MiUseSubMenusSingleFrame.Checked = (bool)!MiUseSubMenusSingleFrame.Checked!; - MenuBar.UseSubMenusSingleFrame = (bool)MiUseSubMenusSingleFrame.Checked; + MenuBar!.UseSubMenusSingleFrame = (bool)MiUseSubMenusSingleFrame.Checked; }; menuItems.Add (MiUseSubMenusSingleFrame); diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs index 91555ca91..80c8e18c2 100644 --- a/UnitTests/Views/OverlappedTests.cs +++ b/UnitTests/Views/OverlappedTests.cs @@ -231,11 +231,11 @@ public class OverlappedTests Application.Iteration += (s, a) => { - Assert.False (overlapped.IsOverlapped); - Assert.True (c1.IsOverlapped); - Assert.True (c2.IsOverlapped); - Assert.True (c3.IsOverlapped); - Assert.False (d.IsOverlapped); + Assert.False (ApplicationOverlapped.IsOverlapped(overlapped)); + Assert.True (ApplicationOverlapped.IsOverlapped(c1)); + Assert.True (ApplicationOverlapped.IsOverlapped(c2)); + Assert.True (ApplicationOverlapped.IsOverlapped(c3)); + Assert.False (ApplicationOverlapped.IsOverlapped(d)); overlapped.RequestStop (); }; @@ -1068,11 +1068,11 @@ public class OverlappedTests Assert.False (top.IsCurrentTop); Assert.Equal (win1, Application.Current); Assert.True (win1.IsCurrentTop); - Assert.True (win1.IsOverlapped); + Assert.True (ApplicationOverlapped.IsOverlapped(win1)); Assert.Null (top.Focused); Assert.Null (top.MostFocused); Assert.Equal (tf1W1, win1.MostFocused); - Assert.True (win1.IsOverlapped); + Assert.True (ApplicationOverlapped.IsOverlapped(win1)); Assert.Single (ApplicationOverlapped.OverlappedChildren!); Application.Begin (win2); Assert.Equal (new (0, 0, 40, 25), win2.Frame); @@ -1080,7 +1080,7 @@ public class OverlappedTests Assert.False (top.IsCurrentTop); Assert.Equal (win2, Application.Current); Assert.True (win2.IsCurrentTop); - Assert.True (win2.IsOverlapped); + Assert.True (ApplicationOverlapped.IsOverlapped(win2)); Assert.Null (top.Focused); Assert.Null (top.MostFocused); Assert.Equal (tf1W2, win2.MostFocused); diff --git a/UnitTests/Views/ToplevelTests.cs b/UnitTests/Views/ToplevelTests.cs index 8688c5d4a..9af790add 100644 --- a/UnitTests/Views/ToplevelTests.cs +++ b/UnitTests/Views/ToplevelTests.cs @@ -17,7 +17,7 @@ public partial class ToplevelTests (ITestOutputHelper output) Assert.Null (top.MenuBar); Assert.Null (top.StatusBar); Assert.False (top.IsOverlappedContainer); - Assert.False (top.IsOverlapped); + Assert.False (ApplicationOverlapped.IsOverlapped(top)); } [Fact]