diff --git a/Terminal.Gui/View/Layout/Dim.cs b/Terminal.Gui/View/Layout/Dim.cs index a04b9798d..dc4b612a9 100644 --- a/Terminal.Gui/View/Layout/Dim.cs +++ b/Terminal.Gui/View/Layout/Dim.cs @@ -3,69 +3,6 @@ using System.Diagnostics; namespace Terminal.Gui; -/// -/// Specifies how will compute the dimension. -/// -[Flags] -public enum DimAutoStyle -{ - /// - /// The dimension will be computed using both the view's and - /// (whichever is larger). - /// - Auto = Content | Text, - - /// - /// The dimensions will be computed based on the View's non-Text content. - /// - /// If is explicitly set (is not ) then - /// - /// will be used to determine the dimension. - /// - /// - /// Otherwise, the Subview in with the largest corresponding position plus dimension - /// will determine the dimension. - /// - /// - /// The corresponding dimension of the view's will be ignored. - /// - /// - Content = 0, - - /// - /// - /// The corresponding dimension of the view's , formatted using the - /// settings, - /// will be used to determine the dimension. - /// - /// - /// The corresponding dimensions of the will be ignored. - /// - /// - Text = 1 -} - -/// -/// Indicates the dimension for operations. -/// -public enum Dimension -{ - /// - /// No dimension specified. - /// - None = 0, - - /// - /// The height dimension. - /// - Height = 1, - - /// - /// The width dimension. - /// - Width = 2 -} - /// /// /// A Dim object describes the dimensions of a . Dim is the type of the @@ -337,479 +274,4 @@ public abstract class Dim #endregion operators -} - -/// -/// Represents a dimension that is a fixed size. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// -public class DimAbsolute (int size) : Dim -{ - /// - public override bool Equals (object? other) { return other is DimAbsolute abs && abs.Size == Size; } - - /// - public override int GetHashCode () { return Size.GetHashCode (); } - - /// - /// Gets the size of the dimension. - /// - public int Size { get; } = size; - - /// - public override string ToString () { return $"Absolute({Size})"; } - - internal override int GetAnchor (int size) { return Size; } - - internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) - { - return Math.Max (GetAnchor (0), 0); - } -} - -/// -/// Represents a dimension that automatically sizes the view to fit all the view's Content, SubViews, and/or Text. -/// -/// -/// -/// See . -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -public class DimAuto () : Dim -{ - private readonly Dim? _maximumContentDim; - - /// - /// Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED. - /// - // ReSharper disable once ConvertToAutoProperty - public required Dim? MaximumContentDim - { - get => _maximumContentDim; - init => _maximumContentDim = value; - } - - private readonly Dim? _minimumContentDim; - - /// - /// Gets the minimum dimension the View's ContentSize will be constrained to. - /// - // ReSharper disable once ConvertToAutoProperty - public required Dim? MinimumContentDim - { - get => _minimumContentDim; - init => _minimumContentDim = value; - } - - private readonly DimAutoStyle _style; - - /// - /// Gets the style of the DimAuto. - /// - // ReSharper disable once ConvertToAutoProperty - public required DimAutoStyle Style - { - get => _style; - init => _style = value; - } - - /// - public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; } - - internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) - { - var textSize = 0; - var subviewsSize = 0; - - int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0; - - if (Style.HasFlag (DimAutoStyle.Text)) - { - textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height); - } - - if (Style.HasFlag (DimAutoStyle.Content)) - { - if (us._contentSize is { }) - { - subviewsSize = dimension == Dimension.Width ? us.ContentSize.Width : us.ContentSize.Height; - } - else - { - // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451). - subviewsSize = 0; - - List subviews; - - if (dimension == Dimension.Width) - { - subviews = us.Subviews.Where (v => v.X is not PosAnchorEnd && v.Width is not DimFill).ToList (); - } - else - { - subviews = us.Subviews.Where (v => v.Y is not PosAnchorEnd && v.Height is not DimFill).ToList (); - } - - for (var i = 0; i < subviews.Count; i++) - { - View v = subviews [i]; - - int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height; - - if (size > subviewsSize) - { - subviewsSize = size; - } - } - - if (dimension == Dimension.Width) - { - subviews = us.Subviews.Where (v => v.X is PosAnchorEnd).ToList (); - } - else - { - subviews = us.Subviews.Where (v => v.Y is PosAnchorEnd).ToList (); - } - - int maxAnchorEnd = 0; - for (var i = 0; i < subviews.Count; i++) - { - View v = subviews [i]; - maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height; - } - - subviewsSize += maxAnchorEnd; - - - if (dimension == Dimension.Width) - { - subviews = us.Subviews.Where (v => v.Width is DimFill).ToList (); - } - else - { - subviews = us.Subviews.Where (v => v.Height is DimFill).ToList (); - } - - for (var i = 0; i < subviews.Count; i++) - { - View v = subviews [i]; - - if (dimension == Dimension.Width) - { - v.SetRelativeLayout (new Size (autoMin - subviewsSize, 0)); - } - else - { - v.SetRelativeLayout (new Size (0, autoMin - subviewsSize)); - } - } - - } - } - - // All sizes here are content-relative; ignoring adornments. - // We take the largest of text and content. - int max = int.Max (textSize, subviewsSize); - - // And, if min: is set, it wins if larger - max = int.Max (max, autoMin); - - // Factor in adornments - Thickness thickness = us.GetAdornmentsThickness (); - - max += dimension switch - { - Dimension.Width => thickness.Horizontal, - Dimension.Height => thickness.Vertical, - Dimension.None => 0, - _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null) - }; - - return int.Min (max, MaximumContentDim?.GetAnchor (superviewContentSize) ?? max); - } - - internal override bool ReferencesOtherViews () - { - // BUGBUG: This is not correct. _contentSize may be null. - return false; //_style.HasFlag (DimAutoStyle.Content); - } - - /// - public override bool Equals (object? other) - { - if (other is not DimAuto auto) - { - return false; - } - - return auto.MinimumContentDim == MinimumContentDim && - auto.MaximumContentDim == MaximumContentDim && - auto.Style == Style; - } - - /// - public override int GetHashCode () - { - return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style); - } - -} - -/// -/// Represents a dimension that is a combination of two other dimensions. -/// -/// -/// Indicates whether the two dimensions are added or subtracted. -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// The left dimension. -/// The right dimension. -public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim -{ - /// - /// Gets whether the two dimensions are added or subtracted. - /// - public AddOrSubtract Add { get; } = add; - - /// - /// Gets the left dimension. - /// - public Dim? Left { get; } = left; - - /// - /// Gets the right dimension. - /// - public Dim? Right { get; } = right; - - /// - public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; } - - internal override int GetAnchor (int size) - { - int la = Left!.GetAnchor (size); - int ra = Right!.GetAnchor (size); - - if (Add == AddOrSubtract.Add) - { - return la + ra; - } - - return la - ra; - } - - internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) - { - int leftNewDim = Left!.Calculate (location, superviewContentSize, us, dimension); - int rightNewDim = Right!.Calculate (location, superviewContentSize, us, dimension); - - int newDimension; - - if (Add == AddOrSubtract.Add) - { - newDimension = leftNewDim + rightNewDim; - } - else - { - newDimension = Math.Max (0, leftNewDim - rightNewDim); - } - - return newDimension; - } - - /// - /// Diagnostics API to determine if this Dim object references other views. - /// - /// - internal override bool ReferencesOtherViews () - { - if (Left!.ReferencesOtherViews ()) - { - return true; - } - - if (Right!.ReferencesOtherViews ()) - { - return true; - } - - return false; - } -} - -/// -/// Represents a dimension that is a percentage of the width or height of the SuperView. -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// The percentage. -/// -/// If the dimension is computed using the View's position ( or -/// ). -/// If the dimension is computed using the View's . -/// -public class DimPercent (float percent, bool usePosition = false) : Dim -{ - /// - public override bool Equals (object? other) { return other is DimPercent f && f.Percent == Percent && f.UsePosition == UsePosition; } - - /// - public override int GetHashCode () { return Percent.GetHashCode (); } - - /// - /// Gets the percentage. - /// - public new float Percent { get; } = percent; - - /// - /// - /// - public override string ToString () { return $"Percent({Percent},{UsePosition})"; } - - /// - /// Gets whether the dimension is computed using the View's position or ContentSize. - /// - public bool UsePosition { get; } = usePosition; - - internal override int GetAnchor (int size) { return (int)(size * Percent); } - - internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) - { - return UsePosition ? Math.Max (GetAnchor (superviewContentSize - location), 0) : GetAnchor (superviewContentSize); - } -} - -/// -/// Represents a dimension that fills the dimension, leaving the specified margin. -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// The margin to not fill. -public class DimFill (int margin) : Dim -{ - /// - public override bool Equals (object? other) { return other is DimFill fill && fill.Margin == Margin; } - - /// - public override int GetHashCode () { return Margin.GetHashCode (); } - - /// - /// Gets the margin to not fill. - /// - public int Margin { get; } = margin; - - /// - public override string ToString () { return $"Fill({Margin})"; } - - internal override int GetAnchor (int size) { return size - Margin; } -} - -/// -/// Represents a function object that computes the dimension by executing the provided function. -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -public class DimFunc (Func dim) : Dim -{ - /// - public override bool Equals (object? other) { return other is DimFunc f && f.Func () == Func (); } - - /// - /// Gets the function that computes the dimension. - /// - public new Func Func { get; } = dim; - - /// - public override int GetHashCode () { return Func.GetHashCode (); } - - /// - public override string ToString () { return $"DimFunc({Func ()})"; } - - internal override int GetAnchor (int size) { return Func (); } -} - -/// -/// Represents a dimension that tracks the Height or Width of the specified View. -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -public class DimView : Dim -{ - /// - /// Initializes a new instance of the class. - /// - /// The view the dimension is anchored to. - /// Indicates which dimension is tracked. - public DimView (View view, Dimension dimension) - { - Target = view; - Dimension = dimension; - } - - /// - /// Gets the indicated dimension of the View. - /// - public Dimension Dimension { get; } - - /// - public override bool Equals (object? other) { return other is DimView abs && abs.Target == Target && abs.Dimension == Dimension; } - - /// - public override int GetHashCode () { return Target.GetHashCode (); } - - /// - /// Gets the View the dimension is anchored to. - /// - public View Target { get; init; } - - /// - public override string ToString () - { - if (Target == null) - { - throw new NullReferenceException (); - } - - string dimString = Dimension switch - { - Dimension.Height => "Height", - Dimension.Width => "Width", - _ => "unknown" - }; - - return $"View({dimString},{Target})"; - } - - internal override int GetAnchor (int size) - { - return Dimension switch - { - Dimension.Height => Target.Frame.Height, - Dimension.Width => Target.Frame.Width, - _ => 0 - }; - } - - internal override bool ReferencesOtherViews () { return true; } -} +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimAbsolute.cs b/Terminal.Gui/View/Layout/DimAbsolute.cs new file mode 100644 index 000000000..72d4e12f7 --- /dev/null +++ b/Terminal.Gui/View/Layout/DimAbsolute.cs @@ -0,0 +1,36 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that is a fixed size. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// +public class DimAbsolute (int size) : Dim +{ + /// + public override bool Equals (object? other) { return other is DimAbsolute abs && abs.Size == Size; } + + /// + public override int GetHashCode () { return Size.GetHashCode (); } + + /// + /// Gets the size of the dimension. + /// + public int Size { get; } = size; + + /// + public override string ToString () { return $"Absolute({Size})"; } + + internal override int GetAnchor (int size) { return Size; } + + internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) + { + return Math.Max (GetAnchor (0), 0); + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimAuto.cs b/Terminal.Gui/View/Layout/DimAuto.cs new file mode 100644 index 000000000..6a569b01c --- /dev/null +++ b/Terminal.Gui/View/Layout/DimAuto.cs @@ -0,0 +1,194 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that automatically sizes the view to fit all the view's Content, SubViews, and/or Text. +/// +/// +/// +/// See . +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +public class DimAuto () : Dim +{ + private readonly Dim? _maximumContentDim; + + /// + /// Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED. + /// + // ReSharper disable once ConvertToAutoProperty + public required Dim? MaximumContentDim + { + get => _maximumContentDim; + init => _maximumContentDim = value; + } + + private readonly Dim? _minimumContentDim; + + /// + /// Gets the minimum dimension the View's ContentSize will be constrained to. + /// + // ReSharper disable once ConvertToAutoProperty + public required Dim? MinimumContentDim + { + get => _minimumContentDim; + init => _minimumContentDim = value; + } + + private readonly DimAutoStyle _style; + + /// + /// Gets the style of the DimAuto. + /// + // ReSharper disable once ConvertToAutoProperty + public required DimAutoStyle Style + { + get => _style; + init => _style = value; + } + + /// + public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; } + + internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) + { + var textSize = 0; + var subviewsSize = 0; + + int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0; + + if (Style.HasFlag (DimAutoStyle.Text)) + { + textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height); + } + + if (Style.HasFlag (DimAutoStyle.Content)) + { + if (us._contentSize is { }) + { + subviewsSize = dimension == Dimension.Width ? us.ContentSize.Width : us.ContentSize.Height; + } + else + { + // TODO: This whole body of code is a WIP (for https://github.com/gui-cs/Terminal.Gui/pull/3451). + subviewsSize = 0; + + List subviews; + + if (dimension == Dimension.Width) + { + subviews = us.Subviews.Where (v => v.X is not PosAnchorEnd && v.Width is not DimFill).ToList (); + } + else + { + subviews = us.Subviews.Where (v => v.Y is not PosAnchorEnd && v.Height is not DimFill).ToList (); + } + + for (var i = 0; i < subviews.Count; i++) + { + View v = subviews [i]; + + int size = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height; + + if (size > subviewsSize) + { + subviewsSize = size; + } + } + + if (dimension == Dimension.Width) + { + subviews = us.Subviews.Where (v => v.X is PosAnchorEnd).ToList (); + } + else + { + subviews = us.Subviews.Where (v => v.Y is PosAnchorEnd).ToList (); + } + + int maxAnchorEnd = 0; + for (var i = 0; i < subviews.Count; i++) + { + View v = subviews [i]; + maxAnchorEnd = dimension == Dimension.Width ? v.Frame.Width : v.Frame.Height; + } + + subviewsSize += maxAnchorEnd; + + + if (dimension == Dimension.Width) + { + subviews = us.Subviews.Where (v => v.Width is DimFill).ToList (); + } + else + { + subviews = us.Subviews.Where (v => v.Height is DimFill).ToList (); + } + + for (var i = 0; i < subviews.Count; i++) + { + View v = subviews [i]; + + if (dimension == Dimension.Width) + { + v.SetRelativeLayout (new Size (autoMin - subviewsSize, 0)); + } + else + { + v.SetRelativeLayout (new Size (0, autoMin - subviewsSize)); + } + } + + } + } + + // All sizes here are content-relative; ignoring adornments. + // We take the largest of text and content. + int max = int.Max (textSize, subviewsSize); + + // And, if min: is set, it wins if larger + max = int.Max (max, autoMin); + + // Factor in adornments + Thickness thickness = us.GetAdornmentsThickness (); + + max += dimension switch + { + Dimension.Width => thickness.Horizontal, + Dimension.Height => thickness.Vertical, + Dimension.None => 0, + _ => throw new ArgumentOutOfRangeException (nameof (dimension), dimension, null) + }; + + return int.Min (max, MaximumContentDim?.GetAnchor (superviewContentSize) ?? max); + } + + internal override bool ReferencesOtherViews () + { + // BUGBUG: This is not correct. _contentSize may be null. + return false; //_style.HasFlag (DimAutoStyle.Content); + } + + /// + public override bool Equals (object? other) + { + if (other is not DimAuto auto) + { + return false; + } + + return auto.MinimumContentDim == MinimumContentDim && + auto.MaximumContentDim == MaximumContentDim && + auto.Style == Style; + } + + /// + public override int GetHashCode () + { + return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style); + } + +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimAutoStyle.cs b/Terminal.Gui/View/Layout/DimAutoStyle.cs new file mode 100644 index 000000000..271a53d8e --- /dev/null +++ b/Terminal.Gui/View/Layout/DimAutoStyle.cs @@ -0,0 +1,43 @@ +namespace Terminal.Gui; + +/// +/// Specifies how will compute the dimension. +/// +[Flags] +public enum DimAutoStyle +{ + /// + /// The dimension will be computed using both the view's and + /// (whichever is larger). + /// + Auto = Content | Text, + + /// + /// The dimensions will be computed based on the View's non-Text content. + /// + /// If is explicitly set (is not ) then + /// + /// will be used to determine the dimension. + /// + /// + /// Otherwise, the Subview in with the largest corresponding position plus dimension + /// will determine the dimension. + /// + /// + /// The corresponding dimension of the view's will be ignored. + /// + /// + Content = 0, + + /// + /// + /// The corresponding dimension of the view's , formatted using the + /// settings, + /// will be used to determine the dimension. + /// + /// + /// The corresponding dimensions of the will be ignored. + /// + /// + Text = 1 +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimCombine.cs b/Terminal.Gui/View/Layout/DimCombine.cs new file mode 100644 index 000000000..d66352855 --- /dev/null +++ b/Terminal.Gui/View/Layout/DimCombine.cs @@ -0,0 +1,86 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that is a combination of two other dimensions. +/// +/// +/// Indicates whether the two dimensions are added or subtracted. +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// The left dimension. +/// The right dimension. +public class DimCombine (AddOrSubtract add, Dim? left, Dim? right) : Dim +{ + /// + /// Gets whether the two dimensions are added or subtracted. + /// + public AddOrSubtract Add { get; } = add; + + /// + /// Gets the left dimension. + /// + public Dim? Left { get; } = left; + + /// + /// Gets the right dimension. + /// + public Dim? Right { get; } = right; + + /// + public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; } + + internal override int GetAnchor (int size) + { + int la = Left!.GetAnchor (size); + int ra = Right!.GetAnchor (size); + + if (Add == AddOrSubtract.Add) + { + return la + ra; + } + + return la - ra; + } + + internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) + { + int leftNewDim = Left!.Calculate (location, superviewContentSize, us, dimension); + int rightNewDim = Right!.Calculate (location, superviewContentSize, us, dimension); + + int newDimension; + + if (Add == AddOrSubtract.Add) + { + newDimension = leftNewDim + rightNewDim; + } + else + { + newDimension = Math.Max (0, leftNewDim - rightNewDim); + } + + return newDimension; + } + + /// + /// Diagnostics API to determine if this Dim object references other views. + /// + /// + internal override bool ReferencesOtherViews () + { + if (Left!.ReferencesOtherViews ()) + { + return true; + } + + if (Right!.ReferencesOtherViews ()) + { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimFill.cs b/Terminal.Gui/View/Layout/DimFill.cs new file mode 100644 index 000000000..03cf6f3d2 --- /dev/null +++ b/Terminal.Gui/View/Layout/DimFill.cs @@ -0,0 +1,29 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that fills the dimension, leaving the specified margin. +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// The margin to not fill. +public class DimFill (int margin) : Dim +{ + /// + public override bool Equals (object? other) { return other is DimFill fill && fill.Margin == Margin; } + + /// + public override int GetHashCode () { return Margin.GetHashCode (); } + + /// + /// Gets the margin to not fill. + /// + public int Margin { get; } = margin; + + /// + public override string ToString () { return $"Fill({Margin})"; } + + internal override int GetAnchor (int size) { return size - Margin; } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimFunc.cs b/Terminal.Gui/View/Layout/DimFunc.cs new file mode 100644 index 000000000..c15e9fc8c --- /dev/null +++ b/Terminal.Gui/View/Layout/DimFunc.cs @@ -0,0 +1,29 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a function object that computes the dimension by executing the provided function. +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +public class DimFunc (Func dim) : Dim +{ + /// + public override bool Equals (object? other) { return other is DimFunc f && f.Func () == Func (); } + + /// + /// Gets the function that computes the dimension. + /// + public new Func Func { get; } = dim; + + /// + public override int GetHashCode () { return Func.GetHashCode (); } + + /// + public override string ToString () { return $"DimFunc({Func ()})"; } + + internal override int GetAnchor (int size) { return Func (); } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimPercent.cs b/Terminal.Gui/View/Layout/DimPercent.cs new file mode 100644 index 000000000..7e535d308 --- /dev/null +++ b/Terminal.Gui/View/Layout/DimPercent.cs @@ -0,0 +1,46 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that is a percentage of the width or height of the SuperView. +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// The percentage. +/// +/// If the dimension is computed using the View's position ( or +/// ). +/// If the dimension is computed using the View's . +/// +public class DimPercent (float percent, bool usePosition = false) : Dim +{ + /// + public override bool Equals (object? other) { return other is DimPercent f && f.Percent == Percent && f.UsePosition == UsePosition; } + + /// + public override int GetHashCode () { return Percent.GetHashCode (); } + + /// + /// Gets the percentage. + /// + public new float Percent { get; } = percent; + + /// + /// + /// + public override string ToString () { return $"Percent({Percent},{UsePosition})"; } + + /// + /// Gets whether the dimension is computed using the View's position or ContentSize. + /// + public bool UsePosition { get; } = usePosition; + + internal override int GetAnchor (int size) { return (int)(size * Percent); } + + internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension) + { + return UsePosition ? Math.Max (GetAnchor (superviewContentSize - location), 0) : GetAnchor (superviewContentSize); + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/DimView.cs b/Terminal.Gui/View/Layout/DimView.cs new file mode 100644 index 000000000..8e7c22b52 --- /dev/null +++ b/Terminal.Gui/View/Layout/DimView.cs @@ -0,0 +1,69 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a dimension that tracks the Height or Width of the specified View. +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +public class DimView : Dim +{ + /// + /// Initializes a new instance of the class. + /// + /// The view the dimension is anchored to. + /// Indicates which dimension is tracked. + public DimView (View view, Dimension dimension) + { + Target = view; + Dimension = dimension; + } + + /// + /// Gets the indicated dimension of the View. + /// + public Dimension Dimension { get; } + + /// + public override bool Equals (object? other) { return other is DimView abs && abs.Target == Target && abs.Dimension == Dimension; } + + /// + public override int GetHashCode () { return Target.GetHashCode (); } + + /// + /// Gets the View the dimension is anchored to. + /// + public View Target { get; init; } + + /// + public override string ToString () + { + if (Target == null) + { + throw new NullReferenceException (); + } + + string dimString = Dimension switch + { + Dimension.Height => "Height", + Dimension.Width => "Width", + _ => "unknown" + }; + + return $"View({dimString},{Target})"; + } + + internal override int GetAnchor (int size) + { + return Dimension switch + { + Dimension.Height => Target.Frame.Height, + Dimension.Width => Target.Frame.Width, + _ => 0 + }; + } + + internal override bool ReferencesOtherViews () { return true; } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/Dimension.cs b/Terminal.Gui/View/Layout/Dimension.cs new file mode 100644 index 000000000..65186b4ab --- /dev/null +++ b/Terminal.Gui/View/Layout/Dimension.cs @@ -0,0 +1,22 @@ +namespace Terminal.Gui; + +/// +/// Indicates the dimension for operations. +/// +public enum Dimension +{ + /// + /// No dimension specified. + /// + None = 0, + + /// + /// The height dimension. + /// + Height = 1, + + /// + /// The width dimension. + /// + Width = 2 +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/LayoutStyle.cs b/Terminal.Gui/View/Layout/LayoutStyle.cs new file mode 100644 index 000000000..36e55a4ec --- /dev/null +++ b/Terminal.Gui/View/Layout/LayoutStyle.cs @@ -0,0 +1,35 @@ +namespace Terminal.Gui; + +/// +/// Indicates the LayoutStyle for the . +/// +/// If Absolute, the , , , and +/// objects are all absolute values and are not relative. The position and size of the +/// view is described by . +/// +/// +/// If Computed, one or more of the , , , or +/// objects are relative to the and are computed at layout +/// time. +/// +/// +public enum LayoutStyle +{ + /// + /// Indicates the , , , and + /// objects are all absolute values and are not relative. The position and size of the view + /// is described by . + /// + Absolute, + + /// + /// Indicates one or more of the , , , or + /// + /// objects are relative to the and are computed at layout time. The position and size of + /// the + /// view + /// will be computed based on these objects at layout time. will provide the absolute computed + /// values. + /// + Computed +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/Pos.cs b/Terminal.Gui/View/Layout/Pos.cs index 1935e3c02..8db733431 100644 --- a/Terminal.Gui/View/Layout/Pos.cs +++ b/Terminal.Gui/View/Layout/Pos.cs @@ -1,31 +1,6 @@ +#nullable enable namespace Terminal.Gui; -/// -/// Indicates the side for operations. -/// -public enum Side -{ - /// - /// The left (X) side of the view. - /// - Left = 0, - - /// - /// The top (Y) side of the view. - /// - Top = 1, - - /// - /// The right (X + Width) side of the view. - /// - Right = 2, - - /// - /// The bottom (Y + Height) side of the view. - /// - Bottom = 3 -} - /// /// Describes the position of a which can be an absolute value, a percentage, centered, or /// relative to the ending dimension. Integer values are implicitly convertible to an absolute . These @@ -385,315 +360,4 @@ public abstract class Pos #endregion operators -} - -/// -/// Represents an absolute position in the layout. This is used to specify a fixed position in the layout. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// -public class PosAbsolute (int position) : Pos -{ - /// - /// The position of the in the layout. - /// - public int Position { get; } = position; - - /// - public override bool Equals (object other) { return other is PosAbsolute abs && abs.Position == Position; } - - /// - public override int GetHashCode () { return Position.GetHashCode (); } - - /// - public override string ToString () { return $"Absolute({Position})"; } - - internal override int GetAnchor (int size) { return Position; } -} - -/// -/// Represents a position anchored to the end (right side or bottom). -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -public class PosAnchorEnd : Pos -{ - /// - /// Gets the offset of the position from the right/bottom. - /// - public int Offset { get; } - - /// - /// Constructs a new position 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. - /// - public PosAnchorEnd () { UseDimForOffset = true; } - - /// - /// Constructs a new position anchored to the end (right side or bottom) of the SuperView, - /// - /// - 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 (); } - - /// - /// If true, the offset is the width of the view, if false, the offset is the offset value. - /// - public bool UseDimForOffset { get; } - - /// - public override string ToString () { return UseDimForOffset ? "AnchorEnd()" : $"AnchorEnd({Offset})"; } - - internal override int GetAnchor (int size) - { - if (UseDimForOffset) - { - return size; - } - - return size - Offset; - } - - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) - { - int newLocation = GetAnchor (superviewDimension); - - if (UseDimForOffset) - { - newLocation -= dim.GetAnchor (superviewDimension); - } - - return newLocation; - } -} - -/// -/// Represents a position that is centered. -/// -public class PosCenter : Pos -{ - /// - public override string ToString () { return "Center"; } - - internal override int GetAnchor (int size) { return size / 2; } - - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) - { - int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0); - - return GetAnchor (superviewDimension - newDimension); - } -} - -/// -/// Represents a position that is a combination of two other positions. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// -/// Indicates whether the two positions are added or subtracted. -/// -/// The left position. -/// The right position. -public class PosCombine (AddOrSubtract add, Pos left, Pos right) : Pos -{ - /// - /// Gets whether the two positions are added or subtracted. - /// - public AddOrSubtract Add { get; } = add; - - /// - /// Gets the left position. - /// - public new Pos Left { get; } = left; - - /// - /// Gets the right position. - /// - public new Pos Right { get; } = right; - - /// - public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; } - - internal override int GetAnchor (int size) - { - int la = Left.GetAnchor (size); - int ra = Right.GetAnchor (size); - - if (Add == AddOrSubtract.Add) - { - return la + ra; - } - - return la - ra; - } - - internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) - { - int left = Left.Calculate (superviewDimension, dim, us, dimension); - int right = Right.Calculate (superviewDimension, dim, us, dimension); - - if (Add == AddOrSubtract.Add) - { - return left + right; - } - - return left - right; - } - - internal override bool ReferencesOtherViews () - { - if (Left.ReferencesOtherViews ()) - { - return true; - } - - if (Right.ReferencesOtherViews ()) - { - return true; - } - - return false; - } -} - -/// -/// Represents a position that is a percentage of the width or height of the SuperView. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// -public class PosPercent (float percent) : Pos -{ - /// - /// Gets the factor that represents the percentage of the width or height of the SuperView. - /// - public new float Percent { get; } = percent; - - /// - public override bool Equals (object other) { return other is PosPercent f && f.Percent == Percent; } - - /// - public override int GetHashCode () { return Percent.GetHashCode (); } - - /// - public override string ToString () { return $"Percent({Percent})"; } - - internal override int GetAnchor (int size) { return (int)(size * Percent); } -} - -/// -/// Represents a position that is computed by executing a function that returns an integer position. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// The position. -public class PosFunc (Func pos) : Pos -{ - /// - /// Gets the function that computes the position. - /// - public new Func Func { get; } = pos; - - /// - public override bool Equals (object other) { return other is PosFunc f && f.Func () == Func (); } - - /// - public override int GetHashCode () { return Func.GetHashCode (); } - - /// - public override string ToString () { return $"PosFunc({Func ()})"; } - - internal override int GetAnchor (int size) { return Func (); } -} - -/// -/// Represents a position that is anchored to the side of another view. -/// -/// -/// -/// This is a low-level API that is typically used internally by the layout system. Use the various static -/// methods on the class to create objects instead. -/// -/// -/// The View the position is anchored to. -/// The side of the View the position is anchored to. -public class PosView (View view, Side side) : Pos -{ - /// - /// Gets the View the position is anchored to. - /// - public View Target { get; } = view; - - /// - /// Gets the side of the View the position is anchored to. - /// - public Side Side { get; } = side; - - /// - public override bool Equals (object other) { return other is PosView abs && abs.Target == Target && abs.Side == Side; } - - /// - public override int GetHashCode () { return Target.GetHashCode (); } - - /// - public override string ToString () - { - string sideString = Side switch - { - Side.Left => "left", - Side.Top => "top", - Side.Right => "right", - Side.Bottom => "bottom", - _ => "unknown" - }; - - if (Target == null) - { - throw new NullReferenceException (nameof (Target)); - } - - return $"View(side={sideString},target={Target})"; - } - - internal override int GetAnchor (int size) - { - return Side switch - { - Side.Left => Target.Frame.X, - Side.Top => Target.Frame.Y, - Side.Right => Target.Frame.Right, - Side.Bottom => Target.Frame.Bottom, - _ => 0 - }; - } - - internal override bool ReferencesOtherViews () { return true; } -} +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosAbsolute.cs b/Terminal.Gui/View/Layout/PosAbsolute.cs new file mode 100644 index 000000000..44afdac97 --- /dev/null +++ b/Terminal.Gui/View/Layout/PosAbsolute.cs @@ -0,0 +1,31 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents an absolute position in the layout. This is used to specify a fixed position in the layout. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// +public class PosAbsolute (int position) : Pos +{ + /// + /// The position of the in the layout. + /// + public int Position { get; } = position; + + /// + public override bool Equals (object? other) { return other is PosAbsolute abs && abs.Position == Position; } + + /// + public override int GetHashCode () { return Position.GetHashCode (); } + + /// + public override string ToString () { return $"Absolute({Position})"; } + + internal override int GetAnchor (int size) { return Position; } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosAnchorEnd.cs b/Terminal.Gui/View/Layout/PosAnchorEnd.cs new file mode 100644 index 000000000..e4641c2b5 --- /dev/null +++ b/Terminal.Gui/View/Layout/PosAnchorEnd.cs @@ -0,0 +1,68 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position anchored to the end (right side or bottom). +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +public class PosAnchorEnd : Pos +{ + /// + /// Gets the offset of the position from the right/bottom. + /// + public int Offset { get; } + + /// + /// Constructs a new position 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. + /// + public PosAnchorEnd () { UseDimForOffset = true; } + + /// + /// Constructs a new position anchored to the end (right side or bottom) of the SuperView, + /// + /// + 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 (); } + + /// + /// If true, the offset is the width of the view, if false, the offset is the offset value. + /// + public bool UseDimForOffset { get; } + + /// + public override string ToString () { return UseDimForOffset ? "AnchorEnd()" : $"AnchorEnd({Offset})"; } + + internal override int GetAnchor (int size) + { + if (UseDimForOffset) + { + return size; + } + + return size - Offset; + } + + internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + { + int newLocation = GetAnchor (superviewDimension); + + if (UseDimForOffset) + { + newLocation -= dim.GetAnchor (superviewDimension); + } + + return newLocation; + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosCenter.cs b/Terminal.Gui/View/Layout/PosCenter.cs new file mode 100644 index 000000000..04c7958bb --- /dev/null +++ b/Terminal.Gui/View/Layout/PosCenter.cs @@ -0,0 +1,20 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position that is centered. +/// +public class PosCenter : Pos +{ + /// + public override string ToString () { return "Center"; } + + internal override int GetAnchor (int size) { return size / 2; } + + internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + { + int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0); + + return GetAnchor (superviewDimension - newDimension); + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosCombine.cs b/Terminal.Gui/View/Layout/PosCombine.cs new file mode 100644 index 000000000..3f9666d9c --- /dev/null +++ b/Terminal.Gui/View/Layout/PosCombine.cs @@ -0,0 +1,78 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position that is a combination of two other positions. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// +/// Indicates whether the two positions are added or subtracted. +/// +/// The left position. +/// The right position. +public class PosCombine (AddOrSubtract add, Pos left, Pos right) : Pos +{ + /// + /// Gets whether the two positions are added or subtracted. + /// + public AddOrSubtract Add { get; } = add; + + /// + /// Gets the left position. + /// + public new Pos Left { get; } = left; + + /// + /// Gets the right position. + /// + public new Pos Right { get; } = right; + + /// + public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; } + + internal override int GetAnchor (int size) + { + int la = Left.GetAnchor (size); + int ra = Right.GetAnchor (size); + + if (Add == AddOrSubtract.Add) + { + return la + ra; + } + + return la - ra; + } + + internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) + { + int left = Left.Calculate (superviewDimension, dim, us, dimension); + int right = Right.Calculate (superviewDimension, dim, us, dimension); + + if (Add == AddOrSubtract.Add) + { + return left + right; + } + + return left - right; + } + + internal override bool ReferencesOtherViews () + { + if (Left.ReferencesOtherViews ()) + { + return true; + } + + if (Right.ReferencesOtherViews ()) + { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosFunc.cs b/Terminal.Gui/View/Layout/PosFunc.cs new file mode 100644 index 000000000..24344f9a8 --- /dev/null +++ b/Terminal.Gui/View/Layout/PosFunc.cs @@ -0,0 +1,31 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position that is computed by executing a function that returns an integer position. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// The position. +public class PosFunc (Func pos) : Pos +{ + /// + /// Gets the function that computes the position. + /// + public new Func Func { get; } = pos; + + /// + public override bool Equals (object? other) { return other is PosFunc f && f.Func () == Func (); } + + /// + public override int GetHashCode () { return Func.GetHashCode (); } + + /// + public override string ToString () { return $"PosFunc({Func ()})"; } + + internal override int GetAnchor (int size) { return Func (); } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosPercent.cs b/Terminal.Gui/View/Layout/PosPercent.cs new file mode 100644 index 000000000..09b6e179b --- /dev/null +++ b/Terminal.Gui/View/Layout/PosPercent.cs @@ -0,0 +1,31 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position that is a percentage of the width or height of the SuperView. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// +public class PosPercent (float percent) : Pos +{ + /// + /// Gets the factor that represents the percentage of the width or height of the SuperView. + /// + public new float Percent { get; } = percent; + + /// + public override bool Equals (object? other) { return other is PosPercent f && f.Percent == Percent; } + + /// + public override int GetHashCode () { return Percent.GetHashCode (); } + + /// + public override string ToString () { return $"Percent({Percent})"; } + + internal override int GetAnchor (int size) { return (int)(size * Percent); } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/PosView.cs b/Terminal.Gui/View/Layout/PosView.cs new file mode 100644 index 000000000..51802337d --- /dev/null +++ b/Terminal.Gui/View/Layout/PosView.cs @@ -0,0 +1,66 @@ +#nullable enable +namespace Terminal.Gui; + +/// +/// Represents a position that is anchored to the side of another view. +/// +/// +/// +/// This is a low-level API that is typically used internally by the layout system. Use the various static +/// methods on the class to create objects instead. +/// +/// +/// The View the position is anchored to. +/// The side of the View the position is anchored to. +public class PosView (View view, Side side) : Pos +{ + /// + /// Gets the View the position is anchored to. + /// + public View Target { get; } = view; + + /// + /// Gets the side of the View the position is anchored to. + /// + public Side Side { get; } = side; + + /// + public override bool Equals (object? other) { return other is PosView abs && abs.Target == Target && abs.Side == Side; } + + /// + public override int GetHashCode () { return Target.GetHashCode (); } + + /// + public override string ToString () + { + string sideString = Side switch + { + Side.Left => "left", + Side.Top => "top", + Side.Right => "right", + Side.Bottom => "bottom", + _ => "unknown" + }; + + if (Target == null) + { + throw new NullReferenceException (nameof (Target)); + } + + return $"View(side={sideString},target={Target})"; + } + + internal override int GetAnchor (int size) + { + return Side switch + { + Side.Left => Target.Frame.X, + Side.Top => Target.Frame.Y, + Side.Right => Target.Frame.Right, + Side.Bottom => Target.Frame.Bottom, + _ => 0 + }; + } + + internal override bool ReferencesOtherViews () { return true; } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/Side.cs b/Terminal.Gui/View/Layout/Side.cs new file mode 100644 index 000000000..6c03d5470 --- /dev/null +++ b/Terminal.Gui/View/Layout/Side.cs @@ -0,0 +1,27 @@ +namespace Terminal.Gui; + +/// +/// Indicates the side for operations. +/// +public enum Side +{ + /// + /// The left (X) side of the view. + /// + Left = 0, + + /// + /// The top (Y) side of the view. + /// + Top = 1, + + /// + /// The right (X + Width) side of the view. + /// + Right = 2, + + /// + /// The bottom (Y + Height) side of the view. + /// + Bottom = 3 +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/View.cs similarity index 96% rename from Terminal.Gui/View/Layout/ViewLayout.cs rename to Terminal.Gui/View/Layout/View.cs index e0ca37eb4..dcb94b91e 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/View.cs @@ -4,40 +4,6 @@ using Microsoft.CodeAnalysis; namespace Terminal.Gui; -/// -/// Indicates the LayoutStyle for the . -/// -/// If Absolute, the , , , and -/// objects are all absolute values and are not relative. The position and size of the -/// view is described by . -/// -/// -/// If Computed, one or more of the , , , or -/// objects are relative to the and are computed at layout -/// time. -/// -/// -public enum LayoutStyle -{ - /// - /// Indicates the , , , and - /// objects are all absolute values and are not relative. The position and size of the view - /// is described by . - /// - Absolute, - - /// - /// Indicates one or more of the , , , or - /// - /// objects are relative to the and are computed at layout time. The position and size of - /// the - /// view - /// will be computed based on these objects at layout time. will provide the absolute computed - /// values. - /// - Computed -} - public partial class View { #region Frame