Skip to content

Commit

Permalink
Merge pull request #13682 from Youssef1313/issues/10263
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund authored Sep 24, 2023
2 parents 2ccfd2d + 581ed75 commit 13bbce8
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
Maximum="100"
x:Name="LeftBorderThicknessSlider"
Value="{x:Bind LeftBorderThickness, Mode=TwoWay}" />
<Slider Header="Left:"
<Slider Header="Top:"
Minimum="0"
Maximum="100"
x:Name="TopBorderThicknessSlider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,96 @@ public async Task Border_CornerRadius_GradientBrush()
ImageAssert.HasColorAt(result, textBoxRect.CenterX, textBoxRect.CenterY, "#FF00FF00", tolerance: 10);
}

[TestMethod]
public async Task When_CornerRadius()
{
var case1A = new Border()
{
Width = 200,
Height = 100,
CornerRadius = new(200),
Background = new SolidColorBrush(Colors.Red),
};

var case1B = new Border()
{
Width = 200,
Height = 100,
CornerRadius = new(100),
Background = new SolidColorBrush(Colors.Red),
};

var case1Expected = new Ellipse()
{
Width = 200,
Height = 100,
Fill = new SolidColorBrush(Colors.Red),
};

var case2 = new Border()
{
Width = 200,
Height = 100,
CornerRadius = new(200, 0, 0, 0),
Background = new SolidColorBrush(Colors.Blue),
};

var case2Expected = new Grid()
{
Width = 200,
Height = 100,
Children =
{
new Ellipse()
{
Width = 400,
Height = 200,
Fill = new SolidColorBrush(Colors.Blue),
}
}
};

var stackPanel = new StackPanel()
{
Children =
{
case1A,
case1B,
case1Expected,
case2,
case2Expected,
}
};

WindowHelper.WindowContent = stackPanel;
await WindowHelper.WaitForLoaded(stackPanel);

var renderer1A = new RenderTargetBitmap();
await renderer1A.RenderAsync(case1A);
var bitmap1A = await RawBitmap.From(renderer1A, case1A);

var renderer1B = new RenderTargetBitmap();
await renderer1B.RenderAsync(case1B);
var bitmap1B = await RawBitmap.From(renderer1B, case1B);

var renderer1Expected = new RenderTargetBitmap();
await renderer1Expected.RenderAsync(case1Expected);
var bitmap1Expected = await RawBitmap.From(renderer1Expected, case1Expected);

await ImageAssert.AreSimilarAsync(bitmap1A, bitmap1Expected, imperceptibilityThreshold: 0.7);
await ImageAssert.AreSimilarAsync(bitmap1B, bitmap1Expected, imperceptibilityThreshold: 0.7);

var renderer2 = new RenderTargetBitmap();
await renderer2.RenderAsync(case2);
var bitmap2 = await RawBitmap.From(renderer2, case2);

var renderer2Expected = new RenderTargetBitmap();
await renderer2Expected.RenderAsync(case2Expected);
var bitmap2Expected = await RawBitmap.From(renderer2Expected, case2Expected);

await ImageAssert.AreSimilarAsync(bitmap2, bitmap2Expected, imperceptibilityThreshold: 0.7);
}

[TestMethod]
public async Task Border_AntiAlias()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Toolkit/ElevatedView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ private void UpdateElevation()
{
#if __WASM__
this.SetElevationInternal(Elevation, ShadowColor);
this.SetCornerRadius(CornerRadius);
this.SetBorder(BorderThickness, BorderBrush, CornerRadius);
#elif __IOS__ || __MACOS__
this.SetElevationInternal(Elevation, ShadowColor, _border.BoundsPath);
#elif __ANDROID__
Expand Down
17 changes: 4 additions & 13 deletions src/Uno.UI/UI/Xaml/Controls/Border/Border.wasm.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using Uno.Extensions;
using System.Linq;
using System.Drawing;
using Uno.Disposables;
using Windows.UI.Xaml.Media;
using Uno.UI;

namespace Windows.UI.Xaml.Controls
namespace Windows.UI.Xaml.Controls
{
public partial class Border
{
public Border()
{
this.SizeChanged += (_, _) => UpdateBorder();
}

partial void OnChildChangedPartial(UIElement previousValue, UIElement newValue)
Expand All @@ -28,7 +19,7 @@ partial void OnChildChangedPartial(UIElement previousValue, UIElement newValue)

private void UpdateBorder()
{
SetBorder(BorderThickness, BorderBrush);
SetBorder(BorderThickness, BorderBrush, CornerRadius);
}

private protected override void OnLoaded()
Expand All @@ -54,7 +45,7 @@ partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue)

partial void OnCornerRadiusUpdatedPartial(CornerRadius oldValue, CornerRadius newValue)
{
SetCornerRadius(newValue);
UpdateBorder();
}

protected override void OnBackgroundChanged(DependencyPropertyChangedEventArgs e)
Expand Down
47 changes: 18 additions & 29 deletions src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;
using Uno;
using Uno.UI.Helpers;
using Uno.UI.Extensions;

namespace Windows.UI.Xaml.Shapes
{
partial class BorderLayerRenderer
{
private Brush _background;
private (Brush, Thickness) _border;
private CornerRadius _cornerRadius;
private (Brush, Thickness, CornerRadius) _border;

private Action _backgroundChanged;

Expand All @@ -38,35 +38,14 @@ public void UpdateLayer(
SetAndObserveBackgroundBrush(fwElt, oldValue, background, ref _backgroundChanged);
}

if (_border != (borderBrush, borderThickness))
if (_border != (borderBrush, borderThickness, cornerRadius))
{
_border = (borderBrush, borderThickness);
SetBorder(element, borderThickness, borderBrush);
}

if (_cornerRadius != cornerRadius)
{
_cornerRadius = cornerRadius;
SetCornerRadius(element, cornerRadius);
}
}

public static void SetCornerRadius(UIElement element, CornerRadius cornerRadius)
{
if (cornerRadius == CornerRadius.None)
{
element.ResetStyle("border-radius", "overflow");
}
else
{
var borderRadiusCssString = $"min(50%,{cornerRadius.TopLeft.ToStringInvariant()}px) min(50%,{cornerRadius.TopRight.ToStringInvariant()}px) min(50%,{cornerRadius.BottomRight.ToStringInvariant()}px) min(50%,{cornerRadius.BottomLeft.ToStringInvariant()}px)";
element.SetStyle(
("border-radius", borderRadiusCssString),
("overflow", "hidden")); // overflow: hidden is required here because the clipping can't do its job when it's non-rectangular.
_border = (borderBrush, borderThickness, cornerRadius);
SetBorder(element, borderThickness, borderBrush, cornerRadius);
}
}

public static void SetBorder(UIElement element, Thickness thickness, Brush brush)
public static void SetBorder(UIElement element, Thickness thickness, Brush brush, CornerRadius cornerRadius)
{
if (thickness == Thickness.Empty)
{
Expand All @@ -89,7 +68,7 @@ public static void SetBorder(UIElement element, Thickness thickness, Brush brush
("border-width", borderWidth));
break;
case GradientBrush gradientBrush:
var border = gradientBrush.ToCssString(element.RenderSize); // TODO: Reevaluate when size is changing
var border = gradientBrush.ToCssString(element.RenderSize);
element.SetStyle(
("border-style", "solid"),
("border-color", ""),
Expand All @@ -98,7 +77,7 @@ public static void SetBorder(UIElement element, Thickness thickness, Brush brush
("border-image-slice", "1"));
break;
case RadialGradientBrush radialGradientBrush:
var radialBorder = radialGradientBrush.ToCssString(element.RenderSize); // TODO: Reevaluate when size is changing
var radialBorder = radialGradientBrush.ToCssString(element.RenderSize);
element.SetStyle(
("border-style", "solid"),
("border-color", ""),
Expand All @@ -119,6 +98,16 @@ public static void SetBorder(UIElement element, Thickness thickness, Brush brush
break;
}
}

if (cornerRadius == CornerRadius.None)
{
element.ResetStyle("border-radius", "overflow");
}
else
{
var outer = cornerRadius.GetRadii(element.RenderSize, thickness).Outer;
WindowManagerInterop.SetCornerRadius(element.HtmlId, outer.TopLeft.X, outer.TopLeft.Y, outer.TopRight.X, outer.TopRight.Y, outer.BottomRight.X, outer.BottomRight.Y, outer.BottomLeft.X, outer.BottomLeft.Y);
}
}

public static void SetAndObserveBackgroundBrush(FrameworkElement element, Brush oldValue, Brush newValue, ref Action brushChanged)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public partial class ContentPresenter : FrameworkElement
public ContentPresenter()
{
InitializeContentPresenter();
this.SizeChanged += (_, _) => UpdateBorder();
}

private void SetUpdateTemplate()
Expand All @@ -39,12 +40,12 @@ partial void UnregisterContentTemplateRoot()

private void UpdateCornerRadius(CornerRadius radius)
{
SetCornerRadius(radius);
UpdateBorder();
}

private void UpdateBorder()
{
SetBorder(BorderThickness, BorderBrush);
SetBorder(BorderThickness, BorderBrush, CornerRadius);
}

private void ClearBorder()
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/Controls/Page/Page.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private void InitializeBorder()

private void UpdateBorder()
{
SetBorder(Thickness.Empty, null);
SetBorder(Thickness.Empty, null, default);
}
}
}
5 changes: 3 additions & 2 deletions src/Uno.UI/UI/Xaml/Controls/Panel/Panel.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ public partial class Panel : IEnumerable
public Panel()
{
Initialize();
this.SizeChanged += (_, _) => UpdateBorder();
}

partial void Initialize();

partial void UpdateBorder()
{
SetBorder(BorderThicknessInternal, BorderBrushInternal);
SetBorder(BorderThicknessInternal, BorderBrushInternal, CornerRadiusInternal);
}

protected virtual void OnChildrenChanged()
Expand All @@ -58,7 +59,7 @@ partial void OnBorderThicknessChangedPartial(Thickness oldValue, Thickness newVa

partial void OnCornerRadiusChangedPartial(CornerRadius oldValue, CornerRadius newValue)
{
SetCornerRadius(newValue);
UpdateBorder();
}

/// <summary>
Expand Down
7 changes: 2 additions & 5 deletions src/Uno.UI/UI/Xaml/FrameworkElement.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,8 @@ public event RoutedEventHandler Unloaded

public IEnumerator GetEnumerator() => _children.GetEnumerator();

protected void SetCornerRadius(CornerRadius cornerRadius)
=> BorderLayerRenderer.SetCornerRadius(this, cornerRadius);

protected void SetBorder(Thickness thickness, Brush brush)
=> BorderLayerRenderer.SetBorder(this, thickness, brush);
protected void SetBorder(Thickness thickness, Brush brush, CornerRadius cornerRadius)
=> BorderLayerRenderer.SetBorder(this, thickness, brush, cornerRadius);

partial void OnBackgroundSizingChangedPartial(DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
Expand Down
7 changes: 7 additions & 0 deletions src/Uno.UI/UI/Xaml/WindowManagerInterop.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,10 @@ internal static void SelectInputRange(IntPtr htmlId, int start, int length)

internal static void SetImageAsMonochrome(IntPtr htmlId, string url, string color)
=> NativeMethods.SetImageAsMonochrome(htmlId, url, color);

internal static void SetCornerRadius(IntPtr htmlId, float topLeftX, float topLeftY, float topRightX, float topRightY, float bottomRightX, float bottomRightY, float bottomLeftX, float bottomLeftY)
=> NativeMethods.SetCornerRadius(htmlId, topLeftX, topLeftY, topRightX, topRightY, bottomRightX, bottomRightY, bottomLeftX, bottomLeftY);

internal static void SetRootElement(IntPtr htmlId)
{
NativeMethods.SetRootElement(htmlId);
Expand Down Expand Up @@ -1144,6 +1148,9 @@ internal static partial void ArrangeElement(
[JSImport("globalThis.Uno.UI.WindowManager.current.setImageAsMonochrome")]
internal static partial void SetImageAsMonochrome(IntPtr htmlId, string url, string color);

[JSImport("globalThis.Uno.UI.WindowManager.current.setCornerRadius")]
internal static partial void SetCornerRadius(IntPtr htmlId, float topLeftX, float topLeftY, float topRightX, float topRightY, float bottomRightX, float bottomRightY, float bottomLeftX, float bottomLeftY);

[JSImport("globalThis.Uno.UI.WindowManager.current.setPointerCapture")]
internal static partial void SetPointerCapture(IntPtr htmlId, double pointerId);

Expand Down
6 changes: 6 additions & 0 deletions src/Uno.UI/ts/WindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,12 @@ namespace Uno.UI {
}
}

public setCornerRadius(viewId: number, topLeftX: number, topLeftY: number, topRightX: number, topRightY: number, bottomRightX: number, bottomRightY: number, bottomLeftX: number, bottomLeftY: number) {
const element = this.getView(viewId);
element.style.borderRadius = `${topLeftX}px ${topRightX}px ${bottomRightX}px ${bottomLeftX}px / ${topLeftY}px ${topRightY}px ${bottomRightY}px ${bottomLeftY}px`;
element.style.overflow = "hidden"; // overflow: hidden is required here because the clipping can't do its job when it's non-rectangular.
}

public setPointerCapture(viewId: number, pointerId: number): void {
this.getView(viewId).setPointerCapture(pointerId);
}
Expand Down

0 comments on commit 13bbce8

Please sign in to comment.