-
Notifications
You must be signed in to change notification settings - Fork 730
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11501 from unoplatform/dev/mazi/CornerRadiusFilte…
…rConverter feat: Add support for `Scale` in `CornerRadiusFilterConverter`
- Loading branch information
Showing
5 changed files
with
467 additions
and
188 deletions.
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/CommonStyles/CommonStylesTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
||
using Common; | ||
using MUXControlsTestApp.Utilities; | ||
using System.Linq; | ||
using System.Threading; | ||
using Windows.Foundation.Metadata; | ||
using Windows.System; | ||
using Windows.UI.Xaml; | ||
using Windows.UI.Xaml.Controls; | ||
using Windows.UI.Xaml.Controls.Primitives; | ||
using Windows.UI.Xaml.Input; | ||
using Windows.UI.Xaml.Media; | ||
using PlatformConfiguration = Common.PlatformConfiguration; | ||
using OSVersion = Common.OSVersion; | ||
using System.Collections.Generic; | ||
using XamlControlsResources = Microsoft.UI.Xaml.Controls.XamlControlsResources; | ||
using Windows.UI.Xaml.Markup; | ||
using System; | ||
using Microsoft.UI.Xaml.Controls; | ||
using System.Text; | ||
|
||
#if USING_TAEF | ||
using WEX.TestExecution; | ||
using WEX.TestExecution.Markup; | ||
using WEX.Logging.Interop; | ||
#else | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting.Logging; | ||
#endif | ||
|
||
namespace Windows.UI.Xaml.Tests.MUXControls.ApiTests | ||
{ | ||
[TestClass] | ||
public class CommonStylesApiTests : MUXApiTestBase | ||
{ | ||
// TODO: Many tests from MUX CommonStylesApiTests.cpp are missing here and should be added in the future to Uno Platform. | ||
|
||
[TestMethod] | ||
#if __MACOS__ | ||
[Ignore("Currently fails on macOS, part of #9282 epic")] | ||
#endif | ||
public void CornerRadiusFilterConverterTest() | ||
{ | ||
if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone4)) | ||
{ | ||
Log.Comment("Corner radius is only available on RS5+"); | ||
return; | ||
} | ||
|
||
RunOnUIThread.Execute(() => | ||
{ | ||
var root = (StackPanel)XamlReader.Load( | ||
@"<StackPanel xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' | ||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' | ||
xmlns:primitives='using:Microsoft.UI.Xaml.Controls.Primitives'> | ||
<StackPanel.Resources> | ||
<primitives:CornerRadiusFilterConverter x:Key='TopCornerRadiusFilterConverter' Filter='Top' Scale='2'/> | ||
<primitives:CornerRadiusFilterConverter x:Key='RightCornerRadiusFilterConverter' Filter='Right'/> | ||
<primitives:CornerRadiusFilterConverter x:Key='BottomCornerRadiusFilterConverter' Filter='Bottom'/> | ||
<primitives:CornerRadiusFilterConverter x:Key='LeftCornerRadiusFilterConverter' Filter='Left'/> | ||
</StackPanel.Resources> | ||
<Grid x:Name='SourceGrid' CornerRadius='6,6,6,6' /> | ||
<Grid x:Name='TopRadiusGrid' | ||
CornerRadius='{Binding ElementName=SourceGrid, Path=CornerRadius, Converter={StaticResource TopCornerRadiusFilterConverter}}'> | ||
</Grid> | ||
<Grid x:Name='RightRadiusGrid' | ||
CornerRadius='{Binding ElementName=SourceGrid, Path=CornerRadius, Converter={StaticResource RightCornerRadiusFilterConverter}}'> | ||
</Grid> | ||
<Grid x:Name='BottomRadiusGrid' | ||
CornerRadius='{Binding ElementName=SourceGrid, Path=CornerRadius, Converter={StaticResource BottomCornerRadiusFilterConverter}}'> | ||
</Grid> | ||
<Grid x:Name='LeftRadiusGrid' | ||
CornerRadius='{Binding ElementName=SourceGrid, Path=CornerRadius, Converter={StaticResource LeftCornerRadiusFilterConverter}}'> | ||
</Grid> | ||
</StackPanel>"); | ||
var topRadiusGrid = (Grid)root.FindName("TopRadiusGrid"); | ||
var rightRadiusGrid = (Grid)root.FindName("RightRadiusGrid"); | ||
var bottomRadiusGrid = (Grid)root.FindName("BottomRadiusGrid"); | ||
var leftRadiusGrid = (Grid)root.FindName("LeftRadiusGrid"); | ||
Verify.AreEqual(new CornerRadius(12, 12, 0, 0), topRadiusGrid.CornerRadius); | ||
Verify.AreEqual(new CornerRadius(0, 6, 6, 0), rightRadiusGrid.CornerRadius); | ||
Verify.AreEqual(new CornerRadius(0, 0, 6, 6), bottomRadiusGrid.CornerRadius); | ||
Verify.AreEqual(new CornerRadius(6, 0, 0, 6), leftRadiusGrid.CornerRadius); | ||
}); | ||
} | ||
} | ||
} |
166 changes: 112 additions & 54 deletions
166
src/Uno.UI/Microsoft/UI/Xaml/Controls/Primitives/CornerRadiusFilterConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,133 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
// MUX Reference CornerRadiusFilterConverter.cpp, commit 22e5052 | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using Windows.UI.Xaml; | ||
using Windows.UI.Xaml.Data; | ||
|
||
namespace Microsoft.UI.Xaml.Controls.Primitives | ||
namespace Microsoft.UI.Xaml.Controls.Primitives; | ||
|
||
/// <summary> | ||
/// Converts an existing CornerRadius struct to a new CornerRadius struct, with filters applied | ||
/// to extract only the specified fields, leaving the others set to 0. | ||
/// </summary> | ||
public partial class CornerRadiusFilterConverter : DependencyObject, IValueConverter | ||
{ | ||
public partial class CornerRadiusFilterConverter : DependencyObject, IValueConverter | ||
/// <summary> | ||
/// Gets or sets the type of the filter applied to the CornerRadiusFilterConverter. | ||
/// </summary> | ||
public CornerRadiusFilterKind Filter | ||
{ | ||
public static DependencyProperty FilterProperty { get; } = DependencyProperty.Register( | ||
nameof(Filter), typeof(CornerRadiusFilterKind), typeof(CornerRadiusFilterConverter), new FrameworkPropertyMetadata(CornerRadiusFilterKind.None)); | ||
get => (CornerRadiusFilterKind)GetValue(FilterProperty); | ||
set => SetValue(FilterProperty, value); | ||
} | ||
|
||
public CornerRadiusFilterKind Filter | ||
{ | ||
get => (CornerRadiusFilterKind)GetValue(FilterProperty); | ||
set => SetValue(FilterProperty, value); | ||
} | ||
/// <summary> | ||
/// Identifies the Filter dependency property. | ||
/// </summary> | ||
public static DependencyProperty FilterProperty { get; } = | ||
DependencyProperty.Register( | ||
nameof(Filter), | ||
typeof(CornerRadiusFilterKind), | ||
typeof(CornerRadiusFilterConverter), | ||
new FrameworkPropertyMetadata(CornerRadiusFilterKind.None)); | ||
|
||
private static CornerRadius Convert(CornerRadius radius, CornerRadiusFilterKind filterKind) | ||
{ | ||
var result = radius; | ||
/// <summary> | ||
/// Gets or sets the scale multiplier applied to the CornerRadiusFilterConverter. | ||
/// </summary> | ||
public double Scale | ||
{ | ||
get => (double)GetValue(ScaleProperty); | ||
set => SetValue(ScaleProperty, value); | ||
} | ||
|
||
switch (filterKind) | ||
{ | ||
case CornerRadiusFilterKind.Top: | ||
result.BottomLeft = 0; | ||
result.BottomRight = 0; | ||
break; | ||
case CornerRadiusFilterKind.Right: | ||
result.TopLeft = 0; | ||
result.BottomLeft = 0; | ||
break; | ||
case CornerRadiusFilterKind.Bottom: | ||
result.TopLeft = 0; | ||
result.TopRight = 0; | ||
break; | ||
case CornerRadiusFilterKind.Left: | ||
result.TopRight = 0; | ||
result.BottomRight = 0; | ||
break; | ||
} | ||
/// <summary> | ||
/// Identifies the Scale dependency property. | ||
/// </summary> | ||
public static DependencyProperty ScaleProperty { get; } = | ||
DependencyProperty.Register( | ||
nameof(Scale), | ||
typeof(double), | ||
typeof(CornerRadiusFilterConverter), | ||
new FrameworkPropertyMetadata(1.0)); | ||
|
||
return result; | ||
private static CornerRadius Convert(CornerRadius radius, CornerRadiusFilterKind filterKind) | ||
{ | ||
var result = radius; | ||
|
||
switch (filterKind) | ||
{ | ||
case CornerRadiusFilterKind.Top: | ||
result.BottomLeft = 0; | ||
result.BottomRight = 0; | ||
break; | ||
case CornerRadiusFilterKind.Right: | ||
result.TopLeft = 0; | ||
result.BottomLeft = 0; | ||
break; | ||
case CornerRadiusFilterKind.Bottom: | ||
result.TopLeft = 0; | ||
result.TopRight = 0; | ||
break; | ||
case CornerRadiusFilterKind.Left: | ||
result.TopRight = 0; | ||
result.BottomRight = 0; | ||
break; | ||
} | ||
|
||
private static double GetDoubleValue(CornerRadius radius, CornerRadiusFilterKind filterKind) | ||
=> | ||
filterKind switch | ||
{ | ||
CornerRadiusFilterKind.TopLeftValue => radius.TopLeft, | ||
CornerRadiusFilterKind.BottomRightValue => radius.BottomRight, | ||
_ => 0d | ||
}; | ||
return result; | ||
} | ||
|
||
private static double GetDoubleValue(CornerRadius radius, CornerRadiusFilterKind filterKind) => | ||
filterKind switch | ||
{ | ||
CornerRadiusFilterKind.TopLeftValue => radius.TopLeft, | ||
CornerRadiusFilterKind.BottomRightValue => radius.BottomRight, | ||
_ => 0d | ||
}; | ||
|
||
public object Convert(object value, Type targetType, object parameter, string language) | ||
/// <summary> | ||
/// Converts the source CornerRadius by extracting only the fields specified | ||
/// by the Filter and leaving others set to 0. | ||
/// </summary> | ||
/// <param name="value">The source CornerRadius being passed to the target.</param> | ||
/// <param name="targetType">The type of the target property. Part of the IValueConverter.Convert interface method, but not used.</param> | ||
/// <param name="parameter">An optional parameter to be used in the converter logic. Part of the IValueConverter.Convert interface method, but not used.</param> | ||
/// <param name="language">The language of the conversion. Part of the IValueConverter.Convert interface method, but not used.</param> | ||
/// <returns>The converted CornerRadius/double value to be passed to the target dependency property.</returns> | ||
public object? Convert(object? value, Type targetType, object? parameter, string language) | ||
{ | ||
if (value is CornerRadius cornerRadius) | ||
{ | ||
var filter = Filter; | ||
var scale = Scale; | ||
if (!double.IsNaN(scale)) | ||
{ | ||
cornerRadius.TopLeft *= scale; | ||
cornerRadius.TopRight *= scale; | ||
cornerRadius.BottomLeft *= scale; | ||
cornerRadius.BottomRight *= scale; | ||
} | ||
|
||
if (value is CornerRadius cornerRadius) | ||
var filterType = Filter; | ||
if (filterType == CornerRadiusFilterKind.TopLeftValue || | ||
filterType == CornerRadiusFilterKind.BottomRightValue) | ||
{ | ||
if (filter == CornerRadiusFilterKind.TopLeftValue || filter == CornerRadiusFilterKind.BottomRightValue) | ||
{ | ||
return GetDoubleValue(cornerRadius, filter); | ||
} | ||
return Convert(cornerRadius, filter); | ||
return GetDoubleValue(cornerRadius, filterType); | ||
} | ||
|
||
return null; | ||
return Convert(cornerRadius, filterType); | ||
} | ||
|
||
public object ConvertBack(object value, Type targetType, object parameter, string language) => | ||
throw new NotSupportedException(); | ||
return null; | ||
} | ||
|
||
/// <summary> | ||
/// Not implemented. | ||
/// </summary> | ||
/// <exception cref="NotImplementedException">Always thrown when called.</exception> | ||
public object? ConvertBack(object? value, Type targetType, object? parameter, string language) => | ||
throw new NotImplementedException(); | ||
} |
57 changes: 46 additions & 11 deletions
57
src/Uno.UI/Microsoft/UI/Xaml/Controls/Primitives/CornerRadiusFilterKind.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,48 @@ | ||
namespace Microsoft.UI.Xaml.Controls.Primitives | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
// MUX Reference CornerRadiusFilterConverters.idl, commit c6174f1 | ||
|
||
#nullable enable | ||
|
||
namespace Microsoft.UI.Xaml.Controls.Primitives; | ||
|
||
/// <summary> | ||
/// Defines constants that specify the filter type for a CornerRadiusFilterConverter instance. | ||
/// </summary> | ||
public enum CornerRadiusFilterKind | ||
{ | ||
public enum CornerRadiusFilterKind | ||
{ | ||
None, | ||
Top, | ||
Right, | ||
Bottom, | ||
Left, | ||
TopLeftValue, | ||
BottomRightValue | ||
} | ||
/// <summary> | ||
/// No filter applied. | ||
/// </summary> | ||
None, | ||
|
||
/// <summary> | ||
/// Filters TopLeft and TopRight values, sets BottomLeft and BottomRight to 0. | ||
/// </summary> | ||
Top, | ||
|
||
/// <summary> | ||
/// Filters TopRight and BottomRight values, sets TopLeft and BottomLeft to 0. | ||
/// </summary> | ||
Right, | ||
|
||
/// <summary> | ||
/// Filters BottomLeft and BottomRight values, sets TopLeft and TopRight to 0. | ||
/// </summary> | ||
Bottom, | ||
|
||
/// <summary> | ||
/// Filters TopLeft and BottomLeft values, sets TopRight and BottomRight to 0. | ||
/// </summary> | ||
Left, | ||
|
||
/// <summary> | ||
/// Gets the double value of TopLeft corner. | ||
/// </summary> | ||
TopLeftValue, | ||
|
||
/// <summary> | ||
/// Gets the double value of BottomRight corner. | ||
/// </summary> | ||
BottomRightValue | ||
} |
Oops, something went wrong.