Skip to content

Commit 598102c

Browse files
Merge pull request #987 from wieslawsoltes/PinnedDockableSizingFixes
Pinned dockable sizing fixes
2 parents b08cdd8 + 31b3aab commit 598102c

8 files changed

Lines changed: 604 additions & 9 deletions

File tree

src/Dock.Avalonia/Controls/DockableControl.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ private void SetBoundsTracking(Rect bounds)
158158
return;
159159
}
160160

161+
if (TrackingMode == TrackingMode.Pinned && this.FindAncestorOfType<ToolPinItemControl>() is not null)
162+
{
163+
return;
164+
}
165+
161166
var x = bounds.X;
162167
var y = bounds.Y;
163168
var width = bounds.Width;

src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs

Lines changed: 242 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Wiesław Šoltés. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for details.
33
using System;
4+
using System.Linq;
45
using Avalonia;
56
using Avalonia.Controls;
67
using Avalonia.Controls.Metadata;
@@ -23,6 +24,8 @@ namespace Dock.Avalonia.Controls;
2324
[TemplatePart("PART_PinnedDockSplitter", typeof(GridSplitter))]
2425
public class PinnedDockControl : TemplatedControl
2526
{
27+
private const double BoundsEpsilon = 0.5;
28+
2629
/// <summary>
2730
/// Define the <see cref="PinnedDockAlignment"/> property.
2831
/// </summary>
@@ -42,6 +45,10 @@ public Alignment PinnedDockAlignment
4245
private GridSplitter? _pinnedDockSplitter;
4346
private PinnedDockWindow? _window;
4447
private Window? _ownerWindow;
48+
private IDockable? _lastPinnedDockable;
49+
private double _lastPinnedWidth = double.NaN;
50+
private double _lastPinnedHeight = double.NaN;
51+
private bool _isResizingPinnedDock;
4552

4653
static PinnedDockControl()
4754
{
@@ -109,28 +116,35 @@ private void UpdateGrid()
109116
default:
110117
throw new ArgumentOutOfRangeException();
111118
}
119+
120+
ApplyPinnedDockSize();
112121
}
113122

114123
/// <inheritdoc/>
115124
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
116125
{
117126
base.OnApplyTemplate(e);
127+
LayoutUpdated -= OnLayoutUpdated;
128+
this.AttachedToVisualTree -= OnAttached;
129+
this.DetachedFromVisualTree -= OnDetached;
130+
DetachSplitterHandlers();
118131
_pinnedDockGrid = e.NameScope.Get<Grid>("PART_PinnedDockGrid");
119132
_pinnedDock = e.NameScope.Get<ContentControl>("PART_PinnedDock");
120133
_pinnedDockSplitter = e.NameScope.Find<GridSplitter>("PART_PinnedDockSplitter");
134+
AttachSplitterHandlers();
121135
UpdateGrid();
122136

123-
if (DockSettings.UsePinnedDockWindow)
124-
{
125-
LayoutUpdated += OnLayoutUpdated;
126-
this.AttachedToVisualTree += OnAttached;
127-
this.DetachedFromVisualTree += OnDetached;
128-
}
137+
LayoutUpdated += OnLayoutUpdated;
138+
this.AttachedToVisualTree += OnAttached;
139+
this.DetachedFromVisualTree += OnDetached;
129140
}
130141

131142
private void OnAttached(object? sender, VisualTreeAttachmentEventArgs e)
132143
{
133-
UpdateWindow();
144+
if (DockSettings.UsePinnedDockWindow)
145+
{
146+
UpdateWindow();
147+
}
134148
}
135149

136150
private void OnDetached(object? sender, VisualTreeAttachmentEventArgs e)
@@ -139,10 +153,13 @@ private void OnDetached(object? sender, VisualTreeAttachmentEventArgs e)
139153
LayoutUpdated -= OnLayoutUpdated;
140154
this.AttachedToVisualTree -= OnAttached;
141155
this.DetachedFromVisualTree -= OnDetached;
156+
DetachSplitterHandlers();
142157
}
143158

144159
private void OnLayoutUpdated(object? sender, EventArgs e)
145160
{
161+
ApplyPinnedDockSize();
162+
UpdatePinnedDockableBounds();
146163
UpdateWindow();
147164
}
148165

@@ -227,6 +244,224 @@ private void CloseWindow()
227244

228245
}
229246

247+
private void ApplyPinnedDockSize()
248+
{
249+
if (_isResizingPinnedDock)
250+
{
251+
return;
252+
}
253+
254+
if (_pinnedDockGrid is null || DataContext is not IRootDock rootDock)
255+
{
256+
return;
257+
}
258+
259+
var dockable = GetPinnedDockable(rootDock);
260+
if (dockable is null)
261+
{
262+
return;
263+
}
264+
265+
dockable.GetPinnedBounds(out _, out _, out var width, out var height);
266+
267+
switch (PinnedDockAlignment)
268+
{
269+
case Alignment.Unset:
270+
case Alignment.Left:
271+
if (!IsValidSize(width))
272+
{
273+
return;
274+
}
275+
if (IsColumnSizeApplied(_pinnedDockGrid.ColumnDefinitions, 0, width))
276+
{
277+
return;
278+
}
279+
SetColumnSize(_pinnedDockGrid.ColumnDefinitions, 0, width);
280+
_lastPinnedDockable = dockable;
281+
_lastPinnedWidth = width;
282+
break;
283+
case Alignment.Right:
284+
if (!IsValidSize(width))
285+
{
286+
return;
287+
}
288+
if (IsColumnSizeApplied(_pinnedDockGrid.ColumnDefinitions, 2, width))
289+
{
290+
return;
291+
}
292+
SetColumnSize(_pinnedDockGrid.ColumnDefinitions, 2, width);
293+
_lastPinnedDockable = dockable;
294+
_lastPinnedWidth = width;
295+
break;
296+
case Alignment.Top:
297+
if (!IsValidSize(height))
298+
{
299+
return;
300+
}
301+
if (IsRowSizeApplied(_pinnedDockGrid.RowDefinitions, 0, height))
302+
{
303+
return;
304+
}
305+
SetRowSize(_pinnedDockGrid.RowDefinitions, 0, height);
306+
_lastPinnedDockable = dockable;
307+
_lastPinnedHeight = height;
308+
break;
309+
case Alignment.Bottom:
310+
if (!IsValidSize(height))
311+
{
312+
return;
313+
}
314+
if (IsRowSizeApplied(_pinnedDockGrid.RowDefinitions, 2, height))
315+
{
316+
return;
317+
}
318+
SetRowSize(_pinnedDockGrid.RowDefinitions, 2, height);
319+
_lastPinnedDockable = dockable;
320+
_lastPinnedHeight = height;
321+
break;
322+
default:
323+
break;
324+
}
325+
}
326+
327+
private void UpdatePinnedDockableBounds()
328+
{
329+
if (_pinnedDock is null || DataContext is not IRootDock rootDock)
330+
{
331+
return;
332+
}
333+
334+
var dockable = GetPinnedDockable(rootDock);
335+
if (dockable is null)
336+
{
337+
return;
338+
}
339+
340+
dockable.GetPinnedBounds(out _, out _, out var storedWidth, out var storedHeight);
341+
342+
var hasStoredBounds = IsValidSize(storedWidth) && IsValidSize(storedHeight);
343+
if (!_isResizingPinnedDock && hasStoredBounds)
344+
{
345+
return;
346+
}
347+
348+
var width = _pinnedDock.Bounds.Width;
349+
var height = _pinnedDock.Bounds.Height;
350+
351+
if (!IsValidSize(width) || !IsValidSize(height))
352+
{
353+
return;
354+
}
355+
356+
if (AreClose(width, storedWidth) && AreClose(height, storedHeight))
357+
{
358+
return;
359+
}
360+
361+
dockable.SetPinnedBounds(0, 0, width, height);
362+
_lastPinnedDockable = dockable;
363+
_lastPinnedWidth = width;
364+
_lastPinnedHeight = height;
365+
}
366+
367+
private static IDockable? GetPinnedDockable(IRootDock rootDock)
368+
{
369+
return rootDock.PinnedDock?.VisibleDockables?.FirstOrDefault();
370+
}
371+
372+
private static void SetColumnSize(ColumnDefinitions definitions, int index, double size)
373+
{
374+
if (index < 0 || index >= definitions.Count)
375+
{
376+
return;
377+
}
378+
379+
definitions[index].Width = new GridLength(size, GridUnitType.Pixel);
380+
}
381+
382+
private static void SetRowSize(RowDefinitions definitions, int index, double size)
383+
{
384+
if (index < 0 || index >= definitions.Count)
385+
{
386+
return;
387+
}
388+
389+
definitions[index].Height = new GridLength(size, GridUnitType.Pixel);
390+
}
391+
392+
private static bool IsColumnSizeApplied(ColumnDefinitions definitions, int index, double size)
393+
{
394+
if (index < 0 || index >= definitions.Count)
395+
{
396+
return false;
397+
}
398+
399+
var length = definitions[index].Width;
400+
return length.IsAbsolute && AreClose(length.Value, size);
401+
}
402+
403+
private static bool IsRowSizeApplied(RowDefinitions definitions, int index, double size)
404+
{
405+
if (index < 0 || index >= definitions.Count)
406+
{
407+
return false;
408+
}
409+
410+
var length = definitions[index].Height;
411+
return length.IsAbsolute && AreClose(length.Value, size);
412+
}
413+
414+
private static bool IsValidSize(double size)
415+
{
416+
return !double.IsNaN(size) && !double.IsInfinity(size) && size > 0;
417+
}
418+
419+
private static bool AreClose(double left, double right)
420+
{
421+
return Math.Abs(left - right) <= BoundsEpsilon;
422+
}
423+
424+
private void AttachSplitterHandlers()
425+
{
426+
if (_pinnedDockSplitter is null)
427+
{
428+
return;
429+
}
430+
431+
_pinnedDockSplitter.DragStarted += OnPinnedDockSplitterDragStarted;
432+
_pinnedDockSplitter.DragDelta += OnPinnedDockSplitterDragDelta;
433+
_pinnedDockSplitter.DragCompleted += OnPinnedDockSplitterDragCompleted;
434+
}
435+
436+
private void DetachSplitterHandlers()
437+
{
438+
if (_pinnedDockSplitter is null)
439+
{
440+
return;
441+
}
442+
443+
_pinnedDockSplitter.DragStarted -= OnPinnedDockSplitterDragStarted;
444+
_pinnedDockSplitter.DragDelta -= OnPinnedDockSplitterDragDelta;
445+
_pinnedDockSplitter.DragCompleted -= OnPinnedDockSplitterDragCompleted;
446+
}
447+
448+
private void OnPinnedDockSplitterDragStarted(object? sender, VectorEventArgs e)
449+
{
450+
_isResizingPinnedDock = true;
451+
UpdatePinnedDockableBounds();
452+
}
453+
454+
private void OnPinnedDockSplitterDragDelta(object? sender, VectorEventArgs e)
455+
{
456+
UpdatePinnedDockableBounds();
457+
}
458+
459+
private void OnPinnedDockSplitterDragCompleted(object? sender, VectorEventArgs e)
460+
{
461+
UpdatePinnedDockableBounds();
462+
_isResizingPinnedDock = false;
463+
}
464+
230465
private void OwnerWindow_PositionChanged(object? sender, PixelPointEventArgs e)
231466
{
232467
CloseWindow();

src/Dock.Controls.ProportionalStackPanel/Internal/ProportionManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ private void NormalizeProportions()
110110

111111
private void ApplyProportions()
112112
{
113+
var hasCollapsedChildren = _childInfos.Any(info => info.IsCollapsed);
114+
113115
foreach (var info in _childInfos)
114116
{
115117
var clampedProportion = _constraintHandler.ClampProportion(info.Control, info.TargetProportion);
116118
ProportionalStackPanel.SetProportion(info.Control, clampedProportion);
117119

118-
if (!info.IsCollapsed)
120+
if (!info.IsCollapsed && !hasCollapsedChildren)
119121
{
120122
ProportionalStackPanel.SetCollapsedProportion(info.Control, clampedProportion);
121123
}
@@ -137,4 +139,4 @@ public ChildInfo(Control control)
137139
TargetProportion = double.NaN;
138140
}
139141
}
140-
}
142+
}

src/Dock.Model/FactoryBase.Dockable.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,28 @@ private Alignment GetPinnedDockableAlignment(IDockable dockable, IRootDock rootD
560560
return Alignment.Unset;
561561
}
562562

563+
private void UpdatePinnedBoundsFromVisible(IDockable dockable, IDock owner)
564+
{
565+
dockable.GetVisibleBounds(out _, out _, out var width, out var height);
566+
567+
if (!IsValidSize(width) || !IsValidSize(height))
568+
{
569+
owner.GetVisibleBounds(out _, out _, out width, out height);
570+
}
571+
572+
if (!IsValidSize(width) || !IsValidSize(height))
573+
{
574+
return;
575+
}
576+
577+
dockable.SetPinnedBounds(0, 0, width, height);
578+
}
579+
580+
private static bool IsValidSize(double value)
581+
{
582+
return !double.IsNaN(value) && !double.IsInfinity(value) && value > 0;
583+
}
584+
563585
/// <inheritdoc/>
564586
public virtual void PinDockable(IDockable dockable)
565587
{
@@ -589,6 +611,7 @@ public virtual void PinDockable(IDockable dockable)
589611
if (isVisible && !isPinned)
590612
{
591613
// Pin dockable.
614+
UpdatePinnedBoundsFromVisible(dockable, toolDock);
592615

593616
switch (alignment)
594617
{

0 commit comments

Comments
 (0)