diff --git a/src/Avalonia.Visuals/CornerRadius.cs b/src/Avalonia.Visuals/CornerRadius.cs index 09163a2dac..5445c5a200 100644 --- a/src/Avalonia.Visuals/CornerRadius.cs +++ b/src/Avalonia.Visuals/CornerRadius.cs @@ -8,7 +8,10 @@ using Avalonia.Utilities; namespace Avalonia { - public struct CornerRadius + /// + /// Represents the radii of a rectangle's corners. + /// + public readonly struct CornerRadius : IEquatable { static CornerRadius() { @@ -33,20 +36,60 @@ namespace Avalonia BottomLeft = bottomLeft; } + /// + /// Radius of the top left corner. + /// public double TopLeft { get; } + + /// + /// Radius of the top right corner. + /// public double TopRight { get; } + + /// + /// Radius of the bottom right corner. + /// public double BottomRight { get; } + + /// + /// Radius of the bottom left corner. + /// public double BottomLeft { get; } + + /// + /// Gets a value indicating whether all corner radii are set to 0. + /// public bool IsEmpty => TopLeft.Equals(0) && IsUniform; + + /// + /// Gets a value indicating whether all corner radii are equal. + /// public bool IsUniform => TopLeft.Equals(TopRight) && BottomLeft.Equals(BottomRight) && TopRight.Equals(BottomRight); + /// + /// Returns a boolean indicating whether the corner radius is equal to the other given corner radius. + /// + /// The other corner radius to test equality against. + /// True if this corner radius is equal to other; False otherwise. + public bool Equals(CornerRadius other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return TopLeft == other.TopLeft && + + TopRight == other.TopRight && + BottomRight == other.BottomRight && + BottomLeft == other.BottomLeft; + // ReSharper restore CompareOfFloatsByEqualityOperator + } + public override bool Equals(object obj) { - if (obj is CornerRadius) + if (!(obj is CornerRadius)) { - return this == (CornerRadius)obj; + return false; } - return false; + + return Equals((CornerRadius)obj); } public override int GetHashCode() @@ -61,7 +104,9 @@ namespace Avalonia public static CornerRadius Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Thickness")) + const string exceptionMessage = "Invalid CornerRadius."; + + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage)) { if (tokenizer.TryReadDouble(out var a)) { @@ -78,21 +123,18 @@ namespace Avalonia return new CornerRadius(a); } - throw new FormatException("Invalid CornerRadius."); + throw new FormatException(exceptionMessage); } } - public static bool operator ==(CornerRadius cr1, CornerRadius cr2) + public static bool operator ==(CornerRadius left, CornerRadius right) { - return cr1.TopLeft.Equals(cr2.TopLeft) - && cr1.TopRight.Equals(cr2.TopRight) - && cr1.BottomRight.Equals(cr2.BottomRight) - && cr1.BottomLeft.Equals(cr2.BottomLeft); + return left.Equals(right); } - public static bool operator !=(CornerRadius cr1, CornerRadius cr2) + public static bool operator !=(CornerRadius left, CornerRadius right) { - return !(cr1 == cr2); + return !(left == right); } } } diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index d083a2aaf8..6f9839b6a1 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -10,7 +10,7 @@ namespace Avalonia /// /// A 2x3 matrix. /// - public readonly struct Matrix + public readonly struct Matrix : IEquatable { private readonly double _m11; private readonly double _m12; @@ -235,12 +235,14 @@ namespace Avalonia /// True if this matrix is equal to other; False otherwise. public bool Equals(Matrix other) { + // ReSharper disable CompareOfFloatsByEqualityOperator return _m11 == other.M11 && _m12 == other.M12 && _m21 == other.M21 && _m22 == other.M22 && _m31 == other.M31 && _m32 == other.M32; + // ReSharper restore CompareOfFloatsByEqualityOperator } /// @@ -316,7 +318,7 @@ namespace Avalonia /// The . public static Matrix Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Matrix")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Matrix.")) { return new Matrix( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/Media/PixelPoint.cs b/src/Avalonia.Visuals/Media/PixelPoint.cs index d62c2a2e55..5a329d0238 100644 --- a/src/Avalonia.Visuals/Media/PixelPoint.cs +++ b/src/Avalonia.Visuals/Media/PixelPoint.cs @@ -10,7 +10,7 @@ namespace Avalonia /// /// Represents a point in device pixels. /// - public readonly struct PixelPoint + public readonly struct PixelPoint : IEquatable { /// /// A point representing 0,0. @@ -46,7 +46,7 @@ namespace Avalonia /// True if the points are equal; otherwise false. public static bool operator ==(PixelPoint left, PixelPoint right) { - return left.X == right.X && left.Y == right.Y; + return left.Equals(right); } /// @@ -120,7 +120,7 @@ namespace Avalonia /// The . public static PixelPoint Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelPoint")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelPoint.")) { return new PixelPoint( tokenizer.ReadInt32(), @@ -128,6 +128,18 @@ namespace Avalonia } } + /// + /// Returns a boolean indicating whether the point is equal to the other given point. + /// + /// The other point to test equality against. + /// True if this point is equal to other; False otherwise. + public bool Equals(PixelPoint other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return X == other.X && Y == other.Y; + // ReSharper restore CompareOfFloatsByEqualityOperator + } + /// /// Checks for equality between a point and an object. /// @@ -139,7 +151,7 @@ namespace Avalonia { if (obj is PixelPoint other) { - return this == other; + return Equals(other); } return false; diff --git a/src/Avalonia.Visuals/Media/PixelRect.cs b/src/Avalonia.Visuals/Media/PixelRect.cs index 0e2094da07..b830f4b4b4 100644 --- a/src/Avalonia.Visuals/Media/PixelRect.cs +++ b/src/Avalonia.Visuals/Media/PixelRect.cs @@ -10,7 +10,7 @@ namespace Avalonia /// /// Represents a rectangle in device pixels. /// - public readonly struct PixelRect + public readonly struct PixelRect : IEquatable { /// /// An empty rectangle. @@ -148,7 +148,7 @@ namespace Avalonia /// True if the rects are equal; otherwise false. public static bool operator ==(PixelRect left, PixelRect right) { - return left.Position == right.Position && left.Size == right.Size; + return left.Equals(right); } /// @@ -196,6 +196,16 @@ namespace Avalonia rect.Height); } + /// + /// Returns a boolean indicating whether the rect is equal to the other given rect. + /// + /// The other rect to test equality against. + /// True if this rect is equal to other; False otherwise. + public bool Equals(PixelRect other) + { + return Position == other.Position && Size == other.Size; + } + /// /// Returns a boolean indicating whether the given object is equal to this rectangle. /// @@ -205,7 +215,7 @@ namespace Avalonia { if (obj is PixelRect other) { - return this == other; + return Equals(other); } return false; @@ -432,7 +442,7 @@ namespace Avalonia /// The parsed . public static PixelRect Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelRect")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelRect.")) { return new PixelRect( tokenizer.ReadInt32(), diff --git a/src/Avalonia.Visuals/Media/PixelSize.cs b/src/Avalonia.Visuals/Media/PixelSize.cs index b903b804f9..e2d6b46225 100644 --- a/src/Avalonia.Visuals/Media/PixelSize.cs +++ b/src/Avalonia.Visuals/Media/PixelSize.cs @@ -10,7 +10,7 @@ namespace Avalonia /// /// Represents a size in device pixels. /// - public readonly struct PixelSize + public readonly struct PixelSize : IEquatable { /// /// A size representing zero @@ -51,7 +51,7 @@ namespace Avalonia /// True if the sizes are equal; otherwise false. public static bool operator ==(PixelSize left, PixelSize right) { - return left.Width == right.Width && left.Height == right.Height; + return left.Equals(right); } /// @@ -72,7 +72,7 @@ namespace Avalonia /// The . public static PixelSize Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelSize")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid PixelSize.")) { return new PixelSize( tokenizer.ReadInt32(), @@ -80,6 +80,16 @@ namespace Avalonia } } + /// + /// Returns a boolean indicating whether the size is equal to the other given size. + /// + /// The other size to test equality against. + /// True if this size is equal to other; False otherwise. + public bool Equals(PixelSize other) + { + return Width == other.Width && Height == other.Height; + } + /// /// Checks for equality between a size and an object. /// @@ -91,7 +101,7 @@ namespace Avalonia { if (obj is PixelSize other) { - return this == other; + return Equals(other); } return false; diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs index 0d3e354615..0d4dcb7c73 100644 --- a/src/Avalonia.Visuals/Point.cs +++ b/src/Avalonia.Visuals/Point.cs @@ -1,6 +1,7 @@ // 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.Animation.Animators; using Avalonia.Utilities; @@ -10,7 +11,7 @@ namespace Avalonia /// /// Defines a point. /// - public readonly struct Point + public readonly struct Point : IEquatable { static Point() { @@ -75,7 +76,7 @@ namespace Avalonia /// True if the points are equal; otherwise false. public static bool operator ==(Point left, Point right) { - return left.X == right.X && left.Y == right.Y; + return left.Equals(right); } /// @@ -177,7 +178,7 @@ namespace Avalonia /// The . public static Point Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point.")) { return new Point( tokenizer.ReadDouble(), @@ -186,6 +187,19 @@ namespace Avalonia } } + /// + /// Returns a boolean indicating whether the point is equal to the other given point. + /// + /// The other point to test equality against. + /// True if this point is equal to other; False otherwise. + public bool Equals(Point other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return _x == other._x && + _y == other._y; + // ReSharper enable CompareOfFloatsByEqualityOperator + } + /// /// Checks for equality between a point and an object. /// @@ -195,13 +209,12 @@ namespace Avalonia /// public override bool Equals(object obj) { - if (obj is Point) + if (!(obj is Point)) { - var other = (Point)obj; - return X == other.X && Y == other.Y; + return false; } - return false; + return Equals((Point)obj); } /// diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 8f08f7f51f..94fd2afb3d 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a rectangle. /// - public readonly struct Rect + public readonly struct Rect : IEquatable { static Rect() { @@ -164,7 +164,9 @@ namespace Avalonia /// /// Gets a value that indicates whether the rectangle is empty. /// + // ReSharper disable CompareOfFloatsByEqualityOperator public bool IsEmpty => _width == 0 && _height == 0; + // ReSharper restore CompareOfFloatsByEqualityOperator /// /// Checks for equality between two s. @@ -174,7 +176,7 @@ namespace Avalonia /// True if the rects are equal; otherwise false. public static bool operator ==(Rect left, Rect right) { - return left.Position == right.Position && left.Size == right.Size; + return left.Equals(right); } /// @@ -297,6 +299,21 @@ namespace Avalonia Size.Deflate(thickness)); } + /// + /// Returns a boolean indicating whether the rect is equal to the other given rect. + /// + /// The other rect to test equality against. + /// True if this rect is equal to other; False otherwise. + public bool Equals(Rect other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return _x == other._x && + _y == other._y && + _width == other._width && + _height == other._height; + // ReSharper enable CompareOfFloatsByEqualityOperator + } + /// /// Returns a boolean indicating whether the given object is equal to this rectangle. /// @@ -304,13 +321,12 @@ namespace Avalonia /// True if the object is equal to this rectangle; false otherwise. public override bool Equals(object obj) { - if (obj is Rect) + if (!(obj is Rect)) { - var other = (Rect)obj; - return Position == other.Position && Size == other.Size; + return false; } - return false; + return Equals((Rect)obj); } /// @@ -422,10 +438,10 @@ namespace Avalonia } else { - var x1 = Math.Min(this.X, rect.X); - var x2 = Math.Max(this.Right, rect.Right); - var y1 = Math.Min(this.Y, rect.Y); - var y2 = Math.Max(this.Bottom, rect.Bottom); + var x1 = Math.Min(X, rect.X); + var x2 = Math.Max(Right, rect.Right); + var y1 = Math.Min(Y, rect.Y); + var y2 = Math.Max(Bottom, rect.Bottom); return new Rect(new Point(x1, y1), new Point(x2, y2)); } @@ -493,7 +509,7 @@ namespace Avalonia /// The parsed . public static Rect Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Rect")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Rect.")) { return new Rect( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/RelativePoint.cs b/src/Avalonia.Visuals/RelativePoint.cs index d38bb1d496..c822486767 100644 --- a/src/Avalonia.Visuals/RelativePoint.cs +++ b/src/Avalonia.Visuals/RelativePoint.cs @@ -130,10 +130,7 @@ namespace Avalonia { unchecked { - int hash = 17; - hash = (hash * 23) + Unit.GetHashCode(); - hash = (hash * 23) + Point.GetHashCode(); - return hash; + return (_point.GetHashCode() * 397) ^ (int)_unit; } } @@ -156,7 +153,7 @@ namespace Avalonia /// The parsed . public static RelativePoint Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid RelativePoint")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid RelativePoint.")) { var x = tokenizer.ReadString(); var y = tokenizer.ReadString(); diff --git a/src/Avalonia.Visuals/RelativeRect.cs b/src/Avalonia.Visuals/RelativeRect.cs index 927ec3ef75..c69dab3c42 100644 --- a/src/Avalonia.Visuals/RelativeRect.cs +++ b/src/Avalonia.Visuals/RelativeRect.cs @@ -139,10 +139,7 @@ namespace Avalonia { unchecked { - int hash = 17; - hash = (hash * 23) + Unit.GetHashCode(); - hash = (hash * 23) + Rect.GetHashCode(); - return hash; + return ((int)Unit * 397) ^ Rect.GetHashCode(); } } @@ -161,7 +158,7 @@ namespace Avalonia Rect.Width * size.Width, Rect.Height * size.Height); } - + /// /// Parses a string. /// @@ -169,7 +166,7 @@ namespace Avalonia /// The parsed . public static RelativeRect Parse(string s) { - using (var tokenizer = new StringTokenizer(s, exceptionMessage: "Invalid RelativeRect")) + using (var tokenizer = new StringTokenizer(s, exceptionMessage: "Invalid RelativeRect.")) { var x = tokenizer.ReadString(); var y = tokenizer.ReadString(); diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs index 782c5ea67b..9d524d6fa7 100644 --- a/src/Avalonia.Visuals/Size.cs +++ b/src/Avalonia.Visuals/Size.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a size. /// - public readonly struct Size + public readonly struct Size : IEquatable { static Size() { @@ -72,7 +72,7 @@ namespace Avalonia /// True if the sizes are equal; otherwise false. public static bool operator ==(Size left, Size right) { - return left._width == right._width && left._height == right._height; + return left.Equals(right); } /// @@ -158,7 +158,7 @@ namespace Avalonia /// The . public static Size Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Size")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Size.")) { return new Size( tokenizer.ReadDouble(), @@ -191,6 +191,19 @@ namespace Avalonia Math.Max(0, _height - thickness.Top - thickness.Bottom)); } + /// + /// Returns a boolean indicating whether the size is equal to the other given size. + /// + /// The other size to test equality against. + /// True if this size is equal to other; False otherwise. + public bool Equals(Size other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return _width == other._width && + _height == other._height; + // ReSharper enable CompareOfFloatsByEqualityOperator + } + /// /// Checks for equality between a size and an object. /// @@ -200,13 +213,12 @@ namespace Avalonia /// public override bool Equals(object obj) { - if (obj is Size) + if (!(obj is Size)) { - var other = (Size)obj; - return Width == other.Width && Height == other.Height; + return false; } - return false; + return Equals((Size)obj); } /// diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs index 830ee4666e..d0fc63e254 100644 --- a/src/Avalonia.Visuals/Thickness.cs +++ b/src/Avalonia.Visuals/Thickness.cs @@ -3,7 +3,6 @@ using System; using System.Globalization; -using Avalonia.Animation; using Avalonia.Animation.Animators; using Avalonia.Utilities; @@ -12,7 +11,7 @@ namespace Avalonia /// /// Describes the thickness of a frame around a rectangle. /// - public readonly struct Thickness + public readonly struct Thickness : IEquatable { static Thickness() { @@ -204,7 +203,9 @@ namespace Avalonia /// The . public static Thickness Parse(string s) { - using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Thickness")) + const string exceptionMessage = "Invalid Thickness."; + + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage)) { if (tokenizer.TryReadDouble(out var a)) { @@ -221,10 +222,25 @@ namespace Avalonia return new Thickness(a); } - throw new FormatException("Invalid Thickness."); + throw new FormatException(exceptionMessage); } } + /// + /// Returns a boolean indicating whether the thickness is equal to the other given point. + /// + /// The other thickness to test equality against. + /// True if this thickness is equal to other; False otherwise. + public bool Equals(Thickness other) + { + // ReSharper disable CompareOfFloatsByEqualityOperator + return _left == other._left && + _top == other._top && + _right == other._right && + _bottom == other._bottom; + // ReSharper restore CompareOfFloatsByEqualityOperator + } + /// /// Checks for equality between a thickness and an object. /// @@ -234,16 +250,12 @@ namespace Avalonia /// public override bool Equals(object obj) { - if (obj is Thickness) + if (!(obj is Thickness)) { - Thickness other = (Thickness)obj; - return Left == other.Left && - Top == other.Top && - Right == other.Right && - Bottom == other.Bottom; + return false; } - return false; + return Equals((Thickness)obj); } /// diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index 11bda8b00e..bd2dfdc828 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -11,7 +11,7 @@ namespace Avalonia /// /// Defines a vector. /// - public readonly struct Vector + public readonly struct Vector : IEquatable { static Vector() { diff --git a/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs b/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs index 39b328adc2..5fb22680dc 100644 --- a/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs +++ b/src/Avalonia.Visuals/VisualTree/TransformedBounds.cs @@ -1,13 +1,14 @@ // 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; namespace Avalonia.VisualTree { /// /// Holds information about the bounds of a control, together with a transform and a clip. /// - public readonly struct TransformedBounds + public readonly struct TransformedBounds : IEquatable { /// /// Initializes a new instance of the struct.