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