diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs
index d2b355549..95a15e457 100644
--- a/Terminal.Gui/Application.cs
+++ b/Terminal.Gui/Application.cs
@@ -196,7 +196,7 @@ public static partial class Application {
Current = Top;
// Ensure Top's layout is up to date.
- Current.SetRelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
+ Current.SetRelativeLayout (Driver.Bounds);
_cachedSupportedCultures = GetSupportedCultures ();
_mainThreadId = Thread.CurrentThread.ManagedThreadId;
@@ -402,7 +402,7 @@ public static partial class Application {
}
//if (Toplevel.LayoutStyle == LayoutStyle.Computed) {
- Toplevel.SetRelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
+ Toplevel.SetRelativeLayout (Driver.Bounds);
//}
Toplevel.LayoutSubviews ();
Toplevel.PositionToplevels ();
@@ -714,7 +714,7 @@ public static partial class Application {
&& (Driver.Cols != state.Toplevel.Frame.Width || Driver.Rows != state.Toplevel.Frame.Height)
&& (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded)) {
- state.Toplevel.Clear (new Rect (Point.Empty, new Size (Driver.Cols, Driver.Rows)));
+ state.Toplevel.Clear (Driver.Bounds);
}
if (state.Toplevel.NeedsDisplay ||
diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
index 4bd0143e1..70a9a4827 100644
--- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs
@@ -552,6 +552,11 @@ public abstract class ConsoleDriver {
///
public static DiagnosticFlags Diagnostics { get; set; }
+ ///
+ /// Gets the dimensions of the terminal.
+ ///
+ public Rect Bounds => new Rect (0, 0, Cols, Rows);
+
///
/// Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.
///
diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs
index 9423b3ed0..4f1277286 100644
--- a/Terminal.Gui/View/Layout/ViewLayout.cs
+++ b/Terminal.Gui/View/Layout/ViewLayout.cs
@@ -11,1433 +11,1360 @@ namespace Terminal.Gui;
/// value from the will be used, if the value is Computed, then
/// will be updated from the X, Y objects and the Width and Height objects.
///
-public enum LayoutStyle
-{
- ///
- /// The position and size of the view are based .
- ///
- Absolute,
+public enum LayoutStyle {
+ ///
+ /// The position and size of the view are based .
+ ///
+ Absolute,
- ///
- /// The position and size of the view will be computed based on
- /// , , , and .
- /// will
- /// provide the absolute computed values.
- ///
- Computed
+ ///
+ /// The position and size of the view will be computed based on
+ /// , , , and .
+ /// will
+ /// provide the absolute computed values.
+ ///
+ Computed
}
-public partial class View
-{
- bool _autoSize;
+public partial class View {
+ bool _autoSize;
- ///
- /// Backing property for Frame - The frame for the object. Relative to the SuperView's Bounds.
- ///
- Rect _frame;
+ ///
+ /// Backing property for Frame - The frame for the object. Relative to the SuperView's Bounds.
+ ///
+ Rect _frame;
- ///
- /// Gets or sets location and size of the view. The frame is relative to the 's
- /// .
- ///
- ///
- /// The rectangle describing the location and size of the view, in coordinates relative to the
- /// .
- ///
- ///
- ///
- /// Change the Frame when using the layout style to move or resize views.
- ///
- ///
- /// Altering the Frame will change to .
- /// Additionally, , , , and will be set
- /// to the values of the Frame (using and ).
- ///
- ///
- /// Altering the Frame will eventually (when the view is next drawn) cause the
- ///
- /// and methods to be called.
- ///
- ///
- public virtual Rect Frame
- {
- get => _frame;
- set
- {
- _frame = new Rect(value.X, value.Y, Math.Max(value.Width, 0), Math.Max(value.Height, 0));
+ ///
+ /// Gets or sets location and size of the view. The frame is relative to the 's
+ /// .
+ ///
+ ///
+ /// The rectangle describing the location and size of the view, in coordinates relative to the
+ /// .
+ ///
+ ///
+ ///
+ /// Change the Frame when using the layout style to move or resize views.
+ ///
+ ///
+ /// Altering the Frame will change to .
+ /// Additionally, , , , and will be set
+ /// to the values of the Frame (using and ).
+ ///
+ ///
+ /// Altering the Frame will eventually (when the view is next drawn) cause the
+ ///
+ /// and methods to be called.
+ ///
+ ///
+ public virtual Rect Frame {
+ get => _frame;
+ set {
+ _frame = new Rect (value.X, value.Y, Math.Max (value.Width, 0), Math.Max (value.Height, 0));
- // If Frame gets set, by definition, the View is now LayoutStyle.Absolute, so
- // set all Pos/Dim to Absolute values.
- _x = _frame.X;
- _y = _frame.Y;
- _width = _frame.Width;
- _height = _frame.Height;
- if (IsInitialized || LayoutStyle == LayoutStyle.Absolute)
- {
- LayoutFrames();
- TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey();
- SetNeedsLayout();
- SetNeedsDisplay();
- }
- }
- }
+ // If Frame gets set, by definition, the View is now LayoutStyle.Absolute, so
+ // set all Pos/Dim to Absolute values.
+ _x = _frame.X;
+ _y = _frame.Y;
+ _width = _frame.Width;
+ _height = _frame.Height;
+ if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
+ LayoutFrames ();
+ TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+ SetNeedsLayout ();
+ SetNeedsDisplay ();
+ }
+ }
+ }
- ///
- /// The frame (specified as a ) that separates a View from other SubViews of the same SuperView.
- /// The margin offsets the from the .
- ///
- ///
- ///
- /// The frames (, , and ) are not part of the View's
- /// content
- /// and are not clipped by the View's Clip Area.
- ///
- ///
- /// Changing the size of a frame (, , or )
- /// will change the size of the and trigger to update the layout
- /// of the
- /// and its .
- ///
- ///
- public Frame Margin { get; private set; }
+ ///
+ /// The frame (specified as a ) that separates a View from other SubViews of the same SuperView.
+ /// The margin offsets the from the .
+ ///
+ ///
+ ///
+ /// The frames (, , and ) are not part of the View's
+ /// content
+ /// and are not clipped by the View's Clip Area.
+ ///
+ ///
+ /// Changing the size of a frame (, , or )
+ /// will change the size of the and trigger to update the layout
+ /// of the
+ /// and its .
+ ///
+ ///
+ public Frame Margin { get; private set; }
- ///
- /// The frame (specified as a ) inside of the view that offsets the from the
- /// .
- /// The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title.
- /// The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and
- /// title will take up the first row and the second row will be filled with spaces.
- ///
- ///
- ///
- /// provides a simple helper for turning a simple border frame on or off.
- ///
- ///
- /// The frames (, , and ) are not part of the View's
- /// content
- /// and are not clipped by the View's Clip Area.
- ///
- ///
- /// Changing the size of a frame (, , or )
- /// will change the size of the and trigger to update the layout
- /// of the
- /// and its .
- ///
- ///
- public Frame Border { get; private set; }
+ ///
+ /// The frame (specified as a ) inside of the view that offsets the from the
+ /// .
+ /// The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title.
+ /// The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and
+ /// title will take up the first row and the second row will be filled with spaces.
+ ///
+ ///
+ ///
+ /// provides a simple helper for turning a simple border frame on or off.
+ ///
+ ///
+ /// The frames (, , and ) are not part of the View's
+ /// content
+ /// and are not clipped by the View's Clip Area.
+ ///
+ ///
+ /// Changing the size of a frame (, , or )
+ /// will change the size of the and trigger to update the layout
+ /// of the
+ /// and its .
+ ///
+ ///
+ public Frame Border { get; private set; }
- ///
- /// Gets or sets whether the view has a one row/col thick border.
- ///
- ///
- ///
- /// This is a helper for manipulating the view's . Setting this property to any value other
- /// than
- /// is equivalent to setting 's
- /// to `1` and to the value.
- ///
- ///
- /// Setting this property to is equivalent to setting 's
- ///
- /// to `0` and to .
- ///
- ///
- /// For more advanced customization of the view's border, manipulate see directly.
- ///
- ///
- public LineStyle BorderStyle
- {
- get => Border?.BorderStyle ?? LineStyle.None;
- set
- {
- if (Border == null)
- {
- throw new InvalidOperationException("Border is null; this is likely a bug.");
- }
- if (value != LineStyle.None)
- {
- Border.Thickness = new Thickness(1);
- }
- else
- {
- Border.Thickness = new Thickness(0);
- }
- Border.BorderStyle = value;
- LayoutFrames();
- SetNeedsLayout();
- }
- }
+ ///
+ /// Gets or sets whether the view has a one row/col thick border.
+ ///
+ ///
+ ///
+ /// This is a helper for manipulating the view's . Setting this property to any value other
+ /// than
+ /// is equivalent to setting 's
+ /// to `1` and to the value.
+ ///
+ ///
+ /// Setting this property to is equivalent to setting 's
+ ///
+ /// to `0` and to .
+ ///
+ ///
+ /// For more advanced customization of the view's border, manipulate see directly.
+ ///
+ ///
+ public LineStyle BorderStyle {
+ get => Border?.BorderStyle ?? LineStyle.None;
+ set {
+ if (Border == null) {
+ throw new InvalidOperationException ("Border is null; this is likely a bug.");
+ }
+ if (value != LineStyle.None) {
+ Border.Thickness = new Thickness (1);
+ } else {
+ Border.Thickness = new Thickness (0);
+ }
+ Border.BorderStyle = value;
+ LayoutFrames ();
+ SetNeedsLayout ();
+ }
+ }
- ///
- /// The frame (specified as a ) inside of the view that offsets the from the
- /// .
- ///
- ///
- ///
- /// The frames (, , and ) are not part of the View's
- /// content
- /// and are not clipped by the View's Clip Area.
- ///
- ///
- /// Changing the size of a frame (, , or )
- /// will change the size of the and trigger to update the layout
- /// of the
- /// and its .
- ///
- ///
- public Frame Padding { get; private set; }
+ ///
+ /// The frame (specified as a ) inside of the view that offsets the from the
+ /// .
+ ///
+ ///
+ ///
+ /// The frames (, , and ) are not part of the View's
+ /// content
+ /// and are not clipped by the View's Clip Area.
+ ///
+ ///
+ /// Changing the size of a frame (, , or )
+ /// will change the size of the and trigger to update the layout
+ /// of the
+ /// and its .
+ ///
+ ///
+ public Frame Padding { get; private set; }
- ///
- /// Controls how the View's is computed during . If the style is set to
- /// , LayoutSubviews does not change the .
- /// If the style is the is updated using
- /// the , , , and properties.
- ///
- ///
- ///
- /// Setting this property to will cause to determine the
- /// size and position of the view. and will be set to
- /// using .
- ///
- ///
- /// Setting this property to will cause the view to use the
- /// method to
- /// size and position of the view. If either of the and properties are `null` they
- /// will be set to using
- /// the current value of .
- /// If either of the and properties are `null` they will be set to
- /// using .
- ///
- ///
- /// The layout style.
- public LayoutStyle LayoutStyle
- {
- get
- {
- if (_x is Pos.PosAbsolute && _y is Pos.PosAbsolute && _width is Dim.DimAbsolute && _height is Dim.DimAbsolute)
- {
- return LayoutStyle.Absolute;
- }
- else
- {
- return LayoutStyle.Computed;
- }
- }
- set
- {
- // TODO: Remove this setter and make LayoutStyle read-only for real.
- throw new InvalidOperationException("LayoutStyle is read-only.");
- }
- }
+ ///
+ /// Controls how the View's is computed during . If the style is set to
+ /// , LayoutSubviews does not change the .
+ /// If the style is the is updated using
+ /// the , , , and properties.
+ ///
+ ///
+ ///
+ /// Setting this property to will cause to determine the
+ /// size and position of the view. and will be set to
+ /// using .
+ ///
+ ///
+ /// Setting this property to will cause the view to use the
+ /// method to
+ /// size and position of the view. If either of the and properties are `null` they
+ /// will be set to using
+ /// the current value of .
+ /// If either of the and properties are `null` they will be set to
+ /// using .
+ ///
+ ///
+ /// The layout style.
+ public LayoutStyle LayoutStyle {
+ get {
+ if (_x is Pos.PosAbsolute && _y is Pos.PosAbsolute && _width is Dim.DimAbsolute && _height is Dim.DimAbsolute) {
+ return LayoutStyle.Absolute;
+ } else {
+ return LayoutStyle.Computed;
+ }
+ }
+ set {
+ // TODO: Remove this setter and make LayoutStyle read-only for real.
+ throw new InvalidOperationException ("LayoutStyle is read-only.");
+ }
+ }
- ///
- /// The bounds represent the View-relative rectangle used for this view; the area inside of the view where subviews and
- /// content are presented.
- ///
- /// The rectangle describing the location and size of the area where the views' subviews and content are drawn.
- ///
- ///
- /// If is the value of Bounds is indeterminate until
- /// the
- /// view has been initialized ( is true) and has been
- /// called.
- ///
- ///
- /// Updates to the Bounds updates , and has the same side effects as updating the
- /// .
- ///
- ///
- /// Altering the Bounds will eventually (when the view is next drawn) cause the
- ///
- /// and methods to be called.
- ///
- ///
- /// Because coordinates are relative to the upper-left corner of the ,
- /// the coordinates of the upper-left corner of the rectangle returned by this property are (0,0).
- /// Use this property to obtain the size of the area of the view for tasks such as drawing the view's contents.
- ///
- ///
- public virtual Rect Bounds
- {
- get
- {
+ ///
+ /// The bounds represent the View-relative rectangle used for this view; the area inside of the view where subviews and
+ /// content are presented.
+ ///
+ /// The rectangle describing the location and size of the area where the views' subviews and content are drawn.
+ ///
+ ///
+ /// If is the value of Bounds is indeterminate until
+ /// the
+ /// view has been initialized ( is true) and has been
+ /// called.
+ ///
+ ///
+ /// Updates to the Bounds updates , and has the same side effects as updating the
+ /// .
+ ///
+ ///
+ /// Altering the Bounds will eventually (when the view is next drawn) cause the
+ ///
+ /// and methods to be called.
+ ///
+ ///
+ /// Because coordinates are relative to the upper-left corner of the ,
+ /// the coordinates of the upper-left corner of the rectangle returned by this property are (0,0).
+ /// Use this property to obtain the size of the area of the view for tasks such as drawing the view's contents.
+ ///
+ ///
+ public virtual Rect Bounds {
+ get {
#if DEBUG
- if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
- {
- Debug.WriteLine($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug in {this}");
- }
+ if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
+ Debug.WriteLine ($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug in {this}");
+ }
#endif // DEBUG
- //var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
- var frameRelativeBounds = FrameGetInsideBounds();
- return new Rect(default, frameRelativeBounds.Size);
- }
- set
- {
- // BUGBUG: Margin etc.. can be null (if typeof(Frame))
- Frame = new Rect(Frame.Location,
- new Size(
- value.Size.Width + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal,
- value.Size.Height + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical
- )
- );
- }
- }
+ //var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
+ var frameRelativeBounds = FrameGetInsideBounds ();
+ return new Rect (default, frameRelativeBounds.Size);
+ }
+ set {
+ // BUGBUG: Margin etc.. can be null (if typeof(Frame))
+ Frame = new Rect (Frame.Location,
+ new Size (
+ value.Size.Width + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal,
+ value.Size.Height + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical
+ )
+ );
+ }
+ }
- Pos _x = Pos.At(0);
+ Pos _x = Pos.At (0);
- ///
- /// Gets or sets the X position for the view (the column).
- ///
- /// The object representing the X position.
- ///
- ///
- /// If is the value is indeterminate until the
- /// view has been initialized ( is true) and has been
- /// called.
- ///
- ///
- /// Changing this property will eventually (when the view is next drawn) cause the
- /// and
- /// methods to be called.
- ///
- ///
- /// If is changing this property will cause the
- /// to be updated. If
- /// the new value is not of type the will change to
- /// .
- ///
- ///
- /// is the same as Pos.Absolute(0).
- ///
- ///
- public Pos X
- {
- get => VerifyIsInitialized(_x, nameof(X));
- set
- {
- _x = value ?? throw new ArgumentNullException(nameof(value), @$"{nameof(X)} cannot be null");
- OnResizeNeeded();
- }
- }
+ ///
+ /// Gets or sets the X position for the view (the column).
+ ///
+ /// The object representing the X position.
+ ///
+ ///
+ /// If is the value is indeterminate until the
+ /// view has been initialized ( is true) and has been
+ /// called.
+ ///
+ ///
+ /// Changing this property will eventually (when the view is next drawn) cause the
+ /// and
+ /// methods to be called.
+ ///
+ ///
+ /// If is changing this property will cause the
+ /// to be updated. If
+ /// the new value is not of type the will change to
+ /// .
+ ///
+ ///
+ /// is the same as Pos.Absolute(0).
+ ///
+ ///
+ public Pos X {
+ get => VerifyIsInitialized (_x, nameof (X));
+ set {
+ _x = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (X)} cannot be null");
+ OnResizeNeeded ();
+ }
+ }
- Pos _y = Pos.At(0);
+ Pos _y = Pos.At (0);
- ///
- /// Gets or sets the Y position for the view (the row).
- ///
- /// The object representing the Y position.
- ///
- ///
- /// If is the value is indeterminate until the
- /// view has been initialized ( is true) and has been
- /// called.
- ///
- ///
- /// Changing this property will eventually (when the view is next drawn) cause the
- /// and
- /// methods to be called.
- ///
- ///
- /// If is changing this property will cause the
- /// to be updated. If
- /// the new value is not of type the will change to
- /// .
- ///
- ///
- /// is the same as Pos.Absolute(0).
- ///
- ///
- public Pos Y
- {
- get => VerifyIsInitialized(_y, nameof(Y));
- set
- {
- _y = value ?? throw new ArgumentNullException(nameof(value), @$"{nameof(Y)} cannot be null");
- OnResizeNeeded();
- }
- }
+ ///
+ /// Gets or sets the Y position for the view (the row).
+ ///
+ /// The object representing the Y position.
+ ///
+ ///
+ /// If is the value is indeterminate until the
+ /// view has been initialized ( is true) and has been
+ /// called.
+ ///
+ ///
+ /// Changing this property will eventually (when the view is next drawn) cause the
+ /// and
+ /// methods to be called.
+ ///
+ ///
+ /// If is changing this property will cause the
+ /// to be updated. If
+ /// the new value is not of type the will change to
+ /// .
+ ///
+ ///
+ /// is the same as Pos.Absolute(0).
+ ///
+ ///
+ public Pos Y {
+ get => VerifyIsInitialized (_y, nameof (Y));
+ set {
+ _y = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Y)} cannot be null");
+ OnResizeNeeded ();
+ }
+ }
- Dim _width = Dim.Sized(0);
+ Dim _width = Dim.Sized (0);
- ///
- /// Gets or sets the width of the view.
- ///
- /// The object representing the width of the view (the number of columns).
- ///
- ///
- /// If is the value is indeterminate until the
- /// view has been initialized ( is true) and has been
- /// called.
- ///
- ///
- /// Changing this property will eventually (when the view is next drawn) cause the
- ///
- /// and methods to be called.
- ///
- ///
- /// If is changing this property will cause the
- /// to be updated. If
- /// the new value is not of type the will change to
- /// .
- ///
- ///
- public Dim Width
- {
- get => VerifyIsInitialized(_width, nameof(Width));
- set
- {
- _width = value ?? throw new ArgumentNullException(nameof(value), @$"{nameof(Width)} cannot be null");
+ ///
+ /// Gets or sets the width of the view.
+ ///
+ /// The object representing the width of the view (the number of columns).
+ ///
+ ///
+ /// If is the value is indeterminate until the
+ /// view has been initialized ( is true) and has been
+ /// called.
+ ///
+ ///
+ /// Changing this property will eventually (when the view is next drawn) cause the
+ ///
+ /// and methods to be called.
+ ///
+ ///
+ /// If is changing this property will cause the
+ /// to be updated. If
+ /// the new value is not of type the will change to
+ /// .
+ ///
+ ///
+ public Dim Width {
+ get => VerifyIsInitialized (_width, nameof (Width));
+ set {
+ _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
- if (ValidatePosDim)
- {
- var isValidNewAutSize = AutoSize && IsValidAutoSizeWidth(_width);
+ if (ValidatePosDim) {
+ var isValidNewAutSize = AutoSize && IsValidAutoSizeWidth (_width);
- if (IsAdded && AutoSize && !isValidNewAutSize)
- {
- throw new InvalidOperationException("Must set AutoSize to false before set the Width.");
- }
- }
- OnResizeNeeded();
- }
- }
+ if (IsAdded && AutoSize && !isValidNewAutSize) {
+ throw new InvalidOperationException ("Must set AutoSize to false before set the Width.");
+ }
+ }
+ OnResizeNeeded ();
+ }
+ }
- Dim _height = Dim.Sized(0);
+ Dim _height = Dim.Sized (0);
- ///
- /// Gets or sets the height of the view.
- ///
- /// The object representing the height of the view (the number of rows).
- ///
- ///
- /// If is the value is indeterminate until the
- /// view has been initialized ( is true) and has been
- /// called.
- ///
- ///
- /// Changing this property will eventually (when the view is next drawn) cause the
- ///
- /// and methods to be called.
- ///
- ///
- /// If is changing this property will cause the
- /// to be updated. If
- /// the new value is not of type the will change to
- /// .
- ///
- ///
- public Dim Height
- {
- get => VerifyIsInitialized(_height, nameof(Height));
- set
- {
- _height = value ?? throw new ArgumentNullException(nameof(value), @$"{nameof(Height)} cannot be null");
+ ///
+ /// Gets or sets the height of the view.
+ ///
+ /// The object representing the height of the view (the number of rows).
+ ///
+ ///
+ /// If is the value is indeterminate until the
+ /// view has been initialized ( is true) and has been
+ /// called.
+ ///
+ ///
+ /// Changing this property will eventually (when the view is next drawn) cause the
+ ///
+ /// and methods to be called.
+ ///
+ ///
+ /// If is changing this property will cause the
+ /// to be updated. If
+ /// the new value is not of type the will change to
+ /// .
+ ///
+ ///
+ public Dim Height {
+ get => VerifyIsInitialized (_height, nameof (Height));
+ set {
+ _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
- if (ValidatePosDim)
- {
- var isValidNewAutSize = AutoSize && IsValidAutoSizeHeight(_height);
+ if (ValidatePosDim) {
+ var isValidNewAutSize = AutoSize && IsValidAutoSizeHeight (_height);
- if (IsAdded && AutoSize && !isValidNewAutSize)
- {
- throw new InvalidOperationException("Must set AutoSize to false before setting the Height.");
- }
- }
- OnResizeNeeded();
- }
- }
+ if (IsAdded && AutoSize && !isValidNewAutSize) {
+ throw new InvalidOperationException ("Must set AutoSize to false before setting the Height.");
+ }
+ }
+ OnResizeNeeded ();
+ }
+ }
- ///
- /// Gets or sets whether validation of and occurs.
- ///
- ///
- /// Setting this to will enable validation of , , ,
- /// and
- /// during set operations and in .If invalid settings are discovered exceptions will be thrown
- /// indicating the error.
- /// This will impose a performance penalty and thus should only be used for debugging.
- ///
- public bool ValidatePosDim { get; set; }
+ ///
+ /// Gets or sets whether validation of and occurs.
+ ///
+ ///
+ /// Setting this to will enable validation of , , ,
+ /// and
+ /// during set operations and in .If invalid settings are discovered exceptions will be thrown
+ /// indicating the error.
+ /// This will impose a performance penalty and thus should only be used for debugging.
+ ///
+ public bool ValidatePosDim { get; set; }
- internal bool LayoutNeeded { get; private set; } = true;
+ internal bool LayoutNeeded { get; private set; } = true;
- ///
- /// Gets or sets a flag that determines whether the View will be automatically resized to fit the
- /// within
- ///
- /// The default is . Set to to turn on AutoSize. If
- /// then
- /// and will be used if can fit;
- /// if won't fit the view will be resized as needed.
- ///
- ///
- /// In addition, if is the new values of and
- /// must be of the same types of the existing one to avoid breaking the settings.
- ///
- ///
- public virtual bool AutoSize
- {
- get => _autoSize;
- set
- {
- var v = ResizeView(value);
- TextFormatter.AutoSize = v;
- if (_autoSize != v)
- {
- _autoSize = v;
- TextFormatter.NeedsFormat = true;
- UpdateTextFormatterText();
- OnResizeNeeded();
- }
- }
- }
+ ///
+ /// Gets or sets a flag that determines whether the View will be automatically resized to fit the
+ /// within
+ ///
+ /// The default is . Set to to turn on AutoSize. If
+ /// then
+ /// and will be used if can fit;
+ /// if won't fit the view will be resized as needed.
+ ///
+ ///
+ /// In addition, if is the new values of and
+ /// must be of the same types of the existing one to avoid breaking the settings.
+ ///
+ ///
+ public virtual bool AutoSize {
+ get => _autoSize;
+ set {
+ var v = ResizeView (value);
+ TextFormatter.AutoSize = v;
+ if (_autoSize != v) {
+ _autoSize = v;
+ TextFormatter.NeedsFormat = true;
+ UpdateTextFormatterText ();
+ OnResizeNeeded ();
+ }
+ }
+ }
- ///
- /// 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;
+ ///
+ /// 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;
- ///
- /// Helper to get the total thickness of the , , and .
- ///
- /// A thickness that describes the sum of the Frames' thicknesses.
- public Thickness GetFramesThickness()
- {
- var left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left;
- var top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top;
- var right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right;
- var bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom;
- return new Thickness(left, top, right, bottom);
- }
+ ///
+ /// Helper to get the total thickness of the , , and .
+ ///
+ /// A thickness that describes the sum of the Frames' thicknesses.
+ public Thickness GetFramesThickness ()
+ {
+ var left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left;
+ var top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top;
+ var right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right;
+ var bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom;
+ return new Thickness (left, top, right, bottom);
+ }
- ///
- /// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
- /// , and .
- ///
- public Point GetBoundsOffset() => new(Padding?.Thickness.GetInside(Padding.Frame).X ?? 0, Padding?.Thickness.GetInside(Padding.Frame).Y ?? 0);
+ ///
+ /// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
+ /// , and .
+ ///
+ public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
- ///
- /// Creates the view's objects. This internal method is overridden by Frame to do nothing
- /// to prevent recursion during View construction.
- ///
- internal virtual void CreateFrames()
- {
- void ThicknessChangedHandler(object sender, EventArgs e)
- {
- if (IsInitialized)
- {
- LayoutFrames();
- }
- SetNeedsLayout();
- SetNeedsDisplay();
- }
+ ///
+ /// Creates the view's objects. This internal method is overridden by Frame to do nothing
+ /// to prevent recursion during View construction.
+ ///
+ internal virtual void CreateFrames ()
+ {
+ void ThicknessChangedHandler (object sender, EventArgs e)
+ {
+ if (IsInitialized) {
+ LayoutFrames ();
+ }
+ SetNeedsLayout ();
+ SetNeedsDisplay ();
+ }
- if (Margin != null)
- {
- Margin.ThicknessChanged -= ThicknessChangedHandler;
- Margin.Dispose();
- }
- Margin = new Frame { Id = "Margin", Thickness = new Thickness(0) };
- Margin.ThicknessChanged += ThicknessChangedHandler;
- Margin.Parent = this;
+ if (Margin != null) {
+ Margin.ThicknessChanged -= ThicknessChangedHandler;
+ Margin.Dispose ();
+ }
+ Margin = new Frame { Id = "Margin", Thickness = new Thickness (0) };
+ Margin.ThicknessChanged += ThicknessChangedHandler;
+ Margin.Parent = this;
- if (Border != null)
- {
- Border.ThicknessChanged -= ThicknessChangedHandler;
- Border.Dispose();
- }
- Border = new Frame { Id = "Border", Thickness = new Thickness(0) };
- Border.ThicknessChanged += ThicknessChangedHandler;
- Border.Parent = this;
+ if (Border != null) {
+ Border.ThicknessChanged -= ThicknessChangedHandler;
+ Border.Dispose ();
+ }
+ Border = new Frame { Id = "Border", Thickness = new Thickness (0) };
+ Border.ThicknessChanged += ThicknessChangedHandler;
+ Border.Parent = this;
- // TODO: Create View.AddAdornment
+ // TODO: Create View.AddAdornment
- if (Padding != null)
- {
- Padding.ThicknessChanged -= ThicknessChangedHandler;
- Padding.Dispose();
- }
- Padding = new Frame { Id = "Padding", Thickness = new Thickness(0) };
- Padding.ThicknessChanged += ThicknessChangedHandler;
- Padding.Parent = this;
- }
+ if (Padding != null) {
+ Padding.ThicknessChanged -= ThicknessChangedHandler;
+ Padding.Dispose ();
+ }
+ Padding = new Frame { Id = "Padding", Thickness = new Thickness (0) };
+ Padding.ThicknessChanged += ThicknessChangedHandler;
+ Padding.Parent = this;
+ }
- Rect FrameGetInsideBounds()
- {
- if (Margin == null || Border == null || Padding == null)
- {
- return new Rect(default, Frame.Size);
- }
- var width = Math.Max(0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
- var height = Math.Max(0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical);
- return new Rect(Point.Empty, new Size(width, height));
- }
+ Rect FrameGetInsideBounds ()
+ {
+ if (Margin == null || Border == null || Padding == null) {
+ return new Rect (default, Frame.Size);
+ }
+ var width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal);
+ var height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical);
+ return new Rect (Point.Empty, new Size (width, height));
+ }
- // Diagnostics to highlight when X or Y is read before the view has been initialized
- Pos VerifyIsInitialized(Pos pos, string member)
- {
+ // Diagnostics to highlight when X or Y is read before the view has been initialized
+ Pos VerifyIsInitialized (Pos pos, string member)
+ {
#if DEBUG
- if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
- {
- Debug.WriteLine($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate {pos}. This is potentially a bug.");
- }
+ if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
+ Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate {pos}. This is potentially a bug.");
+ }
#endif // DEBUG
- return pos;
- }
+ return pos;
+ }
- // Diagnostics to highlight when Width or Height is read before the view has been initialized
- Dim VerifyIsInitialized(Dim dim, string member)
- {
+ // Diagnostics to highlight when Width or Height is read before the view has been initialized
+ Dim VerifyIsInitialized (Dim dim, string member)
+ {
#if DEBUG
- if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
- {
- Debug.WriteLine($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: {dim}. This is potentially a bug.");
- }
+ if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
+ Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: {dim}. This is potentially a bug.");
+ }
#endif // DEBUG
- return dim;
- }
-
- ///
- /// Throws an if is or
- /// .
- /// Used when is turned on to verify correct behavior.
- ///
- ///
- /// Does not verify if this view is Toplevel (WHY??!?).
- ///
- /// The property name.
- ///
- ///
- void CheckAbsolute(string prop, object oldValue, object newValue)
- {
- if (!IsInitialized || !ValidatePosDim || oldValue == null || oldValue.GetType() == newValue.GetType() || this is Toplevel)
- {
- return;
- }
-
- if (oldValue.GetType() != newValue.GetType() && newValue is (Pos.PosAbsolute or Dim.DimAbsolute))
- {
- throw new ArgumentException($@"{prop} must not be Absolute if LayoutStyle is Computed", prop);
- }
- }
-
- ///
- /// Called whenever the view needs to be resized. Sets and
- /// triggers a call.
- ///
- ///
- /// Can be overridden if the view resize behavior is different than the default.
- ///
- protected virtual void OnResizeNeeded()
- {
- var actX = _x is Pos.PosAbsolute ? _x.Anchor(0) : _frame.X;
- var actY = _y is Pos.PosAbsolute ? _y.Anchor(0) : _frame.Y;
-
- if (AutoSize)
- {
- //if (TextAlignment == TextAlignment.Justified) {
- // throw new InvalidOperationException ("TextAlignment.Justified cannot be used with AutoSize");
- //}
- var s = GetAutoSize();
- var w = _width is Dim.DimAbsolute && _width.Anchor(0) > s.Width ? _width.Anchor(0) : s.Width;
- var h = _height is Dim.DimAbsolute && _height.Anchor(0) > s.Height ? _height.Anchor(0) : s.Height;
- _frame = new Rect(new Point(actX, actY), new Size(w, h)); // Set frame, not Frame!
- }
- else
- {
- var w = _width is Dim.DimAbsolute ? _width.Anchor(0) : _frame.Width;
- var h = _height is Dim.DimAbsolute ? _height.Anchor(0) : _frame.Height;
- //// BUGBUG: v2 - ? - If layoutstyle is absolute, this overwrites the current frame h/w with 0. Hmmm...
- //// This is needed for DimAbsolute values by setting the frame before LayoutSubViews.
- _frame = new Rect(new Point(actX, actY), new Size(w, h)); // Set frame, not Frame!
- }
- //// BUGBUG: I think these calls are redundant or should be moved into just the AutoSize case
- if (IsInitialized || LayoutStyle == LayoutStyle.Absolute)
- {
- SetFrameToFitText();
- LayoutFrames();
- TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey();
- SetNeedsLayout();
- SetNeedsDisplay();
- }
- }
-
- internal void SetNeedsLayout()
- {
- if (LayoutNeeded)
- {
- return;
- }
- LayoutNeeded = true;
- foreach (var view in Subviews)
- {
- view.SetNeedsLayout();
- }
- TextFormatter.NeedsFormat = true;
- SuperView?.SetNeedsLayout();
- }
-
- ///
- /// Indicates that the view does not need to be laid out.
- ///
- protected void ClearLayoutNeeded() => LayoutNeeded = false;
-
- ///
- /// Converts a screen-relative coordinate to a Frame-relative coordinate. Frame-relative means
- /// relative to the View's 's .
- ///
- /// The coordinate relative to the 's .
- /// Screen-relative column.
- /// Screen-relative row.
- public Point ScreenToFrame(int x, int y)
- {
- var superViewBoundsOffset = SuperView?.GetBoundsOffset() ?? Point.Empty;
- var ret = new Point(x - Frame.X - superViewBoundsOffset.X, y - Frame.Y - superViewBoundsOffset.Y);
- if (SuperView != null)
- {
- var superFrame = SuperView.ScreenToFrame(x - superViewBoundsOffset.X, y - superViewBoundsOffset.Y);
- ret = new Point(superFrame.X - Frame.X, superFrame.Y - Frame.Y);
- }
- return ret;
- }
-
- ///
- /// Converts a screen-relative coordinate to a bounds-relative coordinate.
- ///
- /// The coordinate relative to this view's .
- /// Screen-relative column.
- /// Screen-relative row.
- public Point ScreenToBounds(int x, int y)
- {
- var screen = ScreenToFrame(x, y);
- var boundsOffset = GetBoundsOffset();
- return new Point(screen.X - boundsOffset.X, screen.Y - boundsOffset.Y);
- }
-
- ///
- /// Converts a -relative coordinate to a screen-relative coordinate. The output is optionally clamped
- /// to the screen dimensions.
- ///
- /// -relative column.
- /// -relative row.
- /// Absolute column; screen-relative.
- /// Absolute row; screen-relative.
- ///
- /// If , and will be clamped to the
- /// screen dimensions (will never be negative and will always be less than and
- /// , respectively.
- ///
- public virtual void BoundsToScreen(int x, int y, out int rx, out int ry, bool clamped = true)
- {
- var boundsOffset = GetBoundsOffset();
- rx = x + Frame.X + boundsOffset.X;
- ry = y + Frame.Y + boundsOffset.Y;
-
- var super = SuperView;
- while (super != null)
- {
- boundsOffset = super.GetBoundsOffset();
- rx += super.Frame.X + boundsOffset.X;
- ry += super.Frame.Y + boundsOffset.Y;
- super = super.SuperView;
- }
-
- // The following ensures that the cursor is always in the screen boundaries.
- if (clamped)
- {
- ry = Math.Min(ry, Driver.Rows - 1);
- rx = Math.Min(rx, Driver.Cols - 1);
- }
- }
-
- ///
- /// Converts a -relative region to a screen-relative region.
- ///
- public Rect BoundsToScreen(Rect region)
- {
- BoundsToScreen(region.X, region.Y, out var x, out var y, false);
- return new Rect(x, y, region.Width, region.Height);
- }
-
- ///
- /// Gets the with a screen-relative location.
- ///
- /// The location and size of the view in screen-relative coordinates.
- public virtual Rect FrameToScreen()
- {
- var ret = Frame;
- var super = SuperView;
- while (super != null)
- {
- var boundsOffset = super.GetBoundsOffset();
- ret.X += super.Frame.X + boundsOffset.X;
- ret.Y += super.Frame.Y + boundsOffset.Y;
- super = super.SuperView;
- }
- return ret;
- }
-
- // TODO: Come up with a better name for this method. "SetRelativeLayout" lacks clarity and confuses. AdjustSizeAndPosition?
- ///
- /// Applies the view's position (, ) and dimension (, and
- /// ) to
- /// , given a rectangle describing the SuperView's Bounds (nominally the same as
- /// this.SuperView.Bounds).
- ///
- ///
- /// The rectangle describing the SuperView's Bounds (nominally the same as
- /// this.SuperView.Bounds).
- ///
- internal void SetRelativeLayout(Rect superviewBounds)
- {
- Debug.Assert(_x != null);
- Debug.Assert(_y != null);
- Debug.Assert(_width != null);
- Debug.Assert(_height != null);
-
- int newX, newW, newY, newH;
- var autosize = Size.Empty;
-
- if (AutoSize)
- {
- // 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();
- }
-
- // TODO: Since GetNewLocationAndDimension does not depend on View, it can be moved into PosDim.cs
- // TODO: to make architecture more clean. Do this after DimAuto is implemented and the
- // TODO: View.AutoSize stuff is removed.
-
- // Returns the new dimension (width or height) and location (x or y) for the View given
- // the superview's Bounds
- // the current Pos (View.X or View.Y)
- // the current Dim (View.Width or View.Height)
- // This method is called recursively if pos is Pos.PosCombine
- (int newLocation, int newDimension) GetNewLocationAndDimension(bool width, Rect superviewBounds, Pos pos, Dim dim, int autosizeDimension)
- {
- // Gets the new dimension (width or height, dependent on `width`) of the given Dim given:
- // location: the current location (x or y)
- // dimension: the current dimension (width or height)
- // autosize: the size to use if autosize = true
- // This mehod is recursive if d is Dim.DimCombine
- int GetNewDimension(Dim d, int location, int dimension, int autosize)
- {
- int newDimension;
- switch (d)
- {
-
- case Dim.DimCombine combine:
- // TODO: Move combine logic into DimCombine?
- var leftNewDim = GetNewDimension(combine._left, location, dimension, autosize);
- var rightNewDim = GetNewDimension(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:
- case Dim.DimAbsolute:
- default:
- newDimension = Math.Max(d.Anchor(dimension - location), 0);
- newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
- break;
- }
-
- return newDimension;
- }
-
- int newDimension, newLocation;
- var superviewDimension = width ? superviewBounds.Width : superviewBounds.Height;
-
- // Determine new location
- switch (pos)
- {
- case Pos.PosCenter posCenter:
- // For Center, the dimension is dependent on location, but we need to force getting the dimension first
- // using a location of 0
- newDimension = Math.Max(GetNewDimension(dim, 0, superviewDimension, autosizeDimension), 0);
- newLocation = posCenter.Anchor(superviewDimension - newDimension);
- newDimension = Math.Max(GetNewDimension(dim, newLocation, superviewDimension, autosizeDimension), 0);
- break;
-
- case Pos.PosCombine combine:
- // TODO: Move combine logic into PosCombine?
- int left, right;
- (left, newDimension) = GetNewLocationAndDimension(width, superviewBounds, combine._left, dim, autosizeDimension);
- (right, newDimension) = GetNewLocationAndDimension(width, superviewBounds, combine._right, dim, autosizeDimension);
- if (combine._add)
- {
- newLocation = left + right;
- }
- else
- {
- newLocation = left - right;
- }
- newDimension = Math.Max(GetNewDimension(dim, newLocation, superviewDimension, autosizeDimension), 0);
- break;
-
- case Pos.PosAnchorEnd:
- case Pos.PosAbsolute:
- case Pos.PosFactor:
- case Pos.PosFunc:
- case Pos.PosView:
- default:
- newLocation = pos?.Anchor(superviewDimension) ?? 0;
- newDimension = Math.Max(GetNewDimension(dim, newLocation, superviewDimension, autosizeDimension), 0);
- break;
- }
-
-
- return (newLocation, newDimension);
- }
-
- // horizontal/width
- (newX, newW) = GetNewLocationAndDimension(true, superviewBounds, _x, _width, autosize.Width);
-
- // vertical/height
- (newY, newH) = GetNewLocationAndDimension(false, superviewBounds, _y, _height, autosize.Height);
-
- var r = new Rect(newX, newY, newW, newH);
- if (Frame != r)
- {
- Frame = r;
- // BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
- if (!SetFrameToFitText())
- {
- TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey();
- }
- }
- }
-
- ///
- /// 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 EventHandler LayoutStarted;
-
- ///
- /// Raises the event. Called from before any subviews have been
- /// laid out.
- ///
- internal virtual void OnLayoutStarted(LayoutEventArgs args) => LayoutStarted?.Invoke(this, 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 EventHandler LayoutComplete;
-
- ///
- /// Raises the event. Called from before all sub-views have been
- /// laid out.
- ///
- internal virtual void OnLayoutComplete(LayoutEventArgs args) => LayoutComplete?.Invoke(this, args);
-
- internal void CollectPos(Pos pos, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- switch (pos)
- {
- case Pos.PosView pv:
- // See #2461
- //if (!from.InternalSubviews.Contains (pv.Target)) {
- // throw new InvalidOperationException ($"View {pv.Target} is not a subview of {from}");
- //}
- if (pv.Target != this)
- {
- nEdges.Add((pv.Target, from));
- }
- return;
- case Pos.PosCombine pc:
- CollectPos(pc._left, from, ref nNodes, ref nEdges);
- CollectPos(pc._right, from, ref nNodes, ref nEdges);
- break;
- }
- }
-
- internal void CollectDim(Dim dim, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- switch (dim)
- {
- case Dim.DimView dv:
- // See #2461
- //if (!from.InternalSubviews.Contains (dv.Target)) {
- // throw new InvalidOperationException ($"View {dv.Target} is not a subview of {from}");
- //}
- if (dv.Target != this)
- {
- nEdges.Add((dv.Target, from));
- }
- return;
- case Dim.DimCombine dc:
- CollectDim(dc._left, from, ref nNodes, ref nEdges);
- CollectDim(dc._right, from, ref nNodes, ref nEdges);
- break;
- }
- }
-
- internal void CollectAll(View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
- {
- // BUGBUG: This should really only work on initialized subviews
- foreach (var v in from.InternalSubviews /*.Where(v => v.IsInitialized)*/)
- {
- 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
- internal static List TopologicalSort(View superView, IEnumerable nodes, ICollection<(View From, View To)> edges)
- {
- var result = new List();
-
- // Set of all nodes with no incoming edges
- var noEdgeNodes = new HashSet(nodes.Where(n => edges.All(e => !e.To.Equals(n))));
-
- while (noEdgeNodes.Any())
- {
- // remove a node n from S
- var n = noEdgeNodes.First();
- noEdgeNodes.Remove(n);
-
- // add n to tail of L
- if (n != superView)
- {
- result.Add(n);
- }
-
- // for each node m with an edge e from n to m do
- foreach (var e in edges.Where(e => e.From.Equals(n)).ToArray())
- {
- var m = e.To;
-
- // remove edge e from the graph
- edges.Remove(e);
-
- // if m has no other incoming edges then
- if (edges.All(me => !me.To.Equals(m)) && m != superView)
- {
- // insert m into S
- noEdgeNodes.Add(m);
- }
- }
- }
-
- if (!edges.Any())
- {
- return result;
- }
-
- foreach ((var from, var to) in edges)
- {
- if (from == to)
- {
- // if not yet added to the result, add it and remove from edge
- if (result.Find(v => v == from) == null)
- {
- result.Add(from);
- }
- edges.Remove((from, to));
- }
- else if (from.SuperView == to.SuperView)
- {
- // if 'from' is not yet added to the result, add it
- if (result.Find(v => v == from) == null)
- {
- result.Add(from);
- }
- // if 'to' is not yet added to the result, add it
- if (result.Find(v => v == to) == null)
- {
- result.Add(to);
- }
- // remove from edge
- edges.Remove((from, to));
- }
- else if (from != superView?.GetTopSuperView(to, from) && !ReferenceEquals(from, to))
- {
- if (ReferenceEquals(from.SuperView, to))
- {
- throw new InvalidOperationException($"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\").");
- }
- throw new InvalidOperationException($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?");
- }
- }
- // return L (a topologically sorted order)
- return result;
- } // TopologicalSort
-
- ///
- /// Overriden by to do nothing, as the does not have frames.
- ///
- internal virtual void LayoutFrames()
- {
- if (Margin == null)
- {
- return; // CreateFrames() has not been called yet
- }
-
- if (Margin.Frame.Size != Frame.Size)
- {
- Margin._frame = new Rect(Point.Empty, Frame.Size);
- Margin.X = 0;
- Margin.Y = 0;
- Margin.Width = Frame.Size.Width;
- Margin.Height = Frame.Size.Height;
- Margin.SetNeedsLayout();
- Margin.SetNeedsDisplay();
- }
-
- var border = Margin.Thickness.GetInside(Margin.Frame);
- if (border != Border.Frame)
- {
- Border._frame = new Rect(new Point(border.Location.X, border.Location.Y), border.Size);
- Border.X = border.Location.X;
- Border.Y = border.Location.Y;
- Border.Width = border.Size.Width;
- Border.Height = border.Size.Height;
- Border.SetNeedsLayout();
- Border.SetNeedsDisplay();
- }
-
- var padding = Border.Thickness.GetInside(Border.Frame);
- if (padding != Padding.Frame)
- {
- Padding._frame = new Rect(new Point(padding.Location.X, padding.Location.Y), padding.Size);
- Padding.X = padding.Location.X;
- Padding.Y = padding.Location.Y;
- Padding.Width = padding.Size.Width;
- Padding.Height = padding.Size.Height;
- Padding.SetNeedsLayout();
- Padding.SetNeedsDisplay();
- }
- }
-
- ///
- /// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
- /// response to the container view or terminal resizing.
- ///
- ///
- ///
- /// The position and dimensions of the view are indeterminate until the view has been initialized. Therefore,
- /// the behavior of this method is indeterminate if is .
- ///
- ///
- /// Raises the event) before it returns.
- ///
- ///
- public virtual void LayoutSubviews()
- {
- if (!IsInitialized)
- {
- Debug.WriteLine($"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}");
- }
-
- if (!LayoutNeeded)
- {
- return;
- }
-
- LayoutFrames();
-
- var oldBounds = Bounds;
- OnLayoutStarted(new LayoutEventArgs { OldBounds = oldBounds });
-
- TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey();
-
- // Sort out the dependencies of the X, Y, Width, Height properties
- var nodes = new HashSet();
- var edges = new HashSet<(View, View)>();
- CollectAll(this, ref nodes, ref edges);
- var ordered = TopologicalSort(SuperView, nodes, edges);
- foreach (var v in ordered)
- {
- LayoutSubview(v, new Rect(GetBoundsOffset(), Bounds.Size));
- }
-
- // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
- // Use LayoutSubview with the Frame of the 'from'
- if (SuperView != null && GetTopSuperView() != null && LayoutNeeded && edges.Count > 0)
- {
- foreach ((var from, var to) in edges)
- {
- LayoutSubview(to, from.Frame);
- }
- }
-
- LayoutNeeded = false;
-
- OnLayoutComplete(new LayoutEventArgs { OldBounds = oldBounds });
- }
-
- void LayoutSubview(View v, Rect contentArea)
- {
- if (v.LayoutStyle == LayoutStyle.Computed)
- {
- v.SetRelativeLayout(contentArea);
- }
-
- v.LayoutSubviews();
- v.LayoutNeeded = false;
- }
-
- bool ResizeView(bool autoSize)
- {
- if (!autoSize)
- {
- return false;
- }
-
- var boundsChanged = true;
- var newFrameSize = GetAutoSize();
- if (IsInitialized && newFrameSize != Frame.Size)
- {
- if (ValidatePosDim)
- {
- // BUGBUG: This ain't right, obviously. We need to figure out how to handle this.
- boundsChanged = ResizeBoundsToFit(newFrameSize);
- }
- else
- {
- Height = newFrameSize.Height;
- Width = newFrameSize.Width;
- }
- }
- return boundsChanged;
- }
-
- ///
- /// Resizes the View to fit the specified size. Factors in the HotKey.
- ///
- ///
- /// whether the Bounds was changed or not
- bool ResizeBoundsToFit(Size size)
- {
- var boundsChanged = false;
- var canSizeW = TrySetWidth(size.Width - GetHotKeySpecifierLength(), out var rW);
- var canSizeH = TrySetHeight(size.Height - GetHotKeySpecifierLength(false), out var rH);
- if (canSizeW)
- {
- boundsChanged = true;
- _width = rW;
- }
- if (canSizeH)
- {
- boundsChanged = true;
- _height = rH;
- }
- if (boundsChanged)
- {
- Bounds = new Rect(Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
- }
-
- return boundsChanged;
- }
-
- ///
- /// Gets the Frame dimensions required to fit within using the text
- /// specified by the
- /// property and accounting for any characters.
- ///
- /// The of the view required to fit the text.
- public Size GetAutoSize()
- {
- var x = 0;
- var y = 0;
- if (IsInitialized)
- {
- x = Bounds.X;
- y = Bounds.Y;
- }
- var rect = TextFormatter.CalcRect(x, y, TextFormatter.Text, TextFormatter.Direction);
- var newWidth = rect.Size.Width - GetHotKeySpecifierLength() + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal;
- var newHeight = rect.Size.Height - GetHotKeySpecifierLength(false) + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical;
- return new Size(newWidth, newHeight);
- }
-
- bool IsValidAutoSize(out Size autoSize)
- {
- var rect = TextFormatter.CalcRect(_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
- autoSize = new Size(rect.Size.Width - GetHotKeySpecifierLength(),
- rect.Size.Height - GetHotKeySpecifierLength(false));
- return !(ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) ||
- _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength() ||
- _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength(false));
- }
-
- bool IsValidAutoSizeWidth(Dim width)
- {
- var rect = TextFormatter.CalcRect(_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
- var dimValue = width.Anchor(0);
- return !(ValidatePosDim && !(width is Dim.DimAbsolute) || dimValue != rect.Size.Width - GetHotKeySpecifierLength());
- }
-
- bool IsValidAutoSizeHeight(Dim height)
- {
- var rect = TextFormatter.CalcRect(_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
- var dimValue = height.Anchor(0);
- return !(ValidatePosDim && !(height is Dim.DimAbsolute) || dimValue != rect.Size.Height - GetHotKeySpecifierLength(false));
- }
-
- ///
- /// Determines if the View's can be set to a new value.
- ///
- ///
- ///
- /// Contains the width that would result if were set to
- /// "/>
- ///
- ///
- /// if the View's can be changed to the specified value. False
- /// otherwise.
- ///
- internal bool TrySetWidth(int desiredWidth, out int resultWidth)
- {
- var w = desiredWidth;
- bool canSetWidth;
- switch (Width)
- {
- case Dim.DimCombine _:
- case Dim.DimView _:
- case Dim.DimFill _:
- // It's a Dim.DimCombine and so can't be assigned. Let it have it's Width anchored.
- w = Width.Anchor(w);
- canSetWidth = !ValidatePosDim;
- break;
- case Dim.DimFactor factor:
- // Tries to get the SuperView Width otherwise the view Width.
- var sw = SuperView != null ? SuperView.Frame.Width : w;
- if (factor.IsFromRemaining())
- {
- sw -= Frame.X;
- }
- w = Width.Anchor(sw);
- canSetWidth = !ValidatePosDim;
- break;
- default:
- canSetWidth = true;
- break;
- }
- resultWidth = w;
-
- return canSetWidth;
- }
-
- ///
- /// Determines if the View's can be set to a new value.
- ///
- ///
- ///
- /// Contains the width that would result if were set to
- /// "/>
- ///
- ///
- /// if the View's can be changed to the specified value. False
- /// otherwise.
- ///
- internal bool TrySetHeight(int desiredHeight, out int resultHeight)
- {
- var h = desiredHeight;
- bool canSetHeight;
- switch (Height)
- {
- case Dim.DimCombine _:
- case Dim.DimView _:
- case Dim.DimFill _:
- // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
- h = Height.Anchor(h);
- canSetHeight = !ValidatePosDim;
- break;
- case Dim.DimFactor factor:
- // Tries to get the SuperView height otherwise the view height.
- var sh = SuperView != null ? SuperView.Frame.Height : h;
- if (factor.IsFromRemaining())
- {
- sh -= Frame.Y;
- }
- h = Height.Anchor(sh);
- canSetHeight = !ValidatePosDim;
- break;
- default:
- canSetHeight = true;
- break;
- }
- resultHeight = h;
-
- return canSetHeight;
- }
-
- ///
- /// Finds which view that belong to the superview at the provided location.
- ///
- /// The superview where to look for.
- /// The column location in the superview.
- /// The row location in the superview.
- /// The found view screen relative column location.
- /// The found view screen relative row location.
- ///
- /// The view that was found at the and coordinates.
- /// if no view was found.
- ///
- public static View FindDeepestView(View start, int x, int y, out int resx, out int resy)
- {
- resy = resx = 0;
- if (start == null || !start.Frame.Contains(x, y))
- {
- return null;
- }
-
- var startFrame = start.Frame;
- if (start.InternalSubviews != null)
- {
- var count = start.InternalSubviews.Count;
- if (count > 0)
- {
- var boundsOffset = start.GetBoundsOffset();
- var rx = x - (startFrame.X + boundsOffset.X);
- var ry = y - (startFrame.Y + boundsOffset.Y);
- for (var i = count - 1; i >= 0; i--)
- {
- var v = start.InternalSubviews[i];
- if (v.Visible && v.Frame.Contains(rx, ry))
- {
- var deep = FindDeepestView(v, rx, ry, out resx, out resy);
- if (deep == null)
- {
- return v;
- }
- return deep;
- }
- }
- }
- }
- resx = x - startFrame.X;
- resy = y - startFrame.Y;
- return start;
- }
+ return dim;
+ }
+
+ ///
+ /// Throws an if is or
+ /// .
+ /// Used when is turned on to verify correct behavior.
+ ///
+ ///
+ /// Does not verify if this view is Toplevel (WHY??!?).
+ ///
+ /// The property name.
+ ///
+ ///
+ void CheckAbsolute (string prop, object oldValue, object newValue)
+ {
+ if (!IsInitialized || !ValidatePosDim || oldValue == null || oldValue.GetType () == newValue.GetType () || this is Toplevel) {
+ return;
+ }
+
+ if (oldValue.GetType () != newValue.GetType () && newValue is (Pos.PosAbsolute or Dim.DimAbsolute)) {
+ throw new ArgumentException ($@"{prop} must not be Absolute if LayoutStyle is Computed", prop);
+ }
+ }
+
+ ///
+ /// Called whenever the view needs to be resized. Sets and
+ /// triggers a call.
+ ///
+ ///
+ ///
+ /// Sets the .
+ ///
+ ///
+ /// Can be overridden if the view resize behavior is different than the default.
+ ///
+ ///
+ protected virtual void OnResizeNeeded ()
+ {
+ //var actX = _x is Pos.PosAbsolute ? _x.Anchor (0) : _frame.X;
+ //var actY = _y is Pos.PosAbsolute ? _y.Anchor (0) : _frame.Y;
+
+ //// TODO: Determine if this API should change Frame as it does.
+ //// TODO: Is it correct behavior? Shouldn't the Frame be changed when SetRelativeLayout
+ //// TODO: is eventually called because SetNeedsLayout get set?
+ //if (AutoSize) {
+ // //if (TextAlignment == TextAlignment.Justified) {
+ // // throw new InvalidOperationException ("TextAlignment.Justified cannot be used with AutoSize");
+ // //}
+ // var s = GetAutoSize ();
+ // var w = _width is Dim.DimAbsolute && _width.Anchor (0) > s.Width ? _width.Anchor (0) : s.Width;
+ // var h = _height is Dim.DimAbsolute && _height.Anchor (0) > s.Height ? _height.Anchor (0) : s.Height;
+ // // Set Frame to cause Pos/Dim to be set. By Definition AutoSize = true means LayoutStyleAbsolute
+ // Frame = new Rect (new Point (actX, actY), new Size (w, h));
+ //} else {
+ // var w = _width is Dim.DimAbsolute ? _width.Anchor (0) : _frame.Width;
+ // var h = _height is Dim.DimAbsolute ? _height.Anchor (0) : _frame.Height;
+ // //// BUGBUG: v2 - ? - If layoutstyle is absolute, this overwrites the current frame h/w with 0. Hmmm...
+ // //// This is needed for DimAbsolute values by setting the frame before LayoutSubViews.
+ // _frame = new Rect (new Point (actX, actY), new Size (w, h)); // Set frame, not Frame!
+ //}
+ // BUGBUG: I think these calls are redundant or should be moved into just the AutoSize case
+
+ SetRelativeLayout (SuperView?.Bounds ?? Application.Top?.Bounds ?? Application.Driver?.Bounds ?? new Rect (0, 0, int.MaxValue, int.MaxValue));
+ if (IsInitialized/* || LayoutStyle == LayoutStyle.Absolute*/) {
+ SetFrameToFitText ();
+ LayoutFrames ();
+ TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+ SetNeedsLayout ();
+ SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// Sets the internal flag for this View and all of it's
+ /// subviews and it's SuperView. The main loop will call SetRelativeLayout and LayoutSubviews
+ /// for any view with set.
+ ///
+ internal void SetNeedsLayout ()
+ {
+ if (LayoutNeeded) {
+ return;
+ }
+ LayoutNeeded = true;
+ foreach (var view in Subviews) {
+ view.SetNeedsLayout ();
+ }
+ TextFormatter.NeedsFormat = true;
+ SuperView?.SetNeedsLayout ();
+ }
+
+ ///
+ /// Indicates that the view does not need to be laid out.
+ ///
+ protected void ClearLayoutNeeded () => LayoutNeeded = false;
+
+ ///
+ /// Converts a screen-relative coordinate to a Frame-relative coordinate. Frame-relative means
+ /// relative to the View's 's .
+ ///
+ /// The coordinate relative to the 's .
+ /// Screen-relative column.
+ /// Screen-relative row.
+ public Point ScreenToFrame (int x, int y)
+ {
+ var superViewBoundsOffset = SuperView?.GetBoundsOffset () ?? Point.Empty;
+ var ret = new Point (x - Frame.X - superViewBoundsOffset.X, y - Frame.Y - superViewBoundsOffset.Y);
+ if (SuperView != null) {
+ var superFrame = SuperView.ScreenToFrame (x - superViewBoundsOffset.X, y - superViewBoundsOffset.Y);
+ ret = new Point (superFrame.X - Frame.X, superFrame.Y - Frame.Y);
+ }
+ return ret;
+ }
+
+ ///
+ /// Converts a screen-relative coordinate to a bounds-relative coordinate.
+ ///
+ /// The coordinate relative to this view's .
+ /// Screen-relative column.
+ /// Screen-relative row.
+ public Point ScreenToBounds (int x, int y)
+ {
+ var screen = ScreenToFrame (x, y);
+ var boundsOffset = GetBoundsOffset ();
+ return new Point (screen.X - boundsOffset.X, screen.Y - boundsOffset.Y);
+ }
+
+ ///
+ /// Converts a -relative coordinate to a screen-relative coordinate. The output is optionally clamped
+ /// to the screen dimensions.
+ ///
+ /// -relative column.
+ /// -relative row.
+ /// Absolute column; screen-relative.
+ /// Absolute row; screen-relative.
+ ///
+ /// If , and will be clamped to the
+ /// screen dimensions (will never be negative and will always be less than and
+ /// , respectively.
+ ///
+ public virtual void BoundsToScreen (int x, int y, out int rx, out int ry, bool clamped = true)
+ {
+ var boundsOffset = GetBoundsOffset ();
+ rx = x + Frame.X + boundsOffset.X;
+ ry = y + Frame.Y + boundsOffset.Y;
+
+ var super = SuperView;
+ while (super != null) {
+ boundsOffset = super.GetBoundsOffset ();
+ rx += super.Frame.X + boundsOffset.X;
+ ry += super.Frame.Y + boundsOffset.Y;
+ super = super.SuperView;
+ }
+
+ // The following ensures that the cursor is always in the screen boundaries.
+ if (clamped) {
+ ry = Math.Min (ry, Driver.Rows - 1);
+ rx = Math.Min (rx, Driver.Cols - 1);
+ }
+ }
+
+ ///
+ /// Converts a -relative region to a screen-relative region.
+ ///
+ public Rect BoundsToScreen (Rect region)
+ {
+ BoundsToScreen (region.X, region.Y, out var x, out var y, false);
+ return new Rect (x, y, region.Width, region.Height);
+ }
+
+ ///
+ /// Gets the with a screen-relative location.
+ ///
+ /// The location and size of the view in screen-relative coordinates.
+ public virtual Rect FrameToScreen ()
+ {
+ var ret = Frame;
+ var super = SuperView;
+ while (super != null) {
+ var boundsOffset = super.GetBoundsOffset ();
+ ret.X += super.Frame.X + boundsOffset.X;
+ ret.Y += super.Frame.Y + boundsOffset.Y;
+ super = super.SuperView;
+ }
+ return ret;
+ }
+
+ // TODO: Come up with a better name for this method. "SetRelativeLayout" lacks clarity and confuses. AdjustSizeAndPosition?
+ ///
+ /// Applies the view's position (, ) and dimension (, and
+ /// ) to
+ /// , given a rectangle describing the SuperView's Bounds (nominally the same as
+ /// this.SuperView.Bounds).
+ ///
+ ///
+ /// The rectangle describing the SuperView's Bounds (nominally the same as
+ /// this.SuperView.Bounds).
+ ///
+ internal void SetRelativeLayout (Rect superviewBounds)
+ {
+ Debug.Assert (_x != null);
+ Debug.Assert (_y != null);
+ Debug.Assert (_width != null);
+ Debug.Assert (_height != null);
+
+ int newX, newW, newY, newH;
+ var autosize = Size.Empty;
+
+ if (AutoSize) {
+ // 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 ();
+ }
+
+ // TODO: Since GetNewLocationAndDimension does not depend on View, it can be moved into PosDim.cs
+ // TODO: to make architecture more clean. Do this after DimAuto is implemented and the
+ // TODO: View.AutoSize stuff is removed.
+
+ // Returns the new dimension (width or height) and location (x or y) for the View given
+ // the superview's Bounds
+ // the current Pos (View.X or View.Y)
+ // the current Dim (View.Width or View.Height)
+ // This method is called recursively if pos is Pos.PosCombine
+ (int newLocation, int newDimension) GetNewLocationAndDimension (bool width, Rect superviewBounds, Pos pos, Dim dim, int autosizeDimension)
+ {
+ // Gets the new dimension (width or height, dependent on `width`) of the given Dim given:
+ // location: the current location (x or y)
+ // dimension: the new dimension (width or height) (if relevant for Dim type)
+ // autosize: the size to use if autosize = true
+ // This method is recursive if d is Dim.DimCombine
+ int GetNewDimension (Dim d, int location, int dimension, int autosize)
+ {
+ int newDimension;
+ switch (d) {
+
+ case Dim.DimCombine combine:
+ // TODO: Move combine logic into DimCombine?
+ var leftNewDim = GetNewDimension (combine._left, location, dimension, autosize);
+ var rightNewDim = GetNewDimension (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.DimAbsolute:
+ // DimAbsoulte.Anchor (int width) ignores width and returns n
+ newDimension = Math.Max (d.Anchor (0), 0);
+ 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;
+ }
+
+ return newDimension;
+ }
+
+ int newDimension, newLocation;
+ var superviewDimension = width ? superviewBounds.Width : superviewBounds.Height;
+
+ // Determine new location
+ switch (pos) {
+ case Pos.PosCenter posCenter:
+ // For Center, the dimension is dependent on location, but we need to force getting the dimension first
+ // using a location of 0
+ newDimension = Math.Max (GetNewDimension (dim, 0, superviewDimension, autosizeDimension), 0);
+ newLocation = posCenter.Anchor (superviewDimension - newDimension);
+ newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
+ break;
+
+ case Pos.PosCombine combine:
+ // TODO: Move combine logic into PosCombine?
+ int left, right;
+ (left, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._left, dim, autosizeDimension);
+ (right, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._right, dim, autosizeDimension);
+ if (combine._add) {
+ newLocation = left + right;
+ } else {
+ newLocation = left - right;
+ }
+ newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
+ break;
+
+ case Pos.PosAnchorEnd:
+ case Pos.PosAbsolute:
+ case Pos.PosFactor:
+ case Pos.PosFunc:
+ case Pos.PosView:
+ default:
+ newLocation = pos?.Anchor (superviewDimension) ?? 0;
+ newDimension = Math.Max (GetNewDimension (dim, newLocation, superviewDimension, autosizeDimension), 0);
+ break;
+ }
+
+
+ return (newLocation, newDimension);
+ }
+
+ // horizontal/width
+ (newX, newW) = GetNewLocationAndDimension (true, superviewBounds, _x, _width, autosize.Width);
+
+ // vertical/height
+ (newY, newH) = GetNewLocationAndDimension (false, superviewBounds, _y, _height, autosize.Height);
+
+ var r = new Rect (newX, newY, newW, newH);
+ if (Frame != r) {
+ // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height, making
+ // the view LayoutStyle.Absolute.
+ _frame = r;
+ if (X is Pos.PosAbsolute) {
+ _x = Frame.X;
+ }
+ if (Y is Pos.PosAbsolute) {
+ _y = Frame.Y;
+ }
+ if (Width is Dim.DimAbsolute) {
+ _width = Frame.Width;
+ }
+ if (Height is Dim.DimAbsolute) {
+ _height = Frame.Height;
+ }
+
+ if (IsInitialized) {
+ //LayoutFrames ();
+ //TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+ SetNeedsLayout ();
+ //SetNeedsDisplay ();
+ }
+
+ // BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
+ if (!SetFrameToFitText ()) {
+ TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+ }
+ }
+ }
+
+ ///
+ /// 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 EventHandler LayoutStarted;
+
+ ///
+ /// Raises the event. Called from before any subviews have been
+ /// laid out.
+ ///
+ internal virtual void OnLayoutStarted (LayoutEventArgs args) => LayoutStarted?.Invoke (this, 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 EventHandler LayoutComplete;
+
+ ///
+ /// Raises the event. Called from before all sub-views have been
+ /// laid out.
+ ///
+ internal virtual void OnLayoutComplete (LayoutEventArgs args) => LayoutComplete?.Invoke (this, args);
+
+ internal void CollectPos (Pos pos, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
+ {
+ switch (pos) {
+ case Pos.PosView pv:
+ // See #2461
+ //if (!from.InternalSubviews.Contains (pv.Target)) {
+ // throw new InvalidOperationException ($"View {pv.Target} is not a subview of {from}");
+ //}
+ if (pv.Target != this) {
+ nEdges.Add ((pv.Target, from));
+ }
+ return;
+ case Pos.PosCombine pc:
+ CollectPos (pc._left, from, ref nNodes, ref nEdges);
+ CollectPos (pc._right, from, ref nNodes, ref nEdges);
+ break;
+ }
+ }
+
+ internal void CollectDim (Dim dim, View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
+ {
+ switch (dim) {
+ case Dim.DimView dv:
+ // See #2461
+ //if (!from.InternalSubviews.Contains (dv.Target)) {
+ // throw new InvalidOperationException ($"View {dv.Target} is not a subview of {from}");
+ //}
+ if (dv.Target != this) {
+ nEdges.Add ((dv.Target, from));
+ }
+ return;
+ case Dim.DimCombine dc:
+ CollectDim (dc._left, from, ref nNodes, ref nEdges);
+ CollectDim (dc._right, from, ref nNodes, ref nEdges);
+ break;
+ }
+ }
+
+ internal void CollectAll (View from, ref HashSet nNodes, ref HashSet<(View, View)> nEdges)
+ {
+ // BUGBUG: This should really only work on initialized subviews
+ foreach (var v in from.InternalSubviews /*.Where(v => v.IsInitialized)*/) {
+ 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
+ internal static List TopologicalSort (View superView, IEnumerable nodes, ICollection<(View From, View To)> edges)
+ {
+ var result = new List ();
+
+ // Set of all nodes with no incoming edges
+ var noEdgeNodes = new HashSet (nodes.Where (n => edges.All (e => !e.To.Equals (n))));
+
+ while (noEdgeNodes.Any ()) {
+ // remove a node n from S
+ var n = noEdgeNodes.First ();
+ noEdgeNodes.Remove (n);
+
+ // add n to tail of L
+ if (n != superView) {
+ result.Add (n);
+ }
+
+ // for each node m with an edge e from n to m do
+ foreach (var e in edges.Where (e => e.From.Equals (n)).ToArray ()) {
+ var m = e.To;
+
+ // remove edge e from the graph
+ edges.Remove (e);
+
+ // if m has no other incoming edges then
+ if (edges.All (me => !me.To.Equals (m)) && m != superView) {
+ // insert m into S
+ noEdgeNodes.Add (m);
+ }
+ }
+ }
+
+ if (!edges.Any ()) {
+ return result;
+ }
+
+ foreach ((var from, var to) in edges) {
+ if (from == to) {
+ // if not yet added to the result, add it and remove from edge
+ if (result.Find (v => v == from) == null) {
+ result.Add (from);
+ }
+ edges.Remove ((from, to));
+ } else if (from.SuperView == to.SuperView) {
+ // if 'from' is not yet added to the result, add it
+ if (result.Find (v => v == from) == null) {
+ result.Add (from);
+ }
+ // if 'to' is not yet added to the result, add it
+ if (result.Find (v => v == to) == null) {
+ result.Add (to);
+ }
+ // remove from edge
+ edges.Remove ((from, to));
+ } else if (from != superView?.GetTopSuperView (to, from) && !ReferenceEquals (from, to)) {
+ if (ReferenceEquals (from.SuperView, to)) {
+ throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\").");
+ }
+ throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?");
+ }
+ }
+ // return L (a topologically sorted order)
+ return result;
+ } // TopologicalSort
+
+ ///
+ /// Overriden by to do nothing, as the does not have frames.
+ ///
+ internal virtual void LayoutFrames ()
+ {
+ if (Margin == null) {
+ return; // CreateFrames() has not been called yet
+ }
+
+ if (Margin.Frame.Size != Frame.Size) {
+ Margin._frame = new Rect (Point.Empty, Frame.Size);
+ Margin.X = 0;
+ Margin.Y = 0;
+ Margin.Width = Frame.Size.Width;
+ Margin.Height = Frame.Size.Height;
+ Margin.SetNeedsLayout ();
+ Margin.SetNeedsDisplay ();
+ }
+
+ var border = Margin.Thickness.GetInside (Margin.Frame);
+ if (border != Border.Frame) {
+ Border._frame = new Rect (new Point (border.Location.X, border.Location.Y), border.Size);
+ Border.X = border.Location.X;
+ Border.Y = border.Location.Y;
+ Border.Width = border.Size.Width;
+ Border.Height = border.Size.Height;
+ Border.SetNeedsLayout ();
+ Border.SetNeedsDisplay ();
+ }
+
+ var padding = Border.Thickness.GetInside (Border.Frame);
+ if (padding != Padding.Frame) {
+ Padding._frame = new Rect (new Point (padding.Location.X, padding.Location.Y), padding.Size);
+ Padding.X = padding.Location.X;
+ Padding.Y = padding.Location.Y;
+ Padding.Width = padding.Size.Width;
+ Padding.Height = padding.Size.Height;
+ Padding.SetNeedsLayout ();
+ Padding.SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
+ /// response to the container view or terminal resizing.
+ ///
+ ///
+ ///
+ /// The position and dimensions of the view are indeterminate until the view has been initialized. Therefore,
+ /// the behavior of this method is indeterminate if is .
+ ///
+ ///
+ /// Raises the event) before it returns.
+ ///
+ ///
+ public virtual void LayoutSubviews ()
+ {
+ if (!IsInitialized) {
+ Debug.WriteLine ($"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}");
+ }
+
+ if (!LayoutNeeded) {
+ return;
+ }
+
+ LayoutFrames ();
+
+ var oldBounds = Bounds;
+ OnLayoutStarted (new LayoutEventArgs { OldBounds = oldBounds });
+
+ TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+
+ // Sort out the dependencies of the X, Y, Width, Height properties
+ var nodes = new HashSet ();
+ var edges = new HashSet<(View, View)> ();
+ CollectAll (this, ref nodes, ref edges);
+ var ordered = TopologicalSort (SuperView, nodes, edges);
+ foreach (var v in ordered) {
+ LayoutSubview (v, new Rect (GetBoundsOffset (), Bounds.Size));
+ }
+
+ // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
+ // Use LayoutSubview with the Frame of the 'from'
+ if (SuperView != null && GetTopSuperView () != null && LayoutNeeded && edges.Count > 0) {
+ foreach ((var from, var to) in edges) {
+ LayoutSubview (to, from.Frame);
+ }
+ }
+
+ LayoutNeeded = false;
+
+ OnLayoutComplete (new LayoutEventArgs { OldBounds = oldBounds });
+ }
+
+ void LayoutSubview (View v, Rect contentArea)
+ {
+ //if (v.LayoutStyle == LayoutStyle.Computed) {
+ v.SetRelativeLayout (contentArea);
+ //}
+
+ v.LayoutSubviews ();
+ v.LayoutNeeded = false;
+ }
+
+ bool ResizeView (bool autoSize)
+ {
+ if (!autoSize) {
+ return false;
+ }
+
+ var boundsChanged = true;
+ var newFrameSize = GetAutoSize ();
+ if (IsInitialized && newFrameSize != Frame.Size) {
+ if (ValidatePosDim) {
+ // BUGBUG: This ain't right, obviously. We need to figure out how to handle this.
+ boundsChanged = ResizeBoundsToFit (newFrameSize);
+ } else {
+ Height = newFrameSize.Height;
+ Width = newFrameSize.Width;
+ }
+ }
+ return boundsChanged;
+ }
+
+ ///
+ /// Resizes the View to fit the specified size. Factors in the HotKey.
+ ///
+ ///
+ /// whether the Bounds was changed or not
+ bool ResizeBoundsToFit (Size size)
+ {
+ var boundsChanged = false;
+ var canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out var rW);
+ var canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out var rH);
+ if (canSizeW) {
+ boundsChanged = true;
+ _width = rW;
+ }
+ if (canSizeH) {
+ boundsChanged = true;
+ _height = rH;
+ }
+ if (boundsChanged) {
+ Bounds = new Rect (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
+ }
+
+ return boundsChanged;
+ }
+
+ ///
+ /// Gets the Frame dimensions required to fit within using the text
+ /// specified by the
+ /// property and accounting for any characters.
+ ///
+ /// The of the view required to fit the text.
+ public Size GetAutoSize ()
+ {
+ var x = 0;
+ var y = 0;
+ if (IsInitialized) {
+ x = Bounds.X;
+ y = Bounds.Y;
+ }
+ var rect = TextFormatter.CalcRect (x, y, TextFormatter.Text, TextFormatter.Direction);
+ var newWidth = rect.Size.Width - GetHotKeySpecifierLength () + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal;
+ var newHeight = rect.Size.Height - GetHotKeySpecifierLength (false) + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical;
+ return new Size (newWidth, newHeight);
+ }
+
+ bool IsValidAutoSize (out Size autoSize)
+ {
+ var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
+ autoSize = new Size (rect.Size.Width - GetHotKeySpecifierLength (),
+ rect.Size.Height - GetHotKeySpecifierLength (false));
+ return !(ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) ||
+ _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () ||
+ _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false));
+ }
+
+ bool IsValidAutoSizeWidth (Dim width)
+ {
+ var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
+ var dimValue = width.Anchor (0);
+ return !(ValidatePosDim && !(width is Dim.DimAbsolute) || dimValue != rect.Size.Width - GetHotKeySpecifierLength ());
+ }
+
+ bool IsValidAutoSizeHeight (Dim height)
+ {
+ var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
+ var dimValue = height.Anchor (0);
+ return !(ValidatePosDim && !(height is Dim.DimAbsolute) || dimValue != rect.Size.Height - GetHotKeySpecifierLength (false));
+ }
+
+ ///
+ /// Determines if the View's can be set to a new value.
+ ///
+ ///
+ ///
+ /// Contains the width that would result if were set to
+ /// "/>
+ ///
+ ///
+ /// if the View's can be changed to the specified value. False
+ /// otherwise.
+ ///
+ internal bool TrySetWidth (int desiredWidth, out int resultWidth)
+ {
+ var w = desiredWidth;
+ bool canSetWidth;
+ switch (Width) {
+ case Dim.DimCombine _:
+ case Dim.DimView _:
+ case Dim.DimFill _:
+ // It's a Dim.DimCombine and so can't be assigned. Let it have it's Width anchored.
+ w = Width.Anchor (w);
+ canSetWidth = !ValidatePosDim;
+ break;
+ case Dim.DimFactor factor:
+ // Tries to get the SuperView Width otherwise the view Width.
+ var sw = SuperView != null ? SuperView.Frame.Width : w;
+ if (factor.IsFromRemaining ()) {
+ sw -= Frame.X;
+ }
+ w = Width.Anchor (sw);
+ canSetWidth = !ValidatePosDim;
+ break;
+ default:
+ canSetWidth = true;
+ break;
+ }
+ resultWidth = w;
+
+ return canSetWidth;
+ }
+
+ ///
+ /// Determines if the View's can be set to a new value.
+ ///
+ ///
+ ///
+ /// Contains the width that would result if were set to
+ /// "/>
+ ///
+ ///
+ /// if the View's can be changed to the specified value. False
+ /// otherwise.
+ ///
+ internal bool TrySetHeight (int desiredHeight, out int resultHeight)
+ {
+ var h = desiredHeight;
+ bool canSetHeight;
+ switch (Height) {
+ case Dim.DimCombine _:
+ case Dim.DimView _:
+ case Dim.DimFill _:
+ // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
+ h = Height.Anchor (h);
+ canSetHeight = !ValidatePosDim;
+ break;
+ case Dim.DimFactor factor:
+ // Tries to get the SuperView height otherwise the view height.
+ var sh = SuperView != null ? SuperView.Frame.Height : h;
+ if (factor.IsFromRemaining ()) {
+ sh -= Frame.Y;
+ }
+ h = Height.Anchor (sh);
+ canSetHeight = !ValidatePosDim;
+ break;
+ default:
+ canSetHeight = true;
+ break;
+ }
+ resultHeight = h;
+
+ return canSetHeight;
+ }
+
+ ///
+ /// Finds which view that belong to the superview at the provided location.
+ ///
+ /// The superview where to look for.
+ /// The column location in the superview.
+ /// The row location in the superview.
+ /// The found view screen relative column location.
+ /// The found view screen relative row location.
+ ///
+ /// The view that was found at the and coordinates.
+ /// if no view was found.
+ ///
+ public static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
+ {
+ resy = resx = 0;
+ if (start == null || !start.Frame.Contains (x, y)) {
+ return null;
+ }
+
+ var startFrame = start.Frame;
+ if (start.InternalSubviews != null) {
+ var count = start.InternalSubviews.Count;
+ if (count > 0) {
+ var boundsOffset = start.GetBoundsOffset ();
+ var rx = x - (startFrame.X + boundsOffset.X);
+ var ry = y - (startFrame.Y + boundsOffset.Y);
+ for (var i = count - 1; i >= 0; i--) {
+ var v = start.InternalSubviews [i];
+ if (v.Visible && v.Frame.Contains (rx, ry)) {
+ var deep = FindDeepestView (v, rx, ry, out resx, out resy);
+ if (deep == null) {
+ return v;
+ }
+ return deep;
+ }
+ }
+ }
+ }
+ resx = x - startFrame.X;
+ resy = y - startFrame.Y;
+ return start;
+ }
}
\ No newline at end of file
diff --git a/Terminal.Gui/View/SuperViewChangedEventArgs.cs b/Terminal.Gui/View/SuperViewChangedEventArgs.cs
index fdd4da3cf..13f710491 100644
--- a/Terminal.Gui/View/SuperViewChangedEventArgs.cs
+++ b/Terminal.Gui/View/SuperViewChangedEventArgs.cs
@@ -1,33 +1,34 @@
using System;
-namespace Terminal.Gui {
+namespace Terminal.Gui;
+
+///
+/// Args for events where the of a is changed
+/// (e.g. / events).
+///
+public class SuperViewChangedEventArgs : EventArgs {
///
- /// Args for events where the of a is changed
- /// (e.g. / events).
+ /// Creates a new instance of the class.
///
- public class SuperViewChangedEventArgs : EventArgs
+ ///
+ ///
+ public SuperViewChangedEventArgs (View parent, View child)
{
- ///
- /// Creates a new instance of the class.
- ///
- ///
- ///
- public SuperViewChangedEventArgs (View parent, View child)
- {
- Parent = parent;
- Child = child;
- }
-
- ///
- /// The parent. For this is the old
- /// parent (new parent now being null). For
- /// it is the new parent to whom view now belongs.
- ///
- public View Parent { get; }
-
- ///
- /// The view that is having it's changed
- ///
- public View Child { get; }
+ Parent = parent;
+ Child = child;
}
-}
+
+ // TODO: Parent is the wrong name. It should be SuperView.
+ ///
+ /// The parent. For this is the old
+ /// parent (new parent now being null). For
+ /// it is the new parent to whom view now belongs.
+ ///
+ public View Parent { get; }
+
+ // TODO: Child is the wrong name. It should be View.
+ ///
+ /// The view that is having it's changed
+ ///
+ public View Child { get; }
+}
\ No newline at end of file
diff --git a/Terminal.Gui/Views/FileDialog.cs b/Terminal.Gui/Views/FileDialog.cs
index 4f8bb4bf1..6bd7557f5 100644
--- a/Terminal.Gui/Views/FileDialog.cs
+++ b/Terminal.Gui/Views/FileDialog.cs
@@ -368,7 +368,10 @@ namespace Terminal.Gui {
private int CalculateOkButtonPosX ()
{
- return this.Bounds.Width
+ if (!IsInitialized) {
+ return 0;
+ }
+ return Bounds.Width
- btnOk.Bounds.Width
- btnCancel.Bounds.Width
- 1
diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs
index 53983536b..c1ec2af7f 100644
--- a/Terminal.Gui/Views/Menu/ContextMenu.cs
+++ b/Terminal.Gui/Views/Menu/ContextMenu.cs
@@ -99,7 +99,7 @@ public sealed class ContextMenu : IDisposable {
}
_container = Application.Current;
_container.Closing += Container_Closing;
- var frame = new Rect (0, 0, View.Driver.Cols, View.Driver.Rows);
+ var frame = Application.Driver.Bounds;
var position = Position;
if (Host != null) {
Host.BoundsToScreen (frame.X, frame.Y, out int x, out int y);
diff --git a/Terminal.Gui/Views/Menu/MenuBar.cs b/Terminal.Gui/Views/Menu/MenuBar.cs
index 830519c53..321a48a4f 100644
--- a/Terminal.Gui/Views/Menu/MenuBar.cs
+++ b/Terminal.Gui/Views/Menu/MenuBar.cs
@@ -1445,7 +1445,7 @@ public class MenuBar : View {
if (Driver == null) {
return Point.Empty;
}
- var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame;
+ var superViewFrame = SuperView == null ? Driver.Bounds : SuperView.Frame;
var sv = SuperView == null ? Application.Current : SuperView;
var boundsOffset = sv.GetBoundsOffset ();
return new Point (superViewFrame.X - sv.Frame.X - boundsOffset.X,
@@ -1458,7 +1458,7 @@ public class MenuBar : View {
/// The location offset.
internal Point GetScreenOffsetFromCurrent ()
{
- var screen = new Rect (0, 0, Driver.Cols, Driver.Rows);
+ var screen = Driver.Bounds;
var currentFrame = Application.Current.Frame;
var boundsOffset = Application.Top.GetBoundsOffset ();
return new Point (screen.X - currentFrame.X - boundsOffset.X
diff --git a/Terminal.Gui/Views/Slider.cs b/Terminal.Gui/Views/Slider.cs
index 21fb8a269..af1759b8f 100644
--- a/Terminal.Gui/Views/Slider.cs
+++ b/Terminal.Gui/Views/Slider.cs
@@ -804,8 +804,6 @@ public class Slider : View {
if (!IsInitialized || AutoSize == false) {
return;
}
- // Hack??? Otherwise we can't go back to Dim.Absolute.
- LayoutStyle = LayoutStyle.Absolute;
Width = 0;
Height = 0;
if (_config._sliderOrientation == Orientation.Horizontal) {
@@ -817,7 +815,6 @@ public class Slider : View {
new Size (int.Min (SuperView.Bounds.Width - GetFramesThickness ().Horizontal, CalcThickness ()),
int.Min (SuperView.Bounds.Height - GetFramesThickness ().Vertical, CalcBestLength ())));
}
- LayoutStyle = LayoutStyle.Computed;
}
///
diff --git a/UICatalog/Scenarios/ASCIICustomButton.cs b/UICatalog/Scenarios/ASCIICustomButton.cs
index 595af572d..8be4a169b 100644
--- a/UICatalog/Scenarios/ASCIICustomButton.cs
+++ b/UICatalog/Scenarios/ASCIICustomButton.cs
@@ -77,7 +77,7 @@ namespace UICatalog.Scenarios {
};
AutoSize = false;
- LayoutStyle = LayoutStyle.Absolute;
+ //LayoutStyle = LayoutStyle.Absolute;
var fillText = new System.Text.StringBuilder ();
for (int i = 0; i < Bounds.Height; i++) {
diff --git a/UICatalog/Scenarios/AllViewsTester.cs b/UICatalog/Scenarios/AllViewsTester.cs
index e5ca76be7..302d0460a 100644
--- a/UICatalog/Scenarios/AllViewsTester.cs
+++ b/UICatalog/Scenarios/AllViewsTester.cs
@@ -246,7 +246,7 @@ public class AllViewsTester : Scenario {
var layout = view.LayoutStyle;
try {
- view.LayoutStyle = LayoutStyle.Absolute;
+ //view.LayoutStyle = LayoutStyle.Absolute;
view.X = _xRadioGroup.SelectedItem switch {
0 => Pos.Percent (_xVal),
@@ -280,7 +280,7 @@ public class AllViewsTester : Scenario {
} catch (Exception e) {
MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
} finally {
- view.LayoutStyle = layout;
+ //view.LayoutStyle = layout;
}
UpdateTitle (view);
}
diff --git a/UnitTests/View/DrawTests.cs b/UnitTests/View/DrawTests.cs
index aaab0f330..d41803d9d 100644
--- a/UnitTests/View/DrawTests.cs
+++ b/UnitTests/View/DrawTests.cs
@@ -4,14 +4,16 @@ using Xunit;
using Xunit.Abstractions;
using Microsoft.VisualStudio.TestPlatform.Utilities;
-namespace Terminal.Gui.ViewsTests;
+namespace Terminal.Gui.ViewsTests;
public class DrawTests {
readonly ITestOutputHelper _output;
public DrawTests (ITestOutputHelper output) => _output = output;
- [Fact] [AutoInitShutdown]
+ // TODO: Refactor this test to not depend on TextView etc... Make it as primitive as possible
+ [Fact]
+ [AutoInitShutdown]
public void Clipping_AddRune_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
{
var tv = new TextView () {
@@ -29,7 +31,8 @@ public class DrawTests {
var win = new Window () { Width = Dim.Fill (), Height = Dim.Fill () };
win.Add (tv);
Application.Top.Add (win);
- var lbl = new Label ("ワイドルーン。");
+ // Don't use Label. It sets AutoSize = true which is not what we're testing here.
+ var lbl = new View ("ワイドルーン。");
// Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
var dg = new Window () { X = 2, Y = 2, Width = 14, Height = 3 };
dg.Add (lbl);
@@ -54,7 +57,8 @@ public class DrawTests {
}
// TODO: The tests below that use Label should use View instead.
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
{
string us = "\U0001d539";
@@ -102,7 +106,8 @@ public class DrawTests {
0000000000", Application.Driver, expectedColors);
}
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two ()
{
string us = "\U0000f900";
@@ -150,7 +155,8 @@ public class DrawTests {
0000000000", Application.Driver, expectedColors);
}
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void Colors_On_TextAlignment_Right_And_Bottom ()
{
var labelRight = new Label ("Test") {
@@ -191,7 +197,8 @@ t ", _output);
0", Application.Driver, new Attribute [] { Colors.Base.Normal });
}
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void Draw_Negative_Bounds_Horizontal_Without_New_Lines ()
{
// BUGBUG: This previously assumed the default height of a View was 1.
@@ -235,7 +242,8 @@ t ", _output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
}
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void Draw_Negative_Bounds_Horizontal_With_New_Lines ()
{
var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "s\nu\nb\nV\ni\ne\nw" };
@@ -304,7 +312,8 @@ t ", _output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
}
- [Fact] [AutoInitShutdown]
+ [Fact]
+ [AutoInitShutdown]
public void Draw_Negative_Bounds_Vertical ()
{
var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "subView", TextDirection = TextDirection.TopBottom_LeftRight };
diff --git a/UnitTests/View/Layout/LayoutTests.cs b/UnitTests/View/Layout/LayoutTests.cs
index 45ea4d217..a2aa2bcaf 100644
--- a/UnitTests/View/Layout/LayoutTests.cs
+++ b/UnitTests/View/Layout/LayoutTests.cs
@@ -248,6 +248,25 @@ public class LayoutTests {
top.Dispose ();
}
+ [Fact]
+ [AutoInitShutdown]
+ public void DimFill_SizedCorrectly ()
+ {
+ var view = new View () {
+ Width = Dim.Fill (),
+ Height = Dim.Fill (),
+ BorderStyle = LineStyle.Single,
+ };
+ Application.Top.Add (view);
+ var rs = Application.Begin (Application.Top);
+ ((FakeDriver)Application.Driver).SetBufferSize (32, 5);
+ //view.SetNeedsLayout ();
+ Application.Top.LayoutSubviews ();
+ //view.SetRelativeLayout (new Rect (0, 0, 32, 5));
+ Assert.Equal (32, view.Frame.Width);
+ Assert.Equal (5, view.Frame.Height);
+ }
+
[Fact] [AutoInitShutdown]
public void Width_Height_SetMinWidthHeight_Narrow_Wide_Runes ()
{
@@ -761,7 +780,7 @@ public class LayoutTests {
// Was named AutoSize_Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
// but doesn't actually have anything to do with AutoSize.
[Fact]
- public void AutoSize_Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
+ public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
{
Application.Init (new FakeDriver ());
@@ -781,7 +800,7 @@ public class LayoutTests {
t.Add (w);
t.Ready += (s, e) => {
- v.LayoutStyle = LayoutStyle.Absolute;
+ v.Frame = new Rect (2, 2, 10, 10);
Assert.Equal (2, v.X = 2);
Assert.Equal (2, v.Y = 2);
};
diff --git a/UnitTests/View/Layout/SetRelativeLayoutTests.cs b/UnitTests/View/Layout/SetRelativeLayoutTests.cs
index cb6cc46a4..aec0f1a94 100644
--- a/UnitTests/View/Layout/SetRelativeLayoutTests.cs
+++ b/UnitTests/View/Layout/SetRelativeLayoutTests.cs
@@ -10,7 +10,46 @@ public class SetRelativeLayoutTests {
readonly ITestOutputHelper _output;
public SetRelativeLayoutTests (ITestOutputHelper output) => _output = output;
-
+
+ [Fact]
+ public void ComputedPosDim_StayComputed ()
+ {
+ var screen = new Rect (0, 0, 10, 15);
+ var view = new View () {
+ X = 1,
+ Y = 2,
+ Width = Dim.Fill (),
+ Height = Dim.Fill ()
+ };
+
+ Assert.Equal ("Absolute(1)", view.X.ToString ());
+ Assert.Equal ("Absolute(2)", view.Y.ToString ());
+ Assert.Equal ("Fill(0)", view.Width.ToString ());
+ Assert.Equal ("Fill(0)", view.Height.ToString ());
+ view.SetRelativeLayout (screen);
+ Assert.Equal ("Fill(0)", view.Width.ToString ());
+ Assert.Equal ("Fill(0)", view.Height.ToString ());
+ }
+
+ [Fact]
+ public void AbsolutePosDim_DontChange ()
+ {
+ var screen = new Rect (0, 0, 10, 15);
+ var view = new View () {
+ X = 1, // outside of screen +10
+ Y = 2, // outside of screen -10
+ Width = 3,
+ Height = 4
+ };
+
+ // Layout is Absolute. So the X and Y are not changed.
+ view.SetRelativeLayout (screen);
+ Assert.Equal (1, view.Frame.X);
+ Assert.Equal (2, view.Frame.Y);
+ Assert.Equal (3, view.Frame.Width);
+ Assert.Equal (4, view.Frame.Height);
+ }
+
[Fact]
public void Fill_Pos_Within_Bounds ()
{
@@ -64,7 +103,7 @@ public class SetRelativeLayoutTests {
}
[Fact]
- public void FIll_Pos_Outside_Bounds ()
+ public void Fill_Pos_Outside_Bounds ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
@@ -74,6 +113,7 @@ public class SetRelativeLayoutTests {
Height = 15
};
+ // Layout is Absolute. So the X and Y are not changed.
view.SetRelativeLayout (screen);
Assert.Equal (90, view.Frame.X);
Assert.Equal (-10, view.Frame.Y);
@@ -125,10 +165,10 @@ public class SetRelativeLayoutTests {
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
- view.Width = Dim.Fill ();
+ view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
- Assert.Equal (-41, view.Frame.X);
+ Assert.Equal (-41, view.Frame.X);
Assert.Equal (-13, view.Frame.Y);
Assert.Equal (121, view.Frame.Width); // 121 = screen.Width - (-Center - 41)
Assert.Equal (38, view.Frame.Height);
@@ -141,12 +181,12 @@ public class SetRelativeLayoutTests {
var view = new View () {
X = Pos.Center (),
Y = Pos.Center (),
- Width = Dim.Fill(),
- Height = Dim.Fill()
+ Width = Dim.Fill (),
+ Height = Dim.Fill ()
};
view.SetRelativeLayout (screen);
- Assert.Equal (0, view.Frame.X);
+ Assert.Equal (0, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
@@ -176,14 +216,14 @@ public class SetRelativeLayoutTests {
view.SetRelativeLayout (screen);
Assert.Equal (-1, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
- Assert.Equal (81, view.Frame.Width);
+ Assert.Equal (81, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 2; // Fill means all the way to right. So width will be 82. (dim gets calc'd before pos).
view.SetRelativeLayout (screen);
Assert.Equal (-2, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
- Assert.Equal (82, view.Frame.Width);
+ Assert.Equal (82, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 3; // Fill means all the way to right. So width will be 83. (dim gets calc'd before pos).
@@ -217,7 +257,8 @@ public class SetRelativeLayoutTests {
Assert.Equal (23, view.Frame.Y);
}
- [Fact] [TestRespondersDisposed]
+ [Fact]
+ [TestRespondersDisposed]
public void PosCombine_Plus_Absolute ()
{
var superView = new View () {
diff --git a/UnitTests/View/Text/AutoSizeTextTests.cs b/UnitTests/View/Text/AutoSizeTextTests.cs
index c6083e2ea..aaec87a0d 100644
--- a/UnitTests/View/Text/AutoSizeTextTests.cs
+++ b/UnitTests/View/Text/AutoSizeTextTests.cs
@@ -769,17 +769,47 @@ Y
Application.End (rs);
}
+ [Fact]
+ public void SetRelativeLayout_Respects_AutoSize ()
+ {
+ var view = new View (new Rect (0, 0, 10, 0)) {
+ AutoSize = true,
+ };
+ view.Text = "01234567890123456789";
+
+ Assert.True (view.AutoSize);
+ Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
+ Assert.Equal (new Rect (0, 0, 20, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(20)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+
+ view.SetRelativeLayout (new Rect (0, 0, 25, 5));
+
+ Assert.True (view.AutoSize);
+ Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
+ Assert.Equal (new Rect (0, 0, 20, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(20)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ }
+
[Fact]
[AutoInitShutdown]
public void Setting_Frame_Dont_Respect_AutoSize_True_On_Layout_Absolute ()
{
- var view1 = new View (new Rect (0, 0, 10, 0)) { Text = "Say Hello view1 你", AutoSize = true };
- var view2 = new View (new Rect (0, 0, 0, 10)) {
+ var view1 = new View (new Rect (0, 0, 10, 0)) {
+ Text = "Say Hello view1 你",
+ AutoSize = true
+ };
+ var viewTopBottom_LeftRight = new View (new Rect (0, 0, 0, 10)) {
Text = "Say Hello view2 你",
AutoSize = true,
TextDirection = TextDirection.TopBottom_LeftRight
};
- Application.Top.Add (view1, view2);
+ Application.Top.Add (view1, viewTopBottom_LeftRight);
var rs = Application.Begin (Application.Top);
@@ -790,7 +820,8 @@ Y
Assert.Equal ("Absolute(0)", view1.Y.ToString ());
Assert.Equal ("Absolute(18)", view1.Width.ToString ());
Assert.Equal ("Absolute(1)", view1.Height.ToString ());
- Assert.True (view2.AutoSize);
+
+ Assert.True (viewTopBottom_LeftRight.AutoSize);
// BUGBUG: v2 - Autosize is broken when setting Width/Height AutoSize. Disabling test for now.
//Assert.Equal (LayoutStyle.Absolute, view2.LayoutStyle);
//Assert.Equal (new Rect (0, 0, 2, 17), view2.Frame);
@@ -811,14 +842,14 @@ Y
Assert.Equal ("Absolute(18)", view1.Width.ToString ());
Assert.Equal ("Absolute(1)", view1.Height.ToString ());
- view2.Frame = new Rect (0, 0, 1, 25);
+ viewTopBottom_LeftRight.Frame = new Rect (0, 0, 1, 25);
Application.RunIteration (ref rs, ref firstIteration);
- Assert.True (view2.AutoSize);
- Assert.Equal (LayoutStyle.Absolute, view2.LayoutStyle);
- Assert.Equal (new Rect (0, 0, 1, 25), view2.Frame);
- Assert.Equal ("Absolute(0)", view2.X.ToString ());
- Assert.Equal ("Absolute(0)", view2.Y.ToString ());
+ Assert.True (viewTopBottom_LeftRight.AutoSize);
+ Assert.Equal (LayoutStyle.Absolute, viewTopBottom_LeftRight.LayoutStyle);
+ Assert.Equal (new Rect (0, 0, 1, 25), viewTopBottom_LeftRight.Frame);
+ Assert.Equal ("Absolute(0)", viewTopBottom_LeftRight.X.ToString ());
+ Assert.Equal ("Absolute(0)", viewTopBottom_LeftRight.Y.ToString ());
// BUGBUG: v2 - Autosize is broken when setting Width/Height AutoSize. Disabling test for now.
//Assert.Equal ("Absolute(2)", view2.Width.ToString ());
//Assert.Equal ("Absolute(17)", view2.Height.ToString ());
@@ -1865,8 +1896,7 @@ Y
Assert.Equal (new Rect (0, 0, 22, 22), pos);
Application.End (rs);
}
-
-
+
[Fact]
[AutoInitShutdown]
public void AutoSize_True_Width_Height_Stay_True_If_TextFormatter_Size_Fit ()
@@ -1905,7 +1935,7 @@ Y
Assert.Equal ("Absolute(0)", horizontalView.X.ToString ());
Assert.Equal ("Absolute(0)", horizontalView.Y.ToString ());
// BUGBUG - v2 - With v1 AutoSize = true Width/Height should always grow or keep initial value,
- // but in v2, autosize will be replaced by Dim.Fit. Disabling test for now.
+
Assert.Equal ("Absolute(9)", horizontalView.Width.ToString ());
Assert.Equal ("Absolute(1)", horizontalView.Height.ToString ());
Assert.Equal (new Rect (0, 3, 2, 8), verticalView.Frame);
@@ -1981,4 +2011,483 @@ Y
Application.End (rs);
}
+
+ [Fact]
+ [AutoInitShutdown]
+ public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_After_IsAdded_And_IsInitialized ()
+ {
+ var win = new Window (new Rect (0, 0, 30, 80));
+ var label = new Label { Width = Dim.Fill () };
+ win.Add (label);
+ Application.Top.Add (win);
+
+ Assert.True (label.IsAdded);
+
+ Assert.True (label.AutoSize);
+
+ // #3127: Before:
+ // Text is empty but height=1 by default, see Label view
+ // BUGBUG: LayoutSubviews has not been called, so this test is not really valid (pos/dim are indeterminate, not 0)
+ // Not really a bug because View call OnResizeNeeded method on the SetInitialProperties method
+ // #3127: After: Text is empty Width=Dim.Fill is honored
+ Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
+
+ label.Text = "First line\nSecond line";
+ Application.Top.LayoutSubviews ();
+
+ Assert.True (label.AutoSize);
+ // BUGBUG: This test is bogus: label has not been initialized. pos/dim is indeterminate!
+ Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
+ Assert.False (label.IsInitialized);
+
+ var rs = Application.Begin (Application.Top);
+
+ Assert.True (label.AutoSize);
+ Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
+ Assert.True (label.IsInitialized);
+
+ label.AutoSize = false;
+ // BUGBUG: Application.Refresh has nothing to do with layout! It just redraws and sets LayoutNeeded to true
+ // Application.Refresh ();
+
+ // Width should still be Dim.Fill
+ Assert.Equal ("Fill(0)", label.Width.ToString ());
+
+ // Height should be 2
+ Assert.Equal ("Absolute(2)", label.Height.ToString ());
+ Assert.Equal (2, label.Frame.Height);
+
+ Assert.False (label.AutoSize);
+ Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
+ Application.End (rs);
+ }
+
+ [Fact]
+ [AutoInitShutdown]
+ public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_With_Initialization ()
+ {
+ var win = new Window (new Rect (0, 0, 30, 80));
+ var label = new Label { Width = Dim.Fill () };
+ win.Add (label);
+ Application.Top.Add (win);
+
+ // Text is empty but height=1 by default, see Label view
+ Assert.True (label.AutoSize);
+ Assert.Equal ("(0,0,0,1)", label.Bounds.ToString ());
+
+ var rs = Application.Begin (Application.Top);
+
+ Assert.True (label.AutoSize);
+ // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
+ // and height 0 because wasn't set and the text is empty
+ // BUGBUG: Because of #2450, this test is bogus: pos/dim is indeterminate!
+ //Assert.Equal ("(0,0,28,0)", label.Bounds.ToString ());
+
+ label.Text = "First line\nSecond line";
+ Application.Refresh ();
+
+ // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
+ // and height 2 because wasn't set and the text has 2 lines
+ Assert.True (label.AutoSize);
+ Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
+
+ label.AutoSize = false;
+ Application.Refresh ();
+
+ // Here the SetMinWidthHeight ensuring the minimum height
+ Assert.False (label.AutoSize);
+ Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
+
+ label.Text = "First changed line\nSecond changed line\nNew line";
+ Application.Refresh ();
+
+ // Here the AutoSize is false and the width 28 (Dim.Fill) and
+ // height 1 because wasn't set and SetMinWidthHeight ensuring the minimum height
+ Assert.False (label.AutoSize);
+ Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
+
+ label.AutoSize = true;
+ Application.Refresh ();
+
+ // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
+ // and height 3 because wasn't set and the text has 3 lines
+ Assert.True (label.AutoSize);
+ // BUGBUG: v2 - AutoSize is broken - temporarily disabling test See #2432
+ //Assert.Equal ("(0,0,28,3)", label.Bounds.ToString ());
+ Application.End (rs);
+ }
+
+
+ [Fact]
+ [AutoInitShutdown]
+ public void AutoSize_False_TextDirection_Toggle ()
+ {
+ var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
+ // View is AutoSize == true
+ var view = new View ();
+ win.Add (view);
+ Application.Top.Add (win);
+
+ var rs = Application.Begin (Application.Top);
+ ((FakeDriver)Application.Driver).SetBufferSize (22, 22);
+
+ Assert.Equal (new Rect (0, 0, 22, 22), win.Frame);
+ Assert.Equal (new Rect (0, 0, 22, 22), win.Margin.Frame);
+ Assert.Equal (new Rect (0, 0, 22, 22), win.Border.Frame);
+ Assert.Equal (new Rect (1, 1, 20, 20), win.Padding.Frame);
+ Assert.False (view.AutoSize);
+ Assert.Equal (TextDirection.LeftRight_TopBottom, view.TextDirection);
+ Assert.Equal (Rect.Empty, view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(0)", view.Width.ToString ());
+ Assert.Equal ("Absolute(0)", view.Height.ToString ());
+ var expected = @"
+┌────────────────────┐
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.Text = "Hello World";
+ view.Width = 11;
+ view.Height = 1;
+ win.LayoutSubviews ();
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(11)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│Hello World │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.AutoSize = true;
+ view.Text = "Hello Worlds";
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 12, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(11)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│Hello Worlds │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.TextDirection = TextDirection.TopBottom_LeftRight;
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 11, 12), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(11)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│H │
+│e │
+│l │
+│l │
+│o │
+│ │
+│W │
+│o │
+│r │
+│l │
+│d │
+│s │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.AutoSize = false;
+ view.Height = 1;
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(11)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│HelloWorlds │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.PreserveTrailingSpaces = true;
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(11)", view.Width.ToString ());
+ Assert.Equal ("Absolute(1)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│Hello World │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.PreserveTrailingSpaces = false;
+ var f = view.Frame;
+ view.Width = f.Height;
+ view.Height = f.Width;
+ view.TextDirection = TextDirection.TopBottom_LeftRight;
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 1, 11), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(1)", view.Width.ToString ());
+ Assert.Equal ("Absolute(11)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│H │
+│e │
+│l │
+│l │
+│o │
+│ │
+│W │
+│o │
+│r │
+│l │
+│d │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+
+ view.AutoSize = true;
+ Application.Refresh ();
+
+ Assert.Equal (new Rect (0, 0, 1, 12), view.Frame);
+ Assert.Equal ("Absolute(0)", view.X.ToString ());
+ Assert.Equal ("Absolute(0)", view.Y.ToString ());
+ Assert.Equal ("Absolute(1)", view.Width.ToString ());
+ Assert.Equal ("Absolute(12)", view.Height.ToString ());
+ expected = @"
+┌────────────────────┐
+│H │
+│e │
+│l │
+│l │
+│o │
+│ │
+│W │
+│o │
+│r │
+│l │
+│d │
+│s │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+│ │
+└────────────────────┘
+";
+
+ pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+ Assert.Equal (new Rect (0, 0, 22, 22), pos);
+ Application.End (rs);
+ }
+
+
+ [Fact, AutoInitShutdown]
+ public void GetTextFormatterBoundsSize_GetSizeNeededForText_HotKeySpecifier ()
+ {
+ var text = "Say Hello 你";
+
+ // Frame: 0, 0, 12, 1
+ var horizontalView = new View () {
+ AutoSize = true,
+ HotKeySpecifier = (Rune)'_'
+ };
+ horizontalView.Text = text;
+
+ // Frame: 0, 0, 1, 12
+ var verticalView = new View () {
+ AutoSize = true,
+ HotKeySpecifier = (Rune)'_',
+ TextDirection = TextDirection.TopBottom_LeftRight
+ };
+ verticalView.Text = text;
+
+ Application.Top.Add (horizontalView, verticalView);
+ Application.Begin (Application.Top);
+ ((FakeDriver)Application.Driver).SetBufferSize (50, 50);
+
+ Assert.True (horizontalView.AutoSize);
+ Assert.Equal (new Rect (0, 0, 12, 1), horizontalView.Frame);
+ Assert.Equal (new Size (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
+ Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
+
+ Assert.True (verticalView.AutoSize);
+ // BUGBUG: v2 - Autosize is broken; disabling this test
+ Assert.Equal (new Rect (0, 0, 2, 11), verticalView.Frame);
+ Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ());
+ //Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextAndHotKey ());
+ //Assert.Equal (verticalView.TextFormatter.Size, verticalView.GetSizeNeededForTextAndHotKey ());
+ Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
+
+ text = "Say He_llo 你";
+ horizontalView.Text = text;
+ verticalView.Text = text;
+
+ Assert.True (horizontalView.AutoSize);
+ Assert.Equal (new Rect (0, 0, 12, 1), horizontalView.Frame);
+ Assert.Equal (new Size (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
+ //Assert.Equal (new Size (13, 1), horizontalView.GetSizeNeededForTextAndHotKey ());
+ //Assert.Equal (horizontalView.TextFormatter.Size, horizontalView.GetSizeNeededForTextAndHotKey ());
+ Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
+
+ Assert.True (verticalView.AutoSize);
+ // BUGBUG: v2 - Autosize is broken; disabling this test
+ //Assert.Equal (new Rect (0, 0, 2, 11), verticalView.Frame);
+ //Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ());
+ //Assert.Equal (new Size (2, 12), verticalView.GetSizeNeededForTextAndHotKey ());
+ //Assert.Equal (verticalView.TextFormatter.Size, verticalView.GetSizeNeededForTextAndHotKey ());
+ //Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
+ }
}
\ No newline at end of file
diff --git a/UnitTests/View/Text/TextTests.cs b/UnitTests/View/Text/TextTests.cs
index a652c12c2..fbcb5b224 100644
--- a/UnitTests/View/Text/TextTests.cs
+++ b/UnitTests/View/Text/TextTests.cs
@@ -33,11 +33,11 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (view.AutoSize);
- Assert.Equal (new Rect (0, 0, 3, 1), view.Frame);
- Assert.Equal (new Size (3, 1), view.TextFormatter.Size);
+ Assert.Equal (new Rect (0, 0, 3, 1), view.Frame);
+ Assert.Equal (new Size (3, 1), view.TextFormatter.Size);
Assert.Equal (new List { "Vie" }, view.TextFormatter.Lines);
- Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
- Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
+ Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+ Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
var expected = @"
┌────────┐
│Vie │
@@ -53,8 +53,8 @@ public class TextTests {
view.Width = Dim.Fill () - text.Length;
Application.Refresh ();
- Assert.Equal (new Rect (0, 0, 0, 1), view.Frame);
- Assert.Equal (new Size (0, 1), view.TextFormatter.Size);
+ Assert.Equal (new Rect (0, 0, 0, 1), view.Frame);
+ Assert.Equal (new Size (0, 1), view.TextFormatter.Size);
Assert.Equal (new List { string.Empty }, view.TextFormatter.Lines);
expected = @"
┌────────┐
@@ -88,7 +88,7 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (view.AutoSize);
Assert.Equal (new Rect (0, 0, 3, 1), view.Frame);
- Assert.Equal (new Size (3, 1), view.TextFormatter.Size);
+ Assert.Equal (new Size (3, 1), view.TextFormatter.Size);
Assert.Single (view.TextFormatter.Lines);
Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
@@ -108,7 +108,7 @@ public class TextTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 0, 1), view.Frame);
- Assert.Equal (new Size (0, 1), view.TextFormatter.Size);
+ Assert.Equal (new Size (0, 1), view.TextFormatter.Size);
var exception = Record.Exception (() => Assert.Equal (new List { string.Empty }, view.TextFormatter.Lines));
Assert.Null (exception);
expected = @"
@@ -144,11 +144,11 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (label.AutoSize);
- Assert.Equal (new Rect (0, 0, 3, 1), label.Frame);
- Assert.Equal (new Size (3, 1), label.TextFormatter.Size);
+ Assert.Equal (new Rect (0, 0, 3, 1), label.Frame);
+ Assert.Equal (new Size (3, 1), label.TextFormatter.Size);
Assert.Equal (new List { "Lab" }, label.TextFormatter.Lines);
- Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
- Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
+ Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+ Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
var expected = @"
┌────────┐
│Lab │
@@ -165,8 +165,8 @@ public class TextTests {
Application.Refresh ();
Assert.False (label.AutoSize);
- Assert.Equal (new Rect (0, 0, 0, 1), label.Frame);
- Assert.Equal (new Size (0, 1), label.TextFormatter.Size);
+ Assert.Equal (new Rect (0, 0, 0, 1), label.Frame);
+ Assert.Equal (new Size (0, 1), label.TextFormatter.Size);
Assert.Equal (new List { string.Empty }, label.TextFormatter.Lines);
expected = @"
┌────────┐
@@ -201,7 +201,7 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (label.AutoSize);
Assert.Equal (new Rect (0, 0, 3, 1), label.Frame);
- Assert.Equal (new Size (3, 1), label.TextFormatter.Size);
+ Assert.Equal (new Size (3, 1), label.TextFormatter.Size);
Assert.Single (label.TextFormatter.Lines);
Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
Assert.Equal (new Rect (0, 0, 10, 4), Application.Top.Frame);
@@ -221,7 +221,7 @@ public class TextTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 0, 1), label.Frame);
- Assert.Equal (new Size (0, 1), label.TextFormatter.Size);
+ Assert.Equal (new Size (0, 1), label.TextFormatter.Size);
var exception = Record.Exception (() => Assert.Equal (new List { string.Empty }, label.TextFormatter.Lines));
Assert.Null (exception);
expected = @"
@@ -257,7 +257,7 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (view.AutoSize);
Assert.Equal (new Rect (0, 0, 1, 3), view.Frame);
- Assert.Equal (new Size (1, 3), view.TextFormatter.Size);
+ Assert.Equal (new Size (1, 3), view.TextFormatter.Size);
Assert.Single (view.TextFormatter.Lines);
Assert.Equal (new Rect (0, 0, 4, 10), win.Frame);
Assert.Equal (new Rect (0, 0, 4, 10), Application.Top.Frame);
@@ -283,7 +283,7 @@ public class TextTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 1, 0), view.Frame);
- Assert.Equal (new Size (1, 0), view.TextFormatter.Size);
+ Assert.Equal (new Size (1, 0), view.TextFormatter.Size);
var exception = Record.Exception (() => Assert.Equal (new List { string.Empty }, view.TextFormatter.Lines));
Assert.Null (exception);
expected = @"
@@ -325,7 +325,7 @@ public class TextTests {
Assert.Equal (5, text.Length);
Assert.False (view.AutoSize);
Assert.Equal (new Rect (0, 0, 2, 3), view.Frame);
- Assert.Equal (new Size (2, 3), view.TextFormatter.Size);
+ Assert.Equal (new Size (2, 3), view.TextFormatter.Size);
Assert.Single (view.TextFormatter.Lines);
Assert.Equal (new Rect (0, 0, 4, 10), win.Frame);
Assert.Equal (new Rect (0, 0, 4, 10), Application.Top.Frame);
@@ -351,7 +351,7 @@ public class TextTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 2, 0), view.Frame);
- Assert.Equal (new Size (2, 0), view.TextFormatter.Size);
+ Assert.Equal (new Size (2, 0), view.TextFormatter.Size);
var exception = Record.Exception (() => Assert.Equal (new List { string.Empty }, view.TextFormatter.Lines));
Assert.Null (exception);
expected = @"
@@ -427,9 +427,10 @@ public class TextTests {
win.Add (label);
Application.Top.Add (win);
- // Text is empty but height=1 by default, see Label view
+ // #3127: Before: Text is empty but height=1 by default, see Label view
+ // After: Text is empty Dim.Fill is honored
Assert.False (label.AutoSize);
- Assert.Equal ("(0,0,0,1)", label.Bounds.ToString ());
+ Assert.Equal ("(0,0,28,78)", label.Bounds.ToString ());
label.Text = "New text\nNew line";
Application.Top.LayoutSubviews ();
@@ -445,100 +446,6 @@ public class TextTests {
Application.End (rs);
}
- [Fact]
- [AutoInitShutdown]
- public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_After_IsAdded_And_IsInitialized ()
- {
- var win = new Window (new Rect (0, 0, 30, 80));
- var label = new Label { Width = Dim.Fill () };
- win.Add (label);
- Application.Top.Add (win);
-
- Assert.True (label.IsAdded);
-
- // Text is empty but height=1 by default, see Label view
- Assert.True (label.AutoSize);
- // BUGBUG: LayoutSubviews has not been called, so this test is not really valid (pos/dim are indeterminate, not 0)
- // Not really a bug because View call OnResizeNeeded method on the SetInitialProperties method
- Assert.Equal ("(0,0,0,1)", label.Bounds.ToString ());
-
- label.Text = "First line\nSecond line";
- Application.Top.LayoutSubviews ();
-
- Assert.True (label.AutoSize);
- // BUGBUG: This test is bogus: label has not been initialized. pos/dim is indeterminate!
- Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
- Assert.False (label.IsInitialized);
-
- var rs = Application.Begin (Application.Top);
-
- Assert.True (label.AutoSize);
- Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
- Assert.True (label.IsInitialized);
-
- label.AutoSize = false;
- Application.Refresh ();
-
- Assert.False (label.AutoSize);
- Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
- Application.End (rs);
- }
-
- [Fact]
- [AutoInitShutdown]
- public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_With_Initialization ()
- {
- var win = new Window (new Rect (0, 0, 30, 80));
- var label = new Label { Width = Dim.Fill () };
- win.Add (label);
- Application.Top.Add (win);
-
- // Text is empty but height=1 by default, see Label view
- Assert.True (label.AutoSize);
- Assert.Equal ("(0,0,0,1)", label.Bounds.ToString ());
-
- var rs = Application.Begin (Application.Top);
-
- Assert.True (label.AutoSize);
- // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
- // and height 0 because wasn't set and the text is empty
- // BUGBUG: Because of #2450, this test is bogus: pos/dim is indeterminate!
- //Assert.Equal ("(0,0,28,0)", label.Bounds.ToString ());
-
- label.Text = "First line\nSecond line";
- Application.Refresh ();
-
- // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
- // and height 2 because wasn't set and the text has 2 lines
- Assert.True (label.AutoSize);
- Assert.Equal ("(0,0,28,2)", label.Bounds.ToString ());
-
- label.AutoSize = false;
- Application.Refresh ();
-
- // Here the SetMinWidthHeight ensuring the minimum height
- Assert.False (label.AutoSize);
- Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
-
- label.Text = "First changed line\nSecond changed line\nNew line";
- Application.Refresh ();
-
- // Here the AutoSize is false and the width 28 (Dim.Fill) and
- // height 1 because wasn't set and SetMinWidthHeight ensuring the minimum height
- Assert.False (label.AutoSize);
- Assert.Equal ("(0,0,28,1)", label.Bounds.ToString ());
-
- label.AutoSize = true;
- Application.Refresh ();
-
- // Here the AutoSize ensuring the right size with width 28 (Dim.Fill)
- // and height 3 because wasn't set and the text has 3 lines
- Assert.True (label.AutoSize);
- // BUGBUG: v2 - AutoSize is broken - temporarily disabling test See #2432
- //Assert.Equal ("(0,0,28,3)", label.Bounds.ToString ());
- Application.End (rs);
- }
-
[Fact]
[AutoInitShutdown]
public void AutoSize_False_Equal_Before_And_After_IsInitialized_With_Differents_Orders ()
@@ -576,28 +483,28 @@ public class TextTests {
Assert.False (view5.IsInitialized);
Assert.False (view1.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view1.Frame);
- Assert.Equal ("Absolute(10)", view1.Width.ToString ());
- Assert.Equal ("Absolute(5)", view1.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view1.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view1.Height.ToString ());
Assert.False (view2.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view2.Frame);
- Assert.Equal ("Absolute(10)", view2.Width.ToString ());
- Assert.Equal ("Absolute(5)", view2.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view2.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view2.Height.ToString ());
Assert.False (view3.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view3.Frame);
- Assert.Equal ("Absolute(10)", view3.Width.ToString ());
- Assert.Equal ("Absolute(5)", view3.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view3.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view3.Height.ToString ());
Assert.False (view4.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view4.Frame);
- Assert.Equal ("Absolute(10)", view4.Width.ToString ());
- Assert.Equal ("Absolute(5)", view4.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view4.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view4.Height.ToString ());
Assert.False (view5.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view5.Frame);
- Assert.Equal ("Absolute(10)", view5.Width.ToString ());
- Assert.Equal ("Absolute(5)", view5.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view5.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view5.Height.ToString ());
Assert.False (view6.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view6.Frame);
- Assert.Equal ("Absolute(10)", view6.Width.ToString ());
- Assert.Equal ("Absolute(5)", view6.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view6.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view6.Height.ToString ());
var rs = Application.Begin (Application.Top);
@@ -608,343 +515,29 @@ public class TextTests {
Assert.True (view5.IsInitialized);
Assert.False (view1.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view1.Frame);
- Assert.Equal ("Absolute(10)", view1.Width.ToString ());
- Assert.Equal ("Absolute(5)", view1.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view1.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view1.Height.ToString ());
Assert.False (view2.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view2.Frame);
- Assert.Equal ("Absolute(10)", view2.Width.ToString ());
- Assert.Equal ("Absolute(5)", view2.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view2.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view2.Height.ToString ());
Assert.False (view3.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view3.Frame);
- Assert.Equal ("Absolute(10)", view3.Width.ToString ());
- Assert.Equal ("Absolute(5)", view3.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view3.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view3.Height.ToString ());
Assert.False (view4.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view4.Frame);
- Assert.Equal ("Absolute(10)", view4.Width.ToString ());
- Assert.Equal ("Absolute(5)", view4.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view4.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view4.Height.ToString ());
Assert.False (view5.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view5.Frame);
- Assert.Equal ("Absolute(10)", view5.Width.ToString ());
- Assert.Equal ("Absolute(5)", view5.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view5.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view5.Height.ToString ());
Assert.False (view6.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 5), view6.Frame);
- Assert.Equal ("Absolute(10)", view6.Width.ToString ());
- Assert.Equal ("Absolute(5)", view6.Height.ToString ());
+ Assert.Equal ("Absolute(10)", view6.Width.ToString ());
+ Assert.Equal ("Absolute(5)", view6.Height.ToString ());
Application.End (rs);
}
- [Fact]
- [AutoInitShutdown]
- public void AutoSize_False_TextDirection_Toggle ()
- {
- var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
- // View is AutoSize == true
- var view = new View ();
- win.Add (view);
- Application.Top.Add (win);
-
- var rs = Application.Begin (Application.Top);
- ((FakeDriver)Application.Driver).SetBufferSize (22, 22);
-
- Assert.Equal (new Rect (0, 0, 22, 22), win.Frame);
- Assert.Equal (new Rect (0, 0, 22, 22), win.Margin.Frame);
- Assert.Equal (new Rect (0, 0, 22, 22), win.Border.Frame);
- Assert.Equal (new Rect (1, 1, 20, 20), win.Padding.Frame);
- Assert.False (view.AutoSize);
- Assert.Equal (TextDirection.LeftRight_TopBottom, view.TextDirection);
- Assert.Equal (Rect.Empty, view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(0)", view.Width.ToString ());
- Assert.Equal ("Absolute(0)", view.Height.ToString ());
- var expected = @"
-┌────────────────────┐
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.Text = "Hello World";
- view.Width = 11;
- view.Height = 1;
- win.LayoutSubviews ();
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(11)", view.Width.ToString ());
- Assert.Equal ("Absolute(1)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│Hello World │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.AutoSize = true;
- view.Text = "Hello Worlds";
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 12, 1), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(11)", view.Width.ToString ());
- Assert.Equal ("Absolute(1)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│Hello Worlds │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.TextDirection = TextDirection.TopBottom_LeftRight;
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 11, 12), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(11)", view.Width.ToString ());
- Assert.Equal ("Absolute(1)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│H │
-│e │
-│l │
-│l │
-│o │
-│ │
-│W │
-│o │
-│r │
-│l │
-│d │
-│s │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.AutoSize = false;
- view.Height = 1;
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(11)", view.Width.ToString ());
- Assert.Equal ("Absolute(1)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│HelloWorlds │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.PreserveTrailingSpaces = true;
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 11, 1), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(11)", view.Width.ToString ());
- Assert.Equal ("Absolute(1)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│Hello World │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.PreserveTrailingSpaces = false;
- var f = view.Frame;
- view.Width = f.Height;
- view.Height = f.Width;
- view.TextDirection = TextDirection.TopBottom_LeftRight;
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 1, 11), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(1)", view.Width.ToString ());
- Assert.Equal ("Absolute(11)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│H │
-│e │
-│l │
-│l │
-│o │
-│ │
-│W │
-│o │
-│r │
-│l │
-│d │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
-
- view.AutoSize = true;
- Application.Refresh ();
-
- Assert.Equal (new Rect (0, 0, 1, 12), view.Frame);
- Assert.Equal ("Absolute(0)", view.X.ToString ());
- Assert.Equal ("Absolute(0)", view.Y.ToString ());
- Assert.Equal ("Absolute(1)", view.Width.ToString ());
- Assert.Equal ("Absolute(12)", view.Height.ToString ());
- expected = @"
-┌────────────────────┐
-│H │
-│e │
-│l │
-│l │
-│o │
-│ │
-│W │
-│o │
-│r │
-│l │
-│d │
-│s │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-│ │
-└────────────────────┘
-";
-
- pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
- Assert.Equal (new Rect (0, 0, 22, 22), pos);
- Application.End (rs);
- }
}
\ No newline at end of file
diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs
index c882daed2..6e6debc5a 100644
--- a/UnitTests/View/ViewTests.cs
+++ b/UnitTests/View/ViewTests.cs
@@ -21,7 +21,7 @@ namespace Terminal.Gui.ViewTests {
// Parameterless
var r = new View ();
Assert.NotNull (r);
- Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
+ Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
Assert.Equal ("View()(0,0,0,0)", r.ToString ());
Assert.False (r.CanFocus);
Assert.False (r.HasFocus);
@@ -29,10 +29,10 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
Assert.Null (r.Focused);
Assert.Null (r.ColorScheme);
- Assert.Null (r.Width);
- Assert.Null (r.Height);
- Assert.Null (r.X);
- Assert.Null (r.Y);
+ Assert.Equal (0, r.Width);
+ Assert.Equal (0, r.Height);
+ Assert.Equal (0, r.X);
+ Assert.Equal (0, r.Y);
Assert.False (r.IsCurrentTop);
Assert.Empty (r.Id);
Assert.Empty (r.Subviews);
@@ -42,7 +42,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Null (r.MostFocused);
Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
r.Dispose ();
-
+
// Empty Rect
r = new View (Rect.Empty);
Assert.NotNull (r);
@@ -54,10 +54,10 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
Assert.Null (r.Focused);
Assert.Null (r.ColorScheme);
- Assert.Null (r.Width); // All view Dim are initialized now in the IsAdded setter,
- Assert.Null (r.Height); // avoiding Dim errors.
- Assert.Null (r.X); // All view Pos are initialized now in the IsAdded setter,
- Assert.Null (r.Y); // avoiding Pos errors.
+ Assert.Equal (0, r.Width);
+ Assert.Equal (0, r.Height);
+ Assert.Equal (0, r.X);
+ Assert.Equal (0, r.Y);
Assert.False (r.IsCurrentTop);
Assert.Empty (r.Id);
Assert.Empty (r.Subviews);
@@ -79,10 +79,10 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (1, 2, 3, 4), r.Frame);
Assert.Null (r.Focused);
Assert.Null (r.ColorScheme);
- Assert.Null (r.Width);
- Assert.Null (r.Height);
- Assert.Null (r.X);
- Assert.Null (r.Y);
+ Assert.Equal (3, r.Width);
+ Assert.Equal (4, r.Height);
+ Assert.Equal (1, r.X);
+ Assert.Equal (2, r.Y);
Assert.False (r.IsCurrentTop);
Assert.Empty (r.Id);
Assert.Empty (r.Subviews);
@@ -96,7 +96,7 @@ namespace Terminal.Gui.ViewTests {
// Initializes a view with a vertical direction
r = new View ("Vertical View", TextDirection.TopBottom_LeftRight);
Assert.NotNull (r);
- Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
+ Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
Assert.Equal ("View(Vertical View)(0,0,1,13)", r.ToString ());
Assert.False (r.CanFocus);
Assert.False (r.HasFocus);
@@ -104,10 +104,6 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 0, 1, 13), r.Frame);
Assert.Null (r.Focused);
Assert.Null (r.ColorScheme);
- Assert.Null (r.Width); // All view Dim are initialized now in the IsAdded setter,
- Assert.Null (r.Height); // avoiding Dim errors.
- Assert.Null (r.X); // All view Pos are initialized now in the IsAdded setter,
- Assert.Null (r.Y); // avoiding Pos errors.
Assert.False (r.IsCurrentTop);
Assert.Equal ("Vertical View", r.Id);
Assert.Empty (r.Subviews);
@@ -183,23 +179,23 @@ namespace Terminal.Gui.ViewTests {
#if DEBUG_IDISPOSABLE
Assert.Empty (Responder.Instances);
#endif
-
+
// Default Constructor
view = new View ();
- Assert.Null (view.X);
- Assert.Null (view.Y);
- Assert.Null (view.Width);
- Assert.Null (view.Height);
+ Assert.Equal (0, view.X);
+ Assert.Equal (0, view.Y);
+ Assert.Equal (0, view.Width);
+ Assert.Equal (0, view.Height);
Assert.True (view.Frame.IsEmpty);
Assert.True (view.Bounds.IsEmpty);
view.Dispose ();
// Constructor
view = new View (1, 2, "");
- Assert.Null (view.X);
- Assert.Null (view.Y);
- Assert.Null (view.Width);
- Assert.Null (view.Height);
+ Assert.Equal (1, view.X);
+ Assert.Equal (2, view.Y);
+ Assert.Equal (0, view.Width);
+ Assert.Equal (0, view.Height);
Assert.False (view.Frame.IsEmpty);
Assert.True (view.Bounds.IsEmpty);
view.Dispose ();
@@ -259,33 +255,33 @@ namespace Terminal.Gui.ViewTests {
{
Application.Init (new FakeDriver ());
- var t = new Toplevel () { Id = "0", };
+ var top = new Toplevel () { Id = "0", }; // Frame: 0, 0, 80, 25; Bounds: 0, 0, 80, 25
- var w = new Window () { Id = "t", Width = Dim.Fill (), Height = Dim.Fill () };
- var v1 = new View () { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () };
- var v2 = new View () { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () };
- var sv1 = new View () { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () };
+ var winAddedToTop = new Window () { Id = "t", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 0, 0, 80, 25; Bounds: 0, 0, 78, 23
+ var v1AddedToWin = new View () { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (because Windows has a border)
+ var v2AddedToWin = new View () { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (because Windows has a border)
+ var svAddedTov1 = new View () { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (same as it's superview v1AddedToWin)
int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
- w.Added += (s, e) => {
- Assert.Equal (e.Parent.Frame.Width, w.Frame.Width);
- Assert.Equal (e.Parent.Frame.Height, w.Frame.Height);
+ winAddedToTop.Added += (s, e) => {
+ Assert.Equal (e.Parent.Bounds.Width, winAddedToTop.Frame.Width);
+ Assert.Equal (e.Parent.Bounds.Height, winAddedToTop.Frame.Height);
};
- v1.Added += (s, e) => {
- Assert.Equal (e.Parent.Frame.Width, v1.Frame.Width);
- Assert.Equal (e.Parent.Frame.Height, v1.Frame.Height);
+ v1AddedToWin.Added += (s, e) => {
+ Assert.Equal (e.Parent.Bounds.Width, v1AddedToWin.Frame.Width);
+ Assert.Equal (e.Parent.Bounds.Height, v1AddedToWin.Frame.Height);
};
- v2.Added += (s, e) => {
- Assert.Equal (e.Parent.Frame.Width, v2.Frame.Width);
- Assert.Equal (e.Parent.Frame.Height, v2.Frame.Height);
+ v2AddedToWin.Added += (s, e) => {
+ Assert.Equal (e.Parent.Bounds.Width, v2AddedToWin.Frame.Width);
+ Assert.Equal (e.Parent.Bounds.Height, v2AddedToWin.Frame.Height);
};
- sv1.Added += (s, e) => {
- Assert.Equal (e.Parent.Frame.Width, sv1.Frame.Width);
- Assert.Equal (e.Parent.Frame.Height, sv1.Frame.Height);
+ svAddedTov1.Added += (s, e) => {
+ Assert.Equal (e.Parent.Bounds.Width, svAddedTov1.Frame.Width);
+ Assert.Equal (e.Parent.Bounds.Height, svAddedTov1.Frame.Height);
};
- t.Initialized += (s, e) => {
+ top.Initialized += (s, e) => {
tc++;
Assert.Equal (1, tc);
Assert.Equal (1, wc);
@@ -293,48 +289,61 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (1, v2c);
Assert.Equal (1, sv1c);
- Assert.True (t.CanFocus);
- Assert.True (w.CanFocus);
- Assert.False (v1.CanFocus);
- Assert.False (v2.CanFocus);
- Assert.False (sv1.CanFocus);
+ Assert.True (top.CanFocus);
+ Assert.True (winAddedToTop.CanFocus);
+ Assert.False (v1AddedToWin.CanFocus);
+ Assert.False (v2AddedToWin.CanFocus);
+ Assert.False (svAddedTov1.CanFocus);
Application.Refresh ();
};
- w.Initialized += (s, e) => {
+ winAddedToTop.Initialized += (s, e) => {
wc++;
- Assert.Equal (t.Frame.Width, w.Frame.Width);
- Assert.Equal (t.Frame.Height, w.Frame.Height);
+ Assert.Equal (top.Bounds.Width, winAddedToTop.Frame.Width);
+ Assert.Equal (top.Bounds.Height, winAddedToTop.Frame.Height);
};
- v1.Initialized += (s, e) => {
+ v1AddedToWin.Initialized += (s, e) => {
v1c++;
- Assert.Equal (t.Frame.Width, v1.Frame.Width);
- Assert.Equal (t.Frame.Height, v1.Frame.Height);
+ // Top.Frame: 0, 0, 80, 25; Top.Bounds: 0, 0, 80, 25
+ // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+ // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Bounds
+ // as it is a subview of winAddedToTop, which has a border!
+ //Assert.Equal (top.Bounds.Width, v1AddedToWin.Frame.Width);
+ //Assert.Equal (top.Bounds.Height, v1AddedToWin.Frame.Height);
};
- v2.Initialized += (s, e) => {
+ v2AddedToWin.Initialized += (s, e) => {
v2c++;
- Assert.Equal (t.Frame.Width, v2.Frame.Width);
- Assert.Equal (t.Frame.Height, v2.Frame.Height);
+ // Top.Frame: 0, 0, 80, 25; Top.Bounds: 0, 0, 80, 25
+ // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+ // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Bounds
+ // as it is a subview of winAddedToTop, which has a border!
+ //Assert.Equal (top.Bounds.Width, v2AddedToWin.Frame.Width);
+ //Assert.Equal (top.Bounds.Height, v2AddedToWin.Frame.Height);
};
- sv1.Initialized += (s, e) => {
+ svAddedTov1.Initialized += (s, e) => {
sv1c++;
- Assert.Equal (t.Frame.Width, sv1.Frame.Width);
- Assert.Equal (t.Frame.Height, sv1.Frame.Height);
- Assert.False (sv1.CanFocus);
- Assert.Throws (() => sv1.CanFocus = true);
- Assert.False (sv1.CanFocus);
+ // Top.Frame: 0, 0, 80, 25; Top.Bounds: 0, 0, 80, 25
+ // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+ // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Bounds
+ // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of
+ // winAddedToTop, which has a border!
+ //Assert.Equal (top.Bounds.Width, svAddedTov1.Frame.Width);
+ //Assert.Equal (top.Bounds.Height, svAddedTov1.Frame.Height);
+ Assert.False (svAddedTov1.CanFocus);
+ Assert.Throws (() => svAddedTov1.CanFocus = true);
+ Assert.False (svAddedTov1.CanFocus);
};
- v1.Add (sv1);
- w.Add (v1, v2);
- t.Add (w);
+ v1AddedToWin.Add (svAddedTov1);
+ winAddedToTop.Add (v1AddedToWin, v2AddedToWin);
+ top.Add (winAddedToTop);
Application.Iteration += (s, a) => {
Application.Refresh ();
- t.Running = false;
+ top.Running = false;
};
- Application.Run (t);
+ Application.Run (top);
Application.Shutdown ();
Assert.Equal (1, tc);
@@ -343,14 +352,14 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (1, v2c);
Assert.Equal (1, sv1c);
- Assert.True (t.CanFocus);
- Assert.True (w.CanFocus);
- Assert.False (v1.CanFocus);
- Assert.False (v2.CanFocus);
- Assert.False (sv1.CanFocus);
+ Assert.True (top.CanFocus);
+ Assert.True (winAddedToTop.CanFocus);
+ Assert.False (v1AddedToWin.CanFocus);
+ Assert.False (v2AddedToWin.CanFocus);
+ Assert.False (svAddedTov1.CanFocus);
- v1.CanFocus = true;
- Assert.False (sv1.CanFocus); // False because sv1 was disposed and it isn't a subview of v1.
+ v1AddedToWin.CanFocus = true;
+ Assert.False (svAddedTov1.CanFocus); // False because sv1 was disposed and it isn't a subview of v1.
}
@@ -384,18 +393,18 @@ namespace Terminal.Gui.ViewTests {
};
w.Initialized += (s, e) => {
wc++;
- Assert.Equal (t.Frame.Width, w.Frame.Width);
- Assert.Equal (t.Frame.Height, w.Frame.Height);
+ Assert.Equal (t.Bounds.Width, w.Frame.Width);
+ Assert.Equal (t.Bounds.Height, w.Frame.Height);
};
v1.Initialized += (s, e) => {
v1c++;
- Assert.Equal (t.Frame.Width, v1.Frame.Width);
- Assert.Equal (t.Frame.Height, v1.Frame.Height);
+ //Assert.Equal (t.Bounds.Width, v1.Frame.Width);
+ //Assert.Equal (t.Bounds.Height, v1.Frame.Height);
};
v2.Initialized += (s, e) => {
v2c++;
- Assert.Equal (t.Frame.Width, v2.Frame.Width);
- Assert.Equal (t.Frame.Height, v2.Frame.Height);
+ //Assert.Equal (t.Bounds.Width, v2.Frame.Width);
+ //Assert.Equal (t.Bounds.Height, v2.Frame.Height);
};
w.Add (v1, v2);
t.Add (w);
@@ -505,12 +514,17 @@ namespace Terminal.Gui.ViewTests {
var runState = Application.Begin (top);
// BUGBUG: This is a SetRelativeLayout test. It should be moved to SetRelativeLayoutTests.cs
- view.Width = Dim.Fill ();
- view.Height = Dim.Fill ();
- Assert.Equal (10, view.Bounds.Width);
- Assert.Equal (1, view.Bounds.Height);
- view.LayoutStyle = LayoutStyle.Computed;
+ view.Width = Dim.Fill (); // Width should be 79 (Top.Width - 1)
+ Assert.Equal ("Fill(0)", view.Width.ToString ());
+ view.Height = Dim.Fill (); // Height should be 24 (Top.Height - 1)
+
+ // #3127: Before: Frame was not being set when Width and Height were set to Dim.Fill()
+ // After: Frame is set to the parent's Frame when Width and Height are set to Dim.Fill()
+ Assert.Equal (79, view.Bounds.Width);
+ Assert.Equal (24, view.Bounds.Height);
+ //view.LayoutStyle = LayoutStyle.Computed;
view.SetRelativeLayout (top.Bounds);
+ Assert.Equal ("Fill(0)", view.Width.ToString ());
Assert.Equal (1, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (79, view.Frame.Width);
@@ -758,61 +772,6 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (Rect.Empty, pos);
}
- [Fact, AutoInitShutdown]
- public void GetTextFormatterBoundsSize_GetSizeNeededForText_HotKeySpecifier ()
- {
- var text = "Say Hello 你";
- var horizontalView = new View () {
- Text = text,
- AutoSize = true,
- HotKeySpecifier = (Rune)'_'
- };
-
- var verticalView = new View () {
- Text = text,
- AutoSize = true,
- HotKeySpecifier = (Rune)'_',
- TextDirection = TextDirection.TopBottom_LeftRight
- };
- Application.Top.Add (horizontalView, verticalView);
- Application.Begin (Application.Top);
- ((FakeDriver)Application.Driver).SetBufferSize (50, 50);
-
- Assert.True (horizontalView.AutoSize);
- Assert.Equal (new Rect (0, 0, 12, 1), horizontalView.Frame);
- Assert.Equal (new Size (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
- //Assert.Equal (new Size (12, 1), horizontalView.GetSizeNeededForTextAndHotKey ());
- //Assert.Equal (horizontalView.TextFormatter.Size, horizontalView.GetSizeNeededForTextAndHotKey ());
- Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
-
- Assert.True (verticalView.AutoSize);
- // BUGBUG: v2 - Autosize is broken; disabling this test
- //Assert.Equal (new Rect (0, 0, 2, 11), verticalView.Frame);
- //Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ());
- //Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextAndHotKey ());
- //Assert.Equal (verticalView.TextFormatter.Size, verticalView.GetSizeNeededForTextAndHotKey ());
- Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
-
- text = "Say He_llo 你";
- horizontalView.Text = text;
- verticalView.Text = text;
-
- Assert.True (horizontalView.AutoSize);
- Assert.Equal (new Rect (0, 0, 12, 1), horizontalView.Frame);
- Assert.Equal (new Size (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ());
- //Assert.Equal (new Size (13, 1), horizontalView.GetSizeNeededForTextAndHotKey ());
- //Assert.Equal (horizontalView.TextFormatter.Size, horizontalView.GetSizeNeededForTextAndHotKey ());
- Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ());
-
- Assert.True (verticalView.AutoSize);
- // BUGBUG: v2 - Autosize is broken; disabling this test
- //Assert.Equal (new Rect (0, 0, 2, 11), verticalView.Frame);
- //Assert.Equal (new Size (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ());
- //Assert.Equal (new Size (2, 12), verticalView.GetSizeNeededForTextAndHotKey ());
- //Assert.Equal (verticalView.TextFormatter.Size, verticalView.GetSizeNeededForTextAndHotKey ());
- //Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ());
- }
-
[Fact, TestRespondersDisposed]
public void IsAdded_Added_Removed ()
{
@@ -823,7 +782,7 @@ namespace Terminal.Gui.ViewTests {
Assert.True (view.IsAdded);
top.Remove (view);
Assert.False (view.IsAdded);
-
+
top.Dispose ();
view.Dispose ();
}
@@ -831,14 +790,16 @@ namespace Terminal.Gui.ViewTests {
[Fact, AutoInitShutdown]
public void Visible_Clear_The_View_Output ()
{
- var label = new Label ("Testing visibility.");
+ var view = new View ("Testing visibility."); // use View, not Label to avoid AutoSize == true
+ Assert.Equal ("Testing visibility.".Length, view.Frame.Width);
+ Assert.Equal (1, view.Height);
var win = new Window ();
- win.Add (label);
+ win.Add (view);
var top = Application.Top;
top.Add (win);
var rs = Application.Begin (top);
- Assert.True (label.Visible);
+ Assert.True (view.Visible);
((FakeDriver)Application.Driver).SetBufferSize (30, 5);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌────────────────────────────┐
@@ -848,7 +809,7 @@ namespace Terminal.Gui.ViewTests {
└────────────────────────────┘
", output);
- label.Visible = false;
+ view.Visible = false;
bool firstIteration = false;
Application.RunIteration (ref rs, ref firstIteration);
@@ -1044,8 +1005,7 @@ At 0,0
view.Frame = new Rect (1, 1, 10, 1);
Assert.Equal (new Rect (1, 1, 10, 1), view.Frame);
- Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
- view.LayoutStyle = LayoutStyle.Absolute;
+ Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
Assert.Equal (new Rect (0, 0, 10, 1), view.Bounds);
Assert.Equal (new Rect (0, 0, 10, 1), view._needsDisplayRect);
top.Draw ();
@@ -1115,8 +1075,7 @@ At 0,0
view.Frame = new Rect (1, 1, 10, 1);
Assert.Equal (new Rect (1, 1, 10, 1), view.Frame);
- Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
- view.LayoutStyle = LayoutStyle.Absolute;
+ Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
Assert.Equal (new Rect (0, 0, 10, 1), view.Bounds);
Assert.Equal (new Rect (0, 0, 10, 1), view._needsDisplayRect);
view.Draw ();
@@ -1189,8 +1148,7 @@ At 0,0
view.Frame = new Rect (3, 3, 10, 1);
Assert.Equal (new Rect (3, 3, 10, 1), view.Frame);
- Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
- view.LayoutStyle = LayoutStyle.Absolute;
+ Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
Assert.Equal (new Rect (0, 0, 10, 1), view.Bounds);
Assert.Equal (new Rect (0, 0, 10, 1), view._needsDisplayRect);
top.Draw ();
@@ -1351,7 +1309,7 @@ At 0,0
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = 0, // don't overcomplicate unit tests
- Y = 0
+ Y = 0
};
var button = new Button ("Press me!") {
diff --git a/UnitTests/Views/Toplevel/WindowTests.cs b/UnitTests/Views/Toplevel/WindowTests.cs
index 08d922321..b71501b9d 100644
--- a/UnitTests/Views/Toplevel/WindowTests.cs
+++ b/UnitTests/Views/Toplevel/WindowTests.cs
@@ -15,19 +15,19 @@ public class WindowTests {
// Parameterless
var r = new Window ();
Assert.NotNull (r);
- Assert.Equal (string.Empty, r.Title);
+ Assert.Equal (string.Empty, r.Title);
Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
- Assert.Equal ("Window()(0,0,0,0)", r.ToString ());
+ Assert.Equal ("Window()(0,0,0,0)", r.ToString ());
Assert.True (r.CanFocus);
Assert.False (r.HasFocus);
Assert.Equal (new Rect (0, 0, 0, 0), r.Bounds);
Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
Assert.Null (r.Focused);
Assert.NotNull (r.ColorScheme);
+ Assert.Equal (0, r.X);
+ Assert.Equal (0, r.Y);
Assert.Equal (Dim.Fill (), r.Width);
Assert.Equal (Dim.Fill (), r.Height);
- Assert.Null (r.X);
- Assert.Null (r.Y);
Assert.False (r.IsCurrentTop);
Assert.Empty (r.Id);
Assert.False (r.WantContinuousButtonPressed);
@@ -39,8 +39,8 @@ public class WindowTests {
// Empty Rect
r = new Window (Rect.Empty) { Title = "title" };
Assert.NotNull (r);
- Assert.Equal ("title", r.Title);
- Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
+ Assert.Equal ("title", r.Title);
+ Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
Assert.Equal ("Window(title)(0,0,0,0)", r.ToString ());
Assert.True (r.CanFocus);
Assert.False (r.HasFocus);
@@ -48,10 +48,10 @@ public class WindowTests {
Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
Assert.Null (r.Focused);
Assert.NotNull (r.ColorScheme);
- Assert.Null (r.Width); // All view Dim are initialized now in the IsAdded setter,
- Assert.Null (r.Height); // avoiding Dim errors.
- Assert.Null (r.X); // All view Pos are initialized now in the IsAdded setter,
- Assert.Null (r.Y); // avoiding Pos errors.
+ Assert.Equal (0, r.X);
+ Assert.Equal (0, r.Y);
+ Assert.Equal (0, r.Width);
+ Assert.Equal (0, r.Height);
Assert.False (r.IsCurrentTop);
Assert.Equal (r.Title, r.Id);
Assert.False (r.WantContinuousButtonPressed);
@@ -64,7 +64,7 @@ public class WindowTests {
r = new Window (new Rect (1, 2, 3, 4)) { Title = "title" };
Assert.Equal ("title", r.Title);
Assert.NotNull (r);
- Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
+ Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
Assert.Equal ("Window(title)(1,2,3,4)", r.ToString ());
Assert.True (r.CanFocus);
Assert.False (r.HasFocus);
@@ -72,10 +72,10 @@ public class WindowTests {
Assert.Equal (new Rect (1, 2, 3, 4), r.Frame);
Assert.Null (r.Focused);
Assert.NotNull (r.ColorScheme);
- Assert.Null (r.Width);
- Assert.Null (r.Height);
- Assert.Null (r.X);
- Assert.Null (r.Y);
+ Assert.Equal (1, r.X);
+ Assert.Equal (2, r.Y);
+ Assert.Equal (3, r.Width);
+ Assert.Equal (4, r.Height);
Assert.False (r.IsCurrentTop);
Assert.Equal (r.Title, r.Id);
Assert.False (r.WantContinuousButtonPressed);