diff --git a/Directory.Build.props b/Directory.Build.props index 54c37d7a0..bd8adf25f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@  - 11.3.12 - preview.1 + 12.0.0 + Wiesław Šoltés Wiesław Šoltés A docking layout system. diff --git a/Directory.Packages.props b/Directory.Packages.props index 5d0613977..9f272a54a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,7 @@ true - 11.3.12 + 12.0.0 @@ -12,12 +12,12 @@ - - - + + + - + @@ -25,13 +25,7 @@ - - - - - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/build/Avalonia.ReactiveUI.props b/build/Avalonia.ReactiveUI.props index e1419432c..a3e8d07f5 100644 --- a/build/Avalonia.ReactiveUI.props +++ b/build/Avalonia.ReactiveUI.props @@ -1,6 +1,6 @@  - + diff --git a/build/XUnit.props b/build/XUnit.props index 9e751bbcb..f85857559 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -1,13 +1,10 @@  + + Exe + - - - - - - - + diff --git a/docfx/articles/dock-styling.md b/docfx/articles/dock-styling.md index b7f2682da..1e19e2853 100644 --- a/docfx/articles/dock-styling.md +++ b/docfx/articles/dock-styling.md @@ -109,8 +109,9 @@ Example overriding the modified indicator: Dock controls mark important elements in their templates with `PART_` names. When copying these templates keep the parts intact so features such as window dragging continue to work. For example `ToolChromeControl` defines `PART_Grip`, -`PART_CloseButton` and `PART_MaximizeRestoreButton`, while `HostWindow` exposes -`PART_TitleBar`. +`PART_CloseButton` and `PART_MaximizeRestoreButton`. `HostWindow` now relies on +Avalonia `WindowDrawnDecorations` for standard caption chrome rather than a Dock +title-bar template part. Controls also toggle pseudo classes to reflect their current state. These can be targeted in selectors to customize the appearance: diff --git a/docfx/articles/dock-window-creation-overrides.md b/docfx/articles/dock-window-creation-overrides.md index 1e63c46dd..38444bbf8 100644 --- a/docfx/articles/dock-window-creation-overrides.md +++ b/docfx/articles/dock-window-creation-overrides.md @@ -189,7 +189,7 @@ Managed windows should look and feel like real windows. The goal is to reuse exi - Avoid duplicating theme XAML by referencing shared resources in `Dock.Avalonia.Themes.*` (Fluent/Simple). ### Theme resource locations (current) -- `DockFluentTheme.axaml` includes window-related templates from `src/Dock.Avalonia.Themes.Fluent/Controls/*.axaml` (for example `HostWindow.axaml`, `HostWindowTitleBar.axaml`, `DragPreviewWindow.axaml`, `PinnedDockWindow.axaml`, `DockAdornerWindow.axaml`, `MdiDocumentWindow.axaml`, `ManagedWindowLayer.axaml`, `WindowChromeResources.axaml`). +- `DockFluentTheme.axaml` includes window-related templates from `src/Dock.Avalonia.Themes.Fluent/Controls/*.axaml` (for example `HostWindow.axaml`, `WindowDrawnDecorations.axaml`, `HostWindowTitleBar.axaml`, `DragPreviewWindow.axaml`, `PinnedDockWindow.axaml`, `DockAdornerWindow.axaml`, `MdiDocumentWindow.axaml`, `ManagedWindowLayer.axaml`, `WindowChromeResources.axaml`). - `DockSimpleTheme.axaml` includes the same `/Controls/*.axaml` resources; the Simple theme links Fluent control resources via `Dock.Avalonia.Themes.Simple.csproj` (see `AvaloniaResource` link to `Dock.Avalonia.Themes.Fluent/Controls`). - New managed-window templates/resources should be added to `src/Dock.Avalonia.Themes.Fluent/Controls/` and referenced in both `DockFluentTheme.axaml` and `DockSimpleTheme.axaml`. diff --git a/samples/BrowserTabTheme/App.axaml b/samples/BrowserTabTheme/App.axaml index 5a939823c..a72d327fe 100644 --- a/samples/BrowserTabTheme/App.axaml +++ b/samples/BrowserTabTheme/App.axaml @@ -1,6 +1,7 @@ @@ -45,7 +46,7 @@ - diff --git a/samples/DockReactiveUICanonicalSample/App.axaml.cs b/samples/DockReactiveUICanonicalSample/App.axaml.cs index b0e05990e..dfaddb39d 100644 --- a/samples/DockReactiveUICanonicalSample/App.axaml.cs +++ b/samples/DockReactiveUICanonicalSample/App.axaml.cs @@ -50,7 +50,7 @@ private void RegisterDockableTemplate() return null; } - if (existing is Avalonia.ReactiveUI.ViewModelViewHost existingHost) + if (existing is ReactiveUI.Avalonia.ViewModelViewHost existingHost) { existingHost.ViewLocator = viewLocator; if (!ReferenceEquals(existingHost.ViewModel, item)) @@ -60,7 +60,7 @@ private void RegisterDockableTemplate() return existingHost; } - return new Avalonia.ReactiveUI.ViewModelViewHost + return new ReactiveUI.Avalonia.ViewModelViewHost { ViewLocator = viewLocator, ViewModel = item @@ -132,8 +132,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/DockReactiveUICanonicalSample/DockReactiveUICanonicalSample.csproj b/samples/DockReactiveUICanonicalSample/DockReactiveUICanonicalSample.csproj index 80cb7aa00..094180178 100644 --- a/samples/DockReactiveUICanonicalSample/DockReactiveUICanonicalSample.csproj +++ b/samples/DockReactiveUICanonicalSample/DockReactiveUICanonicalSample.csproj @@ -15,7 +15,6 @@ - diff --git a/samples/DockReactiveUICanonicalSample/Program.cs b/samples/DockReactiveUICanonicalSample/Program.cs index dfa576971..49330ad7f 100644 --- a/samples/DockReactiveUICanonicalSample/Program.cs +++ b/samples/DockReactiveUICanonicalSample/Program.cs @@ -1,6 +1,6 @@ using System; using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUICanonicalSample; diff --git a/samples/DockReactiveUICanonicalSample/Views/Documents/ProjectFileDocumentView.axaml b/samples/DockReactiveUICanonicalSample/Views/Documents/ProjectFileDocumentView.axaml index 405c9bb64..131f329d6 100644 --- a/samples/DockReactiveUICanonicalSample/Views/Documents/ProjectFileDocumentView.axaml +++ b/samples/DockReactiveUICanonicalSample/Views/Documents/ProjectFileDocumentView.axaml @@ -2,7 +2,7 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DockReactiveUICanonicalSample" - xmlns:rxui="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI" + xmlns:rxui="clr-namespace:ReactiveUI.Avalonia;assembly=ReactiveUI.Avalonia" x:CompileBindings="True" x:DataType="ProjectFileDocumentViewModel"> - diff --git a/samples/DockReactiveUIDiSample/Program.cs b/samples/DockReactiveUIDiSample/Program.cs index e7aa72584..90244bc6b 100644 --- a/samples/DockReactiveUIDiSample/Program.cs +++ b/samples/DockReactiveUIDiSample/Program.cs @@ -1,6 +1,6 @@ using System; using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using Dock.Serializer; using DockReactiveUIDiSample.Models; using DockReactiveUIDiSample.ViewModels; diff --git a/samples/DockReactiveUIDiSample/Views/Documents/DocumentView.axaml.cs b/samples/DockReactiveUIDiSample/Views/Documents/DocumentView.axaml.cs index 85eaa62f8..5c48560de 100644 --- a/samples/DockReactiveUIDiSample/Views/Documents/DocumentView.axaml.cs +++ b/samples/DockReactiveUIDiSample/Views/Documents/DocumentView.axaml.cs @@ -1,6 +1,6 @@ using Avalonia.Markup.Xaml; using DockReactiveUIDiSample.ViewModels.Documents; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIDiSample.Views.Documents; diff --git a/samples/DockReactiveUIDiSample/Views/MainWindow.axaml.cs b/samples/DockReactiveUIDiSample/Views/MainWindow.axaml.cs index 076e5d128..bd535061c 100644 --- a/samples/DockReactiveUIDiSample/Views/MainWindow.axaml.cs +++ b/samples/DockReactiveUIDiSample/Views/MainWindow.axaml.cs @@ -1,7 +1,7 @@ using Avalonia; using Avalonia.Markup.Xaml; using DockReactiveUIDiSample.ViewModels; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIDiSample.Views; diff --git a/samples/DockReactiveUIDiSample/Views/Tools/ToolView.axaml.cs b/samples/DockReactiveUIDiSample/Views/Tools/ToolView.axaml.cs index 2ba57f96c..5440046a0 100644 --- a/samples/DockReactiveUIDiSample/Views/Tools/ToolView.axaml.cs +++ b/samples/DockReactiveUIDiSample/Views/Tools/ToolView.axaml.cs @@ -1,6 +1,6 @@ using Avalonia.Markup.Xaml; using DockReactiveUIDiSample.ViewModels.Tools; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIDiSample.Views.Tools; diff --git a/samples/DockReactiveUIManagedSample/App.axaml.cs b/samples/DockReactiveUIManagedSample/App.axaml.cs index 06929e5f2..a16a7fc58 100644 --- a/samples/DockReactiveUIManagedSample/App.axaml.cs +++ b/samples/DockReactiveUIManagedSample/App.axaml.cs @@ -75,8 +75,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj b/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj index 1dc097293..72e40b48d 100644 --- a/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj +++ b/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj @@ -20,7 +20,6 @@ - diff --git a/samples/DockReactiveUIManagedSample/Program.cs b/samples/DockReactiveUIManagedSample/Program.cs index 122fdd981..2bf34a21c 100644 --- a/samples/DockReactiveUIManagedSample/Program.cs +++ b/samples/DockReactiveUIManagedSample/Program.cs @@ -1,7 +1,7 @@ // Copyright (c) Wiesław Šoltés. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using System; using System.Diagnostics.CodeAnalysis; using Dock.Settings; diff --git a/samples/DockReactiveUIManagedSample/Views/MainWindow.axaml b/samples/DockReactiveUIManagedSample/Views/MainWindow.axaml index 3ec05ae96..28cbd98a7 100644 --- a/samples/DockReactiveUIManagedSample/Views/MainWindow.axaml +++ b/samples/DockReactiveUIManagedSample/Views/MainWindow.axaml @@ -18,7 +18,7 @@ FontFamily="Segoe UI, SF Pro Display, Noto Sans, Cantarel" Title="Dock Avalonia Demo" Height="680" Width="1200" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="PreferSystemChrome"> + > - diff --git a/samples/DockReactiveUIRiderSample/Program.cs b/samples/DockReactiveUIRiderSample/Program.cs index aae99c057..66222508f 100644 --- a/samples/DockReactiveUIRiderSample/Program.cs +++ b/samples/DockReactiveUIRiderSample/Program.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for details. using Avalonia; using Dock.Settings; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using System; using System.Diagnostics.CodeAnalysis; diff --git a/samples/DockReactiveUIRiderSample/Views/MainView.axaml.cs b/samples/DockReactiveUIRiderSample/Views/MainView.axaml.cs index d0f6b2ee9..5640c921a 100644 --- a/samples/DockReactiveUIRiderSample/Views/MainView.axaml.cs +++ b/samples/DockReactiveUIRiderSample/Views/MainView.axaml.cs @@ -56,7 +56,7 @@ private void ApplyPlatformInsets() private async void OnOpenSolutionClicked(object? sender, RoutedEventArgs e) { - var storageProvider = (this.GetVisualRoot() as TopLevel)?.StorageProvider; + var storageProvider = TopLevel.GetTopLevel(this)?.StorageProvider; if (storageProvider is null) { return; diff --git a/samples/DockReactiveUIRiderSample/Views/MainWindow.axaml b/samples/DockReactiveUIRiderSample/Views/MainWindow.axaml index 0e3969f6c..6befc2707 100644 --- a/samples/DockReactiveUIRiderSample/Views/MainWindow.axaml +++ b/samples/DockReactiveUIRiderSample/Views/MainWindow.axaml @@ -21,7 +21,7 @@ Height="780" Width="1280" ExtendClientAreaTitleBarHeightHint="32" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="Default, PreferSystemChrome, OSXThickTitleBar"> + > diff --git a/samples/DockReactiveUIRoutingSample/App.axaml.cs b/samples/DockReactiveUIRoutingSample/App.axaml.cs index a46c4b020..b31ac13f8 100644 --- a/samples/DockReactiveUIRoutingSample/App.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/App.axaml.cs @@ -52,8 +52,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/DockReactiveUIRoutingSample/DockReactiveUIRoutingSample.csproj b/samples/DockReactiveUIRoutingSample/DockReactiveUIRoutingSample.csproj index 872672396..0cb158f1d 100644 --- a/samples/DockReactiveUIRoutingSample/DockReactiveUIRoutingSample.csproj +++ b/samples/DockReactiveUIRoutingSample/DockReactiveUIRoutingSample.csproj @@ -15,7 +15,6 @@ - diff --git a/samples/DockReactiveUIRoutingSample/Program.cs b/samples/DockReactiveUIRoutingSample/Program.cs index d54ba76e7..1973199ef 100644 --- a/samples/DockReactiveUIRoutingSample/Program.cs +++ b/samples/DockReactiveUIRoutingSample/Program.cs @@ -1,6 +1,6 @@ using System; using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIRoutingSample; diff --git a/samples/DockReactiveUIRoutingSample/Views/DockView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/DockView.axaml.cs index d4567beae..6f7da02c3 100644 --- a/samples/DockReactiveUIRoutingSample/Views/DockView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/DockView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels; namespace DockReactiveUIRoutingSample.Views; diff --git a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentDetailView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentDetailView.axaml.cs index f9c2aa76e..5b11caba0 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentDetailView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentDetailView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Documents; namespace DockReactiveUIRoutingSample.Views.Documents; diff --git a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentEditorView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentEditorView.axaml.cs index 33b1d2173..00fbfc7af 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentEditorView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentEditorView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Documents; namespace DockReactiveUIRoutingSample.Views.Documents; diff --git a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentHomeView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentHomeView.axaml.cs index 7f4c30d51..78094c860 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentHomeView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentHomeView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Documents; namespace DockReactiveUIRoutingSample.Views.Documents; diff --git a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml index c342250a7..bff66eb67 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml +++ b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml @@ -1,7 +1,7 @@ diff --git a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml.cs index 3ca445555..470580556 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Documents/DocumentView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Documents; namespace DockReactiveUIRoutingSample.Views.Documents; diff --git a/samples/DockReactiveUIRoutingSample/Views/Inner/InnerView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Inner/InnerView.axaml.cs index 51f148746..eb10c1a08 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Inner/InnerView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Inner/InnerView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Inner; namespace DockReactiveUIRoutingSample.Views.Inner; diff --git a/samples/DockReactiveUIRoutingSample/Views/MainWindow.axaml b/samples/DockReactiveUIRoutingSample/Views/MainWindow.axaml index fe2b033fb..fce5faa1e 100644 --- a/samples/DockReactiveUIRoutingSample/Views/MainWindow.axaml +++ b/samples/DockReactiveUIRoutingSample/Views/MainWindow.axaml @@ -1,6 +1,6 @@ diff --git a/samples/DockReactiveUIRoutingSample/Views/Tools/ToolView.axaml.cs b/samples/DockReactiveUIRoutingSample/Views/Tools/ToolView.axaml.cs index dd00463da..a0c6775a0 100644 --- a/samples/DockReactiveUIRoutingSample/Views/Tools/ToolView.axaml.cs +++ b/samples/DockReactiveUIRoutingSample/Views/Tools/ToolView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using DockReactiveUIRoutingSample.ViewModels.Tools; namespace DockReactiveUIRoutingSample.Views.Tools; diff --git a/samples/DockReactiveUISample/App.axaml.cs b/samples/DockReactiveUISample/App.axaml.cs index 058019dd7..8374357e0 100644 --- a/samples/DockReactiveUISample/App.axaml.cs +++ b/samples/DockReactiveUISample/App.axaml.cs @@ -76,8 +76,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/DockReactiveUISample/DockReactiveUISample.csproj b/samples/DockReactiveUISample/DockReactiveUISample.csproj index 1dc097293..72e40b48d 100644 --- a/samples/DockReactiveUISample/DockReactiveUISample.csproj +++ b/samples/DockReactiveUISample/DockReactiveUISample.csproj @@ -20,7 +20,6 @@ - diff --git a/samples/DockReactiveUISample/Program.cs b/samples/DockReactiveUISample/Program.cs index 3e8e8d048..243319db7 100644 --- a/samples/DockReactiveUISample/Program.cs +++ b/samples/DockReactiveUISample/Program.cs @@ -1,7 +1,7 @@ // Copyright (c) Wiesław Šoltés. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using System; using System.Diagnostics.CodeAnalysis; using Dock.Settings; diff --git a/samples/DockReactiveUISample/Views/MainWindow.axaml b/samples/DockReactiveUISample/Views/MainWindow.axaml index 388e971ac..7089541a1 100644 --- a/samples/DockReactiveUISample/Views/MainWindow.axaml +++ b/samples/DockReactiveUISample/Views/MainWindow.axaml @@ -18,7 +18,7 @@ FontFamily="Segoe UI, SF Pro Display, Noto Sans, Cantarel" Title="Dock Avalonia Demo" Height="680" Width="1200" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="PreferSystemChrome"> + > - diff --git a/samples/DockReactiveUIWindowRelationsSample/Program.cs b/samples/DockReactiveUIWindowRelationsSample/Program.cs index a12fd8ff5..ba727e7e3 100644 --- a/samples/DockReactiveUIWindowRelationsSample/Program.cs +++ b/samples/DockReactiveUIWindowRelationsSample/Program.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using Avalonia; using Dock.Settings; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIWindowRelationsSample; diff --git a/samples/DockReactiveUIWorkspaceSample/Program.cs b/samples/DockReactiveUIWorkspaceSample/Program.cs index 0666b73b4..ace50c1a6 100644 --- a/samples/DockReactiveUIWorkspaceSample/Program.cs +++ b/samples/DockReactiveUIWorkspaceSample/Program.cs @@ -3,7 +3,7 @@ using System; using System.Diagnostics.CodeAnalysis; using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockReactiveUIWorkspaceSample; diff --git a/samples/DockReactiveUIWorkspaceSample/Views/DocumentView.axaml b/samples/DockReactiveUIWorkspaceSample/Views/DocumentView.axaml index 0685f7389..8375f4f73 100644 --- a/samples/DockReactiveUIWorkspaceSample/Views/DocumentView.axaml +++ b/samples/DockReactiveUIWorkspaceSample/Views/DocumentView.axaml @@ -1,6 +1,8 @@ + xmlns:vm="using:DockReactiveUIWorkspaceSample.ViewModels" + x:Class="DockReactiveUIWorkspaceSample.Views.DocumentView" + x:DataType="vm:DocumentViewModel"> diff --git a/samples/DockReactiveUIWorkspaceSample/Views/MainWindow.axaml b/samples/DockReactiveUIWorkspaceSample/Views/MainWindow.axaml index 7d9355e87..adce75840 100644 --- a/samples/DockReactiveUIWorkspaceSample/Views/MainWindow.axaml +++ b/samples/DockReactiveUIWorkspaceSample/Views/MainWindow.axaml @@ -1,7 +1,9 @@ diff --git a/samples/DockReactiveUIWorkspaceSample/Views/ToolView.axaml b/samples/DockReactiveUIWorkspaceSample/Views/ToolView.axaml index 2f79ad2a6..073f3cd97 100644 --- a/samples/DockReactiveUIWorkspaceSample/Views/ToolView.axaml +++ b/samples/DockReactiveUIWorkspaceSample/Views/ToolView.axaml @@ -1,6 +1,8 @@ + xmlns:vm="using:DockReactiveUIWorkspaceSample.ViewModels" + x:Class="DockReactiveUIWorkspaceSample.Views.ToolView" + x:DataType="vm:ToolViewModel"> diff --git a/samples/DockSimplifiedFluentSample/DockSimplifiedFluentSample.csproj b/samples/DockSimplifiedFluentSample/DockSimplifiedFluentSample.csproj index 01498e74e..344b0f5e2 100644 --- a/samples/DockSimplifiedFluentSample/DockSimplifiedFluentSample.csproj +++ b/samples/DockSimplifiedFluentSample/DockSimplifiedFluentSample.csproj @@ -16,7 +16,6 @@ - diff --git a/samples/DockSimplifiedSample/DockSimplifiedSample.csproj b/samples/DockSimplifiedSample/DockSimplifiedSample.csproj index 03add6793..1caca7023 100644 --- a/samples/DockSimplifiedSample/DockSimplifiedSample.csproj +++ b/samples/DockSimplifiedSample/DockSimplifiedSample.csproj @@ -20,7 +20,6 @@ - diff --git a/samples/DockSplitViewSample/DockSplitViewSample.csproj b/samples/DockSplitViewSample/DockSplitViewSample.csproj index a5ce66648..e61386ba2 100644 --- a/samples/DockSplitViewSample/DockSplitViewSample.csproj +++ b/samples/DockSplitViewSample/DockSplitViewSample.csproj @@ -16,7 +16,6 @@ - diff --git a/samples/DockXamlReactiveUISample/Program.cs b/samples/DockXamlReactiveUISample/Program.cs index b9afe3778..4ee574152 100644 --- a/samples/DockXamlReactiveUISample/Program.cs +++ b/samples/DockXamlReactiveUISample/Program.cs @@ -3,7 +3,7 @@ using System; using System.Diagnostics.CodeAnalysis; using Avalonia; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; namespace DockXamlReactiveUISample; diff --git a/samples/DockXamlReactiveUISample/Views/MainWindow.axaml b/samples/DockXamlReactiveUISample/Views/MainWindow.axaml index d9713a769..ef3f4713d 100644 --- a/samples/DockXamlReactiveUISample/Views/MainWindow.axaml +++ b/samples/DockXamlReactiveUISample/Views/MainWindow.axaml @@ -135,14 +135,15 @@ - + Factory="{Binding Factory}"> @@ -153,11 +154,11 @@ Title="Tools" Alignment="Left" Proportion="0.3" - DockCapabilityPolicy="{Binding DataContext.ToolDockCapabilityPolicy, RelativeSource={RelativeSource AncestorType=Window}}" + DockCapabilityPolicy="{Binding ToolDockCapabilityPolicy}" ToolItemContainerTheme="SampleGeneratedToolContainerTheme" ToolItemTemplateSelector="{StaticResource SampleToolItemTemplateSelector}" - CanUpdateItemsSourceOnUnregister="{Binding DataContext.ToolCanUpdateItemsSourceOnUnregister, RelativeSource={RelativeSource AncestorType=Window}}" - ItemsSource="{Binding DataContext.Tools, RelativeSource={RelativeSource AncestorType=Window}}"> + CanUpdateItemsSourceOnUnregister="{Binding ToolCanUpdateItemsSourceOnUnregister}" + ItemsSource="{Binding Tools}"> @@ -183,11 +184,11 @@ Title="Documents" Proportion="0.7" CanCreateDocument="False" - DockCapabilityPolicy="{Binding DataContext.DocumentDockCapabilityPolicy, RelativeSource={RelativeSource AncestorType=Window}}" + DockCapabilityPolicy="{Binding DocumentDockCapabilityPolicy}" DocumentItemContainerTheme="SampleGeneratedDocumentContainerTheme" DocumentItemTemplateSelector="{StaticResource SampleDocumentItemTemplateSelector}" - CanUpdateItemsSourceOnUnregister="{Binding DataContext.DocumentCanUpdateItemsSourceOnUnregister, RelativeSource={RelativeSource AncestorType=Window}}" - ItemsSource="{Binding DataContext.Documents, RelativeSource={RelativeSource AncestorType=Window}}"> + CanUpdateItemsSourceOnUnregister="{Binding DocumentCanUpdateItemsSourceOnUnregister}" + ItemsSource="{Binding Documents}"> diff --git a/samples/DockXamlSample/App.axaml.cs b/samples/DockXamlSample/App.axaml.cs index 886df4397..d0619cdd2 100644 --- a/samples/DockXamlSample/App.axaml.cs +++ b/samples/DockXamlSample/App.axaml.cs @@ -28,8 +28,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/DockXamlSample/DockXamlSample.csproj b/samples/DockXamlSample/DockXamlSample.csproj index f3e01c5ab..0e6626548 100644 --- a/samples/DockXamlSample/DockXamlSample.csproj +++ b/samples/DockXamlSample/DockXamlSample.csproj @@ -14,7 +14,6 @@ - diff --git a/samples/DockXamlSample/ItemsSourceExample.axaml b/samples/DockXamlSample/ItemsSourceExample.axaml index 77364c3e5..ce846e448 100644 --- a/samples/DockXamlSample/ItemsSourceExample.axaml +++ b/samples/DockXamlSample/ItemsSourceExample.axaml @@ -2,7 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:dock="using:Dock.Model.Avalonia.Controls" xmlns:local="using:DockXamlSample" - x:Class="DockXamlSample.ItemsSourceExample"> + x:Class="DockXamlSample.ItemsSourceExample" + x:DataType="local:ItemsSourceExampleViewModel" + x:CompileBindings="True"> @@ -31,7 +33,7 @@ + ItemsSource="{Binding Documents}"> diff --git a/samples/DockXamlSample/MainView.axaml.cs b/samples/DockXamlSample/MainView.axaml.cs index 80f42bf7a..944833d92 100644 --- a/samples/DockXamlSample/MainView.axaml.cs +++ b/samples/DockXamlSample/MainView.axaml.cs @@ -64,7 +64,7 @@ private async Task OpenLayout() return; } - var storageProvider = (this.GetVisualRoot() as TopLevel)?.StorageProvider; + var storageProvider = TopLevel.GetTopLevel(this)?.StorageProvider; if (storageProvider is null) { return; @@ -114,7 +114,7 @@ private async Task SaveLayout() return; } - var storageProvider = (this.GetVisualRoot() as TopLevel)?.StorageProvider; + var storageProvider = TopLevel.GetTopLevel(this)?.StorageProvider; if (storageProvider is null) { return; @@ -212,4 +212,3 @@ private void UpdateViewsMenu() } } } - diff --git a/samples/DockXamlSample/MainWindow.axaml b/samples/DockXamlSample/MainWindow.axaml index bde3bf049..eb52d7505 100644 --- a/samples/DockXamlSample/MainWindow.axaml +++ b/samples/DockXamlSample/MainWindow.axaml @@ -16,7 +16,7 @@ BorderThickness="1" BorderBrush="{DynamicResource DockThemeBorderLowBrush}" Title="Dock Avalonia Demo" Width="800" Height="600" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="PreferSystemChrome"> + > - diff --git a/samples/Notepad/App.axaml.cs b/samples/Notepad/App.axaml.cs index 700832498..98ff880c6 100644 --- a/samples/Notepad/App.axaml.cs +++ b/samples/Notepad/App.axaml.cs @@ -69,8 +69,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/Notepad/Notepad.csproj b/samples/Notepad/Notepad.csproj index da7929f00..da2ce1fd8 100644 --- a/samples/Notepad/Notepad.csproj +++ b/samples/Notepad/Notepad.csproj @@ -20,7 +20,6 @@ - diff --git a/samples/Notepad/Views/MainWindow.axaml b/samples/Notepad/Views/MainWindow.axaml index 4b6a152e6..ac7d25f44 100644 --- a/samples/Notepad/Views/MainWindow.axaml +++ b/samples/Notepad/Views/MainWindow.axaml @@ -16,7 +16,7 @@ FontFamily="Segoe UI, SF Pro Display, Noto Sans, Cantarel" Title="Notepad" Height="600" Width="900" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="PreferSystemChrome"> + > diff --git a/samples/WebViewSample/App.axaml.cs b/samples/WebViewSample/App.axaml.cs index cc20f8626..c6947991a 100644 --- a/samples/WebViewSample/App.axaml.cs +++ b/samples/WebViewSample/App.axaml.cs @@ -28,8 +28,5 @@ public override void OnFrameworkInitializationCompleted() } base.OnFrameworkInitializationCompleted(); -#if DEBUG - this.AttachDevTools(); -#endif } } diff --git a/samples/WebViewSample/MainWindow.axaml b/samples/WebViewSample/MainWindow.axaml index 5552e3d28..6328f31c5 100644 --- a/samples/WebViewSample/MainWindow.axaml +++ b/samples/WebViewSample/MainWindow.axaml @@ -16,7 +16,7 @@ BorderThickness="1" BorderBrush="{DynamicResource DockThemeBorderLowBrush}" Title="Dock WebView Demo" Width="800" Height="600" ExtendClientAreaToDecorationsHint="True" - ExtendClientAreaChromeHints="PreferSystemChrome"> + > - diff --git a/src/Dock.Avalonia.Diagnostics/Dock.Avalonia.Diagnostics.csproj b/src/Dock.Avalonia.Diagnostics/Dock.Avalonia.Diagnostics.csproj index 0f8d0bdbb..ddf23e8eb 100644 --- a/src/Dock.Avalonia.Diagnostics/Dock.Avalonia.Diagnostics.csproj +++ b/src/Dock.Avalonia.Diagnostics/Dock.Avalonia.Diagnostics.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Avalonia.Themes.Browser/Dock.Avalonia.Themes.Browser.csproj b/src/Dock.Avalonia.Themes.Browser/Dock.Avalonia.Themes.Browser.csproj index a70321d35..50fa5d069 100644 --- a/src/Dock.Avalonia.Themes.Browser/Dock.Avalonia.Themes.Browser.csproj +++ b/src/Dock.Avalonia.Themes.Browser/Dock.Avalonia.Themes.Browser.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Avalonia.Themes.Browser/Styles/BrowserTabAccents.axaml b/src/Dock.Avalonia.Themes.Browser/Styles/BrowserTabAccents.axaml index 3f6477af2..4c0b15f7e 100644 --- a/src/Dock.Avalonia.Themes.Browser/Styles/BrowserTabAccents.axaml +++ b/src/Dock.Avalonia.Themes.Browser/Styles/BrowserTabAccents.axaml @@ -121,11 +121,6 @@ 0.55 0 28 - - + - @@ -38,10 +37,7 @@ - - - - + - + @@ -92,10 +87,7 @@ - - - - + - - diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/DockAdornerWindow.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/DockAdornerWindow.axaml index ca58910f2..426782dfc 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/DockAdornerWindow.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/DockAdornerWindow.axaml @@ -3,7 +3,7 @@ x:CompileBindings="True"> - + diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/DragPreviewWindow.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/DragPreviewWindow.axaml index 38a89eeb6..d94690f80 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/DragPreviewWindow.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/DragPreviewWindow.axaml @@ -3,7 +3,7 @@ x:CompileBindings="True"> - + diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindow.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindow.axaml index 832e3b06c..7700036a5 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindow.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindow.axaml @@ -25,10 +25,9 @@ - + - @@ -36,10 +35,7 @@ - - - - + - + @@ -90,10 +85,7 @@ - - - - + - - diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindowTitleBar.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindowTitleBar.axaml index 1dd38e562..db144773d 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindowTitleBar.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/HostWindowTitleBar.axaml @@ -20,7 +20,6 @@ - diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/OverlayLayerDefaults.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/OverlayLayerDefaults.axaml index b1447cdd4..98faf41bf 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/OverlayLayerDefaults.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/OverlayLayerDefaults.axaml @@ -1,6 +1,7 @@ + xmlns:overlays="using:Dock.Avalonia.Controls.Overlays" + x:CompileBindings="False"> diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/PinnedDockWindow.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/PinnedDockWindow.axaml index 68a873265..928f1cf76 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/PinnedDockWindow.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/PinnedDockWindow.axaml @@ -3,7 +3,7 @@ x:CompileBindings="True"> - + diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.axaml new file mode 100644 index 000000000..d1d49c70e --- /dev/null +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.axaml @@ -0,0 +1,204 @@ + + + 45 + 30 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Dock.Avalonia.Themes.Fluent/Dock.Avalonia.Themes.Fluent.csproj b/src/Dock.Avalonia.Themes.Fluent/Dock.Avalonia.Themes.Fluent.csproj index 246d20344..837637611 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Dock.Avalonia.Themes.Fluent.csproj +++ b/src/Dock.Avalonia.Themes.Fluent/Dock.Avalonia.Themes.Fluent.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Avalonia.Themes.Fluent/DockFluentTheme.axaml b/src/Dock.Avalonia.Themes.Fluent/DockFluentTheme.axaml index 0f6ea2b22..7f737b71e 100644 --- a/src/Dock.Avalonia.Themes.Fluent/DockFluentTheme.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/DockFluentTheme.axaml @@ -9,6 +9,7 @@ + diff --git a/src/Dock.Avalonia.Themes.Simple/Dock.Avalonia.Themes.Simple.csproj b/src/Dock.Avalonia.Themes.Simple/Dock.Avalonia.Themes.Simple.csproj index ec9cfd5ac..a7ec81ce3 100644 --- a/src/Dock.Avalonia.Themes.Simple/Dock.Avalonia.Themes.Simple.csproj +++ b/src/Dock.Avalonia.Themes.Simple/Dock.Avalonia.Themes.Simple.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Avalonia.Themes.Simple/DockSimpleTheme.axaml b/src/Dock.Avalonia.Themes.Simple/DockSimpleTheme.axaml index 5dd63190d..6ecec382a 100644 --- a/src/Dock.Avalonia.Themes.Simple/DockSimpleTheme.axaml +++ b/src/Dock.Avalonia.Themes.Simple/DockSimpleTheme.axaml @@ -9,6 +9,7 @@ + diff --git a/src/Dock.Avalonia/Automation/Peers/HostWindowTitleBarAutomationPeer.cs b/src/Dock.Avalonia/Automation/Peers/HostWindowTitleBarAutomationPeer.cs index 10bffe59d..303df8734 100644 --- a/src/Dock.Avalonia/Automation/Peers/HostWindowTitleBarAutomationPeer.cs +++ b/src/Dock.Avalonia/Automation/Peers/HostWindowTitleBarAutomationPeer.cs @@ -1,5 +1,6 @@ // Copyright (c) Wiesław Šoltés. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. +using Avalonia; using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Automation.Provider; diff --git a/src/Dock.Avalonia/Controls/DockControl.axaml.cs b/src/Dock.Avalonia/Controls/DockControl.axaml.cs index 09a36f68e..65efea3af 100644 --- a/src/Dock.Avalonia/Controls/DockControl.axaml.cs +++ b/src/Dock.Avalonia/Controls/DockControl.axaml.cs @@ -1283,13 +1283,18 @@ private static DragAction ToDragAction(PointerEventArgs e) return DragAction.Move; } - private bool ShouldIgnorePressedForWindowDrag(PointerPressedEventArgs e) + private static bool ShouldIgnorePressedForWindowDrag(Control? source) { - if (e.Source is not Control source) + if (source is null) { return false; } + if (ShouldIgnorePressedForFloatingToolWindowDrag(source)) + { + return true; + } + var tabItem = source.FindAncestorOfType(); if (tabItem is null) { @@ -1306,9 +1311,15 @@ private bool ShouldIgnorePressedForWindowDrag(PointerPressedEventArgs e) && tabStrip.DataContext is Dock.Model.Core.IDock { CanCloseLastDockable: false }; } - private static bool ShouldIgnorePressedForItemDrag(PointerPressedEventArgs e) + private static bool ShouldIgnorePressedForFloatingToolWindowDrag(Control source) { - if (e.Source is not Control source) + var toolChrome = source as ToolChromeControl ?? source.FindAncestorOfType(); + return TopLevel.GetTopLevel(toolChrome) is HostWindow { IsToolWindow: true, ToolChromeControlsWholeWindow: true }; + } + + private static bool ShouldIgnorePressedForItemDrag(Control? source) + { + if (source is null) { return false; } @@ -1349,7 +1360,8 @@ private void PressedHandler(object? sender, PointerPressedEventArgs e) return; } - if (ShouldIgnorePressedForWindowDrag(e) || ShouldIgnorePressedForItemDrag(e)) + var source = e.Source as Control; + if (ShouldIgnorePressedForWindowDrag(source) || ShouldIgnorePressedForItemDrag(source)) { return; } diff --git a/src/Dock.Avalonia/Controls/DockTargetBase.cs b/src/Dock.Avalonia/Controls/DockTargetBase.cs index da4b8f30b..3cb9d2116 100644 --- a/src/Dock.Avalonia/Controls/DockTargetBase.cs +++ b/src/Dock.Avalonia/Controls/DockTargetBase.cs @@ -7,7 +7,7 @@ using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; -using Avalonia.Input; +using Avalonia.VisualTree; using Dock.Avalonia.Automation.Peers; using Dock.Avalonia.Contract; using Dock.Model.Core; @@ -346,6 +346,22 @@ protected bool IsDockTargetSelector(Control selector) return false; } + // Avalonia 12 changed subtree hit testing in CompositionTarget/VisualExtensions. + // Use GetVisualsAt for selector containment instead of InputHitTest, then keep + // a local-bounds fallback for floating adorner timing/readback edge cases. + private static bool IsSelectorHit(Control selector, Point selectorPoint) + { + foreach (var visual in selector.GetVisualsAt(selectorPoint)) + { + if (ReferenceEquals(visual, selector) || selector.IsVisualAncestorOf(visual)) + { + return true; + } + } + + return new Rect(selector.Bounds.Size).Contains(selectorPoint); + } + /// /// Invalidates the indicator based on the provided parameters. /// @@ -402,16 +418,12 @@ private bool InvalidateIndicator( if (selectorPoint is not null) { - // Check if the input element is the selector itself. - if (selector.InputHitTest(selectorPoint.Value) is { } inputElement) + if (IsSelectorHit(selector, selectorPoint.Value)) { - if (Equals(inputElement, selector)) + if (validate(point, operation, dragAction, relativeTo)) { - if (validate(point, operation, dragAction, relativeTo)) - { - indicator.Opacity = 0.5; - return true; - } + indicator.Opacity = 0.5; + return true; } } } diff --git a/src/Dock.Avalonia/Controls/DocumentTabStrip.axaml.cs b/src/Dock.Avalonia/Controls/DocumentTabStrip.axaml.cs index 64325c5e9..8a26da866 100644 --- a/src/Dock.Avalonia/Controls/DocumentTabStrip.axaml.cs +++ b/src/Dock.Avalonia/Controls/DocumentTabStrip.axaml.cs @@ -585,7 +585,7 @@ private void AttachDoubleTapped() return; } - _doubleTappedSubscription = this.AddDisposableHandler(Gestures.DoubleTappedEvent, OnDoubleTapped); + _doubleTappedSubscription = this.AddDisposableHandler(InputElement.DoubleTappedEvent, OnDoubleTapped); } private void DetachDoubleTapped() diff --git a/src/Dock.Avalonia/Controls/HostWindow.axaml.cs b/src/Dock.Avalonia/Controls/HostWindow.axaml.cs index 9a27ae51b..6e245166b 100644 --- a/src/Dock.Avalonia/Controls/HostWindow.axaml.cs +++ b/src/Dock.Avalonia/Controls/HostWindow.axaml.cs @@ -7,10 +7,8 @@ using Avalonia.Automation.Peers; using Avalonia.Controls; using Avalonia.Controls.Metadata; -using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.VisualTree; using Dock.Avalonia.Automation.Peers; using Dock.Avalonia.Internal; using Dock.Model; @@ -24,12 +22,10 @@ namespace Dock.Avalonia.Controls; /// Interaction logic for xaml. /// [PseudoClasses(":toolwindow", ":dragging", ":toolchromecontrolswindow", ":documentchromecontrolswindow")] -[TemplatePart("PART_TitleBar", typeof(HostWindowTitleBar))] public class HostWindow : Window, IHostWindow { private readonly HostWindowState _hostWindowState; private List _chromeGrips = new(); - private HostWindowTitleBar? _hostWindowTitleBar; private bool _mouseDown, _draggingWindow; private double _normalX = double.NaN; private double _normalY = double.NaN; @@ -128,26 +124,6 @@ protected override AutomationPeer OnCreateAutomationPeer() return new HostWindowAutomationPeer(this); } - /// - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - - _hostWindowTitleBar = e.NameScope.Find("PART_TitleBar"); - if (_hostWindowTitleBar is { }) - { - _hostWindowTitleBar.ApplyTemplate(); - - if (_hostWindowTitleBar.BackgroundControl is { }) - { - _hostWindowTitleBar.BackgroundControl.PointerPressed += (_, args) => - { - MoveDrag(args); - }; - } - } - } - private PixelPoint ClientPointToScreenRelativeToWindow(Point clientPoint) { var absScreenPoint = this.PointToScreen(clientPoint); @@ -156,14 +132,11 @@ private PixelPoint ClientPointToScreenRelativeToWindow(Point clientPoint) return relativeScreenDiff; } - private void MoveDrag(PointerPressedEventArgs e) + private bool TryBeginWindowDrag(PointerPressedEventArgs e, WindowDragDockScope dockScope, bool ownsPointerRelease) { - if (!ToolChromeControlsWholeWindow) - return; - if (Window?.Factory?.OnWindowMoveDragBegin(Window) != true) { - return; + return false; } if (DockSettings.BringWindowsToFrontOnDrag && Window?.Factory is { } factory) @@ -172,14 +145,15 @@ private void MoveDrag(PointerPressedEventArgs e) } _mouseDown = true; + _draggingWindow = ownsPointerRelease; + WindowDragDockScope = dockScope; _hostWindowState.Process(ClientPointToScreenRelativeToWindow(e.GetPosition(this)), EventType.Pressed); PseudoClasses.Set(":dragging", true); - _draggingWindow = true; - BeginMoveDrag(e); + return true; } - private void EndDrag(PointerEventArgs e) + private void EndWindowDrag(PointerEventArgs e) { PseudoClasses.Set(":dragging", false); @@ -187,6 +161,43 @@ private void EndDrag(PointerEventArgs e) _hostWindowState.Process(ClientPointToScreenRelativeToWindow(e.GetPosition(this)), EventType.Released); _mouseDown = false; _draggingWindow = false; + WindowDragDockScope = WindowDragDockScope.FullWindow; + } + + internal bool TryBeginExternalWindowDrag(PointerPressedEventArgs e, WindowDragDockScope dockScope) + { + return TryBeginWindowDrag(e, dockScope, ownsPointerRelease: false); + } + + internal void EndExternalWindowDrag(PointerEventArgs e) + { + EndWindowDrag(e); + } + + internal void CancelExternalWindowDrag() + { + PseudoClasses.Set(":dragging", false); + Window?.Factory?.OnWindowMoveDragEnd(Window); + _mouseDown = false; + _draggingWindow = false; + WindowDragDockScope = WindowDragDockScope.FullWindow; + } + + private void MoveDrag(PointerPressedEventArgs e) + { + if (!ToolChromeControlsWholeWindow) + return; + + if (!TryBeginWindowDrag(e, WindowDragDockScope.FullWindow, ownsPointerRelease: true)) + { + return; + } + BeginMoveDrag(e); + } + + private void EndDrag(PointerEventArgs e) + { + EndWindowDrag(e); } /// @@ -326,11 +337,6 @@ public void AttachGrip(ToolChromeControl chromeControl) chromeControl.CloseButton.Click += ChromeCloseClick; } - if (chromeControl.Grip is { } grip) - { - _chromeGrips.Add(grip); - } - ((IPseudoClasses)chromeControl.Classes).Add(":floating"); IsToolWindow = true; } @@ -352,11 +358,6 @@ public void AttachGrip(Control grip, string pseudoClass) /// 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; @@ -772,9 +773,22 @@ public void SetTitle(string? title) /// public void SetLayout(IDock layout) { + SetCurrentValue(IsToolWindowProperty, ResolveHostedDock(layout) is IToolDock); DataContext = layout; } + private static IDock? ResolveHostedDock(IDock layout) + { + if (layout is IRootDock root) + { + return root.ActiveDockable as IDock + ?? root.DefaultDockable as IDock + ?? root.VisibleDockables?.OfType().FirstOrDefault(); + } + + return layout; + } + private void CaptureNormalBounds() { if (WindowState != WindowState.Normal) diff --git a/src/Dock.Avalonia/Controls/HostWindowTitleBar.axaml.cs b/src/Dock.Avalonia/Controls/HostWindowTitleBar.axaml.cs index 3bbb03103..bb1147325 100644 --- a/src/Dock.Avalonia/Controls/HostWindowTitleBar.axaml.cs +++ b/src/Dock.Avalonia/Controls/HostWindowTitleBar.axaml.cs @@ -5,7 +5,6 @@ using Avalonia.Automation.Peers; using Avalonia.Controls; using Avalonia.Controls.Metadata; -using Avalonia.Controls.Chrome; using Avalonia.Controls.Primitives; using Avalonia.Styling; using Dock.Avalonia.Automation.Peers; @@ -16,7 +15,7 @@ namespace Dock.Avalonia.Controls; /// Interaction logic for xaml. /// [TemplatePart("PART_Background", typeof(Control))] -public class HostWindowTitleBar : TitleBar +public class HostWindowTitleBar : TemplatedControl { internal Control? BackgroundControl { get; private set; } diff --git a/src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs b/src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs index d09cc58d8..0b04e833b 100644 --- a/src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs +++ b/src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs @@ -1,6 +1,6 @@ // Copyright (c) Wiesław Šoltés. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. -using System.Runtime.InteropServices; +using System; using Avalonia; using Avalonia.Automation.Peers; using Avalonia.Controls; @@ -272,11 +272,15 @@ private static bool IsFocusableChild(Control owner, Control source) return false; } - private WindowDragHelper CreateDragHelper(Control owner, bool ignoreFocusable = false, bool handlePointerPressed = true) + private WindowDragHelper CreateDragHelper( + Control owner, + bool ignoreFocusable = false, + bool handlePointerPressed = true, + Func? isEnabled = null) { return new WindowDragHelper( owner, - () => true, + isEnabled ?? (() => true), source => { if (source is null) @@ -300,24 +304,19 @@ private void AttachToWindow() return; } - // On linux we use WindowDragHelper because of inconsistent drag behaviour with BeginMoveDrag. - if (VisualRoot is Window window) + if (TopLevel.GetTopLevel(this) is Window window) { if (window is HostWindow hostWindow) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - hostWindow.AttachGrip(this); - _attachedWindow = hostWindow; - - SetCurrentValue(IsFloatingProperty, true); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - _windowDragHelper = CreateDragHelper(hostWindow, ignoreFocusable: true, handlePointerPressed: false); - _windowDragHelper.Attach(); - } + hostWindow.AttachGrip(this); + _attachedWindow = hostWindow; + SetCurrentValue(IsFloatingProperty, true); + + _windowDragHelper = CreateDragHelper( + Grip, + ignoreFocusable: true, + isEnabled: () => hostWindow.ToolChromeControlsWholeWindow); + _windowDragHelper.Attach(); } #if false else @@ -346,7 +345,7 @@ private void DetachFromWindow() private void OnMaximizeRestoreButtonClicked(object? sender, RoutedEventArgs e) { - if (VisualRoot is HostWindow window) + if (TopLevel.GetTopLevel(this) is HostWindow window) { if (window.WindowState == WindowState.Maximized) window.WindowState = WindowState.Normal; diff --git a/src/Dock.Avalonia/Dock.Avalonia.csproj b/src/Dock.Avalonia/Dock.Avalonia.csproj index 18a933a5a..2083c5ae9 100644 --- a/src/Dock.Avalonia/Dock.Avalonia.csproj +++ b/src/Dock.Avalonia/Dock.Avalonia.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Avalonia/Internal/AdornerHelper.cs b/src/Dock.Avalonia/Internal/AdornerHelper.cs index 529d0ce0a..6c24fb567 100644 --- a/src/Dock.Avalonia/Internal/AdornerHelper.cs +++ b/src/Dock.Avalonia/Internal/AdornerHelper.cs @@ -68,7 +68,7 @@ private void AddFloatingAdorner(Visual visual, bool indicatorsOnly, bool horizon } } - if (visual.GetVisualRoot() is not Window root) + if (TopLevel.GetTopLevel(visual) is not Window root) { return; } @@ -243,7 +243,7 @@ private void RemoveManagedAdorner() private static Rect ManagedBoundsFromScreen(ManagedWindowLayer layer, PixelPoint screenPoint, Size size) { - if (layer.GetVisualRoot() is not TopLevel topLevel) + if (TopLevel.GetTopLevel(layer) is not TopLevel topLevel) { return new Rect(0, 0, size.Width, size.Height); } diff --git a/src/Dock.Avalonia/Internal/DockHelpers.cs b/src/Dock.Avalonia/Internal/DockHelpers.cs index e44456239..171f1d8c7 100644 --- a/src/Dock.Avalonia/Internal/DockHelpers.cs +++ b/src/Dock.Avalonia/Internal/DockHelpers.cs @@ -66,8 +66,10 @@ public static bool IsManagedWindowHostingEnabled(IDockable? dockable) public static Point GetScreenPoint(Visual visual, Point point) { - // var scaling = (visual.GetVisualRoot() as TopLevel)?.RenderScaling ?? 1.0; - var scaling = (visual.GetVisualRoot() as TopLevel)?.Screens?.ScreenFromVisual(visual)?.Scaling ?? 1.0; + var topLevel = TopLevel.GetTopLevel(visual); + var scaling = topLevel?.Screens?.ScreenFromVisual(visual)?.Scaling + ?? topLevel?.RenderScaling + ?? 1.0; var screenPoint = visual.PointToScreen(point).ToPoint(scaling); return screenPoint; } @@ -353,7 +355,7 @@ public static IEnumerable GetZOrderedDockControls(IList() - .Select(dock => dock.GetVisualRoot() as Window) + .Select(dock => TopLevel.GetTopLevel(dock) as Window) .OfType() .Distinct() .ToArray(); @@ -362,7 +364,7 @@ public static IEnumerable GetZOrderedDockControls(IList() - .Select(dock => (dock, windowOrder: IndexOf(windows, dock.GetVisualRoot() as Window), managedOrder: GetManagedWindowZOrder(dock))) + .Select(dock => (dock, windowOrder: IndexOf(windows, TopLevel.GetTopLevel(dock) as Window), managedOrder: GetManagedWindowZOrder(dock))) .OrderByDescending(x => x.windowOrder) .ThenByDescending(x => x.managedOrder) .Select(pair => pair.dock); diff --git a/src/Dock.Avalonia/Internal/VisualRootCompatExtensions.cs b/src/Dock.Avalonia/Internal/VisualRootCompatExtensions.cs new file mode 100644 index 000000000..f3a4f415e --- /dev/null +++ b/src/Dock.Avalonia/Internal/VisualRootCompatExtensions.cs @@ -0,0 +1,13 @@ +// Copyright (c) Wiesław Šoltés. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. +using Avalonia.VisualTree; + +namespace Avalonia; + +internal static class VisualRootCompatExtensions +{ + public static Visual? GetVisualRoot(this Visual? visual) + { + return visual?.GetPresentationSource()?.RootVisual; + } +} diff --git a/src/Dock.Avalonia/Internal/WindowDragHelper.cs b/src/Dock.Avalonia/Internal/WindowDragHelper.cs index 3685d945f..e9f42916a 100644 --- a/src/Dock.Avalonia/Internal/WindowDragHelper.cs +++ b/src/Dock.Avalonia/Internal/WindowDragHelper.cs @@ -81,6 +81,11 @@ public void Detach() _releasedEventDisposable?.Dispose(); _releasedEventDisposable = null; + if (_dragWindow is HostWindow hostWindow) + { + hostWindow.CancelExternalWindowDrag(); + } + if (_dragWindow is not null && _positionChangedHandler is not null) { _dragWindow.PositionChanged -= _positionChangedHandler; @@ -154,16 +159,7 @@ private void OnPointerReleased(object? sender, PointerReleasedEventArgs e) if (_dragWindow is HostWindow hostWindow) { - hostWindow.WindowDragDockScope = WindowDragDockScope.FullWindow; - - if (hostWindow.HostWindowState is HostWindowState state) - { - var point = hostWindow.PointToScreen(e.GetPosition(hostWindow)) - - hostWindow.PointToScreen(new Point(0, 0)); - state.Process(new PixelPoint(point.X, point.Y), EventType.Released); - } - - hostWindow.Window?.Factory?.OnWindowMoveDragEnd(hostWindow.Window); + hostWindow.EndExternalWindowDrag(e); } } @@ -199,7 +195,7 @@ private void OnPointerMoved(object? sender, PointerEventArgs e) return; } - var root = _owner.GetVisualRoot(); + var root = TopLevel.GetTopLevel(_owner); if (root is not HostWindow hostWindow) { @@ -224,41 +220,13 @@ private void OnPointerMoved(object? sender, PointerEventArgs e) _isDragging = true; _pointerPressed = false; - var dockWindow = hostWindow.Window; - if (dockWindow?.Factory?.OnWindowMoveDragBegin(dockWindow) != true) + if (!hostWindow.TryBeginExternalWindowDrag(_lastPointerPressedArgs, _dockScope)) { _isDragging = false; return; } - if (DockSettings.BringWindowsToFrontOnDrag && dockWindow.Factory is { } factory) - { - WindowActivationHelper.ActivateAllWindows(factory, hostWindow); - } - - if (hostWindow.HostWindowState is HostWindowState state) - { - var start = hostWindow.PointToScreen(_lastPointerPressedArgs.GetPosition(hostWindow)) - hostWindow.PointToScreen(new Point(0, 0)); - state.Process(new PixelPoint(start.X, start.Y), EventType.Pressed); - } - _dragWindow = hostWindow; - hostWindow.WindowDragDockScope = _dockScope; - - _positionChangedHandler = (_, _) => - { - if (hostWindow.Window is { } dw) - { - dw.Factory?.OnWindowMoveDrag(dw); - } - - if (hostWindow.HostWindowState is HostWindowState st) - { - st.Process(_dragWindow.Position, EventType.Moved); - } - }; - - hostWindow.PositionChanged += _positionChangedHandler; _releasedEventDisposable?.Dispose(); _releasedEventDisposable = SubscribeToPointerReleased(hostWindow); diff --git a/src/Dock.Controls.DeferredContentControl/DeferredContentControl.cs b/src/Dock.Controls.DeferredContentControl/DeferredContentControl.cs index c06c73ca1..f22aa7e60 100644 --- a/src/Dock.Controls.DeferredContentControl/DeferredContentControl.cs +++ b/src/Dock.Controls.DeferredContentControl/DeferredContentControl.cs @@ -1082,17 +1082,40 @@ private sealed class DeferredRevealTransition : DoubleTransition internal static DeferredContentPresentationTimeline ResolveTimeline(AvaloniaObject target) { - return DeferredContentScheduling.GetTimeline(target) ?? DeferredContentPresentationSettings.DefaultTimeline; + if (DeferredContentScheduling.GetTimeline(target) is { } timeline) + { + return timeline; + } + + if (!target.IsSet(DeferredContentScheduling.TimelineProperty) + && target is StyledElement { TemplatedParent: AvaloniaObject templatedParent }) + { + return ResolveTimeline(templatedParent); + } + + return DeferredContentPresentationSettings.DefaultTimeline; } internal static TimeSpan ResolveDelay(AvaloniaObject target) { + if (!target.IsSet(DeferredContentScheduling.DelayProperty) + && target is StyledElement { TemplatedParent: AvaloniaObject templatedParent }) + { + return ResolveDelay(templatedParent); + } + var delay = DeferredContentScheduling.GetDelay(target); return delay >= TimeSpan.Zero ? delay : TimeSpan.Zero; } internal static int ResolveOrder(AvaloniaObject target) { + if (!target.IsSet(DeferredContentScheduling.OrderProperty) + && target is StyledElement { TemplatedParent: AvaloniaObject templatedParent }) + { + return ResolveOrder(templatedParent); + } + return DeferredContentScheduling.GetOrder(target); } diff --git a/src/Dock.Controls.DeferredContentControl/Dock.Controls.DeferredContentControl.csproj b/src/Dock.Controls.DeferredContentControl/Dock.Controls.DeferredContentControl.csproj index b85136b2b..b57c7a93e 100644 --- a/src/Dock.Controls.DeferredContentControl/Dock.Controls.DeferredContentControl.csproj +++ b/src/Dock.Controls.DeferredContentControl/Dock.Controls.DeferredContentControl.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Controls.ProportionalStackPanel/Dock.Controls.ProportionalStackPanel.csproj b/src/Dock.Controls.ProportionalStackPanel/Dock.Controls.ProportionalStackPanel.csproj index 0fe865101..040fdbc62 100644 --- a/src/Dock.Controls.ProportionalStackPanel/Dock.Controls.ProportionalStackPanel.csproj +++ b/src/Dock.Controls.ProportionalStackPanel/Dock.Controls.ProportionalStackPanel.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Controls.Recycling/Dock.Controls.Recycling.csproj b/src/Dock.Controls.Recycling/Dock.Controls.Recycling.csproj index f3bdaedd4..dcf68cf0e 100644 --- a/src/Dock.Controls.Recycling/Dock.Controls.Recycling.csproj +++ b/src/Dock.Controls.Recycling/Dock.Controls.Recycling.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.MarkupExtension/Dock.MarkupExtension.csproj b/src/Dock.MarkupExtension/Dock.MarkupExtension.csproj index a02d222e2..9de83f574 100644 --- a/src/Dock.MarkupExtension/Dock.MarkupExtension.csproj +++ b/src/Dock.MarkupExtension/Dock.MarkupExtension.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.MarkupExtension/LoadExtension.cs b/src/Dock.MarkupExtension/LoadExtension.cs index 15c2e2f16..b1e9ced88 100644 --- a/src/Dock.MarkupExtension/LoadExtension.cs +++ b/src/Dock.MarkupExtension/LoadExtension.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for details. using System; using Avalonia.Markup.Xaml; +using Avalonia.Metadata; namespace Avalonia.MarkupExtension; diff --git a/src/Dock.MarkupExtension/ReferenceExtension.cs b/src/Dock.MarkupExtension/ReferenceExtension.cs index f611de0a0..7f95c105e 100644 --- a/src/Dock.MarkupExtension/ReferenceExtension.cs +++ b/src/Dock.MarkupExtension/ReferenceExtension.cs @@ -3,6 +3,7 @@ using System; using Avalonia.Controls; using Avalonia.Markup.Xaml; +using Avalonia.Metadata; namespace Avalonia.MarkupExtension; diff --git a/src/Dock.Model.Avalonia/Dock.Model.Avalonia.csproj b/src/Dock.Model.Avalonia/Dock.Model.Avalonia.csproj index 4f54bee12..f4e83e754 100644 --- a/src/Dock.Model.Avalonia/Dock.Model.Avalonia.csproj +++ b/src/Dock.Model.Avalonia/Dock.Model.Avalonia.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Model.ReactiveUI.Services.Avalonia/Controls/DockReactiveUserControl.cs b/src/Dock.Model.ReactiveUI.Services.Avalonia/Controls/DockReactiveUserControl.cs index e11fc9a3c..13f1f1828 100644 --- a/src/Dock.Model.ReactiveUI.Services.Avalonia/Controls/DockReactiveUserControl.cs +++ b/src/Dock.Model.ReactiveUI.Services.Avalonia/Controls/DockReactiveUserControl.cs @@ -3,7 +3,7 @@ using System.Reactive.Linq; using Dock.Model.ReactiveUI.Services.Lifecycle; using ReactiveUI; -using Avalonia.ReactiveUI; +using ReactiveUI.Avalonia; using Splat; namespace Dock.Model.ReactiveUI.Services.Avalonia.Controls; diff --git a/src/Dock.Model.ReactiveUI.Services.Avalonia/Dock.Model.ReactiveUI.Services.Avalonia.csproj b/src/Dock.Model.ReactiveUI.Services.Avalonia/Dock.Model.ReactiveUI.Services.Avalonia.csproj index 98a730419..f966d5ff1 100644 --- a/src/Dock.Model.ReactiveUI.Services.Avalonia/Dock.Model.ReactiveUI.Services.Avalonia.csproj +++ b/src/Dock.Model.ReactiveUI.Services.Avalonia/Dock.Model.ReactiveUI.Services.Avalonia.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs b/src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs index e257d4dbf..1c5a402eb 100644 --- a/src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs +++ b/src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs @@ -94,7 +94,7 @@ public sealed class AvaloniaHostServiceResolver : IHostServiceResolver foreach (var dockControl in factory.DockControls.OfType()) { - if (dockControl.GetVisualRoot() is null || dockControl.Layout is null) + if (dockControl.GetPresentationSource()?.RootVisual is null || dockControl.Layout is null) { continue; } @@ -153,7 +153,7 @@ private static bool TryGetControl( return resolved; } - if (control.GetVisualRoot() is not TopLevel topLevel) + if (control.GetPresentationSource()?.RootVisual is not TopLevel topLevel) { return null; } diff --git a/src/Dock.Settings/Dock.Settings.csproj b/src/Dock.Settings/Dock.Settings.csproj index 906ebf1b1..4f966b770 100644 --- a/src/Dock.Settings/Dock.Settings.csproj +++ b/src/Dock.Settings/Dock.Settings.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net10.0 + net8.0;net10.0 Library bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml enable diff --git a/tests/Dock.Avalonia.HeadlessTests/AdornerHelperIntegrationTests.cs b/tests/Dock.Avalonia.HeadlessTests/AdornerHelperIntegrationTests.cs new file mode 100644 index 000000000..dde37bdc6 --- /dev/null +++ b/tests/Dock.Avalonia.HeadlessTests/AdornerHelperIntegrationTests.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using Avalonia.Controls; +using Avalonia.Headless.XUnit; +using Avalonia.Threading; +using Dock.Avalonia.Controls; +using Dock.Avalonia.Internal; +using Xunit; + +namespace Dock.Avalonia.HeadlessTests; + +public class AdornerHelperIntegrationTests +{ + [AvaloniaFact] + public void Floating_Adorner_Should_Create_Window_For_Shown_DockControl() + { + var hostWindow = new Window + { + Width = 400, + Height = 300 + }; + var dockControl = new DockControl + { + Width = 240, + Height = 180 + }; + var helper = new AdornerHelper(true); + + hostWindow.Content = dockControl; + hostWindow.Show(); + hostWindow.UpdateLayout(); + dockControl.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + try + { + helper.AddAdorner(dockControl, indicatorsOnly: false); + + var windowField = typeof(AdornerHelper).GetField("_window", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.NotNull(windowField); + + var adornerWindow = Assert.IsType(windowField!.GetValue(helper)); + Assert.True(adornerWindow.IsVisible); + Assert.Same(helper.Adorner, adornerWindow.Content); + } + finally + { + helper.RemoveAdorner(dockControl); + hostWindow.Close(); + } + } +} diff --git a/tests/Dock.Avalonia.HeadlessTests/AdornerHelperTests.cs b/tests/Dock.Avalonia.HeadlessTests/AdornerHelperTests.cs index 30dcf4b2c..3bbe4d22e 100644 --- a/tests/Dock.Avalonia.HeadlessTests/AdornerHelperTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/AdornerHelperTests.cs @@ -1,8 +1,15 @@ +using System; +using System.Linq; +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Headless.XUnit; +using Avalonia.Threading; +using Avalonia.VisualTree; using Dock.Avalonia.Controls; using Dock.Avalonia.Internal; +using Dock.Model.Core; +using Dock.Settings; using Xunit; namespace Dock.Avalonia.HeadlessTests; @@ -12,7 +19,7 @@ public class AdornerHelperTests [AvaloniaFact] public void AddRemove_Reuses_Same_Instance() { - var root = new AdornerLayer(); + var root = (AdornerLayer)Activator.CreateInstance(typeof(AdornerLayer), nonPublic: true)!; var control = new Border(); root.Children.Add(control); @@ -26,4 +33,64 @@ public void AddRemove_Reuses_Same_Instance() Assert.Same(first, second); } + + [AvaloniaFact] + public void Floating_Adorner_Center_Selector_Should_Resolve_Fill_Operation() + { + var hostWindow = new Window + { + Width = 400, + Height = 300, + Position = new PixelPoint(100, 100) + }; + var dockSurface = new Border + { + Width = 240, + Height = 180 + }; + var helper = new AdornerHelper(true); + + hostWindow.Content = dockSurface; + hostWindow.Show(); + hostWindow.UpdateLayout(); + dockSurface.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + try + { + helper.AddAdorner(dockSurface, indicatorsOnly: false); + Dispatcher.UIThread.RunJobs(); + + var dockTarget = Assert.IsType(helper.Adorner); + dockTarget.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + var centerSelector = dockTarget + .GetVisualDescendants() + .OfType() + .Single(control => DockProperties.GetIndicatorDockOperation(control) == DockOperation.Fill + && control is Image); + + var centerScreenPoint = centerSelector.PointToScreen(new Point( + centerSelector.Bounds.Width / 2, + centerSelector.Bounds.Height / 2)); + var hostPoint = hostWindow.PointToClient(centerScreenPoint); + var dockSurfaceOrigin = dockSurface.TranslatePoint(new Point(), hostWindow) ?? new Point(); + var dockSurfacePoint = hostPoint - dockSurfaceOrigin; + + var operation = dockTarget.GetDockOperation( + dockSurfacePoint, + new Border(), + dockSurface, + DragAction.Move, + (_, _, _, _) => true); + + Assert.Equal(DockOperation.Fill, operation); + } + finally + { + helper.RemoveAdorner(dockSurface); + hostWindow.Close(); + } + } } diff --git a/tests/Dock.Avalonia.HeadlessTests/DeferredContentControlTests.cs b/tests/Dock.Avalonia.HeadlessTests/DeferredContentControlTests.cs index 30cd3920b..c5c16a26c 100644 --- a/tests/Dock.Avalonia.HeadlessTests/DeferredContentControlTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/DeferredContentControlTests.cs @@ -1203,7 +1203,7 @@ public void DeferredContentPresenter_AutoScheduled_Time_Budget_Materializes_In_I var slots = new[] { new PresenterSlot("First", firstTemplate, order: -5, delay: TimeSpan.Zero), - new PresenterSlot("Second", secondTemplate, order: 10, delay: TimeSpan.FromMilliseconds(150)) + new PresenterSlot("Second", secondTemplate, order: 10, delay: TimeSpan.FromMilliseconds(300)) }; var timeline = new DeferredContentPresentationTimeline { @@ -1267,7 +1267,7 @@ public void DeferredContentPresenter_AutoScheduled_Time_Budget_Materializes_In_I Assert.All(new[] { firstPresenter, secondPresenter }, presenter => Assert.Null(presenter.Child)); - Thread.Sleep(60); + Thread.Sleep(40); Dispatcher.UIThread.RunJobs(); window.UpdateLayout(); @@ -1276,7 +1276,7 @@ public void DeferredContentPresenter_AutoScheduled_Time_Budget_Materializes_In_I Assert.NotNull(firstPresenter.Child); Assert.Null(secondPresenter.Child); - Thread.Sleep(180); + Thread.Sleep(320); Dispatcher.UIThread.RunJobs(); window.UpdateLayout(); diff --git a/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs b/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs index d3528405f..5ad7fc0b0 100644 --- a/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/HostWindowThemeChangeTests.cs @@ -1,10 +1,18 @@ using System; +using System.Linq; +using System.Reflection; using Avalonia; +using Avalonia.Collections; +using Avalonia.Controls; using Avalonia.Headless.XUnit; using Avalonia.Styling; +using Avalonia.Themes.Fluent; using Avalonia.Threading; +using Avalonia.VisualTree; using Dock.Avalonia.Controls; +using Dock.Avalonia.Themes.Fluent; using Dock.Model.Avalonia; +using Dock.Model.Avalonia.Controls; using Dock.Model.Controls; using Dock.Model.Core; using Xunit; @@ -59,4 +67,114 @@ public void HostWindow_ThemeChange_DoesNotDuplicate_DockControls() app.RequestedThemeVariant = originalVariant; } } + + [AvaloniaFact] + public void DockControl_Should_Ignore_Floating_Tool_Chrome_WindowDrag_Press() + { + var app = Application.Current ?? throw new InvalidOperationException("Application is not initialized."); + var method = typeof(DockControl).GetMethod("ShouldIgnorePressedForWindowDrag", BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(method); + + var previousStyles = app.Styles.ToList(); + app.Styles.Clear(); + app.Styles.Add(new FluentTheme()); + app.Styles.Add(new DockFluentTheme()); + + var tool = new Tool { Title = "Tool1" }; + var toolDock = new ToolDock + { + VisibleDockables = new AvaloniaList { tool }, + ActiveDockable = tool, + OpenedDockablesCount = 1 + }; + var layout = new RootDock + { + VisibleDockables = new AvaloniaList { toolDock }, + ActiveDockable = toolDock, + DefaultDockable = toolDock, + OpenedDockablesCount = 1 + }; + var hostWindow = new HostWindow(); + + try + { + hostWindow.SetLayout(layout); + hostWindow.Show(); + hostWindow.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + var toolChrome = hostWindow.GetVisualDescendants().OfType().FirstOrDefault(); + Assert.NotNull(toolChrome); + Assert.True(hostWindow.IsToolWindow); + Assert.Same(hostWindow, TopLevel.GetTopLevel(toolChrome)); + + var result = (bool?)method!.Invoke(null, new object?[] { toolChrome! }); + Assert.True(result); + } + finally + { + hostWindow.Close(); + app.Styles.Clear(); + foreach (IStyle style in previousStyles) + { + app.Styles.Add(style); + } + } + } + + [AvaloniaFact] + public void DockControl_Should_Not_Ignore_Floating_Multi_Tab_Tool_Chrome_WindowDrag_Press() + { + var app = Application.Current ?? throw new InvalidOperationException("Application is not initialized."); + var method = typeof(DockControl).GetMethod("ShouldIgnorePressedForWindowDrag", BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(method); + + var previousStyles = app.Styles.ToList(); + app.Styles.Clear(); + app.Styles.Add(new FluentTheme()); + app.Styles.Add(new DockFluentTheme()); + + var firstTool = new Tool { Title = "Tool1" }; + var secondTool = new Tool { Title = "Tool2" }; + var toolDock = new ToolDock + { + VisibleDockables = new AvaloniaList { firstTool, secondTool }, + ActiveDockable = firstTool, + OpenedDockablesCount = 2 + }; + var layout = new RootDock + { + VisibleDockables = new AvaloniaList { toolDock }, + ActiveDockable = toolDock, + DefaultDockable = toolDock, + OpenedDockablesCount = 2 + }; + var hostWindow = new HostWindow(); + + try + { + hostWindow.SetLayout(layout); + hostWindow.Show(); + hostWindow.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + var toolChrome = hostWindow.GetVisualDescendants().OfType().FirstOrDefault(); + Assert.NotNull(toolChrome); + Assert.True(hostWindow.IsToolWindow); + Assert.False(hostWindow.ToolChromeControlsWholeWindow); + Assert.Same(hostWindow, TopLevel.GetTopLevel(toolChrome)); + + var result = (bool?)method!.Invoke(null, new object?[] { toolChrome! }); + Assert.False(result); + } + finally + { + hostWindow.Close(); + app.Styles.Clear(); + foreach (IStyle style in previousStyles) + { + app.Styles.Add(style); + } + } + } } diff --git a/tests/Dock.Avalonia.HeadlessTests/ManagedWindowParityTests.cs b/tests/Dock.Avalonia.HeadlessTests/ManagedWindowParityTests.cs index d88e8d379..6992ecb09 100644 --- a/tests/Dock.Avalonia.HeadlessTests/ManagedWindowParityTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/ManagedWindowParityTests.cs @@ -809,7 +809,7 @@ public void FloatingDockable_Uses_Active_Managed_Layer_For_Pointer() var translated = dockControlB.TranslatePoint(point, layerB); Assert.True(translated.HasValue); - var scaling = (dockControlB.GetVisualRoot() as TopLevel) + var scaling = TopLevel.GetTopLevel(dockControlB) ?.Screens ?.ScreenFromVisual(dockControlB) ?.Scaling ?? 1.0; @@ -914,7 +914,7 @@ public void FloatingDockable_From_ManagedWindow_Adjusts_For_ContentOffset() var translated = innerDockControl!.TranslatePoint(point, layer); Assert.True(translated.HasValue); - var scaling = (innerDockControl.GetVisualRoot() as TopLevel) + var scaling = TopLevel.GetTopLevel(innerDockControl) ?.Screens ?.ScreenFromVisual(innerDockControl) ?.Scaling ?? 1.0; diff --git a/tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs b/tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs index 517bd0069..5f0c57b4d 100644 --- a/tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs @@ -133,7 +133,7 @@ public void HostWindowState_ValidateGlobal_UsesDropContextTarget_WithoutDockCont var targetDock = GlobalDockingService.ResolveGlobalTargetDock(dropControl); Assert.NotNull(targetDock); Assert.Same(targetDocument.Owner?.Owner, targetDock); - Assert.NotNull(dropControl.GetVisualRoot()); + Assert.NotNull(TopLevel.GetTopLevel(dropControl)); Assert.NotNull(root.FocusedDockable); Assert.Same(sourceDocument, root.FocusedDockable); Assert.True(DockInheritanceHelper.GetEffectiveEnableGlobalDocking(targetDock!)); @@ -180,7 +180,7 @@ public void ManagedHostWindowState_ValidateGlobal_UsesDropContextTarget_WithoutD var targetDock = GlobalDockingService.ResolveGlobalTargetDock(dropControl); Assert.NotNull(targetDock); Assert.Same(targetDocument.Owner?.Owner, targetDock); - Assert.NotNull(dropControl.GetVisualRoot()); + Assert.NotNull(TopLevel.GetTopLevel(dropControl)); Assert.NotNull(root.FocusedDockable); Assert.Same(sourceDocument, root.FocusedDockable); Assert.True(DockInheritanceHelper.GetEffectiveEnableGlobalDocking(targetDock!)); diff --git a/tests/Dock.Avalonia.LeakTests/HostWindowDragLeakTests.cs b/tests/Dock.Avalonia.LeakTests/HostWindowDragLeakTests.cs index c1d66cc4e..7b212e441 100644 --- a/tests/Dock.Avalonia.LeakTests/HostWindowDragLeakTests.cs +++ b/tests/Dock.Avalonia.LeakTests/HostWindowDragLeakTests.cs @@ -1,6 +1,6 @@ using System; +using System.Reflection; using Avalonia.Controls; -using Avalonia.Input; using Avalonia.Themes.Fluent; using Dock.Avalonia.Controls; using Dock.Avalonia.Themes.Fluent; @@ -19,7 +19,7 @@ namespace Dock.Avalonia.LeakTests; public class HostWindowDragLeakTests { [ReleaseFact] - public void HostWindow_TitleBarDragBegin_CallsFactory_DoesNotLeak() + public void HostWindow_MoveDragBegin_CallsFactory_DoesNotLeak() { var result = RunInSession(() => { @@ -51,19 +51,9 @@ public void HostWindow_TitleBarDragBegin_CallsFactory_DoesNotLeak() window.UpdateLayout(); DrainDispatcher(); - var titleBar = FindTemplateChild(window, "PART_TitleBar") - ?? FindVisualDescendant(window); - Assert.NotNull(titleBar); - - var background = titleBar is null - ? null - : FindTemplateChild(titleBar, "PART_Background"); - Assert.NotNull(background); - - if (background is not null) - { - RaisePointerPressed(background, MouseButton.Left); - } + var moveDrag = typeof(HostWindow).GetMethod("MoveDrag", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.NotNull(moveDrag); + moveDrag!.Invoke(window, [null]); DrainDispatcher(); window.Window = null; @@ -72,14 +62,12 @@ public void HostWindow_TitleBarDragBegin_CallsFactory_DoesNotLeak() var result = new HostWindowDragLeakResult( new WeakReference(window), - titleBar is null ? null : new WeakReference(titleBar), dockWindow, factory, factory.MoveDragBeginCalled); CleanupWindow(window); window = null; - titleBar = null; return result; }); @@ -88,10 +76,6 @@ public void HostWindow_TitleBarDragBegin_CallsFactory_DoesNotLeak() if (string.Equals(Environment.GetEnvironmentVariable("DOCK_LEAK_STRICT"), "1", StringComparison.Ordinal)) { AssertCollected(result.WindowRef); - if (result.TitleBarRef is not null) - { - AssertCollected(result.TitleBarRef); - } } GC.KeepAlive(result.DockWindowKeepAlive); GC.KeepAlive(result.FactoryKeepAlive); @@ -99,7 +83,6 @@ public void HostWindow_TitleBarDragBegin_CallsFactory_DoesNotLeak() private sealed record HostWindowDragLeakResult( WeakReference WindowRef, - WeakReference? TitleBarRef, DockWindow DockWindowKeepAlive, TestFactory FactoryKeepAlive, bool MoveDragBeginCalled); diff --git a/tests/Dock.Avalonia.LeakTests/LeakTestHelpers.cs b/tests/Dock.Avalonia.LeakTests/LeakTestHelpers.cs index 3d79c2ad9..e70eec596 100644 --- a/tests/Dock.Avalonia.LeakTests/LeakTestHelpers.cs +++ b/tests/Dock.Avalonia.LeakTests/LeakTestHelpers.cs @@ -350,7 +350,6 @@ private static void EnsureControlTheme(Control control) internal static void CleanupWindow(Window window) { - window.FocusManager?.ClearFocus(); window.Content = null; window.DataContext = null; window.Close(); @@ -850,7 +849,6 @@ internal static void ClearInputState(TopLevel? topLevel) { ClearPointerOverPreProcessor(topLevel); ClearTopLevelHandlers(topLevel); - topLevel.ClearValue(TopLevel.PointerOverElementProperty); ClearInputManagerPointerState(topLevel); ClearInputManagerObservers(topLevel); ScrubInputManagerInstance(topLevel); @@ -1049,14 +1047,19 @@ private static void ClearInputManagerPointerState(TopLevel topLevel) return; } + if (topLevel.GetPresentationSource() is not IInputRoot inputRoot) + { + return; + } + var position = new Point(0, 0); - var leaveArgs = CreateRawPointerEventArgs(device, topLevel, RawPointerEventType.LeaveWindow, position); + var leaveArgs = CreateRawPointerEventArgs(device, inputRoot, RawPointerEventType.LeaveWindow, position); if (leaveArgs is not null) { InvokeInputManager(inputManager, leaveArgs); } - var cancelArgs = CreateRawPointerEventArgs(device, topLevel, RawPointerEventType.CancelCapture, position); + var cancelArgs = CreateRawPointerEventArgs(device, inputRoot, RawPointerEventType.CancelCapture, position); if (cancelArgs is not null) { InvokeInputManager(inputManager, cancelArgs); diff --git a/tests/Dock.Avalonia.Themes.UnitTests/Dock.Avalonia.Themes.UnitTests.csproj b/tests/Dock.Avalonia.Themes.UnitTests/Dock.Avalonia.Themes.UnitTests.csproj index 8262459f7..5441d6354 100644 --- a/tests/Dock.Avalonia.Themes.UnitTests/Dock.Avalonia.Themes.UnitTests.csproj +++ b/tests/Dock.Avalonia.Themes.UnitTests/Dock.Avalonia.Themes.UnitTests.csproj @@ -14,9 +14,11 @@ + + diff --git a/tests/Dock.Avalonia.Themes.UnitTests/ThemeManagerTests.cs b/tests/Dock.Avalonia.Themes.UnitTests/ThemeManagerTests.cs index 5fa391700..943c52ac8 100644 --- a/tests/Dock.Avalonia.Themes.UnitTests/ThemeManagerTests.cs +++ b/tests/Dock.Avalonia.Themes.UnitTests/ThemeManagerTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Avalonia; +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Headless.XUnit; using Avalonia.Markup.Xaml.Styling; @@ -11,9 +12,13 @@ using Avalonia.Threading; using Avalonia.VisualTree; using Dock.Avalonia.Controls; +using Dock.Avalonia.Themes.Browser; using Dock.Avalonia.Themes.Fluent; using Dock.Avalonia.Themes.Simple; using Dock.Avalonia.Themes; +using Dock.Model.Avalonia.Controls; +using Dock.Model.Controls; +using Dock.Model.Core; using Xunit; namespace Dock.Avalonia.Themes.UnitTests; @@ -221,6 +226,121 @@ public void Fluent_Manager_Should_Update_DocumentTabStripItem_Styled_Brushes() } } + [AvaloniaFact] + public void Fluent_Theme_Should_Keep_Tool_Host_Windows_Border_Only() + { + Application app = Application.Current ?? throw new InvalidOperationException("Avalonia application is not initialized."); + + using var scope = new AppResourcesAndStylesScope(app); + app.Styles.Add(new FluentTheme()); + app.Styles.Add(new DockFluentTheme()); + + var tool = new Tool { Title = "Tool1" }; + var toolDock = new ToolDock + { + VisibleDockables = new AvaloniaList { tool }, + ActiveDockable = tool, + OpenedDockablesCount = 1 + }; + var layout = new RootDock + { + VisibleDockables = new AvaloniaList { toolDock }, + ActiveDockable = toolDock, + DefaultDockable = toolDock, + OpenedDockablesCount = 1 + }; + + var window = new HostWindow + { + Width = 400, + Height = 300 + }; + + try + { + window.SetLayout(layout); + window.Show(); + window.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + Assert.True(window.IsToolWindow); + Assert.True(window.ToolChromeControlsWholeWindow); + Assert.True(window.ExtendClientAreaToDecorationsHint); + Assert.Equal(WindowDecorations.BorderOnly, window.WindowDecorations); + } + finally + { + window.Close(); + } + } + + [AvaloniaFact] + public void Fluent_Theme_Should_Keep_Multi_Tab_Tool_Host_Windows_Full_Decorations() + { + Application app = Application.Current ?? throw new InvalidOperationException("Avalonia application is not initialized."); + + using var scope = new AppResourcesAndStylesScope(app); + app.Styles.Add(new FluentTheme()); + app.Styles.Add(new DockFluentTheme()); + + var window = new HostWindow + { + Width = 400, + Height = 300 + }; + + try + { + window.SetLayout(CreateToolHostLayout(openedDockablesCount: 2)); + window.Show(); + window.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + Assert.True(window.IsToolWindow); + Assert.False(window.ToolChromeControlsWholeWindow); + Assert.False(window.ExtendClientAreaToDecorationsHint); + Assert.Equal(WindowDecorations.Full, window.WindowDecorations); + } + finally + { + window.Close(); + } + } + + [AvaloniaFact] + public void Browser_Theme_Should_Keep_Multi_Tab_Tool_Host_Windows_Full_Decorations() + { + Application app = Application.Current ?? throw new InvalidOperationException("Avalonia application is not initialized."); + + using var scope = new AppResourcesAndStylesScope(app); + app.Styles.Add(new FluentTheme()); + app.Styles.Add(new DockFluentTheme()); + app.Styles.Add(new BrowserTabTheme()); + + var window = new HostWindow + { + Width = 400, + Height = 300 + }; + + try + { + window.SetLayout(CreateToolHostLayout(openedDockablesCount: 2)); + window.Show(); + window.UpdateLayout(); + Dispatcher.UIThread.RunJobs(); + + Assert.True(window.IsToolWindow); + Assert.False(window.ToolChromeControlsWholeWindow); + Assert.True(window.ExtendClientAreaToDecorationsHint); + Assert.Equal(WindowDecorations.Full, window.WindowDecorations); + } + finally + { + window.Close(); + } + } + [AvaloniaFact] public void Fluent_Manager_Should_Insert_Preset_Into_DockTheme_Resources_By_Default() { @@ -660,6 +780,30 @@ private static Grid GetGripGrid(ToolChromeControl toolChrome) return Assert.IsType(gripGrid); } + private static RootDock CreateToolHostLayout(int openedDockablesCount) + { + var dockables = new AvaloniaList(); + for (var index = 0; index < openedDockablesCount; index++) + { + dockables.Add(new Tool { Title = $"Tool{index + 1}" }); + } + + var toolDock = new ToolDock + { + VisibleDockables = dockables, + ActiveDockable = dockables[0], + OpenedDockablesCount = openedDockablesCount + }; + + return new RootDock + { + VisibleDockables = new AvaloniaList { toolDock }, + ActiveDockable = toolDock, + DefaultDockable = toolDock, + OpenedDockablesCount = openedDockablesCount + }; + } + private static void AssertBrushColor(Control host, string resourceKey, Color expectedColor) { Assert.True(host.TryFindResource(resourceKey, out object? resourceValue), $"Missing resource '{resourceKey}'."); diff --git a/tests/Dock.MarkupExtension.UnitTests/Properties/AssemblyInfo.cs b/tests/Dock.MarkupExtension.UnitTests/Properties/AssemblyInfo.cs index 2c2ae5d59..11c0ceac9 100644 --- a/tests/Dock.MarkupExtension.UnitTests/Properties/AssemblyInfo.cs +++ b/tests/Dock.MarkupExtension.UnitTests/Properties/AssemblyInfo.cs @@ -2,6 +2,3 @@ using Xunit; [assembly: AssemblyTitle("Dock.MarkupExtension.UnitTests")] - -// Don't run tests in parallel. -[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceUITests.cs b/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceUITests.cs index 98ef9c160..faaf994d5 100644 --- a/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceUITests.cs +++ b/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceUITests.cs @@ -8,7 +8,6 @@ using Dock.Model.Avalonia.Controls; using Dock.Model.Core; using Xunit; -using Xunit.Abstractions; namespace Dock.Model.Avalonia.UnitTests.Controls; diff --git a/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceXamlDebugTests.cs b/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceXamlDebugTests.cs index f64768cf3..89870aa01 100644 --- a/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceXamlDebugTests.cs +++ b/tests/Dock.Model.Avalonia.UnitTests/Controls/DocumentDockItemsSourceXamlDebugTests.cs @@ -7,7 +7,6 @@ using Dock.Model.Avalonia; using Dock.Model.Avalonia.Controls; using Xunit; -using Xunit.Abstractions; namespace Dock.Model.Avalonia.UnitTests.Controls; @@ -203,4 +202,4 @@ public void ItemsSource_WithoutDockControl_StillWorks() Assert.NotNull(doc); Assert.Equal("Test Doc", doc.Title); } -} \ No newline at end of file +}