// 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 Avalonia.Utilities; namespace Avalonia { /// /// Defines the reference point units of an or /// . /// public enum RelativeUnit { /// /// The point is expressed as a fraction of the containing element's size. /// Relative, /// /// The point is absolute (i.e. in pixels). /// Absolute, } /// /// Defines a point that may be defined relative to a containing element. /// public readonly struct RelativePoint : IEquatable { /// /// A point at the top left of the containing element. /// public static readonly RelativePoint TopLeft = new RelativePoint(0, 0, RelativeUnit.Relative); /// /// A point at the center of the containing element. /// public static readonly RelativePoint Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative); /// /// A point at the bottom right of the containing element. /// public static readonly RelativePoint BottomRight = new RelativePoint(1, 1, RelativeUnit.Relative); private readonly Point _point; private readonly RelativeUnit _unit; /// /// Initializes a new instance of the struct. /// /// The X point. /// The Y point /// The unit. public RelativePoint(double x, double y, RelativeUnit unit) : this(new Point(x, y), unit) { } /// /// Initializes a new instance of the struct. /// /// The point. /// The unit. public RelativePoint(Point point, RelativeUnit unit) { _point = point; _unit = unit; } /// /// Gets the point. /// public Point Point => _point; /// /// Gets the unit. /// public RelativeUnit Unit => _unit; /// /// Checks for equality between two s. /// /// The first point. /// The second point. /// True if the points are equal; otherwise false. public static bool operator ==(RelativePoint left, RelativePoint right) { return left.Equals(right); } /// /// Checks for inequality between two s. /// /// The first point. /// The second point. /// True if the points are unequal; otherwise false. public static bool operator !=(RelativePoint left, RelativePoint 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) => obj is RelativePoint other && Equals(other); /// /// Checks if the equals another point. /// /// The other point. /// True if the objects are equal, otherwise false. public bool Equals(RelativePoint p) { return Unit == p.Unit && Point == p.Point; } /// /// Gets a hashcode for a . /// /// A hash code. public override int GetHashCode() { unchecked { return (_point.GetHashCode() * 397) ^ (int)_unit; } } /// /// Converts a into pixels. /// /// The size of the visual. /// The origin point in pixels. public Point ToPixels(Size size) { return _unit == RelativeUnit.Absolute ? _point : new Point(_point.X * size.Width, _point.Y * size.Height); } /// /// Parses a string. /// /// The string. /// The parsed . public static RelativePoint Parse(string s) { using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid RelativePoint.")) { var x = tokenizer.ReadString(); var y = tokenizer.ReadString(); var unit = RelativeUnit.Absolute; var scale = 1.0; if (x.EndsWith("%")) { if (!y.EndsWith("%")) { throw new FormatException("If one coordinate is relative, both must be."); } x = x.TrimEnd('%'); y = y.TrimEnd('%'); unit = RelativeUnit.Relative; scale = 0.01; } return new RelativePoint( double.Parse(x, CultureInfo.InvariantCulture) * scale, double.Parse(y, CultureInfo.InvariantCulture) * scale, unit); } } } }