From 4be53b2d8a4f9c95b003f35f5055f3cd011ce520 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 2 Jul 2020 14:27:40 -0300 Subject: [PATCH] dont cover titlebar, and allow titlebar to have a background placed in an underlay layer so it doesnt cover content. --- samples/ControlCatalog/MainView.xaml | 3 +- samples/ControlCatalog/MainWindow.xaml | 5 +++ src/Avalonia.Controls/Chrome/TitleBar.cs | 38 +++++++++++++------ .../Primitives/ChromeOverlayLayer.cs | 21 ++++++++++ .../Primitives/VisualLayerManager.cs | 12 ++++++ src/Avalonia.Themes.Fluent/TitleBar.xaml | 2 +- src/Avalonia.Themes.Fluent/Window.xaml | 4 +- 7 files changed, 68 insertions(+), 17 deletions(-) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index ca210300ee..d5794ce243 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,8 +1,7 @@ diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 121878423a..8bd1a274c0 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -60,6 +60,11 @@ + + + diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs index b044ffc59c..f48ca4e4e8 100644 --- a/src/Avalonia.Controls/Chrome/TitleBar.cs +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -14,28 +14,32 @@ namespace Avalonia.Controls.Chrome private CompositeDisposable? _disposables; private readonly Window? _hostWindow; private CaptionButtons? _captionButtons; + private Panel _underlay; - public TitleBar(Window hostWindow) + public TitleBar(Window hostWindow) : this() { _hostWindow = hostWindow; } public TitleBar() { - + _underlay = new Panel + { + IsHitTestVisible = false, + [~Panel.BackgroundProperty] = this[~BackgroundProperty], + VerticalAlignment = Layout.VerticalAlignment.Top + }; } public void Attach() { - if (_disposables == null) + if (_disposables == null && _hostWindow != null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - layer?.Children.Add(this); + overlay?.Children.Add(this); - if (_hostWindow != null) - { - _disposables = new CompositeDisposable + _disposables = new CompositeDisposable { _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) .Subscribe(x => UpdateSize()), @@ -56,11 +60,15 @@ namespace Avalonia.Controls.Chrome }) }; - _captionButtons?.Attach(_hostWindow); - } + _captionButtons?.Attach(_hostWindow); + + var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); + + underlay?.Children.Add(_underlay); UpdateSize(); } + } private void UpdateSize() @@ -76,6 +84,7 @@ namespace Avalonia.Controls.Chrome if (_hostWindow.WindowState != WindowState.FullScreen) { Height = _hostWindow.WindowDecorationMargins.Top; + _underlay.Height = Height; if (_captionButtons != null) { @@ -89,9 +98,14 @@ namespace Avalonia.Controls.Chrome { if (_disposables != null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + if (_hostWindow != null) + { + var overlay = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + overlay?.Children.Remove(this); - layer?.Children.Remove(this); + var underlay = ChromeUnderlayLayer.GetUnderlayLayer(_hostWindow); + underlay?.Children.Remove(_underlay); + } _disposables.Dispose(); _disposables = null; diff --git a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs index ba0fdfd535..2313222bd3 100644 --- a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs @@ -6,6 +6,27 @@ using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { + public class ChromeUnderlayLayer : Panel, ICustomSimpleHitTest + { + public static ChromeUnderlayLayer? GetUnderlayLayer(IVisual visual) + { + foreach (var v in visual.GetVisualAncestors()) + if (v is VisualLayerManager vlm) + if (vlm.OverlayLayer != null) + return vlm.ChromeUnderlayLayer; + + if (visual is TopLevel tl) + { + var layers = tl.GetVisualDescendants().OfType().FirstOrDefault(); + return layers?.ChromeUnderlayLayer; + } + + return null; + } + + public bool HitTest(Point point) => Children.HitTestCustom(point); + } + public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest { public static ChromeOverlayLayer? GetOverlayLayer(IVisual visual) diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index 3084d7fa72..0213c53c57 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -8,6 +8,7 @@ namespace Avalonia.Controls.Primitives private const int AdornerZIndex = int.MaxValue - 100; private const int ChromeZIndex = int.MaxValue - 99; private const int OverlayZIndex = int.MaxValue - 98; + private const int UnderlayZIndex = int.MinValue; private ILogicalRoot _logicalRoot; private readonly List _layers = new List(); @@ -26,6 +27,17 @@ namespace Avalonia.Controls.Primitives } } + public ChromeUnderlayLayer ChromeUnderlayLayer + { + get + { + var rv = FindLayer(); + if (rv == null) + AddLayer(rv = new ChromeUnderlayLayer(), UnderlayZIndex); + return rv; + } + } + public ChromeOverlayLayer ChromeOverlayLayer { get diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 45798d3fa1..72998583b8 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -14,7 +14,7 @@ - + diff --git a/src/Avalonia.Themes.Fluent/Window.xaml b/src/Avalonia.Themes.Fluent/Window.xaml index aee15347eb..086b05bb01 100644 --- a/src/Avalonia.Themes.Fluent/Window.xaml +++ b/src/Avalonia.Themes.Fluent/Window.xaml @@ -1,11 +1,11 @@