* Fixed relative mapping mode for brushes (skia only, pending radial) * Implemented separate RadiusX/RadiusY with proper mapping modes for RadialGradientBrush * tests for conic brush * Added tests for geometry drawing * Updated DrawingBrush test image since it now matches WPF * Update obsolete property usage * Fixed D2D, updated radial test with D2D results that actually match WPF ones * Fixed RadiusX/Y for radial gradients with non-centered origin * Updated obsolete property usage * Code cleanup * Typo * ApiDiff suppression * Removed files for skipped test * More info in obsoletion warning * clarify --------- Co-authored-by: Jumar Macato <16554748+jmacato@users.noreply.github.com>pull/14564/head
@ -0,0 +1,20 @@ |
|||||
|
namespace Avalonia.Animation.Animators |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Animator that handles <see cref="RelativeScalar"/> properties.
|
||||
|
/// </summary>
|
||||
|
internal class RelativeScalarAnimator : Animator<RelativeScalar> |
||||
|
{ |
||||
|
private static readonly DoubleAnimator s_scalarAnimator = new DoubleAnimator(); |
||||
|
|
||||
|
public override RelativeScalar Interpolate(double progress, RelativeScalar oldValue, RelativeScalar newValue) |
||||
|
{ |
||||
|
if (oldValue.Unit != newValue.Unit) |
||||
|
{ |
||||
|
return progress >= 0.5 ? newValue : oldValue; |
||||
|
} |
||||
|
|
||||
|
return new RelativeScalar(s_scalarAnimator.Interpolate(progress, oldValue.Scalar, newValue.Scalar), oldValue.Unit); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines a scalar value that may be defined relative to a containing element.
|
||||
|
/// </summary>
|
||||
|
public struct RelativeScalar : IEquatable<RelativeScalar> |
||||
|
{ |
||||
|
private readonly double _scalar; |
||||
|
|
||||
|
private readonly RelativeUnit _unit; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="RelativeScalar"/> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="scalar">The scalar value.</param>
|
||||
|
/// <param name="unit">The unit.</param>
|
||||
|
public RelativeScalar(double scalar, RelativeUnit unit) |
||||
|
{ |
||||
|
_scalar = scalar; |
||||
|
_unit = unit; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the scalar.
|
||||
|
/// </summary>
|
||||
|
public double Scalar => _scalar; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the unit.
|
||||
|
/// </summary>
|
||||
|
public RelativeUnit Unit => _unit; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The value at the beginning of the range
|
||||
|
/// </summary>
|
||||
|
public static RelativeScalar Beginning { get; } = new RelativeScalar(0, RelativeUnit.Relative); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The value at the middle of the range
|
||||
|
/// </summary>
|
||||
|
public static RelativeScalar Middle { get; } = new RelativeScalar(0.5, RelativeUnit.Relative); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The value at the end of the range
|
||||
|
/// </summary>
|
||||
|
public static RelativeScalar End { get; } = new RelativeScalar(1, RelativeUnit.Relative); |
||||
|
|
||||
|
public bool Equals(RelativeScalar other) |
||||
|
{ |
||||
|
return _scalar.Equals(other._scalar) && _unit == other._unit; |
||||
|
} |
||||
|
|
||||
|
public override bool Equals(object? obj) |
||||
|
{ |
||||
|
return obj is RelativeScalar other && Equals(other); |
||||
|
} |
||||
|
|
||||
|
public override int GetHashCode() |
||||
|
{ |
||||
|
return _scalar.GetHashCode() ^ (int)_unit; |
||||
|
} |
||||
|
|
||||
|
public static bool operator ==(RelativeScalar left, RelativeScalar right) |
||||
|
{ |
||||
|
return left.Equals(right); |
||||
|
} |
||||
|
|
||||
|
public static bool operator !=(RelativeScalar left, RelativeScalar right) |
||||
|
{ |
||||
|
return !left.Equals(right); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts a <see cref="RelativeScalar"/> into a final value.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The origin point in pixels.</returns>
|
||||
|
public double ToValue(double size) |
||||
|
{ |
||||
|
return _unit == RelativeUnit.Absolute |
||||
|
? _scalar |
||||
|
: size * _scalar; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Parses a <see cref="RelativeScalar"/> string.
|
||||
|
/// </summary>
|
||||
|
/// <param name="s">The string.</param>
|
||||
|
/// <returns>The parsed <see cref="RelativeScalar"/>.</returns>
|
||||
|
public static RelativeScalar Parse(string s) |
||||
|
{ |
||||
|
var trimmed = s.Trim(); |
||||
|
if (trimmed.EndsWith("%")) |
||||
|
return new RelativeScalar(double.Parse(trimmed.TrimEnd('%'), CultureInfo.InvariantCulture) * 0.01, |
||||
|
RelativeUnit.Relative); |
||||
|
|
||||
|
return new RelativeScalar(double.Parse(trimmed, CultureInfo.InvariantCulture), RelativeUnit.Absolute); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a String representing this RelativeScalar instance.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The string representation.</returns>
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return _unit == RelativeUnit.Absolute |
||||
|
? _scalar.ToString(CultureInfo.InvariantCulture) |
||||
|
: string.Format(CultureInfo.InvariantCulture, "{0}%", _scalar * 100); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
#nullable enable |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Shapes; |
||||
|
using Avalonia.Layout; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Media.Imaging; |
||||
|
using Xunit; |
||||
|
|
||||
|
#if AVALONIA_SKIA
|
||||
|
namespace Avalonia.Skia.RenderTests |
||||
|
#else
|
||||
|
namespace Avalonia.Direct2D1.RenderTests.Media |
||||
|
#endif
|
||||
|
{ |
||||
|
public class RelativePointTestPrimitivesHelper : Control |
||||
|
{ |
||||
|
private readonly IBrush? _brush; |
||||
|
private readonly bool _shadow; |
||||
|
private readonly IPen _line; |
||||
|
private static readonly Geometry s_Geometry = Geometry.Parse("m 80 200 c 40 20 150 -40 160 0 l 0 30 c -40 -30 -160 10 -160 -30 z"); |
||||
|
|
||||
|
public RelativePointTestPrimitivesHelper(IBrush? brush, bool shadow = false) |
||||
|
{ |
||||
|
_brush = brush; |
||||
|
_shadow = shadow; |
||||
|
if (brush != null) |
||||
|
_line = new Pen(brush, 10); |
||||
|
|
||||
|
MinHeight = MaxHeight = Height = MinWidth = MaxWidth = Width = 256; |
||||
|
} |
||||
|
|
||||
|
public override void Render(DrawingContext context) |
||||
|
{ |
||||
|
if (_shadow) |
||||
|
{ |
||||
|
var full = new Rect(default, Bounds.Size); |
||||
|
context.DrawRectangle(Brushes.White, null, full); |
||||
|
using (context.PushOpacity(0.3)) |
||||
|
context.DrawRectangle(_brush, null, full); |
||||
|
} |
||||
|
|
||||
|
context.DrawRectangle(_brush, null, new Rect(20, 20, 200, 60)); |
||||
|
context.DrawEllipse(_brush, null, new Rect(40, 100, 200, 20)); |
||||
|
context.DrawLine(_line, new Point(60, 140), new Point(240, 160)); |
||||
|
context.DrawGeometry(_brush, null, s_Geometry); |
||||
|
|
||||
|
base.Render(context); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 8.9 KiB |