Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance: Add spacing properties for DockPanel #346

Merged
merged 7 commits into from
Mar 4, 2024
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
6 changes: 4 additions & 2 deletions components/Primitives/samples/DockPanelSample.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="PrimitivesExperiment.Samples.DockPanelSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand Down Expand Up @@ -36,7 +36,9 @@
<controls:DockPanel x:Name="SampleDockPanel"
Grid.Column="1"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
LastChildFill="False">
HorizontalSpacing="5"
LastChildFill="False"
VerticalSpacing="5">
<StackPanel Height="100"
Arlodotexe marked this conversation as resolved.
Show resolved Hide resolved
controls:DockPanel.Dock="Top"
Background="Black" />
Expand Down
54 changes: 47 additions & 7 deletions components/Primitives/src/DockPanel/DockPanel.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class DockPanel
/// Gets or sets a value that indicates the position of a child element within a parent <see cref="DockPanel"/>.
/// </summary>
public static readonly DependencyProperty DockProperty = DependencyProperty.RegisterAttached(
"Dock",
nameof(Dock),
typeof(Dock),
typeof(FrameworkElement),
new PropertyMetadata(Dock.Left, DockChanged));
Expand Down Expand Up @@ -46,15 +46,15 @@ public static readonly DependencyProperty LastChildFillProperty
nameof(LastChildFill),
typeof(bool),
typeof(DockPanel),
new PropertyMetadata(true, LastChildFillChanged));
new PropertyMetadata(true, OnPropertyChanged));

/// <summary>
/// Gets or sets a value indicating whether the last child element within a DockPanel stretches to fill the remaining available space.
/// </summary>
public bool LastChildFill
{
get { return (bool)GetValue(LastChildFillProperty); }
set { SetValue(LastChildFillProperty, value); }
get => (bool)GetValue(LastChildFillProperty);
set => SetValue(LastChildFillProperty, value);
}

/// <summary>
Expand All @@ -66,7 +66,7 @@ public bool LastChildFill
nameof(Padding),
typeof(Thickness),
typeof(DockPanel),
new PropertyMetadata(default(Thickness), OnPaddingChanged));
new PropertyMetadata(default(Thickness), OnPropertyChanged));

/// <summary>
/// Gets or sets the distance between the border and its child object.
Expand All @@ -77,7 +77,47 @@ public bool LastChildFill
/// </returns>
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
get => (Thickness)GetValue(PaddingProperty);
set => SetValue(PaddingProperty, value);
}

/// <summary>
/// Identifies the HorizontalSpacing dependency property.
/// </summary>
/// <returns>The identifier for the <see cref="HorizontalSpacing"/> dependency property.</returns>
public static readonly DependencyProperty HorizontalSpacingProperty
= DependencyProperty.Register(
nameof(HorizontalSpacing),
typeof(double),
typeof(DockPanel),
new PropertyMetadata(0d, OnPropertyChanged));

/// <summary>
/// Gets or sets the horizontal distance between the child objects.
/// </summary>
public double HorizontalSpacing
{
get => (double)GetValue(HorizontalSpacingProperty);
set => SetValue(HorizontalSpacingProperty, value);
}

/// <summary>
/// Identifies the VerticalSpacing dependency property.
/// </summary>
/// <returns>The identifier for the <see cref="VerticalSpacing"/> dependency property.</returns>
public static readonly DependencyProperty VerticalSpacingProperty
= DependencyProperty.Register(
nameof(VerticalSpacing),
typeof(double),
typeof(DockPanel),
new PropertyMetadata(default(double), OnPropertyChanged));

/// <summary>
/// Gets or sets the vertical distance between the child objects.
/// </summary>
public double VerticalSpacing
{
get => (double)GetValue(VerticalSpacingProperty);
set => SetValue(VerticalSpacingProperty, value);
}
}
90 changes: 58 additions & 32 deletions components/Primitives/src/DockPanel/DockPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ private static void DockChanged(DependencyObject sender, DependencyPropertyChang
dockPanel?.InvalidateArrange();
}

private static void LastChildFillChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var dockPanel = (DockPanel)sender;
dockPanel.InvalidateArrange();
}

private static void OnPaddingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var dockPanel = (DockPanel)sender;
dockPanel.InvalidateMeasure();
Expand All @@ -32,15 +26,17 @@ private static void OnPaddingChanged(DependencyObject sender, DependencyProperty
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
if (Children.Count == 0)
{
if (Children.Count is 0)
return finalSize;
}

var currentBounds = new Rect(Padding.Left, Padding.Top, finalSize.Width - Padding.Right, finalSize.Height - Padding.Bottom);
var currentBounds = new Rect(
Padding.Left,
Padding.Top,
GetPositiveOrZero(finalSize.Width - Padding.Left - Padding.Right),
GetPositiveOrZero(finalSize.Height - Padding.Top - Padding.Bottom));
var childrenCount = LastChildFill ? Children.Count - 1 : Children.Count;

for (var index = 0; index < childrenCount; index++)
for (var index = 0; index < childrenCount; ++index)
{
var child = Children[index];
var dock = (Dock)child.GetValue(DockProperty);
Expand All @@ -49,42 +45,45 @@ protected override Size ArrangeOverride(Size finalSize)
{
case Dock.Left:

width = Math.Min(child.DesiredSize.Width, GetPositiveOrZero(currentBounds.Width - currentBounds.X));
child.Arrange(new Rect(currentBounds.X, currentBounds.Y, width, GetPositiveOrZero(currentBounds.Height - currentBounds.Y)));
width = Math.Min(child.DesiredSize.Width, currentBounds.Width);
child.Arrange(new Rect(currentBounds.X, currentBounds.Y, width, currentBounds.Height));
width += HorizontalSpacing;
currentBounds.X += width;
currentBounds.Width = GetPositiveOrZero(currentBounds.Width - width);

break;
case Dock.Top:

height = Math.Min(child.DesiredSize.Height, GetPositiveOrZero(currentBounds.Height - currentBounds.Y));
child.Arrange(new Rect(currentBounds.X, currentBounds.Y, GetPositiveOrZero(currentBounds.Width - currentBounds.X), height));
height = Math.Min(child.DesiredSize.Height, currentBounds.Height);
child.Arrange(new Rect(currentBounds.X, currentBounds.Y, currentBounds.Width, height));
height += VerticalSpacing;
currentBounds.Y += height;
currentBounds.Height = GetPositiveOrZero(currentBounds.Height - height);

break;
case Dock.Right:

width = Math.Min(child.DesiredSize.Width, GetPositiveOrZero(currentBounds.Width - currentBounds.X));
child.Arrange(new Rect(GetPositiveOrZero(currentBounds.Width - width), currentBounds.Y, width, GetPositiveOrZero(currentBounds.Height - currentBounds.Y)));
currentBounds.Width -= (currentBounds.Width - width) > 0 ? width : 0;
width = Math.Min(child.DesiredSize.Width, currentBounds.Width);
child.Arrange(new Rect(currentBounds.X + currentBounds.Width - width, currentBounds.Y, width, currentBounds.Height));
width += HorizontalSpacing;
currentBounds.Width = GetPositiveOrZero(currentBounds.Width - width);

break;
case Dock.Bottom:

height = Math.Min(child.DesiredSize.Height, GetPositiveOrZero(currentBounds.Height - currentBounds.Y));
child.Arrange(new Rect(currentBounds.X, GetPositiveOrZero(currentBounds.Height - height), GetPositiveOrZero(currentBounds.Width - currentBounds.X), height));
currentBounds.Height -= (currentBounds.Height - height) > 0 ? height : 0;
height = Math.Min(child.DesiredSize.Height, currentBounds.Height);
child.Arrange(new Rect(currentBounds.X, currentBounds.Y + currentBounds.Height - height, currentBounds.Width, height));
height += VerticalSpacing;
currentBounds.Height = GetPositiveOrZero(currentBounds.Height - height);

break;
}
}

if (LastChildFill)
{
var width = GetPositiveOrZero(currentBounds.Width - currentBounds.X);
var height = GetPositiveOrZero(currentBounds.Height - currentBounds.Y);
var child = Children[Children.Count - 1];
child.Arrange(
new Rect(currentBounds.X, currentBounds.Y, width, height));
child.Arrange(new Rect(currentBounds.X, currentBounds.Y, currentBounds.Width, currentBounds.Height));
}

return finalSize;
Expand All @@ -98,6 +97,11 @@ protected override Size MeasureOverride(Size availableSize)
var accumulatedWidth = Padding.Left + Padding.Right;
var accumulatedHeight = Padding.Top + Padding.Bottom;

var leftSpacing = false;
var topSpacing = false;
var rightSpacing = false;
var bottomSpacing = false;

foreach (var child in Children)
{
var childConstraint = new Size(
Expand All @@ -110,26 +114,48 @@ protected override Size MeasureOverride(Size availableSize)
switch ((Dock)child.GetValue(DockProperty))
{
case Dock.Left:
if (childConstraint.Width is not 0)
accumulatedWidth += HorizontalSpacing;
leftSpacing = true;
parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height - VerticalSpacing);
accumulatedWidth += childDesiredSize.Width;
break;

case Dock.Right:
parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height);
if (childConstraint.Width is not 0)
accumulatedWidth += HorizontalSpacing;
rightSpacing = true;
parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height - VerticalSpacing);
accumulatedWidth += childDesiredSize.Width;
break;

case Dock.Top:
if (childConstraint.Height is not 0)
accumulatedHeight += VerticalSpacing;
topSpacing = true;
parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width - HorizontalSpacing);
accumulatedHeight += childDesiredSize.Height;
break;

case Dock.Bottom:
parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width);
if (childConstraint.Height is not 0)
accumulatedHeight += VerticalSpacing;
bottomSpacing = true;
parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width - HorizontalSpacing);
accumulatedHeight += childDesiredSize.Height;
break;
}
}

if (leftSpacing || rightSpacing)
accumulatedWidth -= HorizontalSpacing;
if (bottomSpacing || topSpacing)
accumulatedHeight -= VerticalSpacing;

parentWidth = Math.Max(parentWidth, accumulatedWidth);
parentHeight = Math.Max(parentHeight, accumulatedHeight);
return new Size(parentWidth, parentHeight);
}

private static double GetPositiveOrZero(double value)
{
return Math.Max(value, 0);
}
private static double GetPositiveOrZero(double value) => Math.Max(value, 0);
}
Loading