// 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);
}
}
}