// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; using System.Globalization; using System.Linq; namespace Avalonia { /// /// Defines a rectangle that may be defined relative to a containing element. /// public struct RelativeRect : IEquatable { /// /// A rectangle that represents 100% of an area. /// public static readonly RelativeRect Fill = new RelativeRect(0, 0, 1, 1, RelativeUnit.Relative); /// /// Initializes a new instance of the structure. /// /// The X position. /// The Y position. /// The width. /// The height. /// The unit of the rect. public RelativeRect(double x, double y, double width, double height, RelativeUnit unit) { Rect = new Rect(x, y, width, height); Unit = unit; } /// /// Initializes a new instance of the structure. /// /// The rectangle. /// The unit of the rect. public RelativeRect(Rect rect, RelativeUnit unit) { Rect = rect; Unit = unit; } /// /// Initializes a new instance of the structure. /// /// The size of the rectangle. /// The unit of the rect. public RelativeRect(Size size, RelativeUnit unit) { Rect = new Rect(size); Unit = unit; } /// /// Initializes a new instance of the structure. /// /// The position of the rectangle. /// The size of the rectangle. /// The unit of the rect. public RelativeRect(Point position, Size size, RelativeUnit unit) { Rect = new Rect(position, size); Unit = unit; } /// /// Initializes a new instance of the structure. /// /// The top left position of the rectangle. /// The bottom right position of the rectangle. /// The unit of the rect. public RelativeRect(Point topLeft, Point bottomRight, RelativeUnit unit) { Rect = new Rect(topLeft, bottomRight); Unit = unit; } /// /// Gets the unit of the rectangle. /// public RelativeUnit Unit { get; } /// /// Gets the rectangle. /// public Rect Rect { get; } /// /// Checks for equality between two s. /// /// The first rectangle. /// The second rectangle. /// True if the rectangles are equal; otherwise false. public static bool operator ==(RelativeRect left, RelativeRect right) { return left.Equals(right); } /// /// Checks for unequality between two s. /// /// The first rectangle. /// The second rectangle. /// True if the rectangles are unequal; otherwise false. public static bool operator !=(RelativeRect left, RelativeRect right) { return !left.Equals(right); } /// /// Checks if the equals another object. /// /// The other object. /// True if the objects are equal, otherwise false. public override bool Equals(object obj) { return (obj is RelativeRect) && Equals((RelativeRect)obj); } /// /// Checks if the equals another rectangle. /// /// The other rectangle. /// True if the objects are equal, otherwise false. public bool Equals(RelativeRect p) { return Unit == p.Unit && Rect == p.Rect; } /// /// Gets a hashcode for a . /// /// A hash code. public override int GetHashCode() { unchecked { int hash = 17; hash = (hash * 23) + Unit.GetHashCode(); hash = (hash * 23) + Rect.GetHashCode(); return hash; } } /// /// Converts a into pixels. /// /// The size of the visual. /// The origin point in pixels. public Rect ToPixels(Size size) { return Unit == RelativeUnit.Absolute ? Rect : new Rect( Rect.X * size.Width, Rect.Y * size.Height, Rect.Width * size.Width, Rect.Height * size.Height); } /// /// Parses a string. /// /// The string. /// The current culture. /// The parsed . public static RelativeRect Parse(string s, CultureInfo culture) { var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .ToList(); if (parts.Count == 4) { var unit = RelativeUnit.Absolute; var scale = 1.0; if (parts[0].EndsWith("%")) { if (!parts[1].EndsWith("%") || !parts[2].EndsWith("%") || !parts[3].EndsWith("%")) { throw new FormatException("If one coordinate is relative, all other must be too."); } parts[0] = parts[0].TrimEnd('%'); parts[1] = parts[1].TrimEnd('%'); parts[2] = parts[2].TrimEnd('%'); parts[3] = parts[3].TrimEnd('%'); unit = RelativeUnit.Relative; scale = 0.01; } return new RelativeRect( double.Parse(parts[0], culture) * scale, double.Parse(parts[1], culture) * scale, double.Parse(parts[2], culture) * scale, double.Parse(parts[3], culture) * scale, unit); } else { throw new FormatException("Invalid RelativeRect."); } } } }