diff --git a/Terminal.Gui/Drawing/Thickness.cs b/Terminal.Gui/Drawing/Thickness.cs index ad684470b8..532c0af8a3 100644 --- a/Terminal.Gui/Drawing/Thickness.cs +++ b/Terminal.Gui/Drawing/Thickness.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Numerics; +using System.Text.Json.Serialization; namespace Terminal.Gui; @@ -13,28 +14,18 @@ namespace Terminal.Gui; /// frame, /// with the thickness widths subtracted. /// -/// Use the helper API ( to draw the frame with the specified thickness. +/// +/// Use the helper API ( to draw the frame with the specified thickness. +/// +/// +/// Thickness uses intenrally. As a result, there is a potential precision loss for very +/// large numbers. This is typically not an issue for UI dimensions but could be relevant in other contexts. +/// /// -public class Thickness : IEquatable +public record struct Thickness { - /// Gets or sets the width of the lower side of the rectangle. - [JsonInclude] - public int Bottom; - - /// Gets or sets the width of the left side of the rectangle. - [JsonInclude] - public int Left; - - /// Gets or sets the width of the right side of the rectangle. - [JsonInclude] - public int Right; - - /// Gets or sets the width of the upper side of the rectangle. - [JsonInclude] - public int Top; - /// Initializes a new instance of the class with all widths set to 0. - public Thickness () { } + public Thickness () { _sides = Vector4.Zero; } /// Initializes a new instance of the class with a uniform width to each side. /// @@ -56,36 +47,24 @@ public Thickness (int left, int top, int right, int bottom) Bottom = bottom; } - // TODO: add operator overloads - /// Gets an empty thickness. - public static Thickness Empty => new (0); + private Vector4 _sides; /// - /// Gets the total width of the left and right sides of the rectangle. Sets the width of the left and rigth sides - /// of the rectangle to half the specified value. + /// Adds the thickness widths of another to the current , returning a + /// new . /// - public int Horizontal - { - get => Left + Right; - set => Left = Right = value / 2; - } + /// + /// + public readonly Thickness Add (Thickness other) { return new (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom); } - /// - /// Gets the total height of the top and bottom sides of the rectangle. Sets the height of the top and bottom - /// sides of the rectangle to half the specified value. - /// - public int Vertical + /// Gets or sets the width of the lower side of the rectangle. + [JsonInclude] + public int Bottom { - get => Top + Bottom; - set => Top = Bottom = value / 2; + get => (int)_sides.W; + set => _sides.W = value; } - // IEquitable - /// Indicates whether the current object is equal to another object of the same type. - /// - /// true if the current object is equal to the other parameter; otherwise, false. - public bool Equals (Thickness other) { return other is { } && Left == other.Left && Right == other.Right && Top == other.Top && Bottom == other.Bottom; } - /// /// Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside /// the rectangle described by . @@ -100,22 +79,6 @@ public bool Contains (in Rectangle outside, in Point location) return outside.Contains (location) && !inside.Contains (location); } - /// - /// Adds the thickness widths of another to the current , returning a - /// new . - /// - /// - /// - public Thickness Add (Thickness other) { return new (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom); } - - /// - /// Adds the thickness widths of another to another . - /// - /// - /// - /// - public static Thickness operator + (Thickness a, Thickness b) { return a.Add (b); } - /// Draws the rectangle with an optional diagnostics label. /// /// If is set to @@ -240,31 +203,8 @@ rect with return GetInside (rect); } - /// Determines whether the specified object is equal to the current object. - /// The object to compare with the current object. - /// true if the specified object is equal to the current object; otherwise, false. - public override bool Equals (object obj) - { - //Check for null and compare run-time types. - if (obj is null || !GetType ().Equals (obj.GetType ())) - { - return false; - } - - return Equals ((Thickness)obj); - } - - /// - public override int GetHashCode () - { - var hashCode = 1380952125; - hashCode = hashCode * -1521134295 + Left.GetHashCode (); - hashCode = hashCode * -1521134295 + Right.GetHashCode (); - hashCode = hashCode * -1521134295 + Top.GetHashCode (); - hashCode = hashCode * -1521134295 + Bottom.GetHashCode (); - - return hashCode; - } + /// Gets an empty thickness. + public static Thickness Empty => new (0); /// /// Returns a rectangle describing the location and size of the inside area of with the @@ -289,23 +229,59 @@ public Rectangle GetInside (Rectangle rect) return new (x, y, width, height); } - /// - public static bool operator == (Thickness left, Thickness right) { return EqualityComparer.Default.Equals (left, right); } + /// + /// Gets the total width of the left and right sides of the rectangle. Sets the width of the left and rigth sides + /// of the rectangle to half the specified value. + /// + public int Horizontal + { + get => Left + Right; + set => Left = Right = value / 2; + } - /// - public static bool operator != (Thickness left, Thickness right) { return !(left == right); } + /// Gets or sets the width of the left side of the rectangle. + [JsonInclude] + public int Left + { + get => (int)_sides.X; + set => _sides.X = value; + } + + /// + /// Adds the thickness widths of another to another . + /// + /// + /// + /// + public static Thickness operator + (Thickness a, Thickness b) { return a.Add (b); } + + /// Gets or sets the width of the right side of the rectangle. + [JsonInclude] + public int Right + { + get => (int)_sides.Z; + set => _sides.Z = value; + } + + /// Gets or sets the width of the upper side of the rectangle. + [JsonInclude] + public int Top + { + get => (int)_sides.Y; + set => _sides.Y = value; + } /// Returns the thickness widths of the Thickness formatted as a string. /// The thickness widths as a string. public override string ToString () { return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})"; } - private int validate (int width) + /// + /// Gets the total height of the top and bottom sides of the rectangle. Sets the height of the top and bottom + /// sides of the rectangle to half the specified value. + /// + public int Vertical { - if (width < 0) - { - throw new ArgumentException ("Thickness widths cannot be negative."); - } - - return width; + get => Top + Bottom; + set => Top = Bottom = value / 2; } } diff --git a/UnitTests/View/Adornment/BorderTests.cs b/UnitTests/View/Adornment/BorderTests.cs index d2f88916b1..387844dbe6 100644 --- a/UnitTests/View/Adornment/BorderTests.cs +++ b/UnitTests/View/Adornment/BorderTests.cs @@ -18,7 +18,7 @@ public void Border_Parent_HasFocus_Title_Uses_FocusAttribute () view.Border.Thickness = new (0, 1, 0, 0); view.Border.LineStyle = LineStyle.Single; - view.ColorScheme = new() + view.ColorScheme = new () { Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red) @@ -53,7 +53,7 @@ public void Border_Uses_Parent_ColorScheme () view.Border.Thickness = new (0, 1, 0, 0); view.Border.LineStyle = LineStyle.Single; - view.ColorScheme = new() + view.ColorScheme = new () { Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red) }; @@ -90,7 +90,7 @@ public void Border_With_Title_Border_Double_Thickness_Top_Four_Size_Width (int w { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness.Top = 4; + win.Border.Thickness = win.Border.Thickness with { Top = 4 }; RunState rs = Application.Begin (win); var firstIteration = false; @@ -224,7 +224,7 @@ public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness.Top = 3; + win.Border.Thickness = win.Border.Thickness with { Top = 3 }; RunState rs = Application.Begin (win); var firstIteration = false; @@ -358,7 +358,7 @@ public void Border_With_Title_Border_Double_Thickness_Top_Two_Size_Width (int wi { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness.Top = 2; + win.Border.Thickness = win.Border.Thickness with { Top = 2 }; RunState rs = Application.Begin (win); var firstIteration = false;