|
@@ -1,3 +1,4 @@
|
|
|
|
+#nullable enable
|
|
namespace Terminal.Gui;
|
|
namespace Terminal.Gui;
|
|
|
|
|
|
public static partial class Application
|
|
public static partial class Application
|
|
@@ -6,30 +7,32 @@ public static partial class Application
|
|
/// Gets the list of the Overlapped children which are not modal <see cref="Toplevel"/> from the
|
|
/// Gets the list of the Overlapped children which are not modal <see cref="Toplevel"/> from the
|
|
/// <see cref="OverlappedTop"/>.
|
|
/// <see cref="OverlappedTop"/>.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public static List<Toplevel> OverlappedChildren
|
|
|
|
|
|
+ public static List<Toplevel>? OverlappedChildren
|
|
{
|
|
{
|
|
get
|
|
get
|
|
{
|
|
{
|
|
if (OverlappedTop is { })
|
|
if (OverlappedTop is { })
|
|
{
|
|
{
|
|
- List<Toplevel> _overlappedChildren = new ();
|
|
|
|
|
|
+ List<Toplevel> overlappedChildren = new ();
|
|
|
|
|
|
- foreach (Toplevel top in _topLevels)
|
|
|
|
|
|
+ lock (_topLevels)
|
|
{
|
|
{
|
|
- if (top != OverlappedTop && !top.Modal)
|
|
|
|
|
|
+ foreach (Toplevel top in _topLevels)
|
|
{
|
|
{
|
|
- _overlappedChildren.Add (top);
|
|
|
|
|
|
+ if (top != OverlappedTop && !top.Modal)
|
|
|
|
+ {
|
|
|
|
+ overlappedChildren.Add (top);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return _overlappedChildren;
|
|
|
|
|
|
+ return overlappedChildren;
|
|
}
|
|
}
|
|
|
|
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#nullable enable
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// The <see cref="Toplevel"/> object used for the application on startup which
|
|
/// The <see cref="Toplevel"/> object used for the application on startup which
|
|
/// <see cref="Toplevel.IsOverlappedContainer"/> is true.
|
|
/// <see cref="Toplevel.IsOverlappedContainer"/> is true.
|
|
@@ -46,7 +49,6 @@ public static partial class Application
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-#nullable restore
|
|
|
|
|
|
|
|
/// <summary>Brings the superview of the most focused overlapped view is on front.</summary>
|
|
/// <summary>Brings the superview of the most focused overlapped view is on front.</summary>
|
|
public static void BringOverlappedTopToFront ()
|
|
public static void BringOverlappedTopToFront ()
|
|
@@ -56,9 +58,9 @@ public static partial class Application
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- View top = FindTopFromView (Top?.MostFocused);
|
|
|
|
|
|
+ View? top = FindTopFromView (Top?.MostFocused);
|
|
|
|
|
|
- if (top is Toplevel && Top.Subviews.Count > 1 && Top.Subviews [^1] != top)
|
|
|
|
|
|
+ if (top is Toplevel && Top?.Subviews.Count > 1 && Top.Subviews [^1] != top)
|
|
{
|
|
{
|
|
Top.BringSubviewToFront (top);
|
|
Top.BringSubviewToFront (top);
|
|
}
|
|
}
|
|
@@ -68,9 +70,9 @@ public static partial class Application
|
|
/// <param name="type">The type.</param>
|
|
/// <param name="type">The type.</param>
|
|
/// <param name="exclude">The strings to exclude.</param>
|
|
/// <param name="exclude">The strings to exclude.</param>
|
|
/// <returns>The matched view.</returns>
|
|
/// <returns>The matched view.</returns>
|
|
- public static Toplevel GetTopOverlappedChild (Type type = null, string [] exclude = null)
|
|
|
|
|
|
+ public static Toplevel? GetTopOverlappedChild (Type? type = null, string []? exclude = null)
|
|
{
|
|
{
|
|
- if (OverlappedTop is null)
|
|
|
|
|
|
+ if (OverlappedChildren is null || OverlappedTop is null)
|
|
{
|
|
{
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
@@ -118,7 +120,7 @@ public static partial class Application
|
|
/// <summary>Move to the next Overlapped child from the <see cref="OverlappedTop"/>.</summary>
|
|
/// <summary>Move to the next Overlapped child from the <see cref="OverlappedTop"/>.</summary>
|
|
public static void OverlappedMoveNext ()
|
|
public static void OverlappedMoveNext ()
|
|
{
|
|
{
|
|
- if (OverlappedTop is { } && !Current.Modal)
|
|
|
|
|
|
+ if (OverlappedTop is { } && !Current!.Modal)
|
|
{
|
|
{
|
|
lock (_topLevels)
|
|
lock (_topLevels)
|
|
{
|
|
{
|
|
@@ -133,7 +135,7 @@ public static partial class Application
|
|
}
|
|
}
|
|
else if (isOverlapped && _topLevels.Peek () == OverlappedTop)
|
|
else if (isOverlapped && _topLevels.Peek () == OverlappedTop)
|
|
{
|
|
{
|
|
- MoveCurrent (Top);
|
|
|
|
|
|
+ MoveCurrent (Top!);
|
|
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -149,7 +151,7 @@ public static partial class Application
|
|
/// <summary>Move to the previous Overlapped child from the <see cref="OverlappedTop"/>.</summary>
|
|
/// <summary>Move to the previous Overlapped child from the <see cref="OverlappedTop"/>.</summary>
|
|
public static void OverlappedMovePrevious ()
|
|
public static void OverlappedMovePrevious ()
|
|
{
|
|
{
|
|
- if (OverlappedTop is { } && !Current.Modal)
|
|
|
|
|
|
+ if (OverlappedTop is { } && !Current!.Modal)
|
|
{
|
|
{
|
|
lock (_topLevels)
|
|
lock (_topLevels)
|
|
{
|
|
{
|
|
@@ -164,7 +166,7 @@ public static partial class Application
|
|
}
|
|
}
|
|
else if (isOverlapped && _topLevels.Peek () == OverlappedTop)
|
|
else if (isOverlapped && _topLevels.Peek () == OverlappedTop)
|
|
{
|
|
{
|
|
- MoveCurrent (Top);
|
|
|
|
|
|
+ MoveCurrent (Top!);
|
|
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -184,13 +186,16 @@ public static partial class Application
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- foreach (Toplevel top in _topLevels)
|
|
|
|
|
|
+ lock (_topLevels)
|
|
{
|
|
{
|
|
- if (top != Current && top.Visible && (top.NeedsDisplay || top.SubViewNeedsDisplay || top.LayoutNeeded))
|
|
|
|
|
|
+ foreach (Toplevel top in _topLevels)
|
|
{
|
|
{
|
|
- OverlappedTop.SetSubViewNeedsDisplay ();
|
|
|
|
|
|
+ if (top != Current && top.Visible && (top.NeedsDisplay || top.SubViewNeedsDisplay || top.LayoutNeeded))
|
|
|
|
+ {
|
|
|
|
+ OverlappedTop.SetSubViewNeedsDisplay ();
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -208,4 +213,154 @@ public static partial class Application
|
|
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds the first Toplevel in the stack that is Visible and who's Frame contains the <paramref name="location"/>.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="start"></param>
|
|
|
|
+ /// <param name="location"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ private static Toplevel? FindDeepestTop (Toplevel start, in Point location)
|
|
|
|
+ {
|
|
|
|
+ if (!start.Frame.Contains (location))
|
|
|
|
+ {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lock (_topLevels)
|
|
|
|
+ {
|
|
|
|
+ if (_topLevels is not { Count: > 0 })
|
|
|
|
+ {
|
|
|
|
+ return start;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int rx = location.X - start.Frame.X;
|
|
|
|
+ int ry = location.Y - start.Frame.Y;
|
|
|
|
+
|
|
|
|
+ foreach (Toplevel t in _topLevels)
|
|
|
|
+ {
|
|
|
|
+ if (t == Current)
|
|
|
|
+ {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (t != start && t.Visible && t.Frame.Contains (rx, ry))
|
|
|
|
+ {
|
|
|
|
+ start = t;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return start;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Given <paramref name="view"/>, returns the first Superview up the chain that is <see cref="Top"/>.
|
|
|
|
+ /// </summary>
|
|
|
|
+ private static View? FindTopFromView (View? view)
|
|
|
|
+ {
|
|
|
|
+ if (view is null)
|
|
|
|
+ {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ View top = view.SuperView is { } && view.SuperView != Top
|
|
|
|
+ ? view.SuperView
|
|
|
|
+ : view;
|
|
|
|
+
|
|
|
|
+ while (top?.SuperView is { } && top?.SuperView != Top)
|
|
|
|
+ {
|
|
|
|
+ top = top!.SuperView;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return top;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// If the <see cref="Current"/> is not the <paramref name="top"/> then <paramref name="top"/> is moved to the top of
|
|
|
|
+ /// the Toplevel stack and made Current.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="top"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+}
|