-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Experiment] OpacityMaskView #491
base: main
Are you sure you want to change the base?
Changes from 4 commits
c18f789
22fb628
3bcc44f
2041235
b267e56
ad14d18
54e0799
dc3427a
ce46c6f
dafd7fb
4d8f969
5adf13a
1decd44
73bbb47
9b2268e
9ec8111
aa4539f
f022067
fd37449
8e0da1e
38db553
c2d6602
0440794
a23366c
1965f53
2fb74f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
@ECHO OFF | ||
|
||
powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!-- | ||
WinUI 2 under UWP uses TargetFramework uap10.0.* | ||
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.* | ||
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework. | ||
|
||
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you. | ||
|
||
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio. | ||
For UWP / WinAppSDK / Uno packages, place the package references here. | ||
--> | ||
<Project> | ||
<!-- WinUI 2 / UWP --> | ||
<ItemGroup Condition="'$(IsUwp)' == 'true'"> | ||
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 2 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'"> | ||
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / WinAppSdk --> | ||
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'"> | ||
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'"> | ||
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> --> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project> | ||
<PropertyGroup> | ||
<!-- | ||
MultiTarget is a custom property that indicates which target a project is designed to be built for / run on. | ||
Used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages. | ||
--> | ||
<MultiTarget>uwp;wasdk;</MultiTarget> | ||
</PropertyGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Project Sdk="MSBuild.Sdk.Extras/3.0.23"> | ||
<PropertyGroup> | ||
<ToolkitComponentName>OpacityMaskView</ToolkitComponentName> | ||
</PropertyGroup> | ||
|
||
<!-- Sets this up as a toolkit component's sample project --> | ||
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" /> | ||
<ItemGroup> | ||
<None Remove="Assets\Owl.jpg" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Content Include="Assets\Owl.jpg"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</Content> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
title: OpacityMaskView | ||
author: h82258652 | ||
description: A control that applies an opacity mask to its content. | ||
keywords: OpacityMaskView, Control, Layout | ||
dev_langs: | ||
- csharp | ||
category: Controls | ||
subcategory: Layout | ||
discussion-id: 490 | ||
issue-id: 0 | ||
icon: assets/icon.png | ||
--- | ||
# OpacityMaskView | ||
|
||
The `OpacityMaskView` control applies an opacity mask to its content. The mask is defined by the `OpacityMask` property, which can contain a `Brush` object. The `OpacityMask` property is typically set to a `LinearGradientBrush` or `ImageBrush` object. | ||
|
||
> [!Sample OpacityMaskViewSample] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. --> | ||
<Page x:Class="OpacityMaskViewExperiment.Samples.OpacityMaskViewSample" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:controls="using:CommunityToolkit.WinUI.Controls" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:local="using:OpacityMaskViewExperiment.Samples" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
mc:Ignorable="d"> | ||
|
||
<StackPanel Spacing="12"> | ||
<controls:OpacityMaskView> | ||
<controls:OpacityMaskView.OpacityMask> | ||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> | ||
<GradientStop Offset="0" Color="White" /> | ||
<GradientStop Offset="1" Color="Transparent" /> | ||
</LinearGradientBrush> | ||
</controls:OpacityMaskView.OpacityMask> | ||
<Button Content="Hello Windows Community Toolkit" /> | ||
</controls:OpacityMaskView> | ||
<controls:OpacityMaskView> | ||
<controls:OpacityMaskView.OpacityMask> | ||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> | ||
<GradientStop Offset="0" Color="White" /> | ||
<GradientStop Offset="0.6" Color="Transparent" /> | ||
</LinearGradientBrush> | ||
</controls:OpacityMaskView.OpacityMask> | ||
<Border Width="96" | ||
Height="96" | ||
BorderBrush="Red" | ||
BorderThickness="1" | ||
CornerRadius="12"> | ||
<Image Source="ms-appx:///Assets/Owl.jpg" /> | ||
</Border> | ||
</controls:OpacityMaskView> | ||
</StackPanel> | ||
</Page> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using CommunityToolkit.WinUI.Controls; | ||
|
||
namespace OpacityMaskViewExperiment.Samples; | ||
|
||
/// <summary> | ||
/// An example sample page of a custom control inheriting from Panel. | ||
/// </summary> | ||
[ToolkitSample(id: nameof(OpacityMaskViewSample), "OpacityMaskView sample", description: $"A sample for showing how to create and use a {nameof(OpacityMaskView)} control.")] | ||
public sealed partial class OpacityMaskViewSample : Page | ||
{ | ||
public OpacityMaskViewSample() | ||
{ | ||
this.InitializeComponent(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project Sdk="MSBuild.Sdk.Extras/3.0.23"> | ||
<PropertyGroup> | ||
<ToolkitComponentName>OpacityMaskView</ToolkitComponentName> | ||
<Description>This package contains OpacityMaskView.</Description> | ||
|
||
<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 --> | ||
<RootNamespace>CommunityToolkit.WinUI.Controls.OpacityMaskViewRns</RootNamespace> | ||
</PropertyGroup> | ||
|
||
<!-- Sets this up as a toolkit component's source project --> | ||
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" /> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!-- | ||
WinUI 2 under UWP uses TargetFramework uap10.0.* | ||
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.* | ||
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework. | ||
|
||
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you. | ||
|
||
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio. | ||
For UWP / WinAppSDK / Uno packages, place the package references here. | ||
--> | ||
<Project> | ||
<!-- WinUI 2 / UWP --> | ||
<ItemGroup Condition="'$(IsUwp)' == 'true'"> | ||
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 2 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'"> | ||
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / WinAppSdk --> | ||
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'"> | ||
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> --> | ||
</ItemGroup> | ||
|
||
<!-- WinUI 3 / Uno --> | ||
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'"> | ||
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> --> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project> | ||
<PropertyGroup> | ||
<!-- | ||
MultiTarget is a custom property that indicates which target a project is designed to be built for / run on. | ||
Used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages. | ||
--> | ||
<MultiTarget>uwp;wasdk;</MultiTarget> | ||
</PropertyGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Numerics; | ||
#if WINDOWS_WINAPPSDK | ||
using Microsoft.UI.Composition; | ||
using Microsoft.UI.Xaml.Hosting; | ||
using Microsoft.UI.Xaml.Shapes; | ||
#else | ||
using Windows.UI.Composition; | ||
using Windows.UI.Xaml.Hosting; | ||
using Windows.UI.Xaml.Shapes; | ||
#endif | ||
|
||
namespace CommunityToolkit.WinUI.Controls; | ||
|
||
/// <summary> | ||
/// TODO | ||
/// </summary> | ||
[TemplatePart(Name = RootGridTemplateName, Type = typeof(Grid))] | ||
[TemplatePart(Name = MaskRectangleTemplateName, Type = typeof(Rectangle))] | ||
[TemplatePart(Name = ContentPresenterTemplateName, Type = typeof(ContentPresenter))] | ||
public partial class OpacityMaskView : ContentControl | ||
{ | ||
/// <summary> | ||
/// Identifies the <see cref="OpacityMask"/> property. | ||
/// </summary> | ||
public static readonly DependencyProperty OpacityMaskProperty = | ||
DependencyProperty.Register(nameof(OpacityMask), typeof(Brush), typeof(OpacityMaskView), new PropertyMetadata(null, OnOpacityMaskChanged)); | ||
|
||
private const string ContentPresenterTemplateName = "PART_ContentPresenter"; | ||
private const string MaskRectangleTemplateName = "PART_MaskRectangle"; | ||
private const string RootGridTemplateName = "PART_RootGrid"; | ||
|
||
private readonly Compositor _compositor = Window.Current.Compositor; | ||
private CompositionBrush? _mask; | ||
private CompositionMaskBrush? _maskBrush; | ||
|
||
/// <summary> | ||
/// Creates a new instance of the <see cref="OpacityMaskView"/> class. | ||
/// </summary> | ||
public OpacityMaskView() | ||
{ | ||
DefaultStyleKey = typeof(OpacityMaskView); | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets an opacity mask, as a <see cref="Brush"/> implementation that is applied to any alpha-channel masking for the rendered content of the content. | ||
/// </summary> | ||
public Brush? OpacityMask | ||
{ | ||
get => (Brush?)GetValue(OpacityMaskProperty); | ||
set => SetValue(OpacityMaskProperty, value); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override void OnApplyTemplate() | ||
{ | ||
base.OnApplyTemplate(); | ||
|
||
Grid rootGrid = (Grid)GetTemplateChild(RootGridTemplateName); | ||
ContentPresenter contentPresenter = (ContentPresenter)GetTemplateChild(ContentPresenterTemplateName); | ||
Rectangle maskRectangle = (Rectangle)GetTemplateChild(MaskRectangleTemplateName); | ||
|
||
_maskBrush = _compositor.CreateMaskBrush(); | ||
_maskBrush.Source = GetVisualBrush(contentPresenter); | ||
_mask = GetVisualBrush(maskRectangle); | ||
_maskBrush.Mask = OpacityMask is null ? null : _mask; | ||
|
||
SpriteVisual redirectVisual = _compositor.CreateSpriteVisual(); | ||
redirectVisual.RelativeSizeAdjustment = Vector2.One; | ||
redirectVisual.Brush = _maskBrush; | ||
ElementCompositionPreview.SetElementChildVisual(rootGrid, redirectVisual); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to apply any of this like we do for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @michael-hawker I don't think we can do this. Sergio created one like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds similar to what we have to do for the |
||
} | ||
|
||
private static CompositionBrush GetVisualBrush(UIElement element) | ||
{ | ||
Visual visual = ElementCompositionPreview.GetElementVisual(element); | ||
|
||
Compositor compositor = visual.Compositor; | ||
|
||
CompositionVisualSurface visualSurface = compositor.CreateVisualSurface(); | ||
visualSurface.SourceVisual = visual; | ||
ExpressionAnimation sourceSizeAnimation = compositor.CreateExpressionAnimation($"{nameof(visual)}.Size"); | ||
sourceSizeAnimation.SetReferenceParameter(nameof(visual), visual); | ||
visualSurface.StartAnimation(nameof(visualSurface.SourceSize), sourceSizeAnimation); | ||
|
||
CompositionSurfaceBrush brush = compositor.CreateSurfaceBrush(visualSurface); | ||
|
||
visual.Opacity = 0; | ||
|
||
return brush; | ||
} | ||
|
||
private static void OnOpacityMaskChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | ||
{ | ||
OpacityMaskView self = (OpacityMaskView)d; | ||
if (self._maskBrush is not { } maskBrush) | ||
{ | ||
return; | ||
} | ||
|
||
Brush? opacityMask = (Brush?)e.NewValue; | ||
maskBrush.Mask = opacityMask is null ? null : self._mask; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. --> | ||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:local="using:CommunityToolkit.WinUI.Controls"> | ||
|
||
<Style BasedOn="{StaticResource DefaultOpacityMaskViewStyle}" | ||
TargetType="local:OpacityMaskView" /> | ||
|
||
<Style x:Key="DefaultOpacityMaskViewStyle" | ||
TargetType="local:OpacityMaskView"> | ||
<Setter Property="IsTabStop" Value="False" /> | ||
<Setter Property="HorizontalContentAlignment" Value="Left" /> | ||
<Setter Property="VerticalContentAlignment" Value="Top" /> | ||
<Setter Property="Template"> | ||
<Setter.Value> | ||
<ControlTemplate TargetType="local:OpacityMaskView"> | ||
<Grid x:Name="PART_RootGrid" | ||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" | ||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"> | ||
<Rectangle x:Name="PART_MaskRectangle" | ||
Fill="{TemplateBinding OpacityMask}" | ||
IsHitTestVisible="False" /> | ||
<ContentPresenter x:Name="PART_ContentPresenter" | ||
Content="{TemplateBinding Content}" | ||
ContentTemplate="{TemplateBinding ContentTemplate}" /> | ||
</Grid> | ||
</ControlTemplate> | ||
</Setter.Value> | ||
</Setter> | ||
</Style> | ||
|
||
</ResourceDictionary> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"> | ||
|
||
<ResourceDictionary.MergedDictionaries> | ||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.OpacityMaskView/OpacityMaskView.xaml" /> | ||
</ResourceDictionary.MergedDictionaries> | ||
|
||
</ResourceDictionary> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<PropertyGroup> | ||
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' < '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> | ||
<HasSharedItems>true</HasSharedItems> | ||
<SharedGUID>04511143-C2A3-4893-810D-3C1EA2877430</SharedGUID> | ||
</PropertyGroup> | ||
<PropertyGroup Label="Configuration"> | ||
<Import_RootNamespace>OpacityMaskViewExperiment.Tests</Import_RootNamespace> | ||
</PropertyGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<PropertyGroup Label="Globals"> | ||
<ProjectGuid>04511143-C2A3-4893-810D-3C1EA2877430</ProjectGuid> | ||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion> | ||
</PropertyGroup> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" /> | ||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" /> | ||
<PropertyGroup /> | ||
<Import Project="OpacityMaskView.Tests.projitems" Label="Shared" /> | ||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" /> | ||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@niels9001 / @Arlodotexe just need latest icon here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michael-hawker updated.