// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace FlaxEngine.GUI { /// /// Describes the space around a control. /// [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct Margin : IEquatable, IFormattable { private static readonly string _formatString = "Left:{0:F2} Right:{1:F2} Top:{2:F2} Bottom:{3:F2}"; /// /// The size of the type, in bytes. /// public static readonly int SizeInBytes = Marshal.SizeOf(typeof(Margin)); /// /// A with all of its components set to zero. /// public static readonly Margin Zero; /// /// Holds the margin to the left. /// [EditorOrder(0)] public float Left; /// /// Holds the margin to the right. /// [EditorOrder(1)] public float Right; /// /// Holds the margin to the top. /// [EditorOrder(2)] public float Top; /// /// Holds the margin to the bottom. /// [EditorOrder(3)] public float Bottom; /// /// Gets the margin's location (Left, Top). /// public Float2 Location => new Float2(Left, Top); /// /// Gets the margin's total size. Cumulative margin size (Left + Right, Top + Bottom). /// public Float2 Size => new Float2(Left + Right, Top + Bottom); /// /// Gets the width (left + right). /// public float Width => Left + Right; /// /// Gets the height (top + bottom). /// public float Height => Top + Bottom; /// /// Initializes a new instance of the struct. /// /// The value. public Margin(float value) { Left = Right = Top = Bottom = value; } /// /// Initializes a new instance of the struct. /// /// The left. /// The right. /// The top. /// The bottom. public Margin(float left, float right, float top, float bottom) { Left = left; Right = right; Top = top; Bottom = bottom; } /// /// Gets a value indicting whether this margin is zero. /// public bool IsZero => Mathf.IsZero(Left) && Mathf.IsZero(Right) && Mathf.IsZero(Top) && Mathf.IsZero(Bottom); /// /// Shrinks the rectangle by this margin. /// /// The rectangle. public void ShrinkRectangle(ref Rectangle rect) { rect.Location.X += Left; rect.Location.Y += Top; rect.Size.X -= Left + Right; rect.Size.Y -= Top + Bottom; } /// /// Expands the rectangle by this margin. /// /// The rectangle. public void ExpandRectangle(ref Rectangle rect) { rect.Location.X -= Left; rect.Location.Y -= Top; rect.Size.X += Left + Right; rect.Size.Y += Top + Bottom; } /// /// Adds two margins. /// /// The first margins to add. /// The second margins to add. /// The sum of the two margins. public static Margin operator +(Margin left, Margin right) { return new Margin(left.Left + right.Left, left.Right + right.Right, left.Top + right.Top, left.Bottom + right.Bottom); } /// /// Subtracts two margins. /// /// The first margins to subtract from. /// The second margins to subtract. /// The result of subtraction of the two margins. public static Margin operator -(Margin left, Margin right) { return new Margin(left.Left - right.Left, left.Right - right.Right, left.Top - right.Top, left.Bottom - right.Bottom); } /// /// Tests for equality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has the same value as ; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Margin left, Margin right) { return left.Equals(ref right); } /// /// Tests for inequality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has a different value than ; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Margin left, Margin right) { return !left.Equals(ref right); } /// /// Returns a that represents this instance. /// /// A that represents this instance. public override string ToString() { return string.Format(CultureInfo.CurrentCulture, "Left:{0} Right:{1} Top:{2} Bottom:{3}", Left, Right, Top, Bottom); } /// /// Returns a that represents this instance. /// /// The format. /// A that represents this instance. public string ToString(string format) { if (format == null) return ToString(); return string.Format(CultureInfo.CurrentCulture, _formatString, Left.ToString(format, CultureInfo.CurrentCulture), Right.ToString(format, CultureInfo.CurrentCulture), Top.ToString(format, CultureInfo.CurrentCulture), Bottom.ToString(format, CultureInfo.CurrentCulture) ); } /// /// Returns a that represents this instance. /// /// The format provider. /// A that represents this instance. public string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, _formatString, Left, Right, Top, Bottom ); } /// /// Returns a that represents this instance. /// /// The format. /// The format provider. /// A that represents this instance. public string ToString(string format, IFormatProvider formatProvider) { if (format == null) return ToString(formatProvider); return string.Format(formatProvider, _formatString, Left.ToString(format, formatProvider), Right.ToString(format, formatProvider), Top.ToString(format, formatProvider), Bottom.ToString(format, formatProvider) ); } /// /// Returns a hash code for this instance. /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() { unchecked { int hashCode = Left.GetHashCode(); hashCode = (hashCode * 397) ^ Right.GetHashCode(); hashCode = (hashCode * 397) ^ Top.GetHashCode(); hashCode = (hashCode * 397) ^ Bottom.GetHashCode(); return hashCode; } } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public bool Equals(ref Margin other) { return Mathf.NearEqual(other.Left, Left) && Mathf.NearEqual(other.Right, Right) && Mathf.NearEqual(other.Top, Top) && Mathf.NearEqual(other.Bottom, Bottom); } /// /// Determines whether the specified are equal. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Equals(ref Margin a, ref Margin b) { return a.Equals(ref b); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Margin other) { return Equals(ref other); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public override bool Equals(object value) { return value is Margin margin && Equals(ref margin); } } }