diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs
index 202c1ffbfc..8e772c856a 100644
--- a/Terminal.Gui/Core/Border.cs
+++ b/Terminal.Gui/Core/Border.cs
@@ -665,9 +665,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the upper BorderThickness
for (int r = frame.Y - drawMarginFrame - sumThickness.Top;
- r < frame.Y - drawMarginFrame - padding.Top; r++) {
+ r > 0 && r < frame.Y - drawMarginFrame - padding.Top; r++) {
for (int c = frame.X - drawMarginFrame - sumThickness.Left;
- c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -675,9 +675,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the left BorderThickness
for (int r = frame.Y - drawMarginFrame - padding.Top;
- r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
for (int c = frame.X - drawMarginFrame - sumThickness.Left;
- c < frame.X - drawMarginFrame - padding.Left; c++) {
+ c > 0 && c < frame.X - drawMarginFrame - padding.Left; c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -685,9 +685,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the right BorderThickness
for (int r = frame.Y - drawMarginFrame - padding.Top;
- r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
for (int c = frame.Right + drawMarginFrame + padding.Right;
- c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -695,9 +695,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the lower BorderThickness
for (int r = frame.Bottom + drawMarginFrame + padding.Bottom;
- r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
for (int c = frame.X - drawMarginFrame - sumThickness.Left;
- c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+ c > 0 && c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -707,9 +707,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the upper Padding
for (int r = frame.Y - drawMarginFrame - padding.Top;
- r < frame.Y - drawMarginFrame; r++) {
+ r > 0 && r < frame.Y - drawMarginFrame; r++) {
for (int c = frame.X - drawMarginFrame - padding.Left;
- c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -717,9 +717,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the left Padding
for (int r = frame.Y - drawMarginFrame;
- r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
for (int c = frame.X - drawMarginFrame - padding.Left;
- c < frame.X - drawMarginFrame; c++) {
+ c > 0 && c < frame.X - drawMarginFrame; c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -727,9 +727,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the right Padding
for (int r = frame.Y - drawMarginFrame;
- r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
for (int c = frame.Right + drawMarginFrame;
- c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -737,9 +737,9 @@ private void DrawChildBorder (Rect frame, bool fill = true)
// Draw the lower Padding
for (int r = frame.Bottom + drawMarginFrame;
- r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
for (int c = frame.X - drawMarginFrame - padding.Left;
- c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -820,9 +820,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the upper BorderThickness
for (int r = frame.Y;
- r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
+ r > 0 && r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
for (int c = frame.X;
- c < Math.Min (frame.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -830,9 +830,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the left BorderThickness
for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
- r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
for (int c = frame.X;
- c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
+ c > 0 && c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -840,9 +840,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the right BorderThickness
for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
- r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X);
- c < Math.Min (frame.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -850,9 +850,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the lower BorderThickness
for (int r = Math.Max (frame.Bottom - borderThickness.Bottom, frame.Y);
- r < Math.Min (frame.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom, driver.Rows); r++) {
for (int c = frame.X;
- c < Math.Min (frame.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -862,9 +862,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the upper Padding
for (int r = frame.Y + borderThickness.Top;
- r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
+ r > 0 && r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
for (int c = frame.X + borderThickness.Left;
- c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -872,9 +872,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the left Padding
for (int r = frame.Y + sumThickness.Top;
- r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
for (int c = frame.X + borderThickness.Left;
- c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
+ c > 0 && c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -882,9 +882,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the right Padding
for (int r = frame.Y + sumThickness.Top;
- r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left);
- c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {
+ c > 0 && c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -892,9 +892,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the lower Padding
for (int r = Math.Max (frame.Bottom - sumThickness.Bottom, frame.Y + borderThickness.Top);
- r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
for (int c = frame.X + borderThickness.Left;
- c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
AddRuneAt (driver, c, r, ' ');
}
@@ -921,9 +921,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the upper Effect3D
for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
- r < frame.Y; r++) {
+ r > 0 && r < frame.Y; r++) {
for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
- c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
}
@@ -931,9 +931,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the left Effect3D
for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
- r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
- c < frame.X; c++) {
+ c > 0 && c < frame.X; c++) {
AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
}
@@ -941,9 +941,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the right Effect3D
for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
- r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
for (int c = frame.Right;
- c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
}
@@ -951,9 +951,9 @@ private void DrawParentBorder (Rect frame, bool fill = true)
// Draw the lower Effect3D
for (int r = frame.Bottom;
- r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+ r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
- c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+ c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
}
diff --git a/Terminal.Gui/Core/PosDim.cs b/Terminal.Gui/Core/PosDim.cs
index 1169fa0493..696607696b 100644
--- a/Terminal.Gui/Core/PosDim.cs
+++ b/Terminal.Gui/Core/PosDim.cs
@@ -52,7 +52,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Pos.PosFunc({function ()})";
+ return $"PosFunc({function ()})";
}
public override int GetHashCode () => function.GetHashCode ();
@@ -85,7 +85,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Pos.Factor({factor})";
+ return $"Factor({factor})";
}
public override int GetHashCode () => factor.GetHashCode ();
@@ -135,7 +135,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Pos.AnchorEnd(margin={n})";
+ return $"AnchorEnd({n})";
}
}
@@ -174,7 +174,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return "Pos.Center";
+ return "Center";
}
}
@@ -209,7 +209,7 @@ internal class PosAbsolute : Pos {
public override string ToString ()
{
- return $"Pos.Absolute({n})";
+ return $"Absolute({n})";
}
internal override int Anchor (int width)
@@ -244,7 +244,7 @@ public static Pos At (int n)
internal class PosCombine : Pos {
internal Pos left, right;
- bool add;
+ internal bool add;
public PosCombine (bool add, Pos left, Pos right)
{
this.left = left;
@@ -264,7 +264,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Pos.Combine({left.ToString ()}{(add ? '+' : '-')}{right.ToString ()})";
+ return $"Combine({left}{(add ? '+' : '-')}{right})";
}
}
@@ -345,7 +345,7 @@ public override string ToString ()
case 3: tside = "bottom"; break;
default: tside = "unknown"; break;
}
- return $"Pos.View(side={tside}, target={Target.ToString ()})";
+ return $"View({tside},{Target.ToString()})";
}
public override int GetHashCode () => Target.GetHashCode ();
@@ -442,7 +442,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Dim.DimFunc({function ()})";
+ return $"DimFunc({function ()})";
}
public override int GetHashCode () => function.GetHashCode ();
@@ -482,7 +482,7 @@ public bool IsFromRemaining ()
public override string ToString ()
{
- return $"Dim.Factor(factor={factor}, remaining={remaining})";
+ return $"Factor({factor},{remaining})";
}
public override int GetHashCode () => factor.GetHashCode ();
@@ -522,7 +522,7 @@ internal class DimAbsolute : Dim {
public override string ToString ()
{
- return $"Dim.Absolute({n})";
+ return $"Absolute({n})";
}
internal override int Anchor (int width)
@@ -541,7 +541,7 @@ internal class DimFill : Dim {
public override string ToString ()
{
- return $"Dim.Fill(margin={margin})";
+ return $"Fill({margin})";
}
internal override int Anchor (int width)
@@ -613,7 +613,7 @@ internal override int Anchor (int width)
public override string ToString ()
{
- return $"Dim.Combine({left.ToString ()}{(add ? '+' : '-')}{right.ToString ()})";
+ return $"Combine({left}{(add ? '+' : '-')}{right})";
}
}
@@ -691,7 +691,7 @@ public override string ToString ()
case 1: tside = "Width"; break;
default: tside = "unknown"; break;
}
- return $"DimView(side={tside}, target={Target.ToString ()})";
+ return $"DimView({tside},{Target.ToString ()})";
}
public override int GetHashCode () => Target.GetHashCode ();
diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 018cf1384f..e303bb343e 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
using NStack;
@@ -1109,8 +1110,15 @@ public void BringSubviewForward (View subview)
///
public void Clear ()
{
- var h = Frame.Height;
- var w = Frame.Width;
+ Rect containerBounds = GetContainerBounds ();
+ Rect viewBounds = Bounds;
+ if (!containerBounds.IsEmpty) {
+ viewBounds.Width = Math.Min (viewBounds.Width, containerBounds.Width);
+ viewBounds.Height = Math.Min (viewBounds.Height, containerBounds.Height);
+ }
+
+ var h = viewBounds.Height;
+ var w = viewBounds.Width;
for (var line = 0; line < h; line++) {
Move (0, line);
for (var col = 0; col < w; col++)
@@ -1518,7 +1526,7 @@ public virtual void Redraw (Rect bounds)
} else if (ustring.IsNullOrEmpty (TextFormatter.Text) &&
(GetType ().IsNestedPublic && !IsOverridden (this, "Redraw") || GetType ().Name == "View") &&
(!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded)) {
-
+
Clear ();
SetChildNeedsDisplay ();
}
@@ -1543,8 +1551,9 @@ public virtual void Redraw (Rect bounds)
foreach (var view in subviews) {
if (!view.NeedDisplay.IsEmpty || view.ChildNeedsDisplay || view.LayoutNeeded) {
if (view.Frame.IntersectsWith (clipRect) && (view.Frame.IntersectsWith (bounds) || bounds.X < 0 || bounds.Y < 0)) {
- if (view.LayoutNeeded)
+ if (view.LayoutNeeded) {
view.LayoutSubviews ();
+ }
// Draw the subview
// Use the view's bounds (view-relative; Location will always be (0,0)
@@ -2174,119 +2183,226 @@ View GetMostFocused (View view)
}
///
- /// Sets the View's to the relative coordinates if its container, given the for its container.
+ /// Sets the View's to the frame-relative coordinates if its container. The
+ /// container size and location are specified by and are relative to the
+ /// View's superview.
///
- /// The screen-relative frame for the host.
- ///
- /// Reminder: is superview-relative; is view-relative.
- ///
- internal void SetRelativeLayout (Rect hostFrame)
+ /// The supserview-relative rectangle describing View's container (nominally the
+ /// same as this.SuperView.Frame).
+ internal void SetRelativeLayout (Rect superviewFrame)
{
- int actW, actH, actX, actY;
- var s = Size.Empty;
+ int newX, newW, newY, newH;
+ var autosize = Size.Empty;
if (AutoSize) {
- s = GetAutoSize ();
+ // Note this is global to this function and used as such within the local functions defined
+ // below. In v2 AutoSize will be re-factored to not need to be dealt with in this function.
+ autosize = GetAutoSize ();
}
- if (x is Pos.PosCenter) {
- if (width == null) {
- actW = AutoSize ? s.Width : hostFrame.Width;
- } else {
- actW = width.Anchor (hostFrame.Width);
- actW = AutoSize && s.Width > actW ? s.Width : actW;
- }
- actX = x.Anchor (hostFrame.Width - actW);
- } else {
- actX = x?.Anchor (hostFrame.Width) ?? 0;
+ // Returns the new dimension (width or height) and location (x or y) for the View given
+ // the superview's Frame.X or Frame.Y
+ // the superview's width or height
+ // the current Pos (View.X or View.Y)
+ // the current Dim (View.Width or View.Height)
+ (int newLocation, int newDimension) GetNewLocationAndDimension (int superviewLocation, int superviewDimension, Pos pos, Dim dim, int autosizeDimension)
+ {
+ int newDimension, newLocation;
- actW = Math.Max (CalculateActualWidth (width, hostFrame, actX, s), 0);
+ switch (pos) {
+ case Pos.PosCenter:
+ if (dim == null) {
+ newDimension = AutoSize ? autosizeDimension : superviewDimension;
+ } else {
+ newDimension = dim.Anchor (superviewDimension);
+ newDimension = AutoSize && autosizeDimension > newDimension ? autosizeDimension : newDimension;
+ }
+ newLocation = pos.Anchor (superviewDimension - newDimension);
+ break;
+
+ case Pos.PosCombine:
+ var combine = pos as Pos.PosCombine;
+ int left, right;
+ (left, newDimension) = GetNewLocationAndDimension (superviewLocation, superviewDimension, combine.left, dim, autosizeDimension);
+ (right, newDimension) = GetNewLocationAndDimension (superviewLocation, superviewDimension, combine.right, dim, autosizeDimension);
+ if (combine.add) {
+ newLocation = left + right;
+ } else {
+ newLocation = left - right;
+ }
+ newDimension = Math.Max (CalculateNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
+ break;
+
+ case Pos.PosAbsolute:
+ case Pos.PosAnchorEnd:
+ case Pos.PosFactor:
+ case Pos.PosFunc:
+ case Pos.PosView:
+ default:
+ newLocation = pos?.Anchor (superviewDimension) ?? 0;
+ newDimension = Math.Max (CalculateNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
+ break;
+ }
+ return (newLocation, newDimension);
}
- if (y is Pos.PosCenter) {
- if (height == null) {
- actH = AutoSize ? s.Height : hostFrame.Height;
- } else {
- actH = height.Anchor (hostFrame.Height);
- actH = AutoSize && s.Height > actH ? s.Height : actH;
+ // Recursively calculates the new dimension (width or height) of the given Dim given:
+ // the current location (x or y)
+ // the current dimennsion (width or height)
+ int CalculateNewDimension (Dim d, int location, int dimension, int autosize)
+ {
+ int newDimension;
+ switch (d) {
+ case null:
+ newDimension = AutoSize ? autosize : dimension;
+ break;
+ case Dim.DimCombine combine:
+ int leftNewDim = CalculateNewDimension (combine.left, location, dimension, autosize);
+ int rightNewDim = CalculateNewDimension (combine.right, location, dimension, autosize);
+ if (combine.add) {
+ newDimension = leftNewDim + rightNewDim;
+ } else {
+ newDimension = leftNewDim - rightNewDim;
+ }
+ newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
+ break;
+
+ case Dim.DimFactor factor when !factor.IsFromRemaining ():
+ newDimension = d.Anchor (dimension);
+ newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
+ break;
+
+ case Dim.DimFill:
+ default:
+ newDimension = Math.Max (d.Anchor (dimension - location), 0);
+ newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
+ break;
}
- actY = y.Anchor (hostFrame.Height - actH);
- } else {
- actY = y?.Anchor (hostFrame.Height) ?? 0;
- actH = Math.Max (CalculateActualHight (height, hostFrame, actY, s), 0);
+ return newDimension;
}
- var r = new Rect (actX, actY, actW, actH);
+
+ // horiztonal
+ (newX, newW) = GetNewLocationAndDimension (superviewFrame.X, superviewFrame.Width, x, Width, autosize.Width);
+
+ // vertical
+ (newY, newH) = GetNewLocationAndDimension (superviewFrame.Y, superviewFrame.Height, y, Height, autosize.Height);
+
+ var r = new Rect (newX, newY, newW, newH);
if (Frame != r) {
Frame = r;
- if (!SetMinWidthHeight ())
+ if (!SetMinWidthHeight ()) {
TextFormatter.Size = GetBoundsTextFormatterSize ();
+ }
}
}
- private int CalculateActualWidth (Dim width, Rect hostFrame, int actX, Size s)
+ ///
+ /// Event arguments for the event.
+ ///
+ public class LayoutEventArgs : EventArgs {
+ ///
+ /// The view-relative bounds of the before it was laid out.
+ ///
+ public Rect OldBounds { get; set; }
+ }
+
+ ///
+ /// Fired after the View's method has completed.
+ ///
+ ///
+ /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed.
+ ///
+ public event Action LayoutStarted;
+
+ ///
+ /// Raises the event. Called from before any subviews have been laid out.
+ ///
+ internal virtual void OnLayoutStarted (LayoutEventArgs args)
{
- int actW;
- switch (width) {
- case null:
- actW = AutoSize ? s.Width : hostFrame.Width;
- break;
- case Dim.DimCombine combine:
- int leftActW = CalculateActualWidth (combine.left, hostFrame, actX, s);
- int rightActW = CalculateActualWidth (combine.right, hostFrame, actX, s);
- if (combine.add) {
- actW = leftActW + rightActW;
- } else {
- actW = leftActW - rightActW;
+ LayoutStarted?.Invoke (args);
+ }
+
+ ///
+ /// Fired after the View's method has completed.
+ ///
+ ///
+ /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed.
+ ///
+ public event Action LayoutComplete;
+
+ ///
+ /// Event called only once when the is being initialized for the first time.
+ /// Allows configurations and assignments to be performed before the being shown.
+ /// This derived from to allow notify all the views that are being initialized.
+ ///
+ public event EventHandler Initialized;
+
+ ///
+ /// Raises the event. Called from before all sub-views have been laid out.
+ ///
+ internal virtual void OnLayoutComplete (LayoutEventArgs args)
+ {
+ LayoutComplete?.Invoke (args);
+ }
+
+ internal void CollectPos (Pos pos, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
+ {
+ switch (pos) {
+ case Pos.PosView pv:
+ if (pv.Target != this) {
+ nEdges.Add ((pv.Target, from));
+ }
+ foreach (var v in from.InternalSubviews) {
+ CollectAll (v, ref nNodes, ref nEdges);
+ }
+ return;
+ case Pos.PosCombine pc:
+ foreach (var v in from.InternalSubviews) {
+ CollectPos (pc.left, from, ref nNodes, ref nEdges);
+ CollectPos (pc.right, from, ref nNodes, ref nEdges);
}
- actW = AutoSize && s.Width > actW ? s.Width : actW;
- break;
- case Dim.DimFactor factor when !factor.IsFromRemaining ():
- actW = width.Anchor (hostFrame.Width);
- actW = AutoSize && s.Width > actW ? s.Width : actW;
- break;
- default:
- actW = Math.Max (width.Anchor (hostFrame.Width - actX), 0);
- actW = AutoSize && s.Width > actW ? s.Width : actW;
break;
}
-
- return actW;
}
- private int CalculateActualHight (Dim height, Rect hostFrame, int actY, Size s)
+ internal void CollectDim (Dim dim, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
{
- int actH;
- switch (height) {
- case null:
- actH = AutoSize ? s.Height : hostFrame.Height;
- break;
- case Dim.DimCombine combine:
- int leftActH = CalculateActualHight (combine.left, hostFrame, actY, s);
- int rightActH = CalculateActualHight (combine.right, hostFrame, actY, s);
- if (combine.add) {
- actH = leftActH + rightActH;
- } else {
- actH = leftActH - rightActH;
+ switch (dim) {
+ case Dim.DimView dv:
+ if (dv.Target != this) {
+ nEdges.Add ((dv.Target, from));
+ }
+ foreach (var v in from.InternalSubviews) {
+ CollectAll (v, ref nNodes, ref nEdges);
+ }
+ return;
+ case Dim.DimCombine dc:
+ foreach (var v in from.InternalSubviews) {
+ CollectDim (dc.left, from, ref nNodes, ref nEdges);
+ CollectDim (dc.right, from, ref nNodes, ref nEdges);
}
- actH = AutoSize && s.Height > actH ? s.Height : actH;
- break;
- case Dim.DimFactor factor when !factor.IsFromRemaining ():
- actH = height.Anchor (hostFrame.Height);
- actH = AutoSize && s.Height > actH ? s.Height : actH;
- break;
- default:
- actH = Math.Max (height.Anchor (hostFrame.Height - actY), 0);
- actH = AutoSize && s.Height > actH ? s.Height : actH;
break;
}
+ }
- return actH;
+ internal void CollectAll (View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
+ {
+ foreach (var v in from.InternalSubviews) {
+ nNodes.Add (v);
+ if (v.layoutStyle != LayoutStyle.Computed) {
+ continue;
+ }
+ CollectPos (v.X, v, ref nNodes, ref nEdges);
+ CollectPos (v.Y, v, ref nNodes, ref nEdges);
+ CollectDim (v.Width, v, ref nNodes, ref nEdges);
+ CollectDim (v.Height, v, ref nNodes, ref nEdges);
+ }
}
// https://en.wikipedia.org/wiki/Topological_sorting
- List TopologicalSort (IEnumerable nodes, ICollection<(View From, View To)> edges)
+ internal static List TopologicalSort (View superView, IEnumerable nodes, ICollection<(View From, View To)> edges)
{
var result = new List ();
@@ -2299,7 +2415,7 @@ List TopologicalSort (IEnumerable nodes, ICollection<(View From, Vie
noEdgeNodes.Remove (n);
// add n to tail of L
- if (n != this?.SuperView)
+ if (n != superView)
result.Add (n);
// for each node m with an edge e from n to m do
@@ -2310,7 +2426,7 @@ List TopologicalSort (IEnumerable nodes, ICollection<(View From, Vie
edges.Remove (e);
// if m has no other incoming edges then
- if (edges.All (me => !me.To.Equals (m)) && m != this?.SuperView) {
+ if (edges.All (me => !me.To.Equals (m)) && m != superView) {
// insert m into S
noEdgeNodes.Add (m);
}
@@ -2321,65 +2437,16 @@ List TopologicalSort (IEnumerable nodes, ICollection<(View From, Vie
(var from, var to) = edges.First ();
if (from != Application.Top) {
if (!ReferenceEquals (from, to)) {
- throw new InvalidOperationException ($"TopologicalSort (for Pos/Dim) cannot find {from} linked with {to}. Did you forget to add it to {this}?");
+ throw new InvalidOperationException ($"TopologicalSort (for Pos/Dim) cannot find {from} linked with {to}. Did you forget to add it to {superView}?");
} else {
- throw new InvalidOperationException ("TopologicalSort encountered a recursive cycle in the relative Pos/Dim in the views of " + this);
+ throw new InvalidOperationException ("TopologicalSort encountered a recursive cycle in the relative Pos/Dim in the views of " + superView);
}
}
}
-
// return L (a topologically sorted order)
return result;
- }
-
- ///
- /// Event arguments for the event.
- ///
- public class LayoutEventArgs : EventArgs {
- ///
- /// The view-relative bounds of the before it was laid out.
- ///
- public Rect OldBounds { get; set; }
- }
-
- ///
- /// Fired after the View's method has completed.
- ///
- ///
- /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed.
- ///
- public event Action LayoutStarted;
-
- ///
- /// Raises the event. Called from before any subviews have been laid out.
- ///
- internal virtual void OnLayoutStarted (LayoutEventArgs args)
- {
- LayoutStarted?.Invoke (args);
- }
-
- ///
- /// Fired after the View's method has completed.
- ///
- ///
- /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed.
- ///
- public event Action LayoutComplete;
-
- ///
- /// Event called only once when the is being initialized for the first time.
- /// Allows configurations and assignments to be performed before the being shown.
- /// This derived from to allow notify all the views that are being initialized.
- ///
- public event EventHandler Initialized;
+ } // TopologicalSort
- ///
- /// Raises the event. Called from before all sub-views have been laid out.
- ///
- internal virtual void OnLayoutComplete (LayoutEventArgs args)
- {
- LayoutComplete?.Invoke (args);
- }
///
/// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
@@ -2399,69 +2466,11 @@ public virtual void LayoutSubviews ()
TextFormatter.Size = GetBoundsTextFormatterSize ();
-
// Sort out the dependencies of the X, Y, Width, Height properties
var nodes = new HashSet ();
var edges = new HashSet<(View, View)> ();
-
- void CollectPos (Pos pos, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- switch (pos) {
- case Pos.PosView pv:
- if (pv.Target != this) {
- nEdges.Add ((pv.Target, from));
- }
- foreach (var v in from.InternalSubviews) {
- CollectAll (v, ref nNodes, ref nEdges);
- }
- return;
- case Pos.PosCombine pc:
- foreach (var v in from.InternalSubviews) {
- CollectPos (pc.left, from, ref nNodes, ref nEdges);
- CollectPos (pc.right, from, ref nNodes, ref nEdges);
- }
- break;
- }
- }
-
- void CollectDim (Dim dim, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- switch (dim) {
- case Dim.DimView dv:
- if (dv.Target != this) {
- nEdges.Add ((dv.Target, from));
- }
- foreach (var v in from.InternalSubviews) {
- CollectAll (v, ref nNodes, ref nEdges);
- }
- return;
- case Dim.DimCombine dc:
- foreach (var v in from.InternalSubviews) {
- CollectDim (dc.left, from, ref nNodes, ref nEdges);
- CollectDim (dc.right, from, ref nNodes, ref nEdges);
- }
- break;
- }
- }
-
- void CollectAll (View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- foreach (var v in from.InternalSubviews) {
- nNodes.Add (v);
- if (v.layoutStyle != LayoutStyle.Computed) {
- continue;
- }
- CollectPos (v.X, v, ref nNodes, ref nEdges);
- CollectPos (v.Y, v, ref nNodes, ref nEdges);
- CollectDim (v.Width, v, ref nNodes, ref nEdges);
- CollectDim (v.Height, v, ref nNodes, ref nEdges);
- }
- }
-
CollectAll (this, ref nodes, ref edges);
-
- var ordered = TopologicalSort (nodes, edges);
-
+ var ordered = View.TopologicalSort (SuperView, nodes, edges);
foreach (var v in ordered) {
if (v.LayoutStyle == LayoutStyle.Computed) {
v.SetRelativeLayout (Frame);
@@ -2471,9 +2480,12 @@ void CollectAll (View from, ref HashSet nNodes, ref HashSet<(View, View)>
v.LayoutNeeded = false;
}
+ // If our SuperView is Application.Top and the layoutstyle is Computed it's a special-cass.
+ // Use SetRelativeaLayout with the Frame of the Application.Top
if (SuperView != null && SuperView == Application.Top && LayoutNeeded
&& ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) {
- SetRelativeLayout (SuperView.Frame);
+ Debug.Assert (Application.Top.Frame.Location == Point.Empty);
+ SetRelativeLayout (Application.Top.Frame);
}
LayoutNeeded = false;
@@ -2756,9 +2768,11 @@ bool SetWidthHeight (Size nBounds)
}
///
- /// Gets the size to fit all text if is true.
+ /// Gets the dimensions required to fit using the text specified by the
+ /// property and accounting for any characters.
+ /// .
///
- /// The
+ /// The required to fit the text.
public Size GetAutoSize ()
{
var rect = TextFormatter.CalcRect (Bounds.X, Bounds.Y, TextFormatter.Text, TextFormatter.Direction);
@@ -2793,10 +2807,11 @@ bool IsValidAutoSizeHeight (Dim height)
}
///
- /// Get the width or height of the length.
+ /// Gets the width or height of the characters in the property.
///
- /// if is the width (default) if is the height.
- /// The length of the .
+ /// If (the default) the width required for the hotkey specifier is returned. Otherwise the height is returned.
+ /// The number of characters required for the . If the text direction specified
+ /// by does not match the parameter, 0 is returned.
public int GetHotKeySpecifierLength (bool isWidth = true)
{
if (isWidth) {
@@ -2811,7 +2826,7 @@ public int GetHotKeySpecifierLength (bool isWidth = true)
}
///
- /// Gets the bounds size from a .
+ /// Gets the minus the size required for the .
///
/// The bounds size minus the length.
public Size GetTextFormatterBoundsSize ()
diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index 0bab49cbfd..a390fe83fd 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -57,6 +57,7 @@
net472;netstandard2.0;net6.0
+ 9
Terminal.Gui
Terminal.Gui
bin\Release\Terminal.Gui.xml
diff --git a/UICatalog/Scenario.cs b/UICatalog/Scenario.cs
index e26ce29116..ae06c151c9 100644
--- a/UICatalog/Scenario.cs
+++ b/UICatalog/Scenario.cs
@@ -186,8 +186,8 @@ public virtual void Setup ()
}
///
- /// Runs the . Override to start the using a different than `Top`.
- ///
+ /// Runs the . Override to start the
+ /// using a different than `Top`.
///
///
/// Overrides that do not call the base., must call before returning.
diff --git a/UICatalog/Scenarios/ASCIICustomButton.cs b/UICatalog/Scenarios/ASCIICustomButton.cs
deleted file mode 100644
index 77cacf8b95..0000000000
--- a/UICatalog/Scenarios/ASCIICustomButton.cs
+++ /dev/null
@@ -1,313 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using Terminal.Gui;
-
-namespace UICatalog.Scenarios {
- [ScenarioMetadata (Name: "ASCIICustomButtonTest", Description: "ASCIICustomButton sample")]
- [ScenarioCategory ("Controls")]
- public class ASCIICustomButtonTest : Scenario {
- private static bool smallerWindow;
- private ScrollViewTestWindow scrollViewTestWindow;
- private MenuItem miSmallerWindow;
-
- public override void Init (ColorScheme colorScheme)
- {
- Application.Init ();
- scrollViewTestWindow = new ScrollViewTestWindow ();
- var menu = new MenuBar (new MenuBarItem [] {
- new MenuBarItem("Window Size", new MenuItem [] {
- miSmallerWindow = new MenuItem ("Smaller Window", "", ChangeWindowSize) {
- CheckType = MenuItemCheckStyle.Checked
- },
- null,
- new MenuItem("Quit", "",() => Application.RequestStop(),null,null, Key.Q | Key.CtrlMask)
- })
- });
- Application.Top.Add (menu, scrollViewTestWindow);
- Application.Run ();
- }
-
- private void ChangeWindowSize ()
- {
- smallerWindow = miSmallerWindow.Checked = !miSmallerWindow.Checked;
- scrollViewTestWindow.Dispose ();
- Application.Top.Remove (scrollViewTestWindow);
- scrollViewTestWindow = new ScrollViewTestWindow ();
- Application.Top.Add (scrollViewTestWindow);
- }
-
- public override void Run ()
- {
- }
-
- public class ASCIICustomButton : Button {
- public string Description => $"Description of: {id}";
-
- public event Action PointerEnter;
-
- private Label fill;
- private FrameView border;
- private string id;
-
- public ASCIICustomButton (string text, Pos x, Pos y, int width, int height) : base (text)
- {
- CustomInitialize ("", text, x, y, width, height);
- }
-
- public ASCIICustomButton (string id, string text, Pos x, Pos y, int width, int height) : base (text)
- {
- CustomInitialize (id, text, x, y, width, height);
- }
-
- private void CustomInitialize (string id, string text, Pos x, Pos y, int width, int height)
- {
- this.id = id;
- X = x;
- Y = y;
-
- Frame = new Rect {
- Width = width,
- Height = height
- };
-
- border = new FrameView () {
- Width = width,
- Height = height
- };
-
- AutoSize = false;
-
- var fillText = new System.Text.StringBuilder ();
- for (int i = 0; i < Bounds.Height; i++) {
- if (i > 0) {
- fillText.AppendLine ("");
- }
- for (int j = 0; j < Bounds.Width; j++) {
- fillText.Append ("█");
- }
- }
-
- fill = new Label (fillText.ToString ()) {
- Visible = false,
- CanFocus = false
- };
-
- var title = new Label (text) {
- X = Pos.Center (),
- Y = Pos.Center (),
- };
-
- border.MouseClick += This_MouseClick;
- border.Subviews [0].MouseClick += This_MouseClick;
- fill.MouseClick += This_MouseClick;
- title.MouseClick += This_MouseClick;
-
- Add (border, fill, title);
- }
-
- private void This_MouseClick (MouseEventArgs obj)
- {
- OnMouseEvent (obj.MouseEvent);
- }
-
- public override bool OnMouseEvent (MouseEvent mouseEvent)
- {
- Debug.WriteLine ($"{mouseEvent.Flags}");
- if (mouseEvent.Flags == MouseFlags.Button1Clicked) {
- if (!HasFocus && SuperView != null) {
- if (!SuperView.HasFocus) {
- SuperView.SetFocus ();
- }
- SetFocus ();
- SetNeedsDisplay ();
- }
-
- OnClicked ();
- return true;
- }
- return base.OnMouseEvent (mouseEvent);
- }
-
- public override bool OnEnter (View view)
- {
- border.Visible = false;
- fill.Visible = true;
- PointerEnter.Invoke (this);
- view = this;
- return base.OnEnter (view);
- }
-
- public override bool OnLeave (View view)
- {
- border.Visible = true;
- fill.Visible = false;
- if (view == null)
- view = this;
- return base.OnLeave (view);
- }
- }
-
- public class ScrollViewTestWindow : Window {
- private List