forked from unoplatform/uno
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fb7bf3c
commit ea291b8
Showing
1 changed file
with
152 additions
and
0 deletions.
There are no files selected for viewing
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,152 @@ | ||
#nullable enable | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Uno.Foundation.Logging; | ||
using Uno.UI.Xaml.Media; | ||
using Microsoft.UI.Xaml; | ||
using Microsoft.UI.Xaml.Controls; | ||
using Microsoft.UI.Xaml.Media; | ||
|
||
namespace Uno.UI.Controls; | ||
|
||
/// <summary> | ||
/// This presenter provides a way to display "fake" LinearGradientBrush on element border for | ||
/// cases which are unsupported by WebAssembly, iOS and macOS. | ||
/// </summary> | ||
/// <remarks> | ||
/// WASM - the presenter will be used in case the element has CornerRadius applied. | ||
/// iOS and macOS - the presenter will be used in case the element has LinearGradientBrush with a transform applied. | ||
/// All other cases - the presenter is not visible. | ||
/// </remarks> | ||
public partial class FauxGradientBorderPresenter : ContentPresenter | ||
{ | ||
#if __WASM__ || __IOS__ || __MACOS__ | ||
private readonly Border? _displayBorder; | ||
#endif | ||
|
||
public FauxGradientBorderPresenter() | ||
{ | ||
#if __WASM__ || __IOS__ || __MACOS__ | ||
HorizontalContentAlignment = HorizontalAlignment.Stretch; | ||
VerticalContentAlignment = VerticalAlignment.Stretch; | ||
Content = _displayBorder = new Border(); | ||
#else | ||
Visibility = Visibility.Collapsed; | ||
#endif | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets the border brush that is supposed to be displayed. | ||
/// </summary> | ||
public Brush RequestedBorderBrush | ||
{ | ||
get => (Brush)GetValue(RequestedBorderBrushProperty); | ||
set => SetValue(RequestedBorderBrushProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// Identifies the RequestedBorderBrush dependency property. | ||
/// </summary> | ||
public static DependencyProperty RequestedBorderBrushProperty { get; } = | ||
DependencyProperty.Register( | ||
nameof(RequestedBorderBrush), | ||
typeof(Brush), | ||
typeof(FauxGradientBorderPresenter), | ||
new FrameworkPropertyMetadata(null, propertyChangedCallback: (s, args) => ((FauxGradientBorderPresenter)s)?.OnBorderChanged())); | ||
|
||
/// <summary> | ||
/// Gets or sets the thickness of the border that is supposed to be displayed. | ||
/// </summary> | ||
public Thickness RequestedBorderThickness | ||
{ | ||
get => (Thickness)GetValue(RequestedBorderThicknessProperty); | ||
set => SetValue(RequestedBorderThicknessProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// Identifies the RequestedBorderThickness dependency property. | ||
/// </summary> | ||
public static DependencyProperty RequestedBorderThicknessProperty { get; } = | ||
DependencyProperty.Register( | ||
nameof(RequestedBorderThickness), | ||
typeof(Thickness), | ||
typeof(FauxGradientBorderPresenter), | ||
new FrameworkPropertyMetadata(default(Thickness), propertyChangedCallback: (s, args) => ((FauxGradientBorderPresenter)s)?.OnBorderChanged())); | ||
|
||
public CornerRadius RequestedCornerRadius | ||
{ | ||
get => (CornerRadius)GetValue(RequestedCornerRadiusProperty); | ||
set => SetValue(RequestedCornerRadiusProperty, value); | ||
} | ||
|
||
public static DependencyProperty RequestedCornerRadiusProperty { get; } = | ||
DependencyProperty.Register( | ||
nameof(RequestedCornerRadius), | ||
typeof(CornerRadius), | ||
typeof(FauxGradientBorderPresenter), | ||
new FrameworkPropertyMetadata(CornerRadius.None, propertyChangedCallback: (s, args) => ((FauxGradientBorderPresenter)s)?.OnBorderChanged())); | ||
|
||
private void OnBorderChanged() | ||
{ | ||
#if __WASM__ || __IOS__ || __MACOS__ | ||
if (_displayBorder == null) | ||
{ | ||
return; | ||
} | ||
|
||
var requestedThickness = RequestedBorderThickness; | ||
var requestedBorderBrush = RequestedBorderBrush; | ||
var requestedCornerRadius = RequestedCornerRadius; | ||
|
||
if (requestedBorderBrush is not LinearGradientBrush gradientBrush || | ||
!gradientBrush.CanApplySolidColorRendering()) | ||
{ | ||
_displayBorder.Visibility = Visibility.Collapsed; | ||
return; | ||
} | ||
|
||
#if __WASM__ | ||
if (requestedCornerRadius == CornerRadius.None) | ||
{ | ||
// WASM can render linear gradient border unless corner radius is set. | ||
_displayBorder.Visibility = Visibility.Collapsed; | ||
return; | ||
} | ||
#endif | ||
|
||
#if __IOS__ || __MACOS__ | ||
if (gradientBrush.RelativeTransform == null) | ||
{ | ||
// iOS can render linear gradient border unless relative transform is used. | ||
_displayBorder.Visibility = Visibility.Collapsed; | ||
return; | ||
} | ||
#endif | ||
|
||
requestedThickness.Left = 0; | ||
requestedThickness.Right = 0; | ||
var minorStopAlignment = gradientBrush.GetMinorStopAlignment(); | ||
if (minorStopAlignment == VerticalAlignment.Top) | ||
{ | ||
requestedThickness.Bottom = 0; | ||
} | ||
else | ||
{ | ||
requestedThickness.Top = 0; | ||
} | ||
|
||
if (requestedThickness == Thickness.Empty) | ||
{ | ||
_displayBorder.Visibility = Visibility.Collapsed; | ||
return; | ||
} | ||
|
||
_displayBorder.Visibility = Visibility.Visible; | ||
|
||
_displayBorder.CornerRadius = requestedCornerRadius; | ||
_displayBorder.BorderThickness = requestedThickness; | ||
_displayBorder.BorderBrush = gradientBrush.FauxOverlayBrush; | ||
#endif | ||
} | ||
} |