Browse Source

Add Window.WindowDecorationsTheme property (#21061)

pull/21219/head
Julien Lebosquain 3 months ago
committed by GitHub
parent
commit
11ec00205d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 13
      src/Avalonia.Controls/TopLevelHost.Decorations.cs
  2. 25
      src/Avalonia.Controls/Window.cs
  3. 52
      tests/Avalonia.Controls.UnitTests/WindowTests.cs

13
src/Avalonia.Controls/TopLevelHost.Decorations.cs

@ -6,6 +6,7 @@ using Avalonia.Automation.Peers;
using Avalonia.Controls.Chrome;
using Avalonia.Input;
using Avalonia.Reactive;
using Avalonia.Styling;
namespace Avalonia.Controls;
@ -53,7 +54,7 @@ internal partial class TopLevelHost
/// When non-null (including <see cref="DrawnWindowDecorationParts.None"/>), the decoration
/// infrastructure is kept alive and parts/fullscreen state are updated.
/// </summary>
internal void UpdateDrawnDecorations(DrawnWindowDecorationParts? parts, WindowState windowState)
internal void UpdateDrawnDecorations(DrawnWindowDecorationParts? parts, WindowState windowState, ControlTheme? theme)
{
if (parts == null)
{
@ -68,6 +69,14 @@ internal partial class TopLevelHost
// Layers persist across part changes; pseudo-classes driven by EnabledParts
// control visibility of individual decoration elements in the theme.
_decorations.EnabledParts = enabledParts;
var oldTheme = _decorations.Theme;
if (oldTheme != theme)
{
_decorations.Theme = theme;
_decorations.ApplyStyling();
}
if (_resizeGrips != null)
_resizeGrips.IsVisible = enabledParts.HasFlag(DrawnWindowDecorationParts.ResizeGrips);
}
@ -75,6 +84,7 @@ internal partial class TopLevelHost
{
_decorations = new WindowDrawnDecorations();
_decorations.EnabledParts = enabledParts;
_decorations.Theme = theme;
// Set up logical parenting
LogicalChildren.Add(_decorations);
@ -161,6 +171,7 @@ internal partial class TopLevelHost
if (_decorations == null)
return;
_decorations.ApplyStyling();
_decorations.ApplyTemplate();
var content = _decorations.Content;

25
src/Avalonia.Controls/Window.cs

@ -140,6 +140,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<WindowDecorations> WindowDecorationsProperty =
AvaloniaProperty.Register<Window, WindowDecorations>(nameof(WindowDecorations), WindowDecorations.Full);
/// <summary>
/// Defines the <see cref="WindowDecorationsTheme"/> property.
/// </summary>
public static readonly StyledProperty<ControlTheme?> WindowDecorationsThemeProperty =
AvaloniaProperty.Register<Window, ControlTheme?>(nameof(WindowDecorationsTheme));
/// <summary>
/// Defines the <see cref="ShowActivated"/> property.
/// </summary>
@ -376,6 +382,15 @@ namespace Avalonia.Controls
set => SetValue(WindowDecorationsProperty, value);
}
/// <summary>
/// Gets or sets the theme used to render the window decorations when they are not drawn by the system.
/// </summary>
public ControlTheme? WindowDecorationsTheme
{
get => GetValue(WindowDecorationsThemeProperty);
set => SetValue(WindowDecorationsThemeProperty, value);
}
[Obsolete("Use WindowDecorations instead.")]
public WindowDecorations SystemDecorations
{
@ -704,7 +719,7 @@ namespace Avalonia.Controls
// Detect forced mode: platform needs managed decorations but app hasn't opted in
_isForcedDecorationMode = parts != null && !IsExtendedIntoWindowDecorations;
TopLevelHost.UpdateDrawnDecorations(parts, WindowState);
TopLevelHost.UpdateDrawnDecorations(parts, WindowState, WindowDecorationsTheme);
if (parts != null)
{
@ -739,7 +754,7 @@ namespace Avalonia.Controls
if (TopLevelHost.Decorations == null)
return;
TopLevelHost.UpdateDrawnDecorations(ComputeDecorationParts(), WindowState);
TopLevelHost.UpdateDrawnDecorations(ComputeDecorationParts(), WindowState, WindowDecorationsTheme);
}
private Chrome.DrawnWindowDecorationParts? ComputeDecorationParts()
@ -1493,6 +1508,7 @@ namespace Avalonia.Controls
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == WindowDecorationsProperty)
{
var (_, typedNewValue) = change.GetOldAndNewValue<WindowDecorations>();
@ -1500,6 +1516,11 @@ namespace Avalonia.Controls
PlatformImpl?.SetWindowDecorations(typedNewValue);
}
else if (change.Property == WindowDecorationsThemeProperty)
{
UpdateDrawnDecorations();
}
else if (change.Property == OwnerProperty)
{
var oldParent = change.OldValue as Window;

52
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -2,9 +2,13 @@ using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Chrome;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
@ -1590,6 +1594,54 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void WindowDecorationsTheme_Should_Apply_To_Decorations()
{
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
var windowImpl = MockWindowingPlatform.CreateWindowMock();
windowImpl.Setup(x => x.NeedsManagedDecorations).Returns(true);
windowImpl.Setup(x => x.RequestedDrawnDecorations).Returns(
PlatformRequestedDrawnDecoration.TitleBar | PlatformRequestedDrawnDecoration.Border);
var window = new Window(windowImpl.Object);
var (theme1, content1) = CreateTheme();
window.WindowDecorationsTheme = theme1;
window.Show();
var decorations = window.TopLevelHost.Decorations;
Assert.NotNull(decorations);
Assert.Same(theme1, decorations.Theme);
Assert.Same(content1, decorations.Content);
var (theme2, content2) = CreateTheme();
window.WindowDecorationsTheme = theme2;
Assert.Same(theme2, decorations.Theme);
Assert.Same(content2, decorations.Content);
static (ControlTheme theme, WindowDrawnDecorationsContent content) CreateTheme()
{
var content = new WindowDrawnDecorationsContent();
var template = new WindowDrawnDecorationsTemplate
{
Content = (IServiceProvider? _) => new TemplateResult<WindowDrawnDecorationsContent>(content, new NameScope())
};
var theme = new ControlTheme(typeof(WindowDrawnDecorations))
{
Setters =
{
new Setter(WindowDrawnDecorations.TemplateProperty, template)
}
};
return (theme, content);
}
}
private class TopmostWindow : Window
{
static TopmostWindow()

Loading…
Cancel
Save