diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml
index ed74e1d6e..fb34c882c 100644
--- a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml
+++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml
@@ -81,6 +81,10 @@
Spread="0"
Color="#8c76ff" />
+
+
+
+
@@ -90,6 +94,7 @@
+
@@ -202,6 +207,7 @@
+
@@ -303,6 +309,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml.cs b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml.cs
index 7987c7108..d404d680d 100644
--- a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml.cs
+++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/Controls/ShadowContainerSamplePage.WinUI.xaml.cs
@@ -18,11 +18,13 @@ public ShadowContainerSamplePage()
this.Loaded += (s, e) =>
{
- var shadowContainer = SamplePageLayout.GetSampleChild(Design.Agnostic, "ShadowContainer");
- _shadows = shadowContainer.Shadows;
+ if (SamplePageLayout.GetSampleChild(Design.Agnostic, "ShadowContainer") is { } shadowContainer)
+ {
+ _shadows = shadowContainer.Shadows;
- var shadowsItemsControl = SamplePageLayout.GetSampleChild(Design.Agnostic, "ShadowsItemsControl");
- shadowsItemsControl.ItemsSource = _shadows;
+ var shadowsItemsControl = SamplePageLayout.GetSampleChild(Design.Agnostic, "ShadowsItemsControl");
+ shadowsItemsControl.ItemsSource = _shadows;
+ }
};
}
diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml
new file mode 100644
index 000000000..28a626f72
--- /dev/null
+++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml.cs b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml.cs
new file mode 100644
index 000000000..0c6046bbf
--- /dev/null
+++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerRectangleTestPage.WinUI.xaml.cs
@@ -0,0 +1,75 @@
+#if IS_WINUI
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Uno.Toolkit.Samples.Entities;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+using Microsoft.UI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+
+namespace Uno.Toolkit.Samples.Content.TestPages
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+
+ [SamplePage(SampleCategory.Tests, "ShadowContainerRectangleTest")]
+ public sealed partial class ShadowContainerRectangleTestPage : Page
+ {
+ public ShadowContainerRectangleTestPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void runButton_Click(object sender, RoutedEventArgs e)
+ {
+ statusText.Text = "Running";
+ shadowContainer.Shadows.Clear();
+
+ if (!int.TryParse(xOffsetText.Text, out var xOffset))
+ {
+ xOffset = 0;
+ }
+
+ if (!int.TryParse(yOffsetText.Text, out var yOffset))
+ {
+ yOffset = 0;
+ }
+
+ var isInner = inner.IsChecked ?? false;
+
+ shadowContainer.Shadows.Add(new UI.Shadow
+ {
+ OffsetX = xOffset,
+ OffsetY = yOffset,
+ IsInner = isInner,
+ Opacity = 1,
+ Color = Colors.Red,
+ });
+
+ statusText.Text = "Verify";
+ }
+
+ private void reset_Click(object sender, RoutedEventArgs e)
+ {
+ statusText.Text = string.Empty;
+
+ xOffsetText.Text = string.Empty;
+ yOffsetText.Text = string.Empty;
+ inner.IsChecked = false;
+
+ shadowContainer.Shadows.Clear();
+ }
+ }
+}
+#endif
diff --git a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerTestPage.WinUI.xaml b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerTestPage.WinUI.xaml
index 3bc5136eb..ed54670b4 100644
--- a/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerTestPage.WinUI.xaml
+++ b/samples/Uno.Toolkit.Samples/Uno.Toolkit.Samples.Shared/Content/TestPages/ShadowContainerTestPage.WinUI.xaml
@@ -8,29 +8,69 @@
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
-
+
+ VerticalAlignment="Center"
+ x:Name="containerBorder">
-
+
+
+
+
+
+
+
+
+
+
+
+ x:Name="rectangle"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/samples/Uno.Toolkit.WinUI.Samples/Uno.Toolkit.WinUI.Samples.Windows.Desktop/Uno.Toolkit.WinUI.Samples.Windows.Desktop.csproj b/samples/Uno.Toolkit.WinUI.Samples/Uno.Toolkit.WinUI.Samples.Windows.Desktop/Uno.Toolkit.WinUI.Samples.Windows.Desktop.csproj
index d40b5aafb..d9381d884 100644
--- a/samples/Uno.Toolkit.WinUI.Samples/Uno.Toolkit.WinUI.Samples.Windows.Desktop/Uno.Toolkit.WinUI.Samples.Windows.Desktop.csproj
+++ b/samples/Uno.Toolkit.WinUI.Samples/Uno.Toolkit.WinUI.Samples.Windows.Desktop/Uno.Toolkit.WinUI.Samples.Windows.Desktop.csproj
@@ -33,4 +33,8 @@
+
+
+
+
diff --git a/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.Paint.cs b/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.Paint.cs
index cf91d3c87..c05db9c96 100644
--- a/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.Paint.cs
+++ b/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.Paint.cs
@@ -133,19 +133,21 @@ private void OnSurfacePainted(object? sender, SKPaintSurfaceEventArgs e)
};
}
- private IShadowShapeContext GetShadowShapeContext(object? content)
+ private IShadowShapeContext GetShadowShapeContext(object content)
{
return content switch
{
- FrameworkElement fe => new RectangularShadowShapeContext(fe.ActualWidth, fe.ActualHeight, GetCornerRadiusFor(Content) ?? default),
+ // any dp used here, beside width/height that is covered by SizeChanged, needs to register for dp changed in: BindToPaintingProperties\BindToContent()
+ Ellipse ellipse => new RadiusXYRectShadowShapeContext(ellipse.ActualWidth, ellipse.ActualHeight, ellipse.ActualWidth / 2, ellipse.ActualHeight / 2),
+ Rectangle rect => new RadiusXYRectShadowShapeContext(rect.ActualWidth, rect.ActualHeight, rect.RadiusX, rect.RadiusY),
+ FrameworkElement fe => new CornerRadiusRectShadowShapeContext(fe.ActualWidth, fe.ActualHeight, GetCornerRadiusFor(Content) ?? default),
- null => RectangularShadowShapeContext.Empty,
_ => throw new NotSupportedException($"Unsupported content type: {content.GetType().Name}"),
};
}
///
- /// Serves both as a record of states relevant to shadow shape, and the implementations for painting the shadows
+ /// Serves both as a record of states relevant to shadow shape (not , but in the broad sense), and the implementations for painting the shadows.
///
private interface IShadowShapeContext
{
@@ -158,17 +160,9 @@ private interface IShadowShapeContext
void DrawInnerShadow(ShadowPaintState state, SKCanvas canvas, SKPaint paint, ShadowInfo shadow);
}
- private record RectangularShadowShapeContext(double ContentWidth, double ContentHeight, CornerRadius CornerRadius) : IShadowShapeContext
+ private abstract record RoundRectShadowShapeContext(double Width, double Height) : IShadowShapeContext
{
- public static readonly RectangularShadowShapeContext Empty = new(0, 0, default);
-
- private SKRoundRect GetContentShape(ShadowPaintState state)
- {
- var rect = new SKRect(0, 0, (float)ContentWidth * state.PixelRatio, (float)ContentHeight * state.PixelRatio);
- var shape = new SKRoundRect(rect, (float)CornerRadius.BottomRight * state.PixelRatio);
-
- return shape;
- }
+ protected abstract SKRoundRect GetContentShape(ShadowPaintState state);
public void ClipToContent(ShadowPaintState state, SKCanvas canvas)
{
@@ -231,7 +225,6 @@ public void DrawDropShadow(ShadowPaintState state, SKCanvas canvas, SKPaint pain
public void DrawInnerShadow(ShadowPaintState state, SKCanvas canvas, SKPaint paint, ShadowInfo shadow)
{
- var cornerRadius = (float)CornerRadius.BottomRight * state.PixelRatio;
var spread = (float)shadow.Spread * state.PixelRatio;
var offsetX = (float)shadow.OffsetX * state.PixelRatio;
var offsetY = (float)shadow.OffsetY * state.PixelRatio;
@@ -253,12 +246,39 @@ public void DrawInnerShadow(ShadowPaintState state, SKCanvas canvas, SKPaint pai
if (_logger.IsEnabled(LogLevel.Trace))
{
- _logger.Trace($"[ShadowContainer] DrawInnerShadow => strokeWidth: {paint.StrokeWidth}, cornerRadius: {cornerRadius}, x: {offsetX}, y: {offsetY}, width: {shape.Rect.Width}, height: {shape.Rect.Height}");
+ _logger.Trace($"[ShadowContainer] DrawInnerShadow => strokeWidth: {paint.StrokeWidth}, x: {offsetX}, y: {offsetY}, width: {shape.Rect.Width}, height: {shape.Rect.Height}");
}
canvas.DrawRoundRect(shape, paint);
}
}
+ private record CornerRadiusRectShadowShapeContext(double Width, double Height, CornerRadius CornerRadius) : RoundRectShadowShapeContext(Width, Height)
+ {
+ protected override SKRoundRect GetContentShape(ShadowPaintState state)
+ {
+ var rect = new SKRect(0, 0, (float)Width * state.PixelRatio, (float)Height * state.PixelRatio);
+ var radii = new[] { CornerRadius.TopLeft, CornerRadius.TopRight, CornerRadius.BottomRight, CornerRadius.BottomLeft }
+ .Select(x => (float)x * state.PixelRatio)
+ .Select(x => new SKPoint(x, x))
+ .ToArray();
+ var shape = new SKRoundRect();
+ shape.SetRectRadii(rect, radii);
+
+ return shape;
+ }
+ }
+
+ private record RadiusXYRectShadowShapeContext(double Width, double Height, double RadiusX, double RadiusY) : RoundRectShadowShapeContext(Width, Height)
+ {
+ protected override SKRoundRect GetContentShape(ShadowPaintState state)
+ {
+ var rect = new SKRect(0, 0, (float)Width * state.PixelRatio, (float)Height * state.PixelRatio);
+ var shape = new SKRoundRect(rect, (float)RadiusX * state.PixelRatio, (float)RadiusY * state.PixelRatio);
+
+ return shape;
+ }
+ }
+
///
/// Record of properties at one point in time.
///
diff --git a/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.cs b/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.cs
index dbd1187e6..e18828e29 100644
--- a/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.cs
+++ b/src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowContainer.cs
@@ -118,10 +118,6 @@ void OnShadowPropertyChanged(object? sender, PropertyChangedEventArgs e)
}
void OnInnerPropertyChanged(DependencyObject sender, DependencyProperty dp)
{
- if (sender == this && dp == CornerRadiusProperty)
- {
- InvalidateCanvasLayout();
- }
InvalidateShadows();
}
void OnContentPropertyChanged(DependencyObject sender, DependencyProperty dp)
@@ -207,13 +203,29 @@ void BindToContent(object? content)
{
if (content is FrameworkElement contentAsFE)
{
- contentAsFE.SizeChanged += OnContentSizeChanged;
contentNestedDisposable.Disposable = new CompositeDisposable
{
- Disposable.Create(() => contentAsFE.SizeChanged -= OnContentSizeChanged),
- GetCornerRadiusPropertyFor(content) is { } dp ? contentAsFE.RegisterDisposablePropertyChangedCallback(dp, OnContentPropertyChanged) : Disposable.Empty,
- contentAsFE.RegisterDisposablePropertyChangedCallback(FrameworkElement.MarginProperty, OnContentPropertyChanged),
+ RegisterSizeChangedHandler(contentAsFE, OnContentSizeChanged),
+ RegisterNestedPropertyChangedSafe(GetCornerRadiusPropertyFor(content)),
+ RegisterNestedPropertyChangedSafe(Rectangle.RadiusXProperty),
+ RegisterNestedPropertyChangedSafe(Rectangle.RadiusYProperty),
+ RegisterNestedPropertyChangedSafe(FrameworkElement.MarginProperty),
};
+
+ static IDisposable RegisterSizeChangedHandler(FrameworkElement fe, SizeChangedEventHandler handler)
+ {
+ fe.SizeChanged += handler;
+ return Disposable.Create(() => fe.SizeChanged -= handler);
+ }
+ IDisposable RegisterNestedPropertyChangedSafe(DependencyProperty? dp, DependencyPropertyChangedCallback? callback = null)
+ {
+ if (contentAsFE is T && dp is { })
+ {
+ return contentAsFE.RegisterDisposablePropertyChangedCallback(dp, callback ?? OnContentPropertyChanged);
+ }
+
+ return Disposable.Empty;
+ }
}
else
{
@@ -377,7 +389,7 @@ private void InvalidateShadows(bool force = false)
Grid => Grid.CornerRadiusProperty,
StackPanel => StackPanel.CornerRadiusProperty,
- Shape => null,
+ Shape => null, // note: shapes have special handling, see: GetShadowShapeContext
DependencyObject @do => @do.FindDependencyPropertyUsingReflection("CornerRadiusProperty"),
_ => null,
};
@@ -393,7 +405,7 @@ private void InvalidateShadows(bool force = false)
Grid grid => grid.CornerRadius,
StackPanel stackpanel => stackpanel.CornerRadius,
- Shape => null,
+ Shape => null, // note: shapes have special handling, see: GetShadowShapeContext
DependencyObject @do => @do.FindDependencyPropertyUsingReflection("CornerRadiusProperty") is { } dp
? (CornerRadius)@do.GetValue(dp)
: null,
diff --git a/src/Uno.Toolkit.UITest/Constants.cs b/src/Uno.Toolkit.UITest/Constants.cs
index 86cf91e6c..6f666ecd1 100644
--- a/src/Uno.Toolkit.UITest/Constants.cs
+++ b/src/Uno.Toolkit.UITest/Constants.cs
@@ -11,7 +11,7 @@ public class Constants
{
public readonly static string WebAssemblyDefaultUri = "http://localhost:59402/";
public readonly static string iOSAppName = "com.nventive.Uno.Toolkit.Samples";
- public readonly static string AndroidAppName = "Uno.Toolkit.Samples";
+ public readonly static string AndroidAppName = "uno.platform.toolkit";
public readonly static string iOSDeviceNameOrId = "iPad Pro (12.9-inch) (5th generation)";
public readonly static Platform CurrentPlatform = Platform.Android;
diff --git a/src/Uno.Toolkit.UITest/Controls/ShadowContainer/Given_ShadowContainer.cs b/src/Uno.Toolkit.UITest/Controls/ShadowContainer/Given_ShadowContainer.cs
index 316426bba..d5b6bf8f3 100644
--- a/src/Uno.Toolkit.UITest/Controls/ShadowContainer/Given_ShadowContainer.cs
+++ b/src/Uno.Toolkit.UITest/Controls/ShadowContainer/Given_ShadowContainer.cs
@@ -2,8 +2,10 @@
using NUnit.Framework;
using System;
using System.Drawing;
+using System.Reflection;
using Uno.Toolkit.UITest.Extensions;
using Uno.Toolkit.UITest.Framework;
+using Uno.UITest;
using Uno.UITest.Helpers;
using Uno.UITest.Helpers.Queries;
@@ -14,6 +16,10 @@ public class Given_ShadowContainer : TestBase
{
protected override string SampleName => "ShadowContainerTest";
+ const string Red = "#FF0000";
+ const string Blue = "#0000FF";
+ const string Green = "#008000";
+
[Test]
[TestCase(10, 10, false)]
[TestCase(10, 10, false)]
@@ -26,19 +32,19 @@ public class Given_ShadowContainer : TestBase
[TestCase(10, -10, false)]
public void When_Shadows(int xOffset, int yOffset, bool inner)
{
- const string Red = "#FF0000";
- const string Blue = "#0000FF";
- const string Green = "#008000";
var shadowContainer = App.WaitForElementWithMessage("shadowContainer");
var runButton = App.MarkedAnywhere("runButton");
- var statusText = App.MarkedAnywhere("statusText");
+ var resetButton = App.MarkedAnywhere("resetButton");
+ var statusText = App.MarkedAnywhere("statusText");
+ var shadowRect = App.GetPhysicalRect("shadowContainer");
App.MarkedAnywhere("xOffsetText").ClearText().EnterTextAndDismiss(xOffset.ToString());
App.MarkedAnywhere("yOffsetText").ClearText().EnterTextAndDismiss(yOffset.ToString());
- var innerCheck = App.MarkedAnywhere("inner");
+ App.Tap("check_Border");
+ var innerCheck = App.MarkedAnywhere("inner");
innerCheck.SetDependencyPropertyValue("IsChecked", inner.ToString());
App.WaitForDependencyPropertyValue(innerCheck, "IsChecked", inner);
@@ -46,10 +52,191 @@ public void When_Shadows(int xOffset, int yOffset, bool inner)
App.WaitForDependencyPropertyValue(statusText, "Text", "Verify");
var outerBorderRect = App.GetPhysicalRect("outerBorder");
- var borderRect = App.GetPhysicalRect("border");
- var shadowRect = App.GetPhysicalRect("shadowContainer");
+ var elementRect = App.GetPhysicalRect("border");
var caseName = $"Shadow_x{xOffset}_y{yOffset}{(inner ? "_Inner" : "_Outer")}";
+ Check_Assert(outerBorderRect, elementRect, xOffset, yOffset, inner, caseName);
+
+ resetButton.FastTap();
+
+ }
+
+
+ [Test]
+ [TestCase(10, 10, false)]
+ [TestCase(10, 10, false)]
+ [TestCase(10, 10, true)]
+ [TestCase(-10, -10, false)]
+ [TestCase(-10, -10, true)]
+ [TestCase(-10, 10, true)]
+ [TestCase(10, -10, true)]
+ [TestCase(-10, 10, false)]
+ [TestCase(10, -10, false)]
+ public void When_RectangleShadows(int xOffset, int yOffset, bool inner)
+ {
+
+ var shadowContainer = App.WaitForElementWithMessage("shadowContainer");
+ App.Tap("check_Rectangle");
+ shadowContainer = App.WaitForElementWithMessage("shadowContainerRectangle");
+ var runButton = App.MarkedAnywhere("runButton");
+ var resetButton = App.MarkedAnywhere("resetButton");
+
+ var statusText = App.MarkedAnywhere("statusText");
+ var shadowRect = App.GetPhysicalRect("shadowContainerRectangle");
+ App.MarkedAnywhere("xOffsetText").ClearText().EnterTextAndDismiss(xOffset.ToString());
+ App.MarkedAnywhere("yOffsetText").ClearText().EnterTextAndDismiss(yOffset.ToString());
+
+ var innerCheck = App.MarkedAnywhere("inner");
+ innerCheck.SetDependencyPropertyValue("IsChecked", inner.ToString());
+ App.WaitForDependencyPropertyValue(innerCheck, "IsChecked", inner);
+
+ runButton.FastTap();
+
+ App.WaitForDependencyPropertyValue(statusText, "Text", "Verify");
+ var outerBorderRect = App.GetPhysicalRect("outerBorderRetangle");
+ var elementRect = App.GetPhysicalRect("rectangle");
+
+ var caseName = $"ShadowRectangle_x{xOffset}_y{yOffset}{(inner ? "_Inner" : "_Outer")}";
+ Check_Assert(outerBorderRect, elementRect, xOffset, yOffset, inner, caseName);
+ resetButton.FastTap();
+
+ }
+
+
+ [Test]
+ [TestCase(9, 9, false)]
+ [TestCase(-9, -9, false)]
+ public void When_AsymmetricShadowsCorner(int xOffset, int yOffset, bool inner)
+ {
+ var shadowContainer = App.WaitForElementWithMessage("shadowContainer");
+ var resetButton = App.MarkedAnywhere("resetButton");
+ resetButton.FastTap();
+
+ App.Tap("check_IrregularCorner");
+ shadowContainer = App.WaitForElementWithMessage("shadowContainerIrregularCorner");
+ var runButton = App.MarkedAnywhere("runButton");
+ var statusText = App.MarkedAnywhere("statusText");
+
+
+ App.MarkedAnywhere("xOffsetText").ClearText().EnterTextAndDismiss(xOffset.ToString());
+ App.MarkedAnywhere("yOffsetText").ClearText().EnterTextAndDismiss(yOffset.ToString());
+ var innerCheck = App.MarkedAnywhere("inner");
+
+ innerCheck.SetDependencyPropertyValue("IsChecked", inner.ToString());
+ App.WaitForDependencyPropertyValue(innerCheck, "IsChecked", inner);
+
+ runButton.FastTap();
+
+ App.WaitForDependencyPropertyValue(statusText, "Text", "Verify");
+ var outerTestRect = App.GetPhysicalRect("outerBorderIrregularCorner");
+
+ var caseName = $"ShadowIrregular_x{xOffset}_y{yOffset}{(inner ? "_Inner" : "_Outer")}";
+
+ using var screenshot = TakeScreenshot(caseName);
+
+
+
+ int currentX = 3;
+ int currentY = 3;
+
+ int absXOffset = Math.Abs(xOffset);
+ int absYOffset = Math.Abs(yOffset);
+
+ while (currentX < absXOffset || currentY < absYOffset)
+ {
+
+ var beginX = (int)outerTestRect.X;
+ var beginY = (int)outerTestRect.Y;
+ var centerX = (int)outerTestRect.CenterX;
+ var centerY = (int)outerTestRect.CenterY;
+ var endX = (int)outerTestRect.Right;
+ var endY = (int)outerTestRect.Bottom;
+
+ //CornerRadius="0,100,0,100"
+ /*
+ * Points for test
+ _______________________
+ | 1 7 4 |
+ | A C |
+ | 2 8 5 |
+ | B D |
+ | 3 9 6 |
+ _______________________
+ */
+
+ //1
+ var leftTopOuterTestPoint = new Point(beginX + currentX, beginY + currentY);
+ //2
+ var leftMiddleOuterTestPoint = new Point(beginX + currentX, centerY);
+ //3
+ var leftBottomOuterTestPoint = new Point(beginX + currentX, endY - currentY);
+
+ //4
+ var rightTopOuterTestPoint = new Point(endX - currentX, beginY + currentY);
+ //5
+ var rightMiddleOuterTestPoint = new Point(endX - currentX, centerY);
+ //6
+ var rightBottomOuterTestPoint = new Point(endX - currentX, endY - currentY);
+
+ //7
+ var centerTopOuterTestPoint = new Point(centerX - currentX, beginY + currentY);
+ //8
+ var centerMiddleOuterTestPoint = new Point(centerX - currentX, centerY);
+ //9
+ var centerBottomOuterTestPoint = new Point(centerX - currentX, endY - currentY);
+
+ //A
+ var cornerTopLeftOuterTestPoint = new Point(beginX + (endX - beginX) / 5 * 2 + currentX, beginY + (endY - beginY) / 5 * 2 + currentY);
+ //B
+ var cornerBottomLeftOuterTestPoint = new Point(beginX + (endX - beginX) / 5 * 4 + currentX, beginY + (endY - beginY) / 5 * 2 - currentY);
+ //C
+ var cornerTopRightOuterTestPoint = new Point(beginX + (endX - beginX) / 5 * 2 - currentX, beginY + (endY - beginY) / 5 * 4 + currentY);
+ //D
+ var cornerBottomRightOuterTestPoint = new Point(beginX + (endX - beginX) / 5 * 4 - currentX, beginY + (endY - beginY) / 5 * 4 - currentY);
+
+ var outerDefault = inner ? Blue : Red;
+
+ AssertExpectations(new[] {
+ (leftTopOuterTestPoint, xOffset < 0 ? outerDefault : Blue),
+ (leftMiddleOuterTestPoint, Blue),
+ (leftBottomOuterTestPoint, Blue),
+
+ (rightTopOuterTestPoint, Blue),
+ (rightMiddleOuterTestPoint, Blue),
+ (rightBottomOuterTestPoint, xOffset < 0 ? Blue : outerDefault),
+
+ (centerTopOuterTestPoint, Blue),
+ (centerMiddleOuterTestPoint, Green),
+ (centerBottomOuterTestPoint, Blue ),
+
+ (cornerTopLeftOuterTestPoint, Green),
+ (cornerBottomLeftOuterTestPoint, Blue),
+ (cornerTopRightOuterTestPoint, Blue),
+ (cornerBottomRightOuterTestPoint, Green)
+ });
+
+ void AssertExpectations((Point TestPoint, string Color)[] expectations)
+ {
+ foreach (var expectation in expectations)
+ {
+ ImageAssert.HasPixels(
+ screenshot,
+ ExpectedPixels
+ .At(expectation.TestPoint)
+ .Named($"{caseName}_at_{expectation.TestPoint.X}_{expectation.TestPoint.Y}_offset_{currentX}_{currentY}")
+ .Pixel(expectation.Color)
+ );
+ }
+ }
+
+ currentX = Math.Min(++currentX, absXOffset);
+ currentY = Math.Min(++currentY, absYOffset);
+ }
+ //resetButton.FastTap();
+ }
+
+ public void Check_Assert(IAppRect outerBorderRect, IAppRect borderRect, int xOffset, int yOffset, bool inner, string caseName)
+ {
using var screenshot = TakeScreenshot(caseName);
@@ -58,20 +245,18 @@ public void When_Shadows(int xOffset, int yOffset, bool inner)
var xStart = xOffset < 0 ? (int)outerBorderRect.X : (int)outerBorderRect.Right;
var yStart = yOffset < 0 ? (int)outerBorderRect.Y : (int)outerBorderRect.Bottom;
+ int currentX = 1;
+ int currentY = 1;
+
int absXOffset = Math.Abs(xOffset);
int absYOffset = Math.Abs(yOffset);
- int currentX = absXOffset * 2;
- int currentY = absYOffset * 2;
-
while (currentX < absXOffset || currentY < absYOffset)
{
- var outerTestRect = outerBorderRect;
-
- var leftOuterTestPoint = new Point((int)outerTestRect.X + currentX, (int)outerTestRect.CenterY);
- var topOuterTestPoint = new Point((int)outerTestRect.CenterX, (int)outerTestRect.Y + currentY);
- var rightOuterTestPoint = new Point((int)outerTestRect.Right - currentX, (int)outerTestRect.CenterY);
- var bottomOuterTestPoint = new Point((int)outerTestRect.CenterX, (int)outerTestRect.Bottom - currentY);
+ var leftOuterTestPoint = new Point((int)outerBorderRect.X + currentX, (int)outerBorderRect.CenterY);
+ var topOuterTestPoint = new Point((int)outerBorderRect.CenterX, (int)outerBorderRect.Y + currentY);
+ var rightOuterTestPoint = new Point((int)outerBorderRect.Right - currentX, (int)outerBorderRect.CenterY);
+ var bottomOuterTestPoint = new Point((int)outerBorderRect.CenterX, (int)outerBorderRect.Bottom - currentY);
var leftInnerTestPoint = new Point((int)borderRect.X + currentX, (int)borderRect.CenterY);
var topInnerTestPoint = new Point((int)borderRect.CenterX, (int)borderRect.Y + currentY);
@@ -84,16 +269,16 @@ public void When_Shadows(int xOffset, int yOffset, bool inner)
AssertExpectations(new[]
{
(leftOuterTestPoint, xOffset < 0 ? outerDefault : Blue),
- (topOuterTestPoint, yOffset < 0 ? outerDefault : Blue),
- (rightOuterTestPoint, xOffset < 0 ? Blue : outerDefault),
+ (topOuterTestPoint, yOffset < 0 ? outerDefault : Blue),
+ (rightOuterTestPoint, xOffset < 0 ? Blue : outerDefault),
(bottomOuterTestPoint, yOffset < 0 ? Blue : outerDefault),
});
AssertExpectations(new[]
{
(leftInnerTestPoint, xOffset < 0 ? Green : innerDefault),
- (topInnerTestPoint, yOffset < 0 ? Green : innerDefault),
- (rightInnerTestPoint, xOffset < 0 ? innerDefault : Green),
+ (topInnerTestPoint, yOffset < 0 ? Green : innerDefault),
+ (rightInnerTestPoint, xOffset < 0 ? innerDefault : Green),
(bottomInnerTestPoint, yOffset < 0 ? innerDefault : Green),
});