diff --git a/samples/DockControlPanelsSample/MainView.axaml b/samples/DockControlPanelsSample/MainView.axaml index 06b74de2d..b256077ad 100644 --- a/samples/DockControlPanelsSample/MainView.axaml +++ b/samples/DockControlPanelsSample/MainView.axaml @@ -23,7 +23,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -261,7 +261,7 @@ - + diff --git a/src/Dock.Model/Controls/IGridDockSplitter.cs b/src/Dock.Model/Controls/IGridDockSplitter.cs index 06d8a791e..b55b249ab 100644 --- a/src/Dock.Model/Controls/IGridDockSplitter.cs +++ b/src/Dock.Model/Controls/IGridDockSplitter.cs @@ -8,7 +8,7 @@ namespace Dock.Model.Controls; /// Grid splitter dock contract. /// [RequiresDataTemplate] -public interface IGridDockSplitter : IDockable +public interface IGridDockSplitter : ISplitter { /// /// Gets or sets resize direction. diff --git a/src/Dock.Model/Controls/IProportionalDockSplitter.cs b/src/Dock.Model/Controls/IProportionalDockSplitter.cs index 2c65ce7fa..6389d1b28 100644 --- a/src/Dock.Model/Controls/IProportionalDockSplitter.cs +++ b/src/Dock.Model/Controls/IProportionalDockSplitter.cs @@ -8,7 +8,7 @@ namespace Dock.Model.Controls; /// Proportional dock splitter contract. /// [RequiresDataTemplate] -public interface IProportionalDockSplitter : IDockable +public interface IProportionalDockSplitter : ISplitter { /// /// Gets or sets whether the splitter allows resizing. diff --git a/src/Dock.Model/Controls/ISplitter.cs b/src/Dock.Model/Controls/ISplitter.cs new file mode 100644 index 000000000..01a262e45 --- /dev/null +++ b/src/Dock.Model/Controls/ISplitter.cs @@ -0,0 +1,12 @@ +// Copyright (c) Wiesław Šoltés. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. +using Dock.Model.Core; + +namespace Dock.Model.Controls; + +/// +/// Splitter contract. +/// +public interface ISplitter : IDockable +{ +} \ No newline at end of file diff --git a/src/Dock.Model/FactoryBase.Dockable.cs b/src/Dock.Model/FactoryBase.Dockable.cs index b178c7cc9..70f56e88f 100644 --- a/src/Dock.Model/FactoryBase.Dockable.cs +++ b/src/Dock.Model/FactoryBase.Dockable.cs @@ -58,7 +58,7 @@ public virtual void RemoveDockable(IDockable dockable, bool collapse) if (dock.VisibleDockables.Count > 0) { var nextActiveDockable = dock.VisibleDockables[indexActiveDockable]; - dock.ActiveDockable = nextActiveDockable is not IProportionalDockSplitter ? nextActiveDockable : null; + dock.ActiveDockable = nextActiveDockable is not ISplitter ? nextActiveDockable : null; } else { @@ -98,21 +98,21 @@ protected void CleanupOrphanedSplitters(IDock dock) var dockables = dock.VisibleDockables.ToList(); // If we only have splitters, remove all of them - if (dockables.Count > 0 && dockables.All(d => d is IProportionalDockSplitter)) + if (dockables.Count > 0 && dockables.All(d => d is ISplitter)) { toRemove.AddRange(dockables); } else { // Remove splitters that are at the beginning - while (dockables.Count > 0 && dockables[0] is IProportionalDockSplitter) + while (dockables.Count > 0 && dockables[0] is ISplitter) { toRemove.Add(dockables[0]); dockables.RemoveAt(0); } // Remove splitters that are at the end - while (dockables.Count > 0 && dockables[dockables.Count - 1] is IProportionalDockSplitter) + while (dockables.Count > 0 && dockables[dockables.Count - 1] is ISplitter) { toRemove.Add(dockables[dockables.Count - 1]); dockables.RemoveAt(dockables.Count - 1); @@ -121,11 +121,11 @@ protected void CleanupOrphanedSplitters(IDock dock) // Remove consecutive splitters - keep only the first one in each sequence for (int i = 0; i < dockables.Count - 1; i++) { - if (dockables[i] is IProportionalDockSplitter) + if (dockables[i] is ISplitter) { // Remove all consecutive splitters after this one int j = i + 1; - while (j < dockables.Count && dockables[j] is IProportionalDockSplitter) + while (j < dockables.Count && dockables[j] is ISplitter) { toRemove.Add(dockables[j]); j++; @@ -147,10 +147,10 @@ protected void CleanupOrphanedSplitters(IDock dock) } // Update active dockable if it was a splitter that got removed - if (dock.ActiveDockable is IProportionalDockSplitter || + if (dock.ActiveDockable is ISplitter || (dock.ActiveDockable is not null && !dock.VisibleDockables.Contains(dock.ActiveDockable))) { - dock.ActiveDockable = dock.VisibleDockables?.FirstOrDefault(d => d is not IProportionalDockSplitter); + dock.ActiveDockable = dock.VisibleDockables?.FirstOrDefault(d => d is not ISplitter); } } @@ -1254,7 +1254,7 @@ private void UpdateIsEmpty(IDock dock) var newIsEmpty = dock.VisibleDockables == null || dock.VisibleDockables?.Count == 0 - || dock.VisibleDockables!.All(x => x is IDock { IsEmpty: true, IsCollapsable: true } or IProportionalDockSplitter); + || dock.VisibleDockables!.All(x => x is IDock { IsEmpty: true, IsCollapsable: true } or ISplitter); if (oldIsEmpty != newIsEmpty) { diff --git a/src/Dock.Model/FactoryBase.Init.cs b/src/Dock.Model/FactoryBase.Init.cs index 84b14e0b4..1a28a82d0 100644 --- a/src/Dock.Model/FactoryBase.Init.cs +++ b/src/Dock.Model/FactoryBase.Init.cs @@ -35,8 +35,19 @@ public virtual void InitLayout(IDockable layout) } } + // Auto-set ActiveDockable for RootDock if not already set if (layout is IRootDock rootDock) { + if (rootDock.ActiveDockable is null && rootDock.VisibleDockables is not null) + { + // Find first visible dockable that is not a splitter + var firstVisible = FindFirstVisibleDockable(rootDock); + if (firstVisible is not null) + { + rootDock.ActiveDockable = firstVisible; + } + } + if (rootDock.ShowWindows.CanExecute(null)) { rootDock.ShowWindows.Execute(null); @@ -108,6 +119,43 @@ public virtual void InitDockable(IDockable dockable, IDockable? owner) OnDockableInit(dockable); } + /// + /// Finds the first visible dockable in the hierarchy that is not a splitter. + /// + /// The dock to search in. + /// The first visible dockable or null if none found. + private IDockable? FindFirstVisibleDockable(IDock dock) + { + if (dock.VisibleDockables is null) + { + return null; + } + + // First look for direct visible dockables that are not splitters + foreach (var dockable in dock.VisibleDockables) + { + if (dockable is not ISplitter) + { + return dockable; + } + } + + // If no direct dockables found, recursively search in child docks + foreach (var dockable in dock.VisibleDockables) + { + if (dockable is IDock childDock) + { + var result = FindFirstVisibleDockable(childDock); + if (result is not null) + { + return result; + } + } + } + + return null; + } + private void InitDockables(IDockable dockable, IList dockables) { foreach (var child in dockables)