diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs index 556c759825..618c3c4fb2 100644 --- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs +++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs @@ -12,18 +12,11 @@ namespace Avalonia.Controls.Chrome private CompositeDisposable _disposables; private Window _hostWindow; - public CaptionButtons(Window hostWindow) - { - _hostWindow = hostWindow; - } - - public void Attach() + public void Attach(Window hostWindow) { if (_disposables == null) { - var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); - - layer.Children.Add(this); + _hostWindow = hostWindow; _disposables = new CompositeDisposable { @@ -33,7 +26,6 @@ namespace Avalonia.Controls.Chrome Height = x.Top; }), - _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) .Subscribe(x => InvalidateSize()), diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs new file mode 100644 index 0000000000..23eefb5d1b --- /dev/null +++ b/src/Avalonia.Controls/Chrome/TitleBar.cs @@ -0,0 +1,99 @@ +using System; +using System.Reactive.Disposables; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Media; + +namespace Avalonia.Controls.Chrome +{ + public class TitleBar : TemplatedControl + { + private CompositeDisposable _disposables; + private Window _hostWindow; + private CaptionButtons _captionButtons; + + public TitleBar(Window hostWindow) + { + _hostWindow = hostWindow; + } + + public TitleBar() + { + + } + + protected override Size MeasureOverride(Size availableSize) + { + return base.MeasureOverride(availableSize); + } + + protected override Size ArrangeOverride(Size finalSize) + { + return base.ArrangeOverride(finalSize); + } + + public void Attach() + { + if (_disposables == null) + { + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + + layer.Children.Add(this); + + _disposables = new CompositeDisposable + { + _hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) + .Subscribe(x => + { + Height = x.Top; + }), + + _hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) + .Subscribe(x => InvalidateSize()), + + _hostWindow.GetObservable(Window.OffScreenMarginProperty) + .Subscribe(x => InvalidateSize()), + + _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); + }) + }; + } + } + + void InvalidateSize() + { + Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); + Height = _hostWindow.WindowDecorationMargins.Top; + } + + public void Detach() + { + if (_disposables != null) + { + var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); + + layer.Children.Remove(this); + + _disposables.Dispose(); + _disposables = null; + + _captionButtons?.Detach(); + } + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + _captionButtons = e.NameScope.Find("PART_CaptionButtons"); + + _captionButtons.Attach(_hostWindow); + } + } +} diff --git a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs index 5deb9ac408..df47d4a349 100644 --- a/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs @@ -4,7 +4,7 @@ using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives { - public class ChromeOverlayLayer : Canvas, ICustomSimpleHitTest + public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest { public Size AvailableSize { get; private set; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 8d66e03f98..3bbe0ce4e1 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -71,7 +71,7 @@ namespace Avalonia.Controls public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot { private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>(); - private CaptionButtons _managedCaptions; + private TitleBar _managedTitleBar; private bool _isExtendedIntoWindowDecorations; @@ -911,18 +911,18 @@ namespace Avalonia.Controls { if(hints.HasFlag(ExtendClientAreaChromeHints.ManagedChromeButtons)) { - if(_managedCaptions == null) + if(_managedTitleBar == null) { - _managedCaptions = new CaptionButtons(this); + _managedTitleBar = new TitleBar(this); } - _managedCaptions.Attach(); + _managedTitleBar.Attach(); } else { - if(_managedCaptions != null) + if(_managedTitleBar != null) { - _managedCaptions.Detach(); + _managedTitleBar.Detach(); } } } diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/CaptionButtons.xaml index 8ee8a3b0dd..8d6d6fb6fc 100644 --- a/src/Avalonia.Themes.Default/CaptionButtons.xaml +++ b/src/Avalonia.Themes.Default/CaptionButtons.xaml @@ -11,9 +11,6 @@ - @@ -27,13 +24,13 @@ - + - + @@ -42,13 +39,13 @@ - + - + diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/TitleBar.xaml new file mode 100644 index 0000000000..856b90857c --- /dev/null +++ b/src/Avalonia.Themes.Default/TitleBar.xaml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml new file mode 100644 index 0000000000..20efcafcfd --- /dev/null +++ b/src/Avalonia.Themes.Fluent/CaptionButtons.xaml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Styles> diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml index 49b2d9561b..a1f8d97c97 100644 --- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml +++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml @@ -7,7 +7,8 @@ - + + @@ -36,6 +37,7 @@ + diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml new file mode 100644 index 0000000000..6512ee342c --- /dev/null +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index fee6bb90bf..d4d7528ef4 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -90,6 +90,10 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCHITTEST: if (lRet == IntPtr.Zero) { + if(WindowState == WindowState.FullScreen) + { + return (IntPtr)HitTestValues.HTCLIENT; + } var hittestResult = HitTestNCA(hWnd, wParam, lParam); lRet = (IntPtr)hittestResult; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9139a8ccbd..bed6922076 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -181,6 +181,11 @@ namespace Avalonia.Win32 { get { + if(_isFullScreenActive) + { + return WindowState.FullScreen; + } + var placement = default(WINDOWPLACEMENT); GetWindowPlacement(_hwnd, ref placement);