Skip to content

Commit

Permalink
Merge pull request #298 from wieslawsoltes/IsEmpty
Browse files Browse the repository at this point in the history
IsEmpty
  • Loading branch information
wieslawsoltes authored Sep 16, 2023
2 parents 220c42d + e8e7340 commit 41e6f4f
Show file tree
Hide file tree
Showing 18 changed files with 379 additions and 58 deletions.
3 changes: 2 additions & 1 deletion src/Dock.Avalonia/Controls/DockDockControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

<ControlTheme x:Key="{x:Type DockDockControl}" TargetType="DockDockControl">

<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" />
<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" x:DataType="core:IDock" />
<Setter Property="(ProportionalStackPanelSplitter.IsEmpty)" Value="{Binding IsEmpty}" x:DataType="core:IDock" />

<Setter Property="Template">
<ControlTemplate>
Expand Down
6 changes: 4 additions & 2 deletions src/Dock.Avalonia/Controls/DocumentDockControl.axaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="using:Dock.Model.Core">
<Design.PreviewWith>
<DocumentDockControl Width="300" Height="300" />
</Design.PreviewWith>

<ControlTheme x:Key="{x:Type DocumentDockControl}" TargetType="DocumentDockControl">

<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" />
<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" x:DataType="core:IDock" />
<Setter Property="(ProportionalStackPanelSplitter.IsEmpty)" Value="{Binding IsEmpty}" x:DataType="core:IDock" />

<Setter Property="Template">
<ControlTemplate>
Expand Down
5 changes: 3 additions & 2 deletions src/Dock.Avalonia/Controls/HostWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@

<Style Selector="^:toolwindow">

<Setter Property="SystemDecorations" Value="None" />
<Setter Property="SystemDecorations" Value="Full" />
<Setter Property="ExtendClientAreaToDecorationsHint" Value="True" />
<Setter Property="ExtendClientAreaChromeHints" Value="PreferSystemChrome" />
<Setter Property="ExtendClientAreaChromeHints" Value="NoChrome" />
<Setter Property="ExtendClientAreaTitleBarHeightHint" Value="0" />

<Setter Property="Template">
<ControlTemplate>
Expand Down
3 changes: 2 additions & 1 deletion src/Dock.Avalonia/Controls/ProportionalDockControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

<ControlTheme x:Key="{x:Type ProportionalDockControl}" TargetType="ProportionalDockControl">

<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" />
<Setter Property="(ProportionalStackPanelSplitter.Proportion)" Value="{Binding Proportion}" x:DataType="core:IDock" />
<Setter Property="(ProportionalStackPanelSplitter.IsEmpty)" Value="{Binding IsEmpty}" x:DataType="core:IDock" />

<Setter Property="Template">
<ControlTemplate>
Expand Down
198 changes: 156 additions & 42 deletions src/Dock.Avalonia/Controls/ProportionalStackPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,21 @@ private void AssignProportions(global::Avalonia.Controls.Controls children)
var assignedProportion = 0.0;
var unassignedProportions = 0;

foreach (var control in children)
for (var i = 0; i < children.Count; i++)
{
if (control is { } && !ProportionalStackPanelSplitter.IsSplitter(control))
var control = children[i];
var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(control);
var isSplitter = ProportionalStackPanelSplitter.IsSplitter(control, out _);

if (!isSplitter)
{
var proportion = ProportionalStackPanelSplitter.GetControlProportion(control);

if (isEmpty)
{
proportion = 0.0;
}

if (double.IsNaN(proportion))
{
unassignedProportions++;
Expand All @@ -53,9 +62,13 @@ private void AssignProportions(global::Avalonia.Controls.Controls children)
if (unassignedProportions > 0)
{
var toAssign = assignedProportion;
foreach (var control in children.Where(c => double.IsNaN(ProportionalStackPanelSplitter.GetControlProportion(c))))
foreach (var control in children.Where(c =>
{
var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(c);
return !isEmpty && double.IsNaN(ProportionalStackPanelSplitter.GetControlProportion(c));
}))
{
if (!ProportionalStackPanelSplitter.IsSplitter(control))
if (!ProportionalStackPanelSplitter.IsSplitter(control, out _))
{
var proportion = (1.0 - toAssign) / unassignedProportions;
ProportionalStackPanelSplitter.SetControlProportion(control, proportion);
Expand All @@ -66,23 +79,31 @@ private void AssignProportions(global::Avalonia.Controls.Controls children)

if (assignedProportion < 1)
{
var numChildren = (double)children.Count(c => !ProportionalStackPanelSplitter.IsSplitter(c));
var numChildren = (double)children.Count(c => !ProportionalStackPanelSplitter.IsSplitter(c, out _));

var toAdd = (1.0 - assignedProportion) / numChildren;

foreach (var child in children.Where(c => !ProportionalStackPanelSplitter.IsSplitter(c)))
foreach (var child in children.Where(c =>
{
var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(c);
return !isEmpty && !ProportionalStackPanelSplitter.IsSplitter(c, out _);
}))
{
var proportion = ProportionalStackPanelSplitter.GetControlProportion(child) + toAdd;
ProportionalStackPanelSplitter.SetControlProportion(child, proportion);
}
}
else if (assignedProportion > 1)
{
var numChildren = (double)children.Count(c => !ProportionalStackPanelSplitter.IsSplitter(c));
var numChildren = (double)children.Count(c => !ProportionalStackPanelSplitter.IsSplitter(c, out _));

var toRemove = (assignedProportion - 1.0) / numChildren;

foreach (var child in children.Where(c => !ProportionalStackPanelSplitter.IsSplitter(c)))
foreach (var child in children.Where(c =>
{
var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(c);
return !isEmpty && !ProportionalStackPanelSplitter.IsSplitter(c, out _);
}))
{
var proportion = ProportionalStackPanelSplitter.GetControlProportion(child) - toRemove;
ProportionalStackPanelSplitter.SetControlProportion(child, proportion);
Expand All @@ -92,26 +113,42 @@ private void AssignProportions(global::Avalonia.Controls.Controls children)

private double GetTotalSplitterThickness(global::Avalonia.Controls.Controls children)
{
var result = children
.Where(c => ProportionalStackPanelSplitter.IsSplitter(c))
.Select(c =>
var previousIsEmpty = false;
var totalThickness = 0.0;

for (var i = 0; i < children.Count; i++)
{
var c = children[i];
var isSplitter = ProportionalStackPanelSplitter.IsSplitter(c, out var proportionalStackPanelSplitter);

if (isSplitter && proportionalStackPanelSplitter is not null)
{
if (c is ContentPresenter contentPresenter)
if (previousIsEmpty)
{
previousIsEmpty = false;
continue;
}

if (i + 1 < Children.Count)
{
if (contentPresenter.Child is null)
var nextControl = Children[i + 1];
var nextIsEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(nextControl);
if (nextIsEmpty)
{
contentPresenter.UpdateChild();
continue;
}

return contentPresenter.Child as ProportionalStackPanelSplitter;
}

var thickness = proportionalStackPanelSplitter.Thickness;
totalThickness += thickness;
}
else
{
previousIsEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(c);
}
}

return c as ProportionalStackPanelSplitter;
})
.Where(x => x != null)
.Sum(c => c!.Thickness);

return double.IsNaN(result) ? 0 : result;
return double.IsNaN(totalThickness) ? 0 : totalThickness;
}

/// <inheritdoc/>
Expand All @@ -134,70 +171,110 @@ protected override Size MeasureOverride(Size constraint)

AssignProportions(Children);

var previousIsEmpty = false;

// Measure each of the Children
foreach (var control in Children)
for (var i = 0; i < Children.Count; i++)
{
if (control is null)
{
continue;
}

var control = Children[i];
var isSplitter = ProportionalStackPanelSplitter.IsSplitter(control, out _);

// Get the child's desired size
var remainingSize = new Size(
Math.Max(0.0, constraint.Width - usedWidth - splitterThickness),
Math.Max(0.0, constraint.Height - usedHeight - splitterThickness));

var proportion = ProportionalStackPanelSplitter.GetControlProportion(control);

if (!ProportionalStackPanelSplitter.IsSplitter(control))
var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(control);
if (isEmpty)
{
// TODO: Also handle next is empty.
previousIsEmpty = true;
var size = new Size();
control.Measure(size);
continue;
}

if (!isSplitter)
{
Debug.Assert(!double.IsNaN(proportion));

switch (Orientation)
{
case Orientation.Horizontal:
control.Measure(constraint.WithWidth(Math.Max(0, (constraint.Width - splitterThickness) * proportion)));
{
var width = Math.Max(0, (constraint.Width - splitterThickness) * proportion);
var size = constraint.WithWidth(width);
control.Measure(size);
break;

}
case Orientation.Vertical:
control.Measure(constraint.WithHeight(Math.Max(0, (constraint.Height - splitterThickness) * proportion)));
{
var height = Math.Max(0, (constraint.Height - splitterThickness) * proportion);
var size = constraint.WithHeight(height);
control.Measure(size);
break;
}
}
}
else
{
var nextIsEmpty = false;
if (i + 1 < Children.Count)
{
var nextControl = Children[i + 1];
nextIsEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(nextControl);
}

if (previousIsEmpty || nextIsEmpty)
{
var size = new Size();
control.Measure(size);
previousIsEmpty = true;
continue;
}

control.Measure(remainingSize);
}

previousIsEmpty = false;

var desiredSize = control.DesiredSize;

// Decrease the remaining space for the rest of the children
switch (Orientation)
{
case Orientation.Horizontal:
{
maximumHeight = Math.Max(maximumHeight, usedHeight + desiredSize.Height);

if (ProportionalStackPanelSplitter.IsSplitter(control))
if (isSplitter)
{
usedWidth += desiredSize.Width;
}
else
{
usedWidth += Math.Max(0, (constraint.Width - splitterThickness) * proportion);
}

break;
}
case Orientation.Vertical:
{
maximumWidth = Math.Max(maximumWidth, usedWidth + desiredSize.Width);

if (ProportionalStackPanelSplitter.IsSplitter(control))
if (isSplitter)
{
usedHeight += desiredSize.Height;
}
else
{
usedHeight += Math.Max(0, (constraint.Height - splitterThickness) * proportion);
}

break;
}
}
}

Expand All @@ -221,13 +298,42 @@ protected override Size ArrangeOverride(Size arrangeSize)

AssignProportions(Children);

foreach (var control in Children)
var previousIsEmpty = false;

for (var i = 0; i < Children.Count; i++)
{
if (control is null)
var control = Children[i];

var isEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(control);
if (isEmpty)
{
// TODO: Also handle next is empty.
previousIsEmpty = true;
var rect = new Rect();
control.Arrange(rect);
index++;
continue;
}

var isSplitter = ProportionalStackPanelSplitter.IsSplitter(control, out _);

var nextIsEmpty = false;
if (i + 1 < Children.Count)
{
var nextControl = Children[i + 1];
nextIsEmpty = ProportionalStackPanelSplitter.GetControlIsEmpty(nextControl);
}

if (isSplitter && (previousIsEmpty || nextIsEmpty))
{
var rect = new Rect();
control.Arrange(rect);
index++;
continue;
}

previousIsEmpty = false;

// Determine the remaining space left to arrange the element
var remainingRect = new Rect(
left,
Expand All @@ -246,31 +352,39 @@ protected override Size ArrangeOverride(Size arrangeSize)
switch (Orientation)
{
case Orientation.Horizontal:
if (ProportionalStackPanelSplitter.IsSplitter(control))
{
if (isSplitter)
{
left += desiredSize.Width;
remainingRect = remainingRect.WithWidth(desiredSize.Width);
}
else
{
Debug.Assert(!double.IsNaN(proportion));
remainingRect = remainingRect.WithWidth(Math.Max(0, (arrangeSize.Width - splitterThickness) * proportion));
left += Math.Max(0, (arrangeSize.Width - splitterThickness) * proportion);
var width = Math.Max(0, (arrangeSize.Width - splitterThickness) * proportion);
remainingRect = remainingRect.WithWidth(width);
left += width;
}

break;
}
case Orientation.Vertical:
if (ProportionalStackPanelSplitter.IsSplitter(control))
{
if (isSplitter)
{
top += desiredSize.Height;
remainingRect = remainingRect.WithHeight(desiredSize.Height);
}
else
{
Debug.Assert(!double.IsNaN(proportion));
remainingRect = remainingRect.WithHeight(Math.Max(0, (arrangeSize.Height - splitterThickness) * proportion));
top += Math.Max(0, (arrangeSize.Height - splitterThickness) * proportion);
var height = Math.Max(0, (arrangeSize.Height - splitterThickness) * proportion);
remainingRect = remainingRect.WithHeight(height);
top += height;
}

break;
}
}
}

Expand Down
Loading

0 comments on commit 41e6f4f

Please sign in to comment.