Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Dock.Avalonia/Controls/DockableControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ private void SetBoundsTracking(Rect bounds)
return;
}

if (TrackingMode == TrackingMode.Pinned && this.FindAncestorOfType<ToolPinItemControl>() is not null)
{
return;
}

var x = bounds.X;
var y = bounds.Y;
var width = bounds.Width;
Expand Down
249 changes: 242 additions & 7 deletions src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +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 System;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
Expand All @@ -23,6 +24,8 @@ namespace Dock.Avalonia.Controls;
[TemplatePart("PART_PinnedDockSplitter", typeof(GridSplitter))]
public class PinnedDockControl : TemplatedControl
{
private const double BoundsEpsilon = 0.5;

/// <summary>
/// Define the <see cref="PinnedDockAlignment"/> property.
/// </summary>
Expand All @@ -42,6 +45,10 @@ public Alignment PinnedDockAlignment
private GridSplitter? _pinnedDockSplitter;
private PinnedDockWindow? _window;
private Window? _ownerWindow;
private IDockable? _lastPinnedDockable;
private double _lastPinnedWidth = double.NaN;
private double _lastPinnedHeight = double.NaN;
private bool _isResizingPinnedDock;

static PinnedDockControl()
{
Expand Down Expand Up @@ -109,28 +116,35 @@ private void UpdateGrid()
default:
throw new ArgumentOutOfRangeException();
}

ApplyPinnedDockSize();
}

/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
LayoutUpdated -= OnLayoutUpdated;
this.AttachedToVisualTree -= OnAttached;
this.DetachedFromVisualTree -= OnDetached;
DetachSplitterHandlers();
_pinnedDockGrid = e.NameScope.Get<Grid>("PART_PinnedDockGrid");
_pinnedDock = e.NameScope.Get<ContentControl>("PART_PinnedDock");
_pinnedDockSplitter = e.NameScope.Find<GridSplitter>("PART_PinnedDockSplitter");
AttachSplitterHandlers();
UpdateGrid();

if (DockSettings.UsePinnedDockWindow)
{
LayoutUpdated += OnLayoutUpdated;
this.AttachedToVisualTree += OnAttached;
this.DetachedFromVisualTree += OnDetached;
}
LayoutUpdated += OnLayoutUpdated;
this.AttachedToVisualTree += OnAttached;
this.DetachedFromVisualTree += OnDetached;
}

private void OnAttached(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateWindow();
if (DockSettings.UsePinnedDockWindow)
{
UpdateWindow();
}
}

private void OnDetached(object? sender, VisualTreeAttachmentEventArgs e)
Expand All @@ -139,10 +153,13 @@ private void OnDetached(object? sender, VisualTreeAttachmentEventArgs e)
LayoutUpdated -= OnLayoutUpdated;
this.AttachedToVisualTree -= OnAttached;
this.DetachedFromVisualTree -= OnDetached;
DetachSplitterHandlers();
}

private void OnLayoutUpdated(object? sender, EventArgs e)
{
ApplyPinnedDockSize();
UpdatePinnedDockableBounds();
UpdateWindow();
}

Expand Down Expand Up @@ -227,6 +244,224 @@ private void CloseWindow()

}

private void ApplyPinnedDockSize()
{
if (_isResizingPinnedDock)
{
return;
}

if (_pinnedDockGrid is null || DataContext is not IRootDock rootDock)
{
return;
}

var dockable = GetPinnedDockable(rootDock);
if (dockable is null)
{
return;
}

dockable.GetPinnedBounds(out _, out _, out var width, out var height);

switch (PinnedDockAlignment)
{
case Alignment.Unset:
case Alignment.Left:
if (!IsValidSize(width))
{
return;
}
if (IsColumnSizeApplied(_pinnedDockGrid.ColumnDefinitions, 0, width))
{
return;
}
SetColumnSize(_pinnedDockGrid.ColumnDefinitions, 0, width);
_lastPinnedDockable = dockable;
_lastPinnedWidth = width;
break;
case Alignment.Right:
if (!IsValidSize(width))
{
return;
}
if (IsColumnSizeApplied(_pinnedDockGrid.ColumnDefinitions, 2, width))
{
return;
}
SetColumnSize(_pinnedDockGrid.ColumnDefinitions, 2, width);
_lastPinnedDockable = dockable;
_lastPinnedWidth = width;
break;
case Alignment.Top:
if (!IsValidSize(height))
{
return;
}
if (IsRowSizeApplied(_pinnedDockGrid.RowDefinitions, 0, height))
{
return;
}
SetRowSize(_pinnedDockGrid.RowDefinitions, 0, height);
_lastPinnedDockable = dockable;
_lastPinnedHeight = height;
break;
case Alignment.Bottom:
if (!IsValidSize(height))
{
return;
}
if (IsRowSizeApplied(_pinnedDockGrid.RowDefinitions, 2, height))
{
return;
}
SetRowSize(_pinnedDockGrid.RowDefinitions, 2, height);
_lastPinnedDockable = dockable;
_lastPinnedHeight = height;
break;
default:
break;
}
}

private void UpdatePinnedDockableBounds()
{
if (_pinnedDock is null || DataContext is not IRootDock rootDock)
{
return;
}

var dockable = GetPinnedDockable(rootDock);
if (dockable is null)
{
return;
}

dockable.GetPinnedBounds(out _, out _, out var storedWidth, out var storedHeight);

var hasStoredBounds = IsValidSize(storedWidth) && IsValidSize(storedHeight);
if (!_isResizingPinnedDock && hasStoredBounds)
{
return;
}

var width = _pinnedDock.Bounds.Width;
var height = _pinnedDock.Bounds.Height;

if (!IsValidSize(width) || !IsValidSize(height))
{
return;
}

if (AreClose(width, storedWidth) && AreClose(height, storedHeight))
{
return;
}

dockable.SetPinnedBounds(0, 0, width, height);
_lastPinnedDockable = dockable;
_lastPinnedWidth = width;
_lastPinnedHeight = height;
}

private static IDockable? GetPinnedDockable(IRootDock rootDock)
{
return rootDock.PinnedDock?.VisibleDockables?.FirstOrDefault();
}

private static void SetColumnSize(ColumnDefinitions definitions, int index, double size)
{
if (index < 0 || index >= definitions.Count)
{
return;
}

definitions[index].Width = new GridLength(size, GridUnitType.Pixel);
}

private static void SetRowSize(RowDefinitions definitions, int index, double size)
{
if (index < 0 || index >= definitions.Count)
{
return;
}

definitions[index].Height = new GridLength(size, GridUnitType.Pixel);
}

private static bool IsColumnSizeApplied(ColumnDefinitions definitions, int index, double size)
{
if (index < 0 || index >= definitions.Count)
{
return false;
}

var length = definitions[index].Width;
return length.IsAbsolute && AreClose(length.Value, size);
}

private static bool IsRowSizeApplied(RowDefinitions definitions, int index, double size)
{
if (index < 0 || index >= definitions.Count)
{
return false;
}

var length = definitions[index].Height;
return length.IsAbsolute && AreClose(length.Value, size);
}

private static bool IsValidSize(double size)
{
return !double.IsNaN(size) && !double.IsInfinity(size) && size > 0;
}

private static bool AreClose(double left, double right)
{
return Math.Abs(left - right) <= BoundsEpsilon;
}

private void AttachSplitterHandlers()
{
if (_pinnedDockSplitter is null)
{
return;
}

_pinnedDockSplitter.DragStarted += OnPinnedDockSplitterDragStarted;
_pinnedDockSplitter.DragDelta += OnPinnedDockSplitterDragDelta;
_pinnedDockSplitter.DragCompleted += OnPinnedDockSplitterDragCompleted;
}

private void DetachSplitterHandlers()
{
if (_pinnedDockSplitter is null)
{
return;
}

_pinnedDockSplitter.DragStarted -= OnPinnedDockSplitterDragStarted;
_pinnedDockSplitter.DragDelta -= OnPinnedDockSplitterDragDelta;
_pinnedDockSplitter.DragCompleted -= OnPinnedDockSplitterDragCompleted;
}

private void OnPinnedDockSplitterDragStarted(object? sender, VectorEventArgs e)
{
_isResizingPinnedDock = true;
UpdatePinnedDockableBounds();
}

private void OnPinnedDockSplitterDragDelta(object? sender, VectorEventArgs e)
{
UpdatePinnedDockableBounds();
}

private void OnPinnedDockSplitterDragCompleted(object? sender, VectorEventArgs e)
{
UpdatePinnedDockableBounds();
_isResizingPinnedDock = false;
}

private void OwnerWindow_PositionChanged(object? sender, PixelPointEventArgs e)
{
CloseWindow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,14 @@ private void NormalizeProportions()

private void ApplyProportions()
{
var hasCollapsedChildren = _childInfos.Any(info => info.IsCollapsed);

foreach (var info in _childInfos)
{
var clampedProportion = _constraintHandler.ClampProportion(info.Control, info.TargetProportion);
ProportionalStackPanel.SetProportion(info.Control, clampedProportion);

if (!info.IsCollapsed)
if (!info.IsCollapsed && !hasCollapsedChildren)
{
ProportionalStackPanel.SetCollapsedProportion(info.Control, clampedProportion);
}
Expand All @@ -137,4 +139,4 @@ public ChildInfo(Control control)
TargetProportion = double.NaN;
}
}
}
}
23 changes: 23 additions & 0 deletions src/Dock.Model/FactoryBase.Dockable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,28 @@ private Alignment GetPinnedDockableAlignment(IDockable dockable, IRootDock rootD
return Alignment.Unset;
}

private void UpdatePinnedBoundsFromVisible(IDockable dockable, IDock owner)
{
dockable.GetVisibleBounds(out _, out _, out var width, out var height);

if (!IsValidSize(width) || !IsValidSize(height))
{
owner.GetVisibleBounds(out _, out _, out width, out height);
}

if (!IsValidSize(width) || !IsValidSize(height))
{
return;
}

dockable.SetPinnedBounds(0, 0, width, height);
}

private static bool IsValidSize(double value)
{
return !double.IsNaN(value) && !double.IsInfinity(value) && value > 0;
}

/// <inheritdoc/>
public virtual void PinDockable(IDockable dockable)
{
Expand Down Expand Up @@ -589,6 +611,7 @@ public virtual void PinDockable(IDockable dockable)
if (isVisible && !isPinned)
{
// Pin dockable.
UpdatePinnedBoundsFromVisible(dockable, toolDock);

switch (alignment)
{
Expand Down
Loading