Skip to content

Commit

Permalink
Merge pull request #11501 from unoplatform/dev/mazi/CornerRadiusFilte…
Browse files Browse the repository at this point in the history
…rConverter

feat: Add support for `Scale` in `CornerRadiusFilterConverter`
  • Loading branch information
MartinZikmund authored Feb 28, 2023
2 parents e191a6f + b98161f commit 823a506
Show file tree
Hide file tree
Showing 5 changed files with 467 additions and 188 deletions.
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);
});
}
}
}
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();
}
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
}
Loading

0 comments on commit 823a506

Please sign in to comment.