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