RelativePoint.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Globalization;
  5. using Avalonia.Utilities;
  6. namespace Avalonia
  7. {
  8. /// <summary>
  9. /// Defines the reference point units of an <see cref="RelativePoint"/> or
  10. /// <see cref="RelativeRect"/>.
  11. /// </summary>
  12. public enum RelativeUnit
  13. {
  14. /// <summary>
  15. /// The point is expressed as a fraction of the containing element's size.
  16. /// </summary>
  17. Relative,
  18. /// <summary>
  19. /// The point is absolute (i.e. in pixels).
  20. /// </summary>
  21. Absolute,
  22. }
  23. /// <summary>
  24. /// Defines a point that may be defined relative to a containing element.
  25. /// </summary>
  26. public readonly struct RelativePoint : IEquatable<RelativePoint>
  27. {
  28. /// <summary>
  29. /// A point at the top left of the containing element.
  30. /// </summary>
  31. public static readonly RelativePoint TopLeft = new RelativePoint(0, 0, RelativeUnit.Relative);
  32. /// <summary>
  33. /// A point at the center of the containing element.
  34. /// </summary>
  35. public static readonly RelativePoint Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative);
  36. /// <summary>
  37. /// A point at the bottom right of the containing element.
  38. /// </summary>
  39. public static readonly RelativePoint BottomRight = new RelativePoint(1, 1, RelativeUnit.Relative);
  40. private readonly Point _point;
  41. private readonly RelativeUnit _unit;
  42. /// <summary>
  43. /// Initializes a new instance of the <see cref="RelativePoint"/> struct.
  44. /// </summary>
  45. /// <param name="x">The X point.</param>
  46. /// <param name="y">The Y point</param>
  47. /// <param name="unit">The unit.</param>
  48. public RelativePoint(double x, double y, RelativeUnit unit)
  49. : this(new Point(x, y), unit)
  50. {
  51. }
  52. /// <summary>
  53. /// Initializes a new instance of the <see cref="RelativePoint"/> struct.
  54. /// </summary>
  55. /// <param name="point">The point.</param>
  56. /// <param name="unit">The unit.</param>
  57. public RelativePoint(Point point, RelativeUnit unit)
  58. {
  59. _point = point;
  60. _unit = unit;
  61. }
  62. /// <summary>
  63. /// Gets the point.
  64. /// </summary>
  65. public Point Point => _point;
  66. /// <summary>
  67. /// Gets the unit.
  68. /// </summary>
  69. public RelativeUnit Unit => _unit;
  70. /// <summary>
  71. /// Checks for equality between two <see cref="RelativePoint"/>s.
  72. /// </summary>
  73. /// <param name="left">The first point.</param>
  74. /// <param name="right">The second point.</param>
  75. /// <returns>True if the points are equal; otherwise false.</returns>
  76. public static bool operator ==(RelativePoint left, RelativePoint right)
  77. {
  78. return left.Equals(right);
  79. }
  80. /// <summary>
  81. /// Checks for inequality between two <see cref="RelativePoint"/>s.
  82. /// </summary>
  83. /// <param name="left">The first point.</param>
  84. /// <param name="right">The second point.</param>
  85. /// <returns>True if the points are unequal; otherwise false.</returns>
  86. public static bool operator !=(RelativePoint left, RelativePoint right)
  87. {
  88. return !left.Equals(right);
  89. }
  90. /// <summary>
  91. /// Checks if the <see cref="RelativePoint"/> equals another object.
  92. /// </summary>
  93. /// <param name="obj">The other object.</param>
  94. /// <returns>True if the objects are equal, otherwise false.</returns>
  95. public override bool Equals(object obj) => obj is RelativePoint other && Equals(other);
  96. /// <summary>
  97. /// Checks if the <see cref="RelativePoint"/> equals another point.
  98. /// </summary>
  99. /// <param name="p">The other point.</param>
  100. /// <returns>True if the objects are equal, otherwise false.</returns>
  101. public bool Equals(RelativePoint p)
  102. {
  103. return Unit == p.Unit && Point == p.Point;
  104. }
  105. /// <summary>
  106. /// Gets a hashcode for a <see cref="RelativePoint"/>.
  107. /// </summary>
  108. /// <returns>A hash code.</returns>
  109. public override int GetHashCode()
  110. {
  111. unchecked
  112. {
  113. return (_point.GetHashCode() * 397) ^ (int)_unit;
  114. }
  115. }
  116. /// <summary>
  117. /// Converts a <see cref="RelativePoint"/> into pixels.
  118. /// </summary>
  119. /// <param name="size">The size of the visual.</param>
  120. /// <returns>The origin point in pixels.</returns>
  121. public Point ToPixels(Size size)
  122. {
  123. return _unit == RelativeUnit.Absolute ?
  124. _point :
  125. new Point(_point.X * size.Width, _point.Y * size.Height);
  126. }
  127. /// <summary>
  128. /// Parses a <see cref="RelativePoint"/> string.
  129. /// </summary>
  130. /// <param name="s">The string.</param>
  131. /// <returns>The parsed <see cref="RelativePoint"/>.</returns>
  132. public static RelativePoint Parse(string s)
  133. {
  134. using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid RelativePoint."))
  135. {
  136. var x = tokenizer.ReadString();
  137. var y = tokenizer.ReadString();
  138. var unit = RelativeUnit.Absolute;
  139. var scale = 1.0;
  140. if (x.EndsWith("%"))
  141. {
  142. if (!y.EndsWith("%"))
  143. {
  144. throw new FormatException("If one coordinate is relative, both must be.");
  145. }
  146. x = x.TrimEnd('%');
  147. y = y.TrimEnd('%');
  148. unit = RelativeUnit.Relative;
  149. scale = 0.01;
  150. }
  151. return new RelativePoint(
  152. double.Parse(x, CultureInfo.InvariantCulture) * scale,
  153. double.Parse(y, CultureInfo.InvariantCulture) * scale,
  154. unit);
  155. }
  156. }
  157. }
  158. }