|
@@ -5,6 +5,240 @@ namespace Terminal.Gui;
|
|
|
|
|
|
public partial class View
|
|
public partial class View
|
|
{
|
|
{
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="location">SuperView-relative coordinate</param>
|
|
|
|
+ /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
|
|
|
|
+ public virtual bool Contains (in Point location) { return Frame.Contains (location); }
|
|
|
|
+
|
|
|
|
+ /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// <para>
|
|
|
|
+ /// Used to determine what view the mouse is over.
|
|
|
|
+ /// </para>
|
|
|
|
+ /// </remarks>
|
|
|
|
+ /// <param name="start">The view to scope the search by.</param>
|
|
|
|
+ /// <param name="location"><paramref name="start"/>.SuperView-relative coordinate.</param>
|
|
|
|
+ /// <returns>
|
|
|
|
+ /// The view that was found at the <paramref name="location"/> coordinate.
|
|
|
|
+ /// <see langword="null"/> if no view was found.
|
|
|
|
+ /// </returns>
|
|
|
|
+
|
|
|
|
+ // CONCURRENCY: This method is not thread-safe. Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
|
|
|
|
+ internal static View? FindDeepestView (View? start, in Point location)
|
|
|
|
+ {
|
|
|
|
+ Point currentLocation = location;
|
|
|
|
+
|
|
|
|
+ while (start is { Visible: true } && start.Contains (currentLocation))
|
|
|
|
+ {
|
|
|
|
+ Adornment? found = null;
|
|
|
|
+
|
|
|
|
+ if (start.Margin.Contains (currentLocation))
|
|
|
|
+ {
|
|
|
|
+ found = start.Margin;
|
|
|
|
+ }
|
|
|
|
+ else if (start.Border.Contains (currentLocation))
|
|
|
|
+ {
|
|
|
|
+ found = start.Border;
|
|
|
|
+ }
|
|
|
|
+ else if (start.Padding.Contains (currentLocation))
|
|
|
|
+ {
|
|
|
|
+ found = start.Padding;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Point viewportOffset = start.GetViewportOffsetFromFrame ();
|
|
|
|
+
|
|
|
|
+ if (found is { })
|
|
|
|
+ {
|
|
|
|
+ start = found;
|
|
|
|
+ viewportOffset = found.Parent.Frame.Location;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int startOffsetX = currentLocation.X - (start.Frame.X + viewportOffset.X);
|
|
|
|
+ int startOffsetY = currentLocation.Y - (start.Frame.Y + viewportOffset.Y);
|
|
|
|
+
|
|
|
|
+ View? subview = null;
|
|
|
|
+
|
|
|
|
+ for (int i = start.InternalSubviews.Count - 1; i >= 0; i--)
|
|
|
|
+ {
|
|
|
|
+ if (start.InternalSubviews [i].Visible
|
|
|
|
+ && start.InternalSubviews [i].Contains (new (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y)))
|
|
|
|
+ {
|
|
|
|
+ subview = start.InternalSubviews [i];
|
|
|
|
+ currentLocation.X = startOffsetX + start.Viewport.X;
|
|
|
|
+ currentLocation.Y = startOffsetY + start.Viewport.Y;
|
|
|
|
+
|
|
|
|
+ // start is the deepest subview under the mouse; stop searching the subviews
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (subview is null)
|
|
|
|
+ {
|
|
|
|
+ // No subview was found that's under the mouse, so we're done
|
|
|
|
+ return start;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // We found a subview of start that's under the mouse, continue...
|
|
|
|
+ start = subview;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Gets a new location of the <see cref="View"/> that is within the Viewport of the <paramref name="viewToMove"/>'s
|
|
|
|
+ /// <see cref="View.SuperView"/> (e.g. for dragging a Window). The `out` parameters are the new X and Y coordinates.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// If <paramref name="viewToMove"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not
|
|
|
|
+ /// <see cref="Application.Top"/> the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
|
|
|
|
+ /// <see cref="ConsoleDriver.Rows"/>.
|
|
|
|
+ /// </remarks>
|
|
|
|
+ /// <param name="viewToMove">The View that is to be moved.</param>
|
|
|
|
+ /// <param name="targetX">The target x location.</param>
|
|
|
|
+ /// <param name="targetY">The target y location.</param>
|
|
|
|
+ /// <param name="nx">The new x location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
|
|
|
|
+ /// <param name="ny">The new y location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
|
|
|
|
+ /// <param name="statusBar">The new top most statusBar</param>
|
|
|
|
+ /// <returns>
|
|
|
|
+ /// Either <see cref="Application.Top"/> (if <paramref name="viewToMove"/> does not have a Super View) or
|
|
|
|
+ /// <paramref name="viewToMove"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
|
|
|
|
+ /// </returns>
|
|
|
|
+ internal static View GetLocationEnsuringFullVisibility (
|
|
|
|
+ View viewToMove,
|
|
|
|
+ int targetX,
|
|
|
|
+ int targetY,
|
|
|
|
+ out int nx,
|
|
|
|
+ out int ny,
|
|
|
|
+ out StatusBar statusBar
|
|
|
|
+ )
|
|
|
|
+ {
|
|
|
|
+ int maxDimension;
|
|
|
|
+ View superView;
|
|
|
|
+ statusBar = null!;
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
+ {
|
|
|
|
+ maxDimension = Driver.Cols;
|
|
|
|
+ superView = Application.Top;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // Use the SuperView's Viewport, not Frame
|
|
|
|
+ maxDimension = viewToMove!.SuperView.Viewport.Width;
|
|
|
|
+ superView = viewToMove.SuperView;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (superView?.Margin is { } && superView == viewToMove!.SuperView)
|
|
|
|
+ {
|
|
|
|
+ maxDimension -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (viewToMove!.Frame.Width <= maxDimension)
|
|
|
|
+ {
|
|
|
|
+ nx = Math.Max (targetX, 0);
|
|
|
|
+ nx = nx + viewToMove.Frame.Width > maxDimension ? Math.Max (maxDimension - viewToMove.Frame.Width, 0) : nx;
|
|
|
|
+
|
|
|
|
+ if (nx > viewToMove.Frame.X + viewToMove.Frame.Width)
|
|
|
|
+ {
|
|
|
|
+ nx = Math.Max (viewToMove.Frame.Right, 0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ nx = targetX;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
|
|
|
|
+ var menuVisible = false;
|
|
|
|
+ var statusVisible = false;
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
+ {
|
|
|
|
+ menuVisible = Application.Top?.MenuBar?.Visible == true;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ View t = viewToMove!.SuperView;
|
|
|
|
+
|
|
|
|
+ while (t is { } and not Toplevel)
|
|
|
|
+ {
|
|
|
|
+ t = t.SuperView;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (t is Toplevel topLevel)
|
|
|
|
+ {
|
|
|
|
+ menuVisible = topLevel.MenuBar?.Visible == true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
+ {
|
|
|
|
+ maxDimension = menuVisible ? 1 : 0;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ maxDimension = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ny = Math.Max (targetY, maxDimension);
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
+ {
|
|
|
|
+ statusVisible = Application.Top?.StatusBar?.Visible == true;
|
|
|
|
+ statusBar = Application.Top?.StatusBar!;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ View t = viewToMove!.SuperView;
|
|
|
|
+
|
|
|
|
+ while (t is { } and not Toplevel)
|
|
|
|
+ {
|
|
|
|
+ t = t.SuperView;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (t is Toplevel topLevel)
|
|
|
|
+ {
|
|
|
|
+ statusVisible = topLevel.StatusBar?.Visible == true;
|
|
|
|
+ statusBar = topLevel.StatusBar!;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
+ {
|
|
|
|
+ maxDimension = statusVisible ? Driver.Rows - 1 : Driver.Rows;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ maxDimension = statusVisible ? viewToMove!.SuperView.Viewport.Height - 1 : viewToMove!.SuperView.Viewport.Height;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (superView?.Margin is { } && superView == viewToMove?.SuperView)
|
|
|
|
+ {
|
|
|
|
+ maxDimension -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ny = Math.Min (ny, maxDimension);
|
|
|
|
+
|
|
|
|
+ if (viewToMove?.Frame.Height <= maxDimension)
|
|
|
|
+ {
|
|
|
|
+ ny = ny + viewToMove.Frame.Height > maxDimension
|
|
|
|
+ ? Math.Max (maxDimension - viewToMove.Frame.Height, menuVisible ? 1 : 0)
|
|
|
|
+ : ny;
|
|
|
|
+
|
|
|
|
+ if (ny > viewToMove.Frame.Y + viewToMove.Frame.Height)
|
|
|
|
+ {
|
|
|
|
+ ny = Math.Max (viewToMove.Frame.Bottom, 0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
|
|
|
|
+
|
|
|
|
+ return superView!;
|
|
|
|
+ }
|
|
|
|
+
|
|
#region Frame
|
|
#region Frame
|
|
|
|
|
|
private Rectangle _frame;
|
|
private Rectangle _frame;
|
|
@@ -15,7 +249,10 @@ public partial class View
|
|
/// <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
|
|
/// <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
|
|
/// </value>
|
|
/// </value>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
- /// <para>Frame is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.</para>
|
|
|
|
|
|
+ /// <para>
|
|
|
|
+ /// Frame is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
|
|
|
|
+ /// .
|
|
|
|
+ /// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// Setting Frame will set <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> to the
|
|
/// Setting Frame will set <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> to the
|
|
/// values of the corresponding properties of the <paramref name="value"/> parameter.
|
|
/// values of the corresponding properties of the <paramref name="value"/> parameter.
|
|
@@ -131,7 +368,8 @@ public partial class View
|
|
/// <value>The <see cref="Pos"/> object representing the X position.</value>
|
|
/// <value>The <see cref="Pos"/> object representing the X position.</value>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
- /// The position is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
|
|
|
|
|
|
+ /// The position is relative to the <see cref="SuperView"/>'s Content, which is bound by
|
|
|
|
+ /// <see cref="GetContentSize ()"/>.
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
|
|
/// If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
|
|
@@ -169,7 +407,8 @@ public partial class View
|
|
/// <value>The <see cref="Pos"/> object representing the Y position.</value>
|
|
/// <value>The <see cref="Pos"/> object representing the Y position.</value>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
- /// The position is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>.
|
|
|
|
|
|
+ /// The position is relative to the <see cref="SuperView"/>'s Content, which is bound by
|
|
|
|
+ /// <see cref="GetContentSize ()"/>.
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
|
|
/// If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
|
|
@@ -206,7 +445,8 @@ public partial class View
|
|
/// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
|
|
/// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
- /// The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
|
|
|
|
|
|
+ /// The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by
|
|
|
|
+ /// <see cref="GetContentSize ()"/>
|
|
/// .
|
|
/// .
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
@@ -254,7 +494,8 @@ public partial class View
|
|
/// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
|
|
/// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
- /// The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by <see cref="GetContentSize ()"/>
|
|
|
|
|
|
+ /// The dimension is relative to the <see cref="SuperView"/>'s Content, which is bound by
|
|
|
|
+ /// <see cref="GetContentSize ()"/>
|
|
/// .
|
|
/// .
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
@@ -300,241 +541,6 @@ public partial class View
|
|
|
|
|
|
#region Layout Engine
|
|
#region Layout Engine
|
|
|
|
|
|
- #endregion Layout Engine
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <param name="location">SuperView-relative coordinate</param>
|
|
|
|
- /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
|
|
|
|
- public virtual bool Contains (in Point location) { return Frame.Contains (location); }
|
|
|
|
-
|
|
|
|
- /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
|
|
|
|
- /// <remarks>
|
|
|
|
- /// <para>
|
|
|
|
- /// Used to determine what view the mouse is over.
|
|
|
|
- /// </para>
|
|
|
|
- /// </remarks>
|
|
|
|
- /// <param name="start">The view to scope the search by.</param>
|
|
|
|
- /// <param name="location"><paramref name="start"/>.SuperView-relative coordinate.</param>
|
|
|
|
- /// <returns>
|
|
|
|
- /// The view that was found at the <paramref name="location"/> coordinate.
|
|
|
|
- /// <see langword="null"/> if no view was found.
|
|
|
|
- /// </returns>
|
|
|
|
-
|
|
|
|
- // CONCURRENCY: This method is not thread-safe. Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
|
|
|
|
- internal static View? FindDeepestView (View? start, in Point location)
|
|
|
|
- {
|
|
|
|
- Point currentLocation = location;
|
|
|
|
- while (start is { Visible: true } && start.Contains (currentLocation))
|
|
|
|
- {
|
|
|
|
- Adornment? found = null;
|
|
|
|
-
|
|
|
|
- if (start.Margin.Contains (currentLocation))
|
|
|
|
- {
|
|
|
|
- found = start.Margin;
|
|
|
|
- }
|
|
|
|
- else if (start.Border.Contains (currentLocation))
|
|
|
|
- {
|
|
|
|
- found = start.Border;
|
|
|
|
- }
|
|
|
|
- else if (start.Padding.Contains (currentLocation))
|
|
|
|
- {
|
|
|
|
- found = start.Padding;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Point viewportOffset = start.GetViewportOffsetFromFrame ();
|
|
|
|
-
|
|
|
|
- if (found is { })
|
|
|
|
- {
|
|
|
|
- start = found;
|
|
|
|
- viewportOffset = found.Parent.Frame.Location;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- int startOffsetX = currentLocation.X - (start.Frame.X + viewportOffset.X);
|
|
|
|
- int startOffsetY = currentLocation.Y - (start.Frame.Y + viewportOffset.Y);
|
|
|
|
-
|
|
|
|
- View? subview = null;
|
|
|
|
-
|
|
|
|
- for (int i = start.InternalSubviews.Count - 1; i >= 0; i--)
|
|
|
|
- {
|
|
|
|
- if (start.InternalSubviews [i].Visible
|
|
|
|
- && start.InternalSubviews [i].Contains (new (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y)))
|
|
|
|
- {
|
|
|
|
- subview = start.InternalSubviews [i];
|
|
|
|
- currentLocation.X = startOffsetX + start.Viewport.X;
|
|
|
|
- currentLocation.Y = startOffsetY + start.Viewport.Y;
|
|
|
|
-
|
|
|
|
- // start is the deepest subview under the mouse; stop searching the subviews
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (subview is null)
|
|
|
|
- {
|
|
|
|
- // No subview was found that's under the mouse, so we're done
|
|
|
|
- return start;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // We found a subview of start that's under the mouse, continue...
|
|
|
|
- start = subview;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Gets a new location of the <see cref="View"/> that is within the Viewport of the <paramref name="viewToMove"/>'s
|
|
|
|
- /// <see cref="View.SuperView"/> (e.g. for dragging a Window). The `out` parameters are the new X and Y coordinates.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <remarks>
|
|
|
|
- /// If <paramref name="viewToMove"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not
|
|
|
|
- /// <see cref="Application.Top"/> the position will be bound by the <see cref="ConsoleDriver.Cols"/> and
|
|
|
|
- /// <see cref="ConsoleDriver.Rows"/>.
|
|
|
|
- /// </remarks>
|
|
|
|
- /// <param name="viewToMove">The View that is to be moved.</param>
|
|
|
|
- /// <param name="targetX">The target x location.</param>
|
|
|
|
- /// <param name="targetY">The target y location.</param>
|
|
|
|
- /// <param name="nx">The new x location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
|
|
|
|
- /// <param name="ny">The new y location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
|
|
|
|
- /// <param name="statusBar">The new top most statusBar</param>
|
|
|
|
- /// <returns>
|
|
|
|
- /// Either <see cref="Application.Top"/> (if <paramref name="viewToMove"/> does not have a Super View) or
|
|
|
|
- /// <paramref name="viewToMove"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
|
|
|
|
- /// </returns>
|
|
|
|
- internal static View GetLocationEnsuringFullVisibility (
|
|
|
|
- View viewToMove,
|
|
|
|
- int targetX,
|
|
|
|
- int targetY,
|
|
|
|
- out int nx,
|
|
|
|
- out int ny,
|
|
|
|
- out StatusBar statusBar
|
|
|
|
- )
|
|
|
|
- {
|
|
|
|
- int maxDimension;
|
|
|
|
- View superView;
|
|
|
|
- statusBar = null!;
|
|
|
|
-
|
|
|
|
- if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
- {
|
|
|
|
- maxDimension = Driver.Cols;
|
|
|
|
- superView = Application.Top;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- // Use the SuperView's Viewport, not Frame
|
|
|
|
- maxDimension = viewToMove!.SuperView.Viewport.Width;
|
|
|
|
- superView = viewToMove.SuperView;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (superView?.Margin is { } && superView == viewToMove!.SuperView)
|
|
|
|
- {
|
|
|
|
- maxDimension -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (viewToMove!.Frame.Width <= maxDimension)
|
|
|
|
- {
|
|
|
|
- nx = Math.Max (targetX, 0);
|
|
|
|
- nx = nx + viewToMove.Frame.Width > maxDimension ? Math.Max (maxDimension - viewToMove.Frame.Width, 0) : nx;
|
|
|
|
-
|
|
|
|
- if (nx > viewToMove.Frame.X + viewToMove.Frame.Width)
|
|
|
|
- {
|
|
|
|
- nx = Math.Max (viewToMove.Frame.Right, 0);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- nx = targetX;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
|
|
|
|
- var menuVisible = false;
|
|
|
|
- var statusVisible = false;
|
|
|
|
-
|
|
|
|
- if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
- {
|
|
|
|
- menuVisible = Application.Top?.MenuBar?.Visible == true;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- View t = viewToMove!.SuperView;
|
|
|
|
-
|
|
|
|
- while (t is { } and not Toplevel)
|
|
|
|
- {
|
|
|
|
- t = t.SuperView;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (t is Toplevel topLevel)
|
|
|
|
- {
|
|
|
|
- menuVisible = topLevel.MenuBar?.Visible == true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
- {
|
|
|
|
- maxDimension = menuVisible ? 1 : 0;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- maxDimension = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ny = Math.Max (targetY, maxDimension);
|
|
|
|
-
|
|
|
|
- if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
- {
|
|
|
|
- statusVisible = Application.Top?.StatusBar?.Visible == true;
|
|
|
|
- statusBar = Application.Top?.StatusBar!;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- View t = viewToMove!.SuperView;
|
|
|
|
-
|
|
|
|
- while (t is { } and not Toplevel)
|
|
|
|
- {
|
|
|
|
- t = t.SuperView;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (t is Toplevel topLevel)
|
|
|
|
- {
|
|
|
|
- statusVisible = topLevel.StatusBar?.Visible == true;
|
|
|
|
- statusBar = topLevel.StatusBar!;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
|
|
|
|
- {
|
|
|
|
- maxDimension = statusVisible ? Driver.Rows - 1 : Driver.Rows;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- maxDimension = statusVisible ? viewToMove!.SuperView.Viewport.Height - 1 : viewToMove!.SuperView.Viewport.Height;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (superView?.Margin is { } && superView == viewToMove?.SuperView)
|
|
|
|
- {
|
|
|
|
- maxDimension -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ny = Math.Min (ny, maxDimension);
|
|
|
|
-
|
|
|
|
- if (viewToMove?.Frame.Height <= maxDimension)
|
|
|
|
- {
|
|
|
|
- ny = ny + viewToMove.Frame.Height > maxDimension
|
|
|
|
- ? Math.Max (maxDimension - viewToMove.Frame.Height, menuVisible ? 1 : 0)
|
|
|
|
- : ny;
|
|
|
|
-
|
|
|
|
- if (ny > viewToMove.Frame.Y + viewToMove.Frame.Height)
|
|
|
|
- {
|
|
|
|
- ny = Math.Max (viewToMove.Frame.Bottom, 0);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
|
|
|
|
-
|
|
|
|
- return superView!;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
|
|
/// <summary>Fired after the View's <see cref="LayoutSubviews"/> method has completed.</summary>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
|
|
/// Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has
|
|
@@ -562,7 +568,8 @@ public partial class View
|
|
/// are left unchanged.
|
|
/// are left unchanged.
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
- /// If any of the view's subviews have a position or dimension dependent on either <see cref="GetContentSize"/> or other subviews, <see cref="LayoutSubview"/> on
|
|
|
|
|
|
+ /// If any of the view's subviews have a position or dimension dependent on either <see cref="GetContentSize"/> or
|
|
|
|
+ /// other subviews, <see cref="LayoutSubview"/> on
|
|
/// will be called for that subview.
|
|
/// will be called for that subview.
|
|
/// </para>
|
|
/// </para>
|
|
/// </remarks>
|
|
/// </remarks>
|
|
@@ -650,12 +657,11 @@ public partial class View
|
|
{
|
|
{
|
|
TextFormatter.Height = GetContentSize ().Height;
|
|
TextFormatter.Height = GetContentSize ().Height;
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Invoked when the dimensions of the view have changed, for example in response to the container view or terminal resizing.
|
|
|
|
|
|
+ /// Invoked when the dimensions of the view have changed, for example in response to the container view or terminal
|
|
|
|
+ /// resizing.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
@@ -678,7 +684,7 @@ public partial class View
|
|
|
|
|
|
CheckDimAuto ();
|
|
CheckDimAuto ();
|
|
|
|
|
|
- var contentSize = GetContentSize ();
|
|
|
|
|
|
+ Size contentSize = GetContentSize ();
|
|
OnLayoutStarted (new (contentSize));
|
|
OnLayoutStarted (new (contentSize));
|
|
|
|
|
|
LayoutAdornments ();
|
|
LayoutAdornments ();
|
|
@@ -756,8 +762,8 @@ public partial class View
|
|
// First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
|
|
// First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
|
|
// Finally, if none of those are valid, use 2048 (for Unit tests).
|
|
// Finally, if none of those are valid, use 2048 (for Unit tests).
|
|
Size superViewContentSize = SuperView is { IsInitialized: true } ? SuperView.GetContentSize () :
|
|
Size superViewContentSize = SuperView is { IsInitialized: true } ? SuperView.GetContentSize () :
|
|
- Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.GetContentSize () :
|
|
|
|
- Application.Screen.Size;
|
|
|
|
|
|
+ Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.GetContentSize () :
|
|
|
|
+ Application.Screen.Size;
|
|
|
|
|
|
SetRelativeLayout (superViewContentSize);
|
|
SetRelativeLayout (superViewContentSize);
|
|
|
|
|
|
@@ -795,12 +801,15 @@ public partial class View
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Collects all views and their dependencies from a given starting view for layout purposes. Used by <see cref="TopologicalSort"/> to create an ordered list of views to layout.
|
|
|
|
|
|
+ /// Collects all views and their dependencies from a given starting view for layout purposes. Used by
|
|
|
|
+ /// <see cref="TopologicalSort"/> to create an ordered list of views to layout.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="from">The starting view from which to collect dependencies.</param>
|
|
/// <param name="from">The starting view from which to collect dependencies.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
- /// <param name="nEdges">A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views indicating a dependency.</param>
|
|
|
|
-
|
|
|
|
|
|
+ /// <param name="nEdges">
|
|
|
|
+ /// A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
|
|
|
|
+ /// indicating a dependency.
|
|
|
|
+ /// </param>
|
|
internal void CollectAll (View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
internal void CollectAll (View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
{
|
|
{
|
|
foreach (View? v in from.InternalSubviews)
|
|
foreach (View? v in from.InternalSubviews)
|
|
@@ -812,14 +821,17 @@ public partial class View
|
|
CollectDim (v.Height, v, ref nNodes, ref nEdges);
|
|
CollectDim (v.Height, v, ref nNodes, ref nEdges);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Collects dimension (where Width or Height is `DimView`) dependencies for a given view.
|
|
|
|
|
|
+ /// Collects dimension (where Width or Height is `DimView`) dependencies for a given view.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="dim">The dimension (width or height) to collect dependencies for.</param>
|
|
/// <param name="dim">The dimension (width or height) to collect dependencies for.</param>
|
|
/// <param name="from">The view for which to collect dimension dependencies.</param>
|
|
/// <param name="from">The view for which to collect dimension dependencies.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
- /// <param name="nEdges">A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views indicating a dependency.</param>
|
|
|
|
-
|
|
|
|
|
|
+ /// <param name="nEdges">
|
|
|
|
+ /// A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
|
|
|
|
+ /// indicating a dependency.
|
|
|
|
+ /// </param>
|
|
internal void CollectDim (Dim? dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
internal void CollectDim (Dim? dim, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
{
|
|
{
|
|
switch (dim)
|
|
switch (dim)
|
|
@@ -844,12 +856,15 @@ public partial class View
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Collects position (where X or Y is `PosView`) dependencies for a given view.
|
|
|
|
|
|
+ /// Collects position (where X or Y is `PosView`) dependencies for a given view.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="pos">The position (X or Y) to collect dependencies for.</param>
|
|
/// <param name="pos">The position (X or Y) to collect dependencies for.</param>
|
|
/// <param name="from">The view for which to collect position dependencies.</param>
|
|
/// <param name="from">The view for which to collect position dependencies.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
/// <param name="nNodes">A reference to a set of views representing nodes in the layout graph.</param>
|
|
- /// <param name="nEdges">A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views indicating a dependency.</param>
|
|
|
|
|
|
+ /// <param name="nEdges">
|
|
|
|
+ /// A reference to a set of tuples representing edges in the layout graph, where each tuple consists of a pair of views
|
|
|
|
+ /// indicating a dependency.
|
|
|
|
+ /// </param>
|
|
internal void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
internal void CollectPos (Pos pos, View from, ref HashSet<View> nNodes, ref HashSet<(View, View)> nEdges)
|
|
{
|
|
{
|
|
switch (pos)
|
|
switch (pos)
|
|
@@ -1008,7 +1023,6 @@ public partial class View
|
|
/// </remarks>
|
|
/// </remarks>
|
|
public bool ValidatePosDim { get; set; }
|
|
public bool ValidatePosDim { get; set; }
|
|
|
|
|
|
-
|
|
|
|
// TODO: Move this logic into the Pos/Dim classes
|
|
// TODO: Move this logic into the Pos/Dim classes
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
|
|
/// Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
|
|
@@ -1022,8 +1036,8 @@ public partial class View
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- DimAuto? widthAuto = Width as DimAuto;
|
|
|
|
- DimAuto? heightAuto = Height as DimAuto;
|
|
|
|
|
|
+ var widthAuto = Width as DimAuto;
|
|
|
|
+ var heightAuto = Height as DimAuto;
|
|
|
|
|
|
// Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
|
|
// Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
|
|
foreach (View view in Subviews)
|
|
foreach (View view in Subviews)
|
|
@@ -1088,8 +1102,10 @@ public partial class View
|
|
throw new InvalidOperationException (
|
|
throw new InvalidOperationException (
|
|
$"{view.GetType ().Name}.{name} = {bad.GetType ().Name} "
|
|
$"{view.GetType ().Name}.{name} = {bad.GetType ().Name} "
|
|
+ $"which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."
|
|
+ $"which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."
|
|
- );
|
|
|
|
|
|
+ );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ #endregion Layout Engine
|
|
}
|
|
}
|