diff --git a/samples/DockMvvmSample/ViewModels/DockFactory.cs b/samples/DockMvvmSample/ViewModels/DockFactory.cs index 9098cce70..b04e16bfb 100644 --- a/samples/DockMvvmSample/ViewModels/DockFactory.cs +++ b/samples/DockMvvmSample/ViewModels/DockFactory.cs @@ -137,6 +137,17 @@ public override IRootDock CreateLayout() return rootDock; } + public override IDockWindow? CreateWindowFrom(IDockable dockable) + { + var window = base.CreateWindowFrom(dockable); + + if (window != null) + { + window.Title = "Dock Avalonia Demo"; + } + return window; + } + public override void InitLayout(IDockable layout) { ContextLocator = new Dictionary> diff --git a/src/Dock.Avalonia/Controls/HostWindow.axaml b/src/Dock.Avalonia/Controls/HostWindow.axaml index d64af0d17..cab9c7213 100644 --- a/src/Dock.Avalonia/Controls/HostWindow.axaml +++ b/src/Dock.Avalonia/Controls/HostWindow.axaml @@ -6,6 +6,8 @@ + + @@ -17,7 +19,8 @@ - + + @@ -56,10 +59,13 @@ + diff --git a/src/Dock.Avalonia/Controls/HostWindow.axaml.cs b/src/Dock.Avalonia/Controls/HostWindow.axaml.cs index a1ebff1df..f929318f7 100644 --- a/src/Dock.Avalonia/Controls/HostWindow.axaml.cs +++ b/src/Dock.Avalonia/Controls/HostWindow.axaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using Avalonia; @@ -6,10 +7,12 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Styling; using Avalonia.VisualTree; using Dock.Avalonia.Internal; using Dock.Model; +using Dock.Model.Controls; using Dock.Model.Core; namespace Dock.Avalonia.Controls; @@ -22,7 +25,7 @@ public class HostWindow : Window, IHostWindow { private readonly DockManager _dockManager; private readonly HostWindowState _hostWindowState; - private Control? _chromeGrip; + private List _chromeGrips = new(); private HostWindowTitleBar? _hostWindowTitleBar; private bool _mouseDown, _draggingWindow; @@ -32,6 +35,12 @@ public class HostWindow : Window, IHostWindow public static readonly StyledProperty IsToolWindowProperty = AvaloniaProperty.Register(nameof(IsToolWindow)); + /// + /// Define property. + /// + public static readonly StyledProperty ToolChromeControlsWholeWindowProperty = + AvaloniaProperty.Register(nameof(ToolChromeControlsWholeWindow)); + /// protected override Type StyleKeyOverride => typeof(HostWindow); @@ -44,6 +53,15 @@ public bool IsToolWindow set => SetValue(IsToolWindowProperty, value); } + /// + /// Gets or sets if the tool chrome controls the whole window. + /// + public bool ToolChromeControlsWholeWindow + { + get => GetValue(ToolChromeControlsWholeWindowProperty); + set => SetValue(ToolChromeControlsWholeWindowProperty, value); + } + /// public IDockManager DockManager => _dockManager; @@ -66,7 +84,7 @@ public HostWindow() _dockManager = new DockManager(); _hostWindowState = new HostWindowState(_dockManager, this); - UpdatePseudoClasses(IsToolWindow); + UpdatePseudoClasses(IsToolWindow, ToolChromeControlsWholeWindow); } /// @@ -99,6 +117,9 @@ private PixelPoint ClientPointToScreenRelativeToWindow(Point clientPoint) private void MoveDrag(PointerPressedEventArgs e) { + if (!ToolChromeControlsWholeWindow) + return; + if (Window?.Factory?.OnWindowMoveDragBegin(Window) != true) { return; @@ -127,7 +148,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) { base.OnPointerPressed(e); - if (_chromeGrip is { } && _chromeGrip.IsPointerOver) + if (_chromeGrips.Any(grip => grip.IsPointerOver)) { if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { @@ -177,14 +198,35 @@ public void AttachGrip(ToolChromeControl chromeControl) { if (chromeControl.CloseButton is not null) { - chromeControl.CloseButton.Click += (_, _) => Exit(); + chromeControl.CloseButton.Click += ChromeCloseClick; + } + + if (chromeControl.Grip is { } grip) + { + _chromeGrips.Add(grip); } - _chromeGrip = chromeControl.Grip; ((IPseudoClasses)chromeControl.Classes).Add(":floating"); IsToolWindow = true; } + /// + /// Detaches grip to chrome. + /// + /// The chrome control. + public void DetachGrip(ToolChromeControl chromeControl) + { + if (chromeControl.Grip is { } grip) + { + _chromeGrips.Remove(grip); + } + + if (chromeControl.CloseButton is not null) + { + chromeControl.CloseButton.Click -= ChromeCloseClick; + } + } + /// protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { @@ -192,13 +234,36 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang if (change.Property == IsToolWindowProperty) { - UpdatePseudoClasses(change.GetNewValue()); + UpdatePseudoClasses(change.GetNewValue(), ToolChromeControlsWholeWindow); + } + else if (change.Property == ToolChromeControlsWholeWindowProperty) + { + UpdatePseudoClasses(IsToolWindow, change.GetNewValue()); } } - private void UpdatePseudoClasses(bool isToolWindow) + private void UpdatePseudoClasses(bool isToolWindow, bool toolChromeControlsWholeWindow) { PseudoClasses.Set(":toolwindow", isToolWindow); + PseudoClasses.Set(":toolchromecontrolswindow", toolChromeControlsWholeWindow); + } + + private int CountVisibleToolsAndDocuments(IDockable? dockable) + { + switch (dockable) + { + case ITool: return 1; + case IDocument: return 1; + case IDock dock: + return dock.VisibleDockables?.Sum(CountVisibleToolsAndDocuments) ?? 0; + default: return 0; + } + } + + private void ChromeCloseClick(object? sender, RoutedEventArgs e) + { + if (CountVisibleToolsAndDocuments(DataContext as IRootDock) <= 1) + Exit(); } /// @@ -282,6 +347,8 @@ public void Present(bool isDialog) var ownerDockControl = Window?.Layout?.Factory?.DockControls.FirstOrDefault(); if (ownerDockControl is Control control && control.GetVisualRoot() is Window parentWindow) { + Title = parentWindow.Title; + Icon = parentWindow.Icon; Show(parentWindow); } else diff --git a/src/Dock.Avalonia/Controls/ToolChromeControl.axaml b/src/Dock.Avalonia/Controls/ToolChromeControl.axaml index f871bceb5..b4a8a9a35 100644 --- a/src/Dock.Avalonia/Controls/ToolChromeControl.axaml +++ b/src/Dock.Avalonia/Controls/ToolChromeControl.axaml @@ -178,7 +178,7 @@