Skip to content

Commit

Permalink
Replace WindowTransparencyLevel enum with list of structs
Browse files Browse the repository at this point in the history
The transparency level is not yet communicated to the backends though.

Co-Authored-By: Max Katz <[email protected]>
  • Loading branch information
grokys and maxkatz6 committed May 23, 2023
1 parent 6533972 commit b2d7805
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 165 deletions.
2 changes: 1 addition & 1 deletion samples/ControlCatalog/MainView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public MainView()
if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected)
{
var topLevel = (TopLevel)this.GetVisualRoot()!;
topLevel.TransparencyLevelHint = selected;
topLevel.TransparencyLevelHint = new[] { selected };

if (selected != WindowTransparencyLevel.None)
{
Expand Down
2 changes: 1 addition & 1 deletion samples/IntegrationTestApp/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private void ShowTransparentWindow()
Name = "TransparentWindow",
SystemDecorations = SystemDecorations.None,
Background = Brushes.Transparent,
TransparencyLevelHint = WindowTransparencyLevel.Transparent,
TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent },
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Width = 200,
Height = 200,
Expand Down
118 changes: 60 additions & 58 deletions src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,78 +307,80 @@ public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
bool isAboveR = Build.VERSION.SdkInt > BuildVersionCodes.R;
if (_view.Context is AvaloniaMainActivity activity)
{
switch (transparencyLevel)
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur ||
transparencyLevel == WindowTransparencyLevel.Mica ||
transparencyLevel == WindowTransparencyLevel.None)
{
case WindowTransparencyLevel.AcrylicBlur:
case WindowTransparencyLevel.ForceAcrylicBlur:
case WindowTransparencyLevel.Mica:
case WindowTransparencyLevel.None:
if (!isBelowR)
if (!isBelowR)
{
activity.SetTranslucent(false);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);

var attr = activity.Window?.Attributes;
if (attr != null)
{
activity.SetTranslucent(false);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);

var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
attr.BlurBehindRadius = 0;

activity.Window.Attributes = attr;
}
activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));

if(transparencyLevel != WindowTransparencyLevel.None)
{
return;
}
break;
case WindowTransparencyLevel.Transparent:
if (!isBelowR)
{
activity.SetTranslucent(true);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
if (transparencyLevel != WindowTransparencyLevel.None)
{
return;
}
}

var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;
if (transparencyLevel == WindowTransparencyLevel.Transparent)
{
if (!isBelowR)
{
activity.SetTranslucent(true);
}
if (isAboveR)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);

var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 0;

activity.Window.Attributes = attr;
}
activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
break;
case WindowTransparencyLevel.Blur:
if (isAboveR)
{
activity.SetTranslucent(true);
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}

var attr = activity.Window?.Attributes;
if (attr != null)
{
attr.BlurBehindRadius = 120;
if (transparencyLevel == WindowTransparencyLevel.Blur)
{
if (isAboveR)
{
activity.SetTranslucent(true);
activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);

activity.Window.Attributes = attr;
}
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
else
var attr = activity.Window?.Attributes;
if (attr != null)
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
attr.BlurBehindRadius = 120;

return;
activity.Window.Attributes = attr;
}
break;
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
else
{
activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));

return;
}
}

TransparencyLevel = transparencyLevel;
}
}
Expand Down
22 changes: 6 additions & 16 deletions src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,12 @@ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
if (tl.PlatformImpl is null)
return;

switch (x)
{
case WindowTransparencyLevel.Transparent:
case WindowTransparencyLevel.None:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.TransparentLevel;
break;

case WindowTransparencyLevel.Blur:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.BlurLevel;
break;

case WindowTransparencyLevel.AcrylicBlur:
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.AcrylicBlurLevel;
break;
}
if (x == WindowTransparencyLevel.Transparent || x == WindowTransparencyLevel.None)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.TransparentLevel;
else if (x == WindowTransparencyLevel.Blur)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.BlurLevel;
else if (x == WindowTransparencyLevel.AcrylicBlur)
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.AcrylicBlurLevel;
});
UpdateMaterialSubscription();
}
Expand Down
38 changes: 13 additions & 25 deletions src/Avalonia.Controls/TopLevel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using Avalonia.Reactive;
Expand All @@ -22,6 +23,7 @@
using Avalonia.Input.Platform;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Metadata;

namespace Avalonia.Controls
{
Expand Down Expand Up @@ -64,8 +66,8 @@ public abstract class TopLevel : ContentControl,
/// <summary>
/// Defines the <see cref="TransparencyLevelHint"/> property.
/// </summary>
public static readonly StyledProperty<WindowTransparencyLevel> TransparencyLevelHintProperty =
AvaloniaProperty.Register<TopLevel, WindowTransparencyLevel>(nameof(TransparencyLevelHint), WindowTransparencyLevel.None);
public static readonly StyledProperty<IReadOnlyList<WindowTransparencyLevel>> TransparencyLevelHintProperty =
AvaloniaProperty.Register<TopLevel, IReadOnlyList<WindowTransparencyLevel>>(nameof(TransparencyLevelHint), Array.Empty<WindowTransparencyLevel>());

/// <summary>
/// Defines the <see cref="ActualTransparencyLevel"/> property.
Expand Down Expand Up @@ -172,7 +174,7 @@ public TopLevel(ITopLevelImpl impl, IAvaloniaDependencyResolver? dependencyResol
PlatformImpl = impl ?? throw new InvalidOperationException(
"Could not create window implementation: maybe no windowing subsystem was initialized?");

_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;

dependencyResolver ??= AvaloniaLocator.Current;

Expand Down Expand Up @@ -310,8 +312,11 @@ public Size? FrameSize

/// <summary>
/// Gets or sets the <see cref="WindowTransparencyLevel"/> that the TopLevel should use when possible.
/// Accepts multiple values which are applied in a fallback order.
/// For instance, with "Mica, Blur" Mica will be applied only on platforms where it is possible,
/// and Blur will be used on the rest of them. Default value is an empty array or "None".
/// </summary>
public WindowTransparencyLevel TransparencyLevelHint
public IReadOnlyList<WindowTransparencyLevel> TransparencyLevelHint
{
get { return GetValue(TransparencyLevelHintProperty); }
set { SetValue(TransparencyLevelHintProperty, value); }
Expand Down Expand Up @@ -518,8 +523,8 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
{
if (PlatformImpl != null)
{
PlatformImpl.SetTransparencyLevelHint(change.GetNewValue<WindowTransparencyLevel>());
HandleTransparencyLevelChanged(PlatformImpl.TransparencyLevel);
////PlatformImpl.SetTransparencyLevelHint(
//// change.GetNewValue<IReadOnlyList<WindowTransparencyLevel>>() ?? Array.Empty<WindowTransparencyLevel>());
}
}
else if (change.Property == ActualThemeVariantProperty)
Expand Down Expand Up @@ -610,27 +615,11 @@ private void HandleScalingChanged(double scaling)
ScalingChanged?.Invoke(this, EventArgs.Empty);
}

private static bool TransparencyLevelsMatch (WindowTransparencyLevel requested, WindowTransparencyLevel received)
{
if(requested == received)
{
return true;
}
else if(requested >= WindowTransparencyLevel.Blur && received >= WindowTransparencyLevel.Blur)
{
return true;
}

return false;
}

private void HandleTransparencyLevelChanged(WindowTransparencyLevel transparencyLevel)
{
if(_transparencyFallbackBorder != null)
if (_transparencyFallbackBorder != null)
{
if(transparencyLevel == WindowTransparencyLevel.None ||
TransparencyLevelHint == WindowTransparencyLevel.None ||
!TransparencyLevelsMatch(TransparencyLevelHint, transparencyLevel))
if (transparencyLevel == WindowTransparencyLevel.None)
{
_transparencyFallbackBorder.Background = TransparencyBackgroundFallback;
}
Expand Down Expand Up @@ -660,7 +649,6 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
return;

_transparencyFallbackBorder = e.NameScope.Find<Border>("PART_TransparencyFallback");

HandleTransparencyLevelChanged(PlatformImpl.TransparencyLevel);
}

Expand Down
78 changes: 47 additions & 31 deletions src/Avalonia.Controls/WindowTransparencyLevel.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
namespace Avalonia.Controls
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Avalonia.Controls;

public readonly record struct WindowTransparencyLevel
{
public enum WindowTransparencyLevel
private readonly string _value;

private WindowTransparencyLevel(string value)
{
/// <summary>
/// The window background is Black where nothing is drawn in the window.
/// </summary>
None,

/// <summary>
/// The window background is Transparent where nothing is drawn in the window.
/// </summary>
Transparent,

/// <summary>
/// The window background is a blur-behind where nothing is drawn in the window.
/// </summary>
Blur,

/// <summary>
/// The window background is a blur-behind with a high blur radius. This level may fallback to Blur.
/// </summary>
AcrylicBlur,

/// <summary>
/// Force acrylic on some incompatible versions of Windows 10.
/// </summary>
ForceAcrylicBlur,

/// <summary>
/// The window background is based on desktop wallpaper tint with a blur. This will only work on Windows 11
/// </summary>
Mica
_value = value;
}

/// <summary>
/// The window background is Black where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel None { get; } = new(nameof(None));

/// <summary>
/// The window background is Transparent where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel Transparent { get; } = new(nameof(Transparent));

/// <summary>
/// The window background is a blur-behind where nothing is drawn in the window.
/// </summary>
public static WindowTransparencyLevel Blur { get; } = new(nameof(Blur));

/// <summary>
/// The window background is a blur-behind with a high blur radius. This level may fallback to Blur.
/// </summary>
public static WindowTransparencyLevel AcrylicBlur { get; } = new(nameof(AcrylicBlur));

/// <summary>
/// The window background is based on desktop wallpaper tint with a blur. This will only work on Windows 11
/// </summary>
public static WindowTransparencyLevel Mica { get; } = new(nameof(Mica));

public override string ToString()
{
return _value;
}
}

public class WindowTransparencyLevelCollection : ReadOnlyCollection<WindowTransparencyLevel>
{
public WindowTransparencyLevelCollection(IList<WindowTransparencyLevel> list) : base(list)
{
}
}
6 changes: 5 additions & 1 deletion src/Avalonia.Native/WindowImplBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,12 @@ public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{
if (TransparencyLevel != transparencyLevel)
{
if (transparencyLevel > WindowTransparencyLevel.Transparent)
if (transparencyLevel == WindowTransparencyLevel.Blur ||
transparencyLevel == WindowTransparencyLevel.AcrylicBlur ||
transparencyLevel == WindowTransparencyLevel.Mica)
{
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
}

TransparencyLevel = transparencyLevel;

Expand Down
Loading

0 comments on commit b2d7805

Please sign in to comment.