Browse Source

managed titlebar declared in xaml.

pull/4336/head
Dan Walmsley 6 years ago
parent
commit
b88ec08b54
  1. 110
      src/Avalonia.Controls/Chrome/TitleBar.cs
  2. 5
      src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs
  3. 34
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  4. 27
      src/Avalonia.Controls/Window.cs
  5. 3
      src/Avalonia.Themes.Default/Window.xaml
  6. 3
      src/Avalonia.Themes.Fluent/Window.xaml

110
src/Avalonia.Controls/Chrome/TitleBar.cs

@ -12,91 +12,34 @@ namespace Avalonia.Controls.Chrome
public class TitleBar : TemplatedControl
{
private CompositeDisposable? _disposables;
private readonly Window? _hostWindow;
private CaptionButtons? _captionButtons;
public TitleBar(Window hostWindow)
{
_hostWindow = hostWindow;
}
public TitleBar()
{
}
public void Attach()
{
if (_disposables == null)
{
if (_hostWindow != null)
{
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
layer?.Children.Add(this);
_disposables = new CompositeDisposable
{
_hostWindow.GetObservable(Window.WindowDecorationMarginProperty)
.Subscribe(x => UpdateSize()),
_hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
.Subscribe(x => UpdateSize()),
_hostWindow.GetObservable(Window.OffScreenMarginProperty)
.Subscribe(x => UpdateSize()),
_hostWindow.GetObservable(Window.WindowStateProperty)
.Subscribe(x =>
{
PseudoClasses.Set(":minimized", x == WindowState.Minimized);
PseudoClasses.Set(":normal", x == WindowState.Normal);
PseudoClasses.Set(":maximized", x == WindowState.Maximized);
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
})
};
_captionButtons?.Attach(_hostWindow);
}
UpdateSize();
}
}
private void UpdateSize()
private void UpdateSize(Window window)
{
if (_hostWindow != null)
if (window != null)
{
Margin = new Thickness(
_hostWindow.OffScreenMargin.Left,
_hostWindow.OffScreenMargin.Top,
_hostWindow.OffScreenMargin.Right,
_hostWindow.OffScreenMargin.Bottom);
window.OffScreenMargin.Left,
window.OffScreenMargin.Top,
window.OffScreenMargin.Right,
window.OffScreenMargin.Bottom);
if (_hostWindow.WindowState != WindowState.FullScreen)
if (window.WindowState != WindowState.FullScreen)
{
Height = _hostWindow.WindowDecorationMargin.Top;
Height = window.WindowDecorationMargin.Top;
if (_captionButtons != null)
{
_captionButtons.Height = Height;
}
}
}
}
public void Detach()
{
if (_disposables != null)
{
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
layer?.Children.Remove(this);
_disposables.Dispose();
_disposables = null;
_captionButtons?.Detach();
IsVisible = window.PlatformImpl.NeedsManagedDecorations;
}
}
@ -106,12 +49,39 @@ namespace Avalonia.Controls.Chrome
_captionButtons = e.NameScope.Get<CaptionButtons>("PART_CaptionButtons");
if (_hostWindow != null)
if (VisualRoot is Window window)
{
_captionButtons.Attach(_hostWindow);
}
_disposables = new CompositeDisposable
{
window.GetObservable(Window.WindowDecorationMarginProperty)
.Subscribe(x => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
.Subscribe(x => UpdateSize(window)),
UpdateSize();
window.GetObservable(Window.OffScreenMarginProperty)
.Subscribe(x => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaChromeHintsProperty)
.Subscribe(x => UpdateSize(window)),
window.GetObservable(Window.WindowStateProperty)
.Subscribe(x =>
{
PseudoClasses.Set(":minimized", x == WindowState.Minimized);
PseudoClasses.Set(":normal", x == WindowState.Normal);
PseudoClasses.Set(":maximized", x == WindowState.Maximized);
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
}),
window.GetObservable(Window.IsExtendedIntoWindowDecorationsProperty)
.Subscribe(x => UpdateSize(window))
};
_captionButtons.Attach(window);
UpdateSize(window);
}
}
}
}

5
src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs

@ -24,6 +24,11 @@ namespace Avalonia.Controls.Primitives
return null;
}
public void Add(Control c)
{
base.Children.Add(c);
}
public bool HitTest(Point point) => Children.HitTestCustom(point);
}
}

34
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
namespace Avalonia.Controls.Primitives
{
@ -12,15 +13,8 @@ namespace Avalonia.Controls.Primitives
private ILogicalRoot _logicalRoot;
private readonly List<Control> _layers = new List<Control>();
public static readonly StyledProperty<Panel> ChromeOverlayLayerProperty =
AvaloniaProperty.Register<VisualLayerManager, Panel>(nameof(ChromeOverlayLayer));
public VisualLayerManager()
{
var chromeOverlayLayer = new ChromeOverlayLayer();
AddLayer(chromeOverlayLayer, ChromeZIndex);
ChromeOverlayLayer = chromeOverlayLayer;
}
public static readonly StyledProperty<ChromeOverlayLayer> ChromeOverlayLayerProperty =
AvaloniaProperty.Register<VisualLayerManager, ChromeOverlayLayer>(nameof(ChromeOverlayLayer));
public bool IsPopup { get; set; }
@ -34,11 +28,25 @@ namespace Avalonia.Controls.Primitives
return rv;
}
}
public Panel ChromeOverlayLayer
public ChromeOverlayLayer ChromeOverlayLayer
{
get => GetValue(ChromeOverlayLayerProperty);
private set => SetValue(ChromeOverlayLayerProperty, value);
get
{
var current = GetValue(ChromeOverlayLayerProperty);
if (current is null)
{
var chromeOverlayLayer = new ChromeOverlayLayer();
AddLayer(chromeOverlayLayer, ChromeZIndex);
SetValue(ChromeOverlayLayerProperty, chromeOverlayLayer);
current = chromeOverlayLayer;
}
return current;
}
}
public OverlayLayer OverlayLayer

27
src/Avalonia.Controls/Window.cs

@ -71,12 +71,10 @@ namespace Avalonia.Controls
/// </summary>
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot
{
private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>();
private TitleBar _managedTitleBar;
private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>();
private bool _isExtendedIntoWindowDecorations;
private Thickness _windowDecorationMargin;
private Thickness _offScreenMargin;
private bool _templateApplied;
/// <summary>
/// Defines the <see cref="SizeToContent"/> property.
@ -554,29 +552,6 @@ namespace Avalonia.Controls
IsExtendedIntoWindowDecorations = isExtended;
WindowDecorationMargin = PlatformImpl.ExtendedMargins;
OffScreenMargin = PlatformImpl.OffScreenMargin;
if (PlatformImpl.NeedsManagedDecorations && _templateApplied)
{
if (_managedTitleBar == null)
{
_managedTitleBar = new TitleBar(this);
_managedTitleBar.Attach();
}
}
else
{
_managedTitleBar?.Detach();
_managedTitleBar = null;
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_templateApplied = true;
ExtendClientAreaToDecorationsChanged(PlatformImpl.IsClientAreaExtendedToDecorations);
}
/// <summary>

3
src/Avalonia.Themes.Default/Window.xaml

@ -10,6 +10,9 @@
<Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
<Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
<VisualLayerManager>
<VisualLayerManager.ChromeOverlayLayer>
<TitleBar />
</VisualLayerManager.ChromeOverlayLayer>
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"

3
src/Avalonia.Themes.Fluent/Window.xaml

@ -10,6 +10,9 @@
<Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
<Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
<VisualLayerManager>
<VisualLayerManager.ChromeOverlayLayer>
<TitleBar />
</VisualLayerManager.ChromeOverlayLayer>
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"

Loading…
Cancel
Save