Skip to content

Commit

Permalink
refactor: Move UWP elevation code to Toolkit
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Sep 17, 2021
1 parent 0de499a commit cbc56bb
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 78 deletions.
99 changes: 99 additions & 0 deletions src/Uno.UI.Toolkit/Helpers/ElevationHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#if NETFX_CORE
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using Uno.Extensions;
using Uno.Logging;
using Uno.UI.Helpers;

#if NETCOREAPP
using Microsoft.UI;
#endif

namespace Uno.UI.Helpers
{
internal static class ElevationHelper
{
internal static void SetElevation(this DependencyObject element, double elevation, Color shadowColor, DependencyObject host = null, CornerRadius cornerRadius = default(CornerRadius))
{
if (element is UIElement uiElement)
{
var compositor = ElementCompositionPreview.GetElementVisual(uiElement).Compositor;
var spriteVisual = compositor.CreateSpriteVisual();

var newSize = new Vector2(0, 0);
if (uiElement is FrameworkElement contentFE)
{
newSize = new Vector2((float)contentFE.ActualWidth, (float)contentFE.ActualHeight);
}

if (!(host is Canvas uiHost) || newSize == default)
{
return;
}

spriteVisual.Size = newSize;
if (elevation > 0)
{
// Values for 1dp elevation according to https://material.io/guidelines/resources/shadows.html#shadows-illustrator
const float x = 0.25f;
const float y = 0.92f * 0.5f; // Looks more accurate than the recommended 0.92f.
const float blur = 0.5f;

var shadow = compositor.CreateDropShadow();
shadow.Offset = new Vector3((float)elevation * x, (float)elevation * y, -(float)elevation);
shadow.BlurRadius = (float)(blur * elevation);

shadow.Mask = uiElement switch
{
// GetAlphaMask is only available for shapes, images, and textblocks
Shape shape => shape.GetAlphaMask(),
Image image => image.GetAlphaMask(),
TextBlock tb => tb.GetAlphaMask(),
_ => shadow.Mask
};

if (!cornerRadius.Equals(default))
{
var averageRadius =
(cornerRadius.TopLeft +
cornerRadius.TopRight +
cornerRadius.BottomLeft +
cornerRadius.BottomRight) / 4f;

// Create a rectangle with similar corner radius (average for now)
var rect = new Rectangle()
{
Fill = new SolidColorBrush(Colors.White),
Width = newSize.X,
Height = newSize.Y,
RadiusX = averageRadius,
RadiusY = averageRadius
};

uiHost.Children.Add(rect); // The rect need to be in th VisualTree for .GetAlphaMask() to work

shadow.Mask = rect.GetAlphaMask();

uiHost.Children.Remove(rect); // No need anymore, we can discard it.
}

shadow.Color = shadowColor;
shadow.Opacity = shadowColor.A / 255f;
spriteVisual.Shadow = shadow;
}

ElementCompositionPreview.SetElementChildVisual(uiHost, spriteVisual);
}
}
}
}
#endif
83 changes: 5 additions & 78 deletions src/Uno.UI/Helpers/ElevationHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#if !NETFX_CORE
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
Expand All @@ -13,10 +14,6 @@
using Uno.Logging;
using Uno.UI.Helpers;

#if NETCOREAPP
using Microsoft.UI;
#endif

#if __IOS__ || __MACOS__
using CoreGraphics;
#endif
Expand All @@ -25,11 +22,8 @@ namespace Uno.UI.Helpers
{
internal static class ElevationHelper
{

#if __IOS__ || __MACOS__
internal static void SetElevation(this DependencyObject element, double elevation, Color shadowColor, CGPath path = null)
#elif NETFX_CORE || NETCOREAPP
internal static void SetElevation(this DependencyObject element, double elevation, Color shadowColor, DependencyObject host = null, CornerRadius cornerRadius = default(CornerRadius))
#else
internal static void SetElevation(this DependencyObject element, double elevation, Color shadowColor)
#endif
Expand Down Expand Up @@ -99,77 +93,10 @@ internal static void SetElevation(this DependencyObject element, double elevatio
uiElement.UnsetCssClasses("noclip");
}
}
#elif NETFX_CORE || NETCOREAPP
if (element is UIElement uiElement)
{
var compositor = ElementCompositionPreview.GetElementVisual(uiElement).Compositor;
var spriteVisual = compositor.CreateSpriteVisual();

var newSize = new Vector2(0, 0);
if (uiElement is FrameworkElement contentFE)
{
newSize = new Vector2((float)contentFE.ActualWidth, (float)contentFE.ActualHeight);
}

if (!(host is Canvas uiHost) || newSize == default)
{
return;
}

spriteVisual.Size = newSize;
if (elevation > 0)
{
// Values for 1dp elevation according to https://material.io/guidelines/resources/shadows.html#shadows-illustrator
const float x = 0.25f;
const float y = 0.92f * 0.5f; // Looks more accurate than the recommended 0.92f.
const float blur = 0.5f;

var shadow = compositor.CreateDropShadow();
shadow.Offset = new Vector3((float)elevation * x, (float)elevation * y, -(float)elevation);
shadow.BlurRadius = (float)(blur * elevation);

shadow.Mask = uiElement switch
{
// GetAlphaMask is only available for shapes, images, and textblocks
Shape shape => shape.GetAlphaMask(),
Image image => image.GetAlphaMask(),
TextBlock tb => tb.GetAlphaMask(),
_ => shadow.Mask
};

if (!cornerRadius.Equals(default))
{
var averageRadius =
(cornerRadius.TopLeft +
cornerRadius.TopRight +
cornerRadius.BottomLeft +
cornerRadius.BottomRight) / 4f;

// Create a rectangle with similar corner radius (average for now)
var rect = new Rectangle()
{
Fill = new SolidColorBrush(Colors.White),
Width = newSize.X,
Height = newSize.Y,
RadiusX = averageRadius,
RadiusY = averageRadius
};

uiHost.Children.Add(rect); // The rect need to be in th VisualTree for .GetAlphaMask() to work

shadow.Mask = rect.GetAlphaMask();

uiHost.Children.Remove(rect); // No need anymore, we can discard it.
}

shadow.Color = shadowColor;
shadow.Opacity = shadowColor.A / 255f;
spriteVisual.Shadow = shadow;
}

ElementCompositionPreview.SetElementChildVisual(uiHost, spriteVisual);
}
#elif __SKIA__
// TODO Uno: Not yet supported, no-op.
#endif
}
}
}
#endif
1 change: 1 addition & 0 deletions src/Uno.UI/UI/Xaml/Controls/ContentDialog/ContentDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.ViewManagement;
using Uno.UI.Helpers;
using Color = Windows.UI.Color;

namespace Windows.UI.Xaml.Controls
{
Expand Down

0 comments on commit cbc56bb

Please sign in to comment.