diff --git a/Terminal.Gui/View/Layout/PosDim.cs b/Terminal.Gui/View/Layout/PosDim.cs index 6da3a0a03..8a171f8c7 100644 --- a/Terminal.Gui/View/Layout/PosDim.cs +++ b/Terminal.Gui/View/Layout/PosDim.cs @@ -1,4 +1,6 @@ -namespace Terminal.Gui; +using static Terminal.Gui.Dialog; + +namespace Terminal.Gui; /// /// Describes the position of a which can be an absolute value, a percentage, centered, or @@ -43,7 +45,7 @@ /// /// /// -/// +/// /// /// /// Creates a object that is anchored to the end (right side or bottom) of @@ -125,20 +127,36 @@ public class Pos { /// - /// Creates a object that is anchored to the end (right side or bottom) of the dimension, useful - /// to flush the layout from the right or bottom. + /// Creates a object that is anchored to the end (right side or + /// bottom) of the SuperView, minus the respective dimension of the View. This is equivalent to using + /// , + /// with an offset equivalent to the View's respective dimension. + /// + /// The object anchored to the end (the bottom or the right side) minus the View's dimension. + /// + /// This sample shows how align a to the bottom-right the SuperView. + /// + /// anchorButton.X = Pos.AnchorEnd (); + /// anchorButton.Y = Pos.AnchorEnd (); + /// + /// + public static Pos AnchorEnd () { return new PosAnchorEnd (); } + + /// + /// Creates a object that is anchored to the end (right side or bottom) of the SuperView, + /// useful to flush the layout from the right or bottom. See also , which uses the view + /// dimension to ensure the view is fully visible. /// /// The object anchored to the end (the bottom or the right side). /// The view will be shifted left or up by the amount specified. /// - /// This sample shows how align a to the bottom-right of a . + /// This sample shows how align a 10 column wide to the bottom-right the SuperView. /// - /// // See Issue #502 - /// anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton)); - /// anchorButton.Y = Pos.AnchorEnd (1); + /// anchorButton.X = Pos.AnchorEnd (10); + /// anchorButton.Y = 1 /// /// - public static Pos AnchorEnd (int offset = 0) + public static Pos AnchorEnd (int offset) { if (offset < 0) { @@ -153,25 +171,17 @@ public class Pos /// The value to convert to the . public static Pos At (int n) { return new PosAbsolute (n); } - /// - /// Creates a object that tracks the Bottom (Y+Height) coordinate of the specified - /// - /// - /// The that depends on the other view. - /// The that will be tracked. - public static Pos Bottom (View view) { return new PosView (view, 3); } - /// Creates a object that can be used to center the . /// The center Pos. /// - /// This creates a that is centered horizontally, is 50% of the way down, is 30% the height, and + /// This creates a centered horizontally, is 50% of the way down, is 30% the height, and /// is 80% the width of the it added to. /// /// var textView = new TextView () { - /// X = Pos.Center (), - /// Y = Pos.Percent (50), - /// Width = Dim.Percent (80), - /// Height = Dim.Percent (30), + /// X = Pos.Center (), + /// Y = Pos.Percent (50), + /// Width = Dim.Percent (80), + /// Height = Dim.Percent (30), /// }; /// /// @@ -197,11 +207,6 @@ public class Pos /// A hash code for the current object. public override int GetHashCode () { return Anchor (0).GetHashCode (); } - /// Creates a object that tracks the Left (X) position of the specified . - /// The that depends on the other view. - /// The that will be tracked. - public static Pos Left (View view) { return new PosView (view, 0); } - /// Adds a to a , yielding a new . /// The first to add. /// The second to add. @@ -214,7 +219,11 @@ public class Pos } var newPos = new PosCombine (true, left, right); - SetPosCombine (left, newPos); + + if (left is PosView view) + { + view.Target.SetNeedsLayout (); + } return newPos; } @@ -239,75 +248,109 @@ public class Pos } var newPos = new PosCombine (false, left, right); - SetPosCombine (left, newPos); + + if (left is PosView view) + { + view.Target.SetNeedsLayout (); + } return newPos; } /// Creates a percentage object /// The percent object. - /// A value between 0 and 100 representing the percentage. + /// A value between 0 and 100 representing the percentage. /// - /// This creates a that is centered horizontally, is 50% of the way down, is 30% the height, and + /// This creates a centered horizontally, is 50% of the way down, is 30% the height, and /// is 80% the width of the it added to. /// - /// var textView = new TextView () { - /// X = Pos.Center (), - /// Y = Pos.Percent (50), - /// Width = Dim.Percent (80), - /// Height = Dim.Percent (30), + /// var textView = new TextField { + /// X = Pos.Center (), + /// Y = Pos.Percent (50), + /// Width = Dim.Percent (80), + /// Height = Dim.Percent (30), /// }; /// /// - public static Pos Percent (float n) + public static Pos Percent (float percent) { - if (n is < 0 or > 100) + if (percent is < 0 or > 100) { - throw new ArgumentException ("Percent value must be between 0 and 100"); + throw new ArgumentException ("Percent value must be between 0 and 100."); } - return new PosFactor (n / 100); + return new PosFactor (percent / 100); } + /// Creates a object that tracks the Top (Y) position of the specified . + /// The that depends on the other view. + /// The that will be tracked. + public static Pos Top (View view) { return new PosView (view, Side.Top); } + + /// Creates a object that tracks the Top (Y) position of the specified . + /// The that depends on the other view. + /// The that will be tracked. + public static Pos Y (View view) { return new PosView (view, Side.Top); } + + /// Creates a object that tracks the Left (X) position of the specified . + /// The that depends on the other view. + /// The that will be tracked. + public static Pos Left (View view) { return new PosView (view, Side.Left); } + + /// Creates a object that tracks the Left (X) position of the specified . + /// The that depends on the other view. + /// The that will be tracked. + public static Pos X (View view) { return new PosView (view, Side.Left); } + + /// + /// Creates a object that tracks the Bottom (Y+Height) coordinate of the specified + /// + /// + /// The that depends on the other view. + /// The that will be tracked. + public static Pos Bottom (View view) { return new PosView (view, Side.Bottom); } + /// /// Creates a object that tracks the Right (X+Width) coordinate of the specified /// . /// /// The that depends on the other view. /// The that will be tracked. - public static Pos Right (View view) { return new PosView (view, 2); } - - /// Creates a object that tracks the Top (Y) position of the specified . - /// The that depends on the other view. - /// The that will be tracked. - public static Pos Top (View view) { return new PosView (view, 1); } - - /// Creates a object that tracks the Left (X) position of the specified . - /// The that depends on the other view. - /// The that will be tracked. - public static Pos X (View view) { return new PosView (view, 0); } - - /// Creates a object that tracks the Top (Y) position of the specified . - /// The that depends on the other view. - /// The that will be tracked. - public static Pos Y (View view) { return new PosView (view, 1); } + public static Pos Right (View view) { return new PosView (view, Side.Right); } + /// + /// Gets a position that is anchored to a certain point in the layout. This method is typically used + /// internally by the layout system to determine where a View should be positioned. + /// + /// The width of the area where the View is being positioned (Superview.ContentSize). + /// + /// An integer representing the calculated position. The way this position is calculated depends on the specific + /// subclass of Pos that is used. For example, PosAbsolute returns a fixed position, PosAnchorEnd returns a + /// position that is anchored to the end of the layout, and so on. + /// internal virtual int Anchor (int width) { return 0; } - private static void SetPosCombine (Pos left, PosCombine newPos) - { - var view = left as PosView; + /// + /// Calculates and returns the position of a object. It takes into account the dimension of the + /// superview and the dimension of the view itself. + /// + /// + /// The dimension of the superview. This could be the width for x-coordinate calculation or the + /// height for y-coordinate calculation. + /// + /// The dimension of the View. It could be the current width or height. + /// Obsolete; to be deprecated. + /// Obsolete; to be deprecated. + /// + /// The calculated position of the View. The way this position is calculated depends on the specific subclass of Pos + /// that + /// is used. + /// + internal virtual int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize) { return Anchor (superviewDimension); } - if (view is { }) - { - view.Target.SetNeedsLayout (); - } - } - - internal class PosAbsolute : Pos + internal class PosAbsolute (int n) : Pos { - private readonly int _n; - public PosAbsolute (int n) { _n = n; } + private readonly int _n = n; public override bool Equals (object other) { return other is PosAbsolute abs && abs._n == _n; } public override int GetHashCode () { return _n.GetHashCode (); } public override string ToString () { return $"Absolute({_n})"; } @@ -317,30 +360,58 @@ public class Pos internal class PosAnchorEnd : Pos { private readonly int _offset; + public PosAnchorEnd () { UseDimForOffset = true; } public PosAnchorEnd (int offset) { _offset = offset; } public override bool Equals (object other) { return other is PosAnchorEnd anchorEnd && anchorEnd._offset == _offset; } public override int GetHashCode () { return _offset.GetHashCode (); } - public override string ToString () { return $"AnchorEnd({_offset})"; } - internal override int Anchor (int width) { return width - _offset; } + + /// + /// If true, the offset is the width of the view, if false, the offset is the offset value. + /// + internal bool UseDimForOffset { get; set; } + + public override string ToString () { return UseDimForOffset ? "AnchorEnd()" : $"AnchorEnd({_offset})"; } + + internal override int Anchor (int width) + { + if (UseDimForOffset) + { + return width; + } + + return width - _offset; + } + + internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize) + { + int newLocation = Anchor (superviewDimension); + + if (UseDimForOffset) + { + newLocation -= dim.Anchor (superviewDimension); + } + + return newLocation; + } } internal class PosCenter : Pos { public override string ToString () { return "Center"; } internal override int Anchor (int width) { return width / 2; } + + internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize) + { + int newDimension = Math.Max (dim.Calculate (0, superviewDimension, autosize, autoSize), 0); + + return Anchor (superviewDimension - newDimension); + } } - internal class PosCombine : Pos + internal class PosCombine (bool add, Pos left, Pos right) : Pos { - internal bool _add; - internal Pos _left, _right; - - public PosCombine (bool add, Pos left, Pos right) - { - _left = left; - _right = right; - _add = add; - } + internal bool _add = add; + internal Pos _left = left, _right = right; public override string ToString () { return $"Combine({_left}{(_add ? '+' : '-')}{_right})"; } @@ -356,12 +427,25 @@ public class Pos return la - ra; } + + internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize) + { + int newDimension = dim.Calculate (0, superviewDimension, autosize, autoSize); + int left = _left.Calculate (superviewDimension, dim, autosize, autoSize); + int right = _right.Calculate (superviewDimension, dim, autosize, autoSize); + + if (_add) + { + return left + right; + } + + return left - right; + } } - internal class PosFactor : Pos + internal class PosFactor (float factor) : Pos { - private readonly float _factor; - public PosFactor (float n) { _factor = n; } + private readonly float _factor = factor; public override bool Equals (object other) { return other is PosFactor f && f._factor == _factor; } public override int GetHashCode () { return _factor.GetHashCode (); } public override string ToString () { return $"Factor({_factor})"; } @@ -369,78 +453,77 @@ public class Pos } // Helper class to provide dynamic value by the execution of a function that returns an integer. - internal class PosFunc : Pos + internal class PosFunc (Func n) : Pos { - private readonly Func _function; - public PosFunc (Func n) { _function = n; } + private readonly Func _function = n; public override bool Equals (object other) { return other is PosFunc f && f._function () == _function (); } public override int GetHashCode () { return _function.GetHashCode (); } public override string ToString () { return $"PosFunc({_function ()})"; } internal override int Anchor (int width) { return _function (); } } - internal class PosView : Pos + /// + /// Describes which side of the view to use for the position. + /// + public enum Side { - public readonly View Target; + /// + /// The left (X) side of the view. + /// + Left = 0, - private readonly int side; + /// + /// The top (Y) side of the view. + /// + Top = 1, - public PosView (View view, int side) - { - Target = view; - this.side = side; - } + /// + /// The right (X + Width) side of the view. + /// + Right = 2, + + /// + /// The bottom (Y + Height) side of the view. + /// + Bottom = 3 + } + + internal class PosView (View view, Side side) : Pos + { + public readonly View Target = view; public override bool Equals (object other) { return other is PosView abs && abs.Target == Target; } public override int GetHashCode () { return Target.GetHashCode (); } public override string ToString () { - string tside; - - switch (side) + string sideString = side switch { - case 0: - tside = "x"; + Side.Left => "left", + Side.Top => "top", + Side.Right => "right", + Side.Bottom => "bottom", + _ => "unknown" + }; - break; - case 1: - tside = "y"; - - break; - case 2: - tside = "right"; - - break; - case 3: - tside = "bottom"; - - break; - default: - tside = "unknown"; - - break; - } - - if (Target is null) + if (Target == null) { throw new NullReferenceException (nameof (Target)); } - return $"View(side={tside},target={Target})"; + return $"View(side={sideString},target={Target})"; } internal override int Anchor (int width) { - switch (side) + return side switch { - case 0: return Target.Frame.X; - case 1: return Target.Frame.Y; - case 2: return Target.Frame.Right; - case 3: return Target.Frame.Bottom; - default: - return 0; - } + Side.Left => Target.Frame.X, + Side.Top => Target.Frame.Y, + Side.Right => Target.Frame.Right, + Side.Bottom => Target.Frame.Bottom, + _ => 0 + }; } } } @@ -486,8 +569,8 @@ public class Pos /// /// /// -/// Creates a object that fills the dimension, leaving the specified number -/// of columns for a margin. +/// Creates a object that fills the dimension from the View's X position +/// to the end of the super view's width, leaving the specified number of columns for a margin. /// /// /// @@ -545,11 +628,11 @@ public class Dim /// Creates a object that tracks the Height of the specified . /// The height of the other . /// The view that will be tracked. - public static Dim Height (View view) { return new DimView (view, 0); } + public static Dim Height (View view) { return new DimView (view, Dimension.Height); } - /// Adds a to a , yielding a new . - /// The first to add. - /// The second to add. + /// Adds a to a , yielding a new . + /// The first to add. + /// The second to add. /// The that is the sum of the values of left and right. public static Dim operator + (Dim left, Dim right) { @@ -559,7 +642,7 @@ public class Dim } var newDim = new DimCombine (true, left, right); - SetDimCombine (left, newDim); + (left as DimView)?.Target.SetNeedsLayout (); return newDim; } @@ -570,11 +653,11 @@ public class Dim public static implicit operator Dim (int n) { return new DimAbsolute (n); } /// - /// Subtracts a from a , yielding a new + /// Subtracts a from a , yielding a new /// . /// - /// The to subtract from (the minuend). - /// The to subtract (the subtrahend). + /// The to subtract from (the minuend). + /// The to subtract (the subtrahend). /// The that is the left minus right. public static Dim operator - (Dim left, Dim right) { @@ -584,38 +667,40 @@ public class Dim } var newDim = new DimCombine (false, left, right); - SetDimCombine (left, newDim); + (left as DimView)?.Target.SetNeedsLayout (); return newDim; } /// Creates a percentage object that is a percentage of the width or height of the SuperView. /// The percent object. - /// A value between 0 and 100 representing the percentage. - /// - /// If true the Percent is computed based on the remaining space after the X/Y anchor positions. If - /// false is computed based on the whole original space. + /// A value between 0 and 100 representing the percentage. + /// + /// If the dimension is computed using the View's position ( or + /// ). + /// If the dimension is computed using the View's . /// /// - /// This initializes a that is centered horizontally, is 50% of the way down, is 30% the height, - /// and is 80% the width of the it added to. + /// This initializes a that will be centered horizontally, is 50% of the way down, is 30% the + /// height, + /// and is 80% the width of the SuperView. /// - /// var textView = new TextView () { - /// X = Pos.Center (), - /// Y = Pos.Percent (50), - /// Width = Dim.Percent (80), - /// Height = Dim.Percent (30), + /// var textView = new TextField { + /// X = Pos.Center (), + /// Y = Pos.Percent (50), + /// Width = Dim.Percent (80), + /// Height = Dim.Percent (30), /// }; /// /// - public static Dim Percent (float n, bool r = false) + public static Dim Percent (float percent, bool usePosition = false) { - if (n is < 0 or > 100) + if (percent is < 0 or > 100) { throw new ArgumentException ("Percent value must be between 0 and 100"); } - return new DimFactor (n / 100, r); + return new DimFactor (percent / 100, usePosition); } /// Creates an Absolute from the specified integer value. @@ -626,34 +711,63 @@ public class Dim /// Creates a object that tracks the Width of the specified . /// The width of the other . /// The view that will be tracked. - public static Dim Width (View view) { return new DimView (view, 1); } + public static Dim Width (View view) { return new DimView (view, Dimension.Width); } + /// + /// Gets a dimension that is anchored to a certain point in the layout. + /// This method is typically used internally by the layout system to determine the size of a View. + /// + /// The width of the area where the View is being sized (Superview.ContentSize). + /// + /// An integer representing the calculated dimension. The way this dimension is calculated depends on the specific + /// subclass of Dim that is used. For example, DimAbsolute returns a fixed dimension, DimFactor returns a + /// dimension that is a certain percentage of the super view's size, and so on. + /// internal virtual int Anchor (int width) { return 0; } - // BUGBUG: newPos is never used. - private static void SetDimCombine (Dim left, DimCombine newPos) { (left as DimView)?.Target.SetNeedsLayout (); } - - internal class DimAbsolute : Dim + /// + /// Calculates and returns the dimension of a object. It takes into account the location of the + /// , its current size, and whether it should automatically adjust its size based on its content. + /// + /// + /// The starting point from where the size calculation begins. It could be the left edge for width calculation or the + /// top edge for height calculation. + /// + /// The current size of the View. It could be the current width or height. + /// Obsolete; To be deprecated. + /// Obsolete; To be deprecated. + /// + /// The calculated size of the View. The way this size is calculated depends on the specific subclass of Dim that + /// is used. + /// + internal virtual int Calculate (int location, int dimension, int autosize, bool autoSize) { - private readonly int _n; - public DimAbsolute (int n) { _n = n; } + int newDimension = Math.Max (Anchor (dimension - location), 0); + + return autoSize && autosize > newDimension ? autosize : newDimension; + } + + internal class DimAbsolute (int n) : Dim + { + private readonly int _n = n; public override bool Equals (object other) { return other is DimAbsolute abs && abs._n == _n; } public override int GetHashCode () { return _n.GetHashCode (); } public override string ToString () { return $"Absolute({_n})"; } internal override int Anchor (int width) { return _n; } + + internal override int Calculate (int location, int dimension, int autosize, bool autoSize) + { + // DimAbsolute.Anchor (int width) ignores width and returns n + int newDimension = Math.Max (Anchor (0), 0); + + return autoSize && autosize > newDimension ? autosize : newDimension; + } } - internal class DimCombine : Dim + internal class DimCombine (bool add, Dim left, Dim right) : Dim { - internal bool _add; - internal Dim _left, _right; - - public DimCombine (bool add, Dim left, Dim right) - { - _left = left; - _right = right; - _add = add; - } + internal bool _add = add; + internal Dim _left = left, _right = right; public override string ToString () { return $"Combine({_left}{(_add ? '+' : '-')}{_right})"; } @@ -669,30 +783,49 @@ public class Dim return la - ra; } + + internal override int Calculate (int location, int dimension, int autosize, bool autoSize) + { + int leftNewDim = _left.Calculate (location, dimension, autosize, autoSize); + int rightNewDim = _right.Calculate (location, dimension, autosize, autoSize); + + int newDimension; + + if (_add) + { + newDimension = leftNewDim + rightNewDim; + } + else + { + newDimension = Math.Max (0, leftNewDim - rightNewDim); + } + + return autoSize && autosize > newDimension ? autosize : newDimension; + } } - internal class DimFactor : Dim + internal class DimFactor (float factor, bool remaining = false) : Dim { - private readonly float _factor; - private readonly bool _remaining; - - public DimFactor (float n, bool r = false) - { - _factor = n; - _remaining = r; - } + private readonly float _factor = factor; + private readonly bool _remaining = remaining; public override bool Equals (object other) { return other is DimFactor f && f._factor == _factor && f._remaining == _remaining; } public override int GetHashCode () { return _factor.GetHashCode (); } public bool IsFromRemaining () { return _remaining; } public override string ToString () { return $"Factor({_factor},{_remaining})"; } internal override int Anchor (int width) { return (int)(width * _factor); } + + internal override int Calculate (int location, int dimension, int autosize, bool autoSize) + { + int newDimension = _remaining ? Math.Max (Anchor (dimension - location), 0) : Anchor (dimension); + + return autoSize && autosize > newDimension ? autosize : newDimension; + } } - internal class DimFill : Dim + internal class DimFill (int margin) : Dim { - private readonly int _margin; - public DimFill (int margin) { _margin = margin; } + private readonly int _margin = margin; public override bool Equals (object other) { return other is DimFill fill && fill._margin == _margin; } public override int GetHashCode () { return _margin.GetHashCode (); } public override string ToString () { return $"Fill({_margin})"; } @@ -700,21 +833,36 @@ public class Dim } // Helper class to provide dynamic value by the execution of a function that returns an integer. - internal class DimFunc : Dim + internal class DimFunc (Func n) : Dim { - private readonly Func _function; - public DimFunc (Func n) { _function = n; } + private readonly Func _function = n; public override bool Equals (object other) { return other is DimFunc f && f._function () == _function (); } public override int GetHashCode () { return _function.GetHashCode (); } public override string ToString () { return $"DimFunc({_function ()})"; } internal override int Anchor (int width) { return _function (); } } + /// + /// + /// + public enum Dimension + { + /// + /// The height dimension. + /// + Height = 0, + + /// + /// The width dimension. + /// + Width = 1 + } + internal class DimView : Dim { - private readonly int _side; + private readonly Dimension _side; - public DimView (View view, int side) + internal DimView (View view, Dimension side) { Target = view; _side = side; @@ -726,29 +874,29 @@ public class Dim public override string ToString () { - if (Target is null) + if (Target == null) { throw new NullReferenceException (); } - string tside = _side switch - { - 0 => "Height", - 1 => "Width", - _ => "unknown" - }; + string sideString = _side switch + { + Dimension.Height => "Height", + Dimension.Width => "Width", + _ => "unknown" + }; - return $"View({tside},{Target})"; + return $"View({sideString},{Target})"; } internal override int Anchor (int width) { return _side switch - { - 0 => Target.Frame.Height, - 1 => Target.Frame.Width, - _ => 0 - }; + { + Dimension.Height => Target.Frame.Height, + Dimension.Width => Target.Frame.Width, + _ => 0 + }; } } } diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index f593d93d2..1afa0994b 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.IO.Compression; namespace Terminal.Gui; @@ -88,11 +87,13 @@ public partial class View private void SetFrame (Rectangle frame) { - Rectangle oldViewport = Rectangle.Empty; + var oldViewport = Rectangle.Empty; + if (IsInitialized) { oldViewport = Viewport; } + // This is the only place where _frame should be set directly. Use Frame = or SetFrame instead. _frame = frame; @@ -113,7 +114,7 @@ public partial class View // Adornments don't have SuperViews; use Adornment.FrameToScreen override // which will give us the screen coordinates of the parent - var parentScreen = adornment.FrameToScreen (); + Rectangle parentScreen = adornment.FrameToScreen (); // Now add our Frame location parentScreen.Offset (screen.X, screen.Y); @@ -142,7 +143,7 @@ public partial class View { if (SuperView is null) { - return new Point (x - Frame.X, y - Frame.Y); + return new (x - Frame.X, y - Frame.Y); } Point superViewViewportOffset = SuperView.GetViewportOffsetFromFrame (); @@ -242,7 +243,8 @@ public partial class View /// The object representing the height of the view (the number of rows). /// /// - /// The dimension is relative to the 's Content, which is bound by . + /// The dimension is relative to the 's Content, which is bound by + /// . /// /// /// If set to a relative value (e.g. ) the value is indeterminate until the view has @@ -283,8 +285,8 @@ public partial class View if (IsAdded && AutoSize && !isValidNewAutoSize) { Debug.WriteLine ( - @$"Must set AutoSize to false before setting the {nameof (Height)}." - ); + @$"Must set AutoSize to false before setting the {nameof (Height)}." + ); AutoSize = false; } @@ -299,7 +301,8 @@ public partial class View /// The object representing the width of the view (the number of columns). /// /// - /// The dimension is relative to the 's Content, which is bound by . + /// The dimension is relative to the 's Content, which is bound by + /// . /// /// /// If set to a relative value (e.g. ) the value is indeterminate until the view has @@ -330,7 +333,7 @@ public partial class View if (AutoSize) { - Debug.WriteLine($@"Must set AutoSize to false before setting {nameof(Width)}."); + Debug.WriteLine ($@"Must set AutoSize to false before setting {nameof (Width)}."); AutoSize = false; } @@ -338,7 +341,7 @@ public partial class View if (IsAdded && AutoSize && !isValidNewAutoSize) { - Debug.WriteLine($@"Must set AutoSize to false before setting {nameof(Width)}."); + Debug.WriteLine ($@"Must set AutoSize to false before setting {nameof (Width)}."); AutoSize = false; } @@ -656,6 +659,7 @@ public partial class View int startOffsetY = y - (start.Frame.Y + viewportOffset.Y); View? subview = null; + for (int i = start.InternalSubviews.Count - 1; i >= 0; i--) { if (start.InternalSubviews [i].Visible @@ -750,8 +754,8 @@ public partial class View } //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}"); - bool menuVisible = false; - bool statusVisible = false; + var menuVisible = false; + var statusVisible = false; if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top) { @@ -907,6 +911,7 @@ public partial class View OnLayoutComplete (new (ContentSize)); } + private void LayoutSubview (View v, Size contentSize) { v.SetRelativeLayout (contentSize); @@ -964,6 +969,7 @@ public partial class View SetNeedsLayout (); } } + internal bool LayoutNeeded { get; private set; } = true; /// @@ -995,11 +1001,11 @@ public partial class View /// ). /// /// - /// - /// If , , , or are - /// absolute, they will be updated to reflect the new size and position of the view. Otherwise, they - /// are left unchanged. - /// + /// + /// If , , , or are + /// absolute, they will be updated to reflect the new size and position of the view. Otherwise, they + /// are left unchanged. + /// /// /// /// The size of the SuperView's content (nominally the same as this.SuperView.ContentSize). @@ -1011,175 +1017,25 @@ public partial class View Debug.Assert (_width is { }); Debug.Assert (_height is { }); - int newX, newW, newY, newH; - var autosize = Size.Empty; + 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 (); + 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. + int newX = _x.Calculate (superviewContentSize.Width, _width, autoSize.Width, AutoSize); + int newW = _width.Calculate (newX, superviewContentSize.Width, autoSize.Width, AutoSize); + int newY = _y.Calculate (superviewContentSize.Height, _height, autoSize.Height, AutoSize); + int newH = _height.Calculate (newY, superviewContentSize.Height, autoSize.Height, AutoSize); - // Returns the new dimension (width or height) and location (x or y) for the View given - // the superview's Viewport - // 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, - Size superviewContentSize, - 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; + Rectangle newFrame = new (newX, newY, newW, newH); - switch (d) - { - case Dim.DimCombine combine: - // TODO: Move combine logic into DimCombine? - int leftNewDim = GetNewDimension (combine._left, location, dimension, autosize); - int 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: - // DimAbsolute.Anchor (int width) ignores width and returns n - newDimension = Math.Max (d.Anchor (0), 0); - - // BUGBUG: AutoSize does two things: makes text fit AND changes the view's dimensions - 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; - int superviewDimension = width ? superviewContentSize.Width : superviewContentSize.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, - superviewContentSize, - combine._left, - dim, - autosizeDimension - ); - - (right, newDimension) = GetNewLocationAndDimension ( - width, - superviewContentSize, - 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, superviewContentSize, _x, _width, autosize.Width); - - // vertical/height - (newY, newH) = GetNewLocationAndDimension (false, superviewContentSize, _y, _height, autosize.Height); - - Rectangle r = new (newX, newY, newW, newH); - - if (Frame != r) + if (Frame != newFrame) { // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height, making // the view LayoutStyle.Absolute. - SetFrame (r); + SetFrame (newFrame); if (_x is Pos.PosAbsolute) { @@ -1207,18 +1063,18 @@ public partial class View if (AutoSize) { - if (autosize.Width == 0 || autosize.Height == 0) + if (autoSize.Width == 0 || autoSize.Height == 0) { // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height, making // the view LayoutStyle.Absolute. - SetFrame (_frame with { Size = autosize }); + SetFrame (_frame with { Size = autoSize }); - if (autosize.Width == 0) + if (autoSize.Width == 0) { _width = 0; } - if (autosize.Height == 0) + if (autoSize.Height == 0) { _height = 0; } @@ -1432,4 +1288,4 @@ public partial class View public bool ValidatePosDim { get; set; } #endregion -} \ No newline at end of file +} diff --git a/UICatalog/Scenarios/Adornments.cs b/UICatalog/Scenarios/Adornments.cs index 27aefbddc..ab68fb961 100644 --- a/UICatalog/Scenarios/Adornments.cs +++ b/UICatalog/Scenarios/Adornments.cs @@ -38,7 +38,7 @@ public class Adornments : Scenario app.Add (window); var tf1 = new TextField { Width = 10, Text = "TextField" }; - var color = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (11) }; + var color = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () }; color.BorderStyle = LineStyle.RoundedDotted; color.ColorChanged += (s, e) => @@ -68,15 +68,16 @@ public class Adornments : Scenario }; label.Border.Thickness = new (1, 3, 1, 1); - var btnButtonInWindow = new Button { X = Pos.AnchorEnd (10), Y = Pos.AnchorEnd (1), Text = "Button" }; + var btnButtonInWindow = new Button { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" }; - var tv = new Label + var labelAnchorEnd = new Label { AutoSize = false, - Y = Pos.AnchorEnd (3), - Width = 25, - Height = Dim.Fill (), - Text = "Label\nY=AnchorEnd(3),Height=Dim.Fill()" + Y = Pos.AnchorEnd (), + Width = 40, + Height = Dim.Percent(20), + Text = "Label\nY=AnchorEnd(),Height=Dim.Percent(10)", + ColorScheme = Colors.ColorSchemes ["Error"] }; window.Margin.Data = "Margin"; @@ -94,7 +95,7 @@ public class Adornments : Scenario }; longLabel.TextFormatter.WordWrap = true; - window.Add (tf1, color, button, label, btnButtonInWindow, tv, longLabel); + window.Add (tf1, color, button, label, btnButtonInWindow, labelAnchorEnd, longLabel); editor.Initialized += (s, e) => { editor.ViewToEdit = window; }; diff --git a/UICatalog/Scenarios/AllViewsTester.cs b/UICatalog/Scenarios/AllViewsTester.cs index 22d6d11dc..b9b20377e 100644 --- a/UICatalog/Scenarios/AllViewsTester.cs +++ b/UICatalog/Scenarios/AllViewsTester.cs @@ -147,7 +147,7 @@ public class AllViewsTester : Scenario }; _settingsPane.Add (_computedCheckBox); - string [] radioItems = { "_Percent(x)", "_AnchorEnd(x)", "_Center", "A_t(x)" }; + string [] radioItems = { "_Percent(x)", "_AnchorEnd", "_Center", "A_t(x)" }; _locationFrame = new FrameView { @@ -179,7 +179,7 @@ public class AllViewsTester : Scenario _locationFrame.Add (_xRadioGroup); - radioItems = new [] { "P_ercent(y)", "A_nchorEnd(y)", "C_enter", "At(_y)" }; + radioItems = new [] { "P_ercent(y)", "A_nchorEnd", "C_enter", "At(_y)" }; label = new Label { X = Pos.Right (_xRadioGroup) + 1, Y = 0, Text = "Y:" }; _locationFrame.Add (label); _yText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_yVal}" }; @@ -388,7 +388,7 @@ public class AllViewsTester : Scenario view.X = _xRadioGroup.SelectedItem switch { 0 => Pos.Percent (_xVal), - 1 => Pos.AnchorEnd (_xVal), + 1 => Pos.AnchorEnd (), 2 => Pos.Center (), 3 => Pos.At (_xVal), _ => view.X @@ -397,7 +397,7 @@ public class AllViewsTester : Scenario view.Y = _yRadioGroup.SelectedItem switch { 0 => Pos.Percent (_yVal), - 1 => Pos.AnchorEnd (_yVal), + 1 => Pos.AnchorEnd (), 2 => Pos.Center (), 3 => Pos.At (_yVal), _ => view.Y diff --git a/UICatalog/Scenarios/Animation.cs b/UICatalog/Scenarios/Animation.cs index 80bebdec2..42ad540c1 100644 --- a/UICatalog/Scenarios/Animation.cs +++ b/UICatalog/Scenarios/Animation.cs @@ -34,12 +34,12 @@ public class Animation : Scenario win.Add (imageView); - var lbl = new Label { Y = Pos.AnchorEnd (2), Text = "Image by Wikiscient" }; + var lbl = new Label { Y = Pos.AnchorEnd (), Text = "Image by Wikiscient" }; win.Add (lbl); var lbl2 = new Label { - Y = Pos.AnchorEnd (1), Text = "https://commons.wikimedia.org/wiki/File:Spinning_globe.gif" + X = Pos.AnchorEnd(), Y = Pos.AnchorEnd (), Text = "https://commons.wikimedia.org/wiki/File:Spinning_globe.gif" }; win.Add (lbl2); diff --git a/UICatalog/Scenarios/BasicColors.cs b/UICatalog/Scenarios/BasicColors.cs index 9fc6fead5..e12e51284 100644 --- a/UICatalog/Scenarios/BasicColors.cs +++ b/UICatalog/Scenarios/BasicColors.cs @@ -8,8 +8,15 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Text and Formatting")] public class BasicColors : Scenario { - public override void Setup () + public override void Main () { + Application.Init (); + + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + }; + var vx = 30; var x = 30; var y = 14; @@ -31,7 +38,7 @@ public class BasicColors : Scenario Text = bg.ToString (), TextDirection = TextDirection.TopBottom_LeftRight }; - Win.Add (vl); + app.Add (vl); var hl = new Label { @@ -44,7 +51,7 @@ public class BasicColors : Scenario ColorScheme = new ColorScheme { Normal = attr }, Text = bg.ToString () }; - Win.Add (hl); + app.Add (hl); vx++; foreach (ColorName fg in colors) @@ -56,7 +63,7 @@ public class BasicColors : Scenario { ColorScheme = new ColorScheme { Normal = c }, X = x, Y = y, Text = t [^1].ToString () }; - Win.Add (l); + app.Add (l); x++; } @@ -64,24 +71,24 @@ public class BasicColors : Scenario y++; } - Win.Add ( + app.Add ( new Label { X = Pos.AnchorEnd (36), Text = "Mouse over to get the Attribute:" } ); - Win.Add (new Label { X = Pos.AnchorEnd (35), Y = 2, Text = "Foreground:" }); + app.Add (new Label { X = Pos.AnchorEnd (35), Y = 2, Text = "Foreground:" }); var lblForeground = new Label { X = Pos.AnchorEnd (23), Y = 2 }; - Win.Add (lblForeground); + app.Add (lblForeground); var viewForeground = new View { X = Pos.AnchorEnd (2), Y = 2, ColorScheme = new ColorScheme (), Text = " " }; - Win.Add (viewForeground); + app.Add (viewForeground); - Win.Add (new Label { X = Pos.AnchorEnd (35), Y = 4, Text = "Background:" }); + app.Add (new Label { X = Pos.AnchorEnd (35), Y = 4, Text = "Background:" }); var lblBackground = new Label { X = Pos.AnchorEnd (23), Y = 4 }; - Win.Add (lblBackground); + app.Add (lblBackground); var viewBackground = new View { X = Pos.AnchorEnd (2), Y = 4, ColorScheme = new ColorScheme (), Text = " " }; - Win.Add (viewBackground); + app.Add (viewBackground); Application.MouseEvent += (s, e) => { @@ -103,5 +110,8 @@ public class BasicColors : Scenario new ColorScheme (viewBackground.ColorScheme) { Normal = new Attribute (back, back) }; } }; + + Application.Run (app); + app.Dispose (); } } diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index f405e063c..33590a7e0 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -29,7 +29,7 @@ public class Buttons : Scenario // This is the default button (IsDefault = true); if user presses ENTER in the TextField // the scenario will quit - var defaultButton = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (1), IsDefault = true, Text = "_Quit" }; + var defaultButton = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (), IsDefault = true, Text = "_Quit" }; defaultButton.Accept += (s, e) => Application.RequestStop (); main.Add (defaultButton); @@ -459,7 +459,7 @@ public class Buttons : Scenario _up = new () { AutoSize = false, - X = Pos.AnchorEnd (1), + X = Pos.AnchorEnd (), Y = Pos.Top (_number), Height = 1, Width = 1, diff --git a/UICatalog/Scenarios/ColorPicker.cs b/UICatalog/Scenarios/ColorPicker.cs index 8ae76c5dc..fe2b08fad 100644 --- a/UICatalog/Scenarios/ColorPicker.cs +++ b/UICatalog/Scenarios/ColorPicker.cs @@ -24,42 +24,45 @@ public class ColorPickers : Scenario private ColorPicker foregroundColorPicker; /// Setup the scenario. - public override void Setup () + public override void Main () { - // Scenario Window's. - Win.Title = GetName (); + Application.Init (); + + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + }; // Foreground ColorPicker. foregroundColorPicker = new ColorPicker { Title = "Foreground Color", BorderStyle = LineStyle.Single }; foregroundColorPicker.ColorChanged += ForegroundColor_ColorChanged; - Win.Add (foregroundColorPicker); + app.Add (foregroundColorPicker); _foregroundColorLabel = new Label { X = Pos.Left (foregroundColorPicker), Y = Pos.Bottom (foregroundColorPicker) + 1 }; - Win.Add (_foregroundColorLabel); + app.Add (_foregroundColorLabel); // Background ColorPicker. backgroundColorPicker = new ColorPicker { Title = "Background Color", - // TODO: Replace with Pos.AnchorEnd () when #2900 is done - X = Pos.AnchorEnd ((8 * 4) + 2), // 8 box * 4 width + 2 for border + X = Pos.AnchorEnd (), BoxHeight = 1, BoxWidth = 4, - BorderStyle = LineStyle.Single + BorderStyle = LineStyle.Single, }; - //backgroundColorPicker.X = Pos.AnchorEnd () - (Pos.Right (backgroundColorPicker) - Pos.Left (backgroundColorPicker)); backgroundColorPicker.ColorChanged += BackgroundColor_ColorChanged; - Win.Add (backgroundColorPicker); - _backgroundColorLabel = new Label (); + app.Add (backgroundColorPicker); + _backgroundColorLabel = new Label () + { + X = Pos.AnchorEnd (), + Y = Pos.Bottom (backgroundColorPicker) + 1 + }; - _backgroundColorLabel.X = - Pos.AnchorEnd () - (Pos.Right (_backgroundColorLabel) - Pos.Left (_backgroundColorLabel)); - _backgroundColorLabel.Y = Pos.Bottom (backgroundColorPicker) + 1; - Win.Add (_backgroundColorLabel); + app.Add (_backgroundColorLabel); // Demo Label. _demoView = new View @@ -74,12 +77,15 @@ public class ColorPickers : Scenario Height = 5, Width = 20 }; - Win.Add (_demoView); + app.Add (_demoView); // Set default colors. foregroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Foreground.GetClosestNamedColor (); backgroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Background.GetClosestNamedColor (); - Win.Initialized += (s, e) => Win.LayoutSubviews (); + app.Initialized += (s, e) => app.LayoutSubviews (); + + Application.Run (app); + app.Dispose (); } /// Fired when background color is changed. diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs index d51311c90..c8013c46a 100644 --- a/UICatalog/Scenarios/ComputedLayout.cs +++ b/UICatalog/Scenarios/ComputedLayout.cs @@ -13,17 +13,15 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Layout")] public class ComputedLayout : Scenario { - public override void Init () + public override void Main () { Application.Init (); - ConfigurationManager.Themes.Theme = Theme; - ConfigurationManager.Apply (); - Top = new (); - Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]; - } - public override void Setup () - { + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + }; + // Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width const string rule = "|123456789"; @@ -38,7 +36,7 @@ public class ComputedLayout : Scenario Text = rule }; - Top.Add (horizontalRuler); + app.Add (horizontalRuler); // Demonstrate using Dim to create a vertical ruler that always measures the parent window's height const string vrule = "|\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"; @@ -54,7 +52,7 @@ public class ComputedLayout : Scenario Text = vrule }; - Top.LayoutComplete += (s, a) => + app.LayoutComplete += (s, a) => { horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling (horizontalRuler.Viewport.Width / (double)rule.Length)) [ @@ -65,15 +63,15 @@ public class ComputedLayout : Scenario [..(verticalRuler.Viewport.Height * 2)]; }; - Top.Add (verticalRuler); + app.Add (verticalRuler); // Demonstrate At - Using Pos.At to locate a view in an absolute location var atButton = new Button { Text = "At(2,1)", X = Pos.At (2), Y = Pos.At (1) }; - Top.Add (atButton); + app.Add (atButton); // Throw in a literal absolute - Should function identically to above var absoluteButton = new Button { Text = "X = 30, Y = 1", X = 30, Y = 1 }; - Top.Add (absoluteButton); + app.Add (absoluteButton); // Demonstrate using Dim to create a window that fills the parent with a margin var margin = 10; @@ -84,7 +82,7 @@ public class ComputedLayout : Scenario subWin.Title = $"{subWin.GetType ().Name} {{X={subWin.X},Y={subWin.Y},Width={subWin.Width},Height={subWin.Height}}}"; }; - Top.Add (subWin); + app.Add (subWin); var i = 1; var txt = "Resize the terminal to see computed layout in action."; @@ -209,7 +207,7 @@ public class ComputedLayout : Scenario } ); frameView.Add (labelList.ToArray ()); - Top.Add (frameView); + app.Add (frameView); frameView = new FrameView { @@ -223,7 +221,7 @@ public class ComputedLayout : Scenario fv.Title = $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}"; }; - Top.Add (frameView); + app.Add (frameView); // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide var textView = new TextView @@ -237,7 +235,7 @@ public class ComputedLayout : Scenario textView.Text = "This TextView should horizontally & vertically centered and \n10% of the screeen height, and 80% of its width."; - Top.Add (textView); + app.Add (textView); var oddballButton = new Button { @@ -245,7 +243,7 @@ public class ComputedLayout : Scenario X = Pos.Center (), Y = Pos.Bottom (textView) + 1 }; - Top.Add (oddballButton); + app.Add (oddballButton); #region Issue2358 @@ -253,19 +251,19 @@ public class ComputedLayout : Scenario // Until https://github.com/gui-cs/Terminal.Gui/issues/2358 is fixed these won't work right oddballButton = new Button { Text = "Center + 0", X = Pos.Center () + 0, Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); oddballButton = new Button { Text = "Center + 1", X = Pos.Center () + 1, Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); oddballButton = new Button { Text = "0 + Center", X = 0 + Pos.Center (), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); oddballButton = new Button { Text = "1 + Center", X = 1 + Pos.Center (), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); oddballButton = new Button { Text = "Center - 1", X = Pos.Center () - 1, Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50) // The `- Pos.Percent(5)` is there so at least something is visible @@ -275,7 +273,7 @@ public class ComputedLayout : Scenario X = Pos.Center () + Pos.Center () - Pos.Percent (50), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50) // The `- Pos.Percent(5)` is there so at least something is visible @@ -285,7 +283,7 @@ public class ComputedLayout : Scenario X = Pos.Percent (50) + Pos.Center () - Pos.Percent (50), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50) // The `- Pos.Percent(5)` is there so at least something is visible @@ -295,7 +293,7 @@ public class ComputedLayout : Scenario X = Pos.Center () + Pos.Percent (50) - Pos.Percent (50), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); #endregion @@ -306,29 +304,29 @@ public class ComputedLayout : Scenario X = Pos.Center () + Pos.Center () - Pos.Percent (50), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); // This demonstrates combining Percents) oddballButton = new Button { Text = "Percent(40) + Percent(10)", X = Pos.Percent (40) + Pos.Percent (10), Y = Pos.Bottom (oddballButton) }; - Top.Add (oddballButton); + app.Add (oddballButton); // Demonstrate AnchorEnd - Button is anchored to bottom/right - var anchorButton = new Button { Text = "Button using AnchorEnd", Y = Pos.AnchorEnd () - 1 }; - anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton)); + var anchorButton = new Button { Text = "Button using AnchorEnd", Y = Pos.AnchorEnd ()}; + anchorButton.X = Pos.AnchorEnd (); anchorButton.Accept += (s, e) => { // This demonstrates how to have a dynamically sized button // Each time the button is clicked the button's text gets longer - // The call to Top.LayoutSubviews causes the Computed layout to + // The call to app.LayoutSubviews causes the Computed layout to // get updated. anchorButton.Text += "!"; - Top.LayoutSubviews (); + app.LayoutSubviews (); }; - Top.Add (anchorButton); + app.Add (anchorButton); // Demonstrate AnchorEnd(n) // This is intentionally convoluted to illustrate potential bugs. @@ -342,7 +340,7 @@ public class ComputedLayout : Scenario X = 5, Y = Pos.AnchorEnd (2) }; - Top.Add (anchorEndLabel1); + app.Add (anchorEndLabel1); // Demonstrate DimCombine (via AnchorEnd(n) - 1) // This is intentionally convoluted to illustrate potential bugs. @@ -357,22 +355,22 @@ public class ComputedLayout : Scenario X = 5, Y = Pos.AnchorEnd (2) - 1 // Pos.Combine }; - Top.Add (anchorEndLabel2); + app.Add (anchorEndLabel2); // Show positioning vertically using Pos.AnchorEnd via Pos.Combine var leftButton = new Button { - Text = "Left", Y = Pos.AnchorEnd () - 1 // Pos.Combine + Text = "Left", Y = Pos.AnchorEnd (0) - 1 // Pos.Combine }; leftButton.Accept += (s, e) => { // This demonstrates how to have a dynamically sized button // Each time the button is clicked the button's text gets longer - // The call to Top.LayoutSubviews causes the Computed layout to + // The call to app.LayoutSubviews causes the Computed layout to // get updated. leftButton.Text += "!"; - Top.LayoutSubviews (); + app.LayoutSubviews (); }; // show positioning vertically using Pos.AnchorEnd @@ -385,10 +383,10 @@ public class ComputedLayout : Scenario { // This demonstrates how to have a dynamically sized button // Each time the button is clicked the button's text gets longer - // The call to Top.LayoutSubviews causes the Computed layout to + // The call to app.LayoutSubviews causes the Computed layout to // get updated. centerButton.Text += "!"; - Top.LayoutSubviews (); + app.LayoutSubviews (); }; // show positioning vertically using another window and Pos.Bottom @@ -398,18 +396,21 @@ public class ComputedLayout : Scenario { // This demonstrates how to have a dynamically sized button // Each time the button is clicked the button's text gets longer - // The call to Top.LayoutSubviews causes the Computed layout to + // The call to app.LayoutSubviews causes the Computed layout to // get updated. rightButton.Text += "!"; - Top.LayoutSubviews (); + app.LayoutSubviews (); }; // Center three buttons with 5 spaces between them leftButton.X = Pos.Left (centerButton) - (Pos.Right (leftButton) - Pos.Left (leftButton)) - 5; rightButton.X = Pos.Right (centerButton) + 5; - Top.Add (leftButton); - Top.Add (centerButton); - Top.Add (rightButton); + app.Add (leftButton); + app.Add (centerButton); + app.Add (rightButton); + + Application.Run (app); + app.Dispose (); } } diff --git a/UICatalog/Scenarios/ContentScrolling.cs b/UICatalog/Scenarios/ContentScrolling.cs index 5109e63e6..9a92b4bc4 100644 --- a/UICatalog/Scenarios/ContentScrolling.cs +++ b/UICatalog/Scenarios/ContentScrolling.cs @@ -321,7 +321,7 @@ public class ContentScrolling : Scenario // Add demo views to show that things work correctly var textField = new TextField { X = 20, Y = 7, Width = 15, Text = "Test TextField" }; - var colorPicker = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (11), Y = 10 }; + var colorPicker = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (), Y = 10 }; colorPicker.BorderStyle = LineStyle.RoundedDotted; colorPicker.ColorChanged += (s, e) => @@ -358,18 +358,9 @@ public class ContentScrolling : Scenario charMap.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No"); - var buttonAnchoredRight = new Button + var buttonAnchored = new Button { - X = Pos.AnchorEnd (10), Y = 0, Text = "Button" - }; - - var labelAnchoredBottomLeft = new Label - { - AutoSize = false, - Y = Pos.AnchorEnd (3), - Width = 25, - Height = Dim.Fill (), - Text = "Label\nY=AnchorEnd(3),Height=Dim.Fill()" + X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Bottom Right" }; view.Margin.Data = "Margin"; @@ -380,7 +371,7 @@ public class ContentScrolling : Scenario view.Padding.Data = "Padding"; - view.Add (buttonAnchoredRight, textField, colorPicker, charMap, textView, labelAnchoredBottomLeft); + view.Add (buttonAnchored, textField, colorPicker, charMap, textView); var longLabel = new Label { diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs index bb5451655..650e854db 100644 --- a/UICatalog/Scenarios/DynamicMenuBar.cs +++ b/UICatalog/Scenarios/DynamicMenuBar.cs @@ -604,7 +604,7 @@ public class DynamicMenuBar : Scenario var _btnRemoveMenuBar = new Button { Y = 1, Text = "Remove a MenuBar" }; - _btnRemoveMenuBar.X = Pos.AnchorEnd () - (Pos.Right (_btnRemoveMenuBar) - Pos.Left (_btnRemoveMenuBar)); + _btnRemoveMenuBar.X = Pos.AnchorEnd (0) - (Pos.Right (_btnRemoveMenuBar) - Pos.Left (_btnRemoveMenuBar)); _frmMenu.Add (_btnRemoveMenuBar); var _btnPrevious = new Button @@ -614,7 +614,7 @@ public class DynamicMenuBar : Scenario _frmMenu.Add (_btnPrevious); var _btnAdd = new Button { Y = Pos.Top (_btnPrevious) + 2, Text = " Add " }; - _btnAdd.X = Pos.AnchorEnd () - (Pos.Right (_btnAdd) - Pos.Left (_btnAdd)); + _btnAdd.X = Pos.AnchorEnd (); _frmMenu.Add (_btnAdd); var _btnNext = new Button { X = Pos.X (_btnAdd), Y = Pos.Top (_btnPrevious), Text = ">" }; diff --git a/UICatalog/Scenarios/DynamicStatusBar.cs b/UICatalog/Scenarios/DynamicStatusBar.cs index 55a114d38..316e3d263 100644 --- a/UICatalog/Scenarios/DynamicStatusBar.cs +++ b/UICatalog/Scenarios/DynamicStatusBar.cs @@ -371,11 +371,11 @@ public class DynamicStatusBar : Scenario var _btnRemoveStatusBar = new Button { Y = 1, Text = "Remove a StatusBar" }; - _btnRemoveStatusBar.X = Pos.AnchorEnd () - (Pos.Right (_btnRemoveStatusBar) - Pos.Left (_btnRemoveStatusBar)); + _btnRemoveStatusBar.X = Pos.AnchorEnd (); _frmStatusBar.Add (_btnRemoveStatusBar); var _btnAdd = new Button { Y = Pos.Top (_btnRemoveStatusBar) + 2, Text = " Add " }; - _btnAdd.X = Pos.AnchorEnd () - (Pos.Right (_btnAdd) - Pos.Left (_btnAdd)); + _btnAdd.X = Pos.AnchorEnd (0); _frmStatusBar.Add (_btnAdd); _lstItems = new ListView diff --git a/UICatalog/Scenarios/HotKeys.cs b/UICatalog/Scenarios/HotKeys.cs index 8201a140f..5b9507374 100644 --- a/UICatalog/Scenarios/HotKeys.cs +++ b/UICatalog/Scenarios/HotKeys.cs @@ -4,108 +4,102 @@ namespace UICatalog.Scenarios; [ScenarioMetadata ("HotKeys", "Demonstrates how HotKeys work.")] [ScenarioCategory ("Controls")] -[ScenarioCategory("Mouse and Keyboard")] +[ScenarioCategory ("Mouse and Keyboard")] public class HotKeys : Scenario { - public override void Init () + public override void Main () { Application.Init (); - ConfigurationManager.Themes.Theme = Theme; - ConfigurationManager.Apply (); - Top = new (); - Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]; - Top.BorderStyle = LineStyle.RoundedDotted; - Top.Title = $"{Application.QuitKey} to _Quit - Scenario: {GetName ()}"; - } - public override void Run () - { + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + }; + var textViewLabel = new Label { Text = "_TextView:", X = 0, Y = 0 }; - Top.Add (textViewLabel); - - var textField = new TextField (){ X = Pos.Right (textViewLabel) + 1, Y = 0, Width = 10 }; - Top.Add (textField); + app.Add (textViewLabel); + + var textField = new TextField { X = Pos.Right (textViewLabel) + 1, Y = 0, Width = 10 }; + app.Add (textField); var viewLabel = new Label { Text = "_View:", X = 0, Y = Pos.Bottom (textField) + 1 }; - Top.Add (viewLabel); + app.Add (viewLabel); - var view = new View () { - Title = "View (_focusable)", - Text = "Text renders _Underscore", + var view = new View + { + Title = "View (_focusable)", + Text = "Text renders _Underscore", CanFocus = true, X = Pos.Right (viewLabel) + 1, Y = Pos.Top (viewLabel), Width = 30, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (view); + app.Add (view); - viewLabel = new Label { Text = "Vi_ew:", X = 0, Y = Pos.Bottom (view) + 1 }; - Top.Add (viewLabel); + viewLabel = new() { Text = "Vi_ew:", X = 0, Y = Pos.Bottom (view) + 1 }; + app.Add (viewLabel); - view = new View () + view = new() { Title = "View (n_ot focusable)", Text = "Text renders _Underscore", X = Pos.Right (viewLabel) + 1, Y = Pos.Top (viewLabel), Width = 30, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (view); + app.Add (view); var labelWithFrameLabel = new Label { Text = "_Label with Frame:", X = 0, Y = Pos.Bottom (view) + 1 }; - Top.Add (labelWithFrameLabel); + app.Add (labelWithFrameLabel); - var labelWithFrameFocusable = new Label () + var labelWithFrameFocusable = new Label { AutoSize = false, Title = "Label _with Frame (focusable)", CanFocus = true, X = Pos.Right (labelWithFrameLabel) + 1, Y = Pos.Top (labelWithFrameLabel), Width = 40, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (labelWithFrameFocusable); + app.Add (labelWithFrameFocusable); - labelWithFrameLabel = new Label { Text = "L_abel with Frame:", X = 0, Y = Pos.Bottom (labelWithFrameFocusable) + 1 }; - Top.Add (labelWithFrameLabel); + labelWithFrameLabel = new() { Text = "L_abel with Frame:", X = 0, Y = Pos.Bottom (labelWithFrameFocusable) + 1 }; + app.Add (labelWithFrameLabel); - var labelWithFrame = new Label () + var labelWithFrame = new Label { AutoSize = false, Title = "Label with Frame (_not focusable)", X = Pos.Right (labelWithFrameLabel) + 1, Y = Pos.Top (labelWithFrameLabel), Width = 40, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (labelWithFrame); + app.Add (labelWithFrame); - var buttonWithFrameLabel = new Label { Text = "_Button with Frame:", X = 0, Y = Pos.Bottom (labelWithFrame) + 1 }; - Top.Add (buttonWithFrameLabel); + app.Add (buttonWithFrameLabel); - var buttonWithFrameFocusable = new Button () + var buttonWithFrameFocusable = new Button { AutoSize = false, Title = "B_utton with Frame (focusable)", CanFocus = true, X = Pos.Right (buttonWithFrameLabel) + 1, Y = Pos.Top (buttonWithFrameLabel), Width = 40, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (buttonWithFrameFocusable); + app.Add (buttonWithFrameFocusable); - buttonWithFrameLabel = new Label { Text = "Butt_on with Frame:", X = 0, Y = Pos.Bottom (buttonWithFrameFocusable) + 1 }; - Top.Add (buttonWithFrameLabel); + buttonWithFrameLabel = new() { Text = "Butt_on with Frame:", X = 0, Y = Pos.Bottom (buttonWithFrameFocusable) + 1 }; + app.Add (buttonWithFrameLabel); - var buttonWithFrame = new Button () + var buttonWithFrame = new Button { AutoSize = false, Title = "Button with Frame (not focusab_le)", X = Pos.Right (buttonWithFrameLabel) + 1, Y = Pos.Top (buttonWithFrameLabel), Width = 40, Height = 3, CanFocus = false, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (buttonWithFrame); - - + app.Add (buttonWithFrame); var checkboxWithFrameLabel = new Label { Text = "_Checkbox with Frame:", X = 0, Y = Pos.Bottom (buttonWithFrame) + 1 }; - Top.Add (checkboxWithFrameLabel); + app.Add (checkboxWithFrameLabel); var checkboxWithFrameFocusable = new CheckBox { @@ -113,12 +107,12 @@ public class HotKeys : Scenario Title = "C_heckbox with Frame (focusable)", CanFocus = true, X = Pos.Right (checkboxWithFrameLabel) + 1, Y = Pos.Top (checkboxWithFrameLabel), Width = 40, Height = 3, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (checkboxWithFrameFocusable); + app.Add (checkboxWithFrameFocusable); - checkboxWithFrameLabel = new Label { Text = "Checkb_ox with Frame:", X = 0, Y = Pos.Bottom (checkboxWithFrameFocusable) + 1 }; - Top.Add (checkboxWithFrameLabel); + checkboxWithFrameLabel = new() { Text = "Checkb_ox with Frame:", X = 0, Y = Pos.Bottom (checkboxWithFrameFocusable) + 1 }; + app.Add (checkboxWithFrameLabel); var checkboxWithFrame = new CheckBox { @@ -126,14 +120,14 @@ public class HotKeys : Scenario Title = "Checkbox with Frame (not focusable)", X = Pos.Right (checkboxWithFrameLabel) + 1, Y = Pos.Top (checkboxWithFrameLabel), Width = 40, Height = 3, CanFocus = false, - BorderStyle = LineStyle.Dashed, + BorderStyle = LineStyle.Dashed }; - Top.Add (checkboxWithFrame); + app.Add (checkboxWithFrame); + var button = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (), Text = "_Press me!" }; + app.Add (button); - var button = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (1), Text = "_Press me!" }; - Top.Add (button); - - Application.Run (Top); + Application.Run (app); + app.Dispose (); } } diff --git a/UICatalog/Scenarios/LineCanvasExperiment.cs b/UICatalog/Scenarios/LineCanvasExperiment.cs index 651d82f56..d015cd23e 100644 --- a/UICatalog/Scenarios/LineCanvasExperiment.cs +++ b/UICatalog/Scenarios/LineCanvasExperiment.cs @@ -8,21 +8,14 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Proof of Concept")] public class LineCanvasExperiment : Scenario { - public override void Init () + public override void Main () { Application.Init (); - Top = new (); - } - /// Setup the scenario. - public override void Setup () - { - //var menu = new MenuBar (new MenuBarItem [] { - //new MenuBarItem ("_File", new MenuItem [] { - // new MenuItem ("_Quit", "", () => Application.RequestStop()), - //}) }); - - //Top.Add (menu); + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + }; var frame1 = new FrameView { @@ -37,7 +30,7 @@ public class LineCanvasExperiment : Scenario //View.Diagnostics ^= DiagnosticFlags.FrameRuler; - Top.Add (frame1); + app.Add (frame1); var win1 = new Window { @@ -52,7 +45,7 @@ public class LineCanvasExperiment : Scenario BorderStyle = LineStyle.Heavy, SuperViewRendersLineCanvas = true }; - win1.Padding.Thickness = new Thickness (1); + win1.Padding.Thickness = new (1); frame1.Add (win1); @@ -140,9 +133,12 @@ public class LineCanvasExperiment : Scenario SuperViewRendersLineCanvas = true }; marginWindow.Margin.ColorScheme = Colors.ColorSchemes ["Dialog"]; - marginWindow.Margin.Thickness = new Thickness (1); - marginWindow.Border.Thickness = new Thickness (1, 2, 1, 1); + marginWindow.Margin.Thickness = new (1); + marginWindow.Border.Thickness = new (1, 2, 1, 1); frame1.Add (marginWindow); + + Application.Run (app); + app.Dispose (); } } diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs index aaf4ae626..ec17a1d16 100644 --- a/UICatalog/Scenarios/Scrolling.cs +++ b/UICatalog/Scenarios/Scrolling.cs @@ -122,10 +122,10 @@ public class Scrolling : Scenario ); // Demonstrate AnchorEnd - Button is anchored to bottom/right - var anchorButton = new Button { Y = Pos.AnchorEnd () - 1, Text = "Bottom Right" }; + var anchorButton = new Button { Y = Pos.AnchorEnd (0) - 1, Text = "Bottom Right" }; // TODO: Use Pos.Width instead of (Right-Left) when implemented (#502) - anchorButton.X = Pos.AnchorEnd () - (Pos.Right (anchorButton) - Pos.Left (anchorButton)); + anchorButton.X = Pos.AnchorEnd (0) - (Pos.Right (anchorButton) - Pos.Left (anchorButton)); anchorButton.Accept += (s, e) => { diff --git a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs index 2abe35177..52c7c5b5e 100644 --- a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs +++ b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs @@ -10,14 +10,21 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Text and Formatting")] public class TextAlignmentsAndDirections : Scenario { - public override void Setup () + public override void Main () { + Application.Init (); + + Window app = new () + { + Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + }; + // string txt = ".\n...\n.....\nHELLO\n.....\n...\n."; // string txt = "┌──┴──┐\n┤HELLO├\n└──┬──┘"; var txt = "HELLO WORLD"; - var color1 = new ColorScheme { Normal = new Attribute (Color.Black, Color.Gray) }; - var color2 = new ColorScheme { Normal = new Attribute (Color.Black, Color.DarkGray) }; + var color1 = new ColorScheme { Normal = new (Color.Black, Color.Gray) }; + var color2 = new ColorScheme { Normal = new (Color.Black, Color.DarkGray) }; List