Skip to content

Commit

Permalink
feat(layoutpanel): Implementation of LayoutPanel
Browse files Browse the repository at this point in the history
  • Loading branch information
carldebilly committed Apr 27, 2021
1 parent 7f0a361 commit f2380ef
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Windows.UI.Xaml;

namespace Microsoft.UI.Xaml.Controls
{
partial class LayoutPanel
{
public static DependencyProperty LayoutProperty { get; } = DependencyProperty.Register(
"Layout", typeof(Layout), typeof(LayoutPanel), new PropertyMetadata(default(Layout)));

public Layout Layout
{
get => (Layout)GetValue(LayoutProperty);
set => SetValue(LayoutProperty, value);
}
}
}
188 changes: 188 additions & 0 deletions src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.


using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls.Primitives;

namespace Microsoft.UI.Xaml.Controls
{

partial class LayoutPanel
{

public LayoutPanel()
{
this.RegisterDisposablePropertyChangedCallback((i, s, e) => OnPropertyChanged(e));
}


void OnPropertyChanged(DependencyPropertyChangedEventArgs args)
{
var dependencyProperty = args.Property;

if (dependencyProperty == LayoutProperty)
{
OnLayoutChanged(args.OldValue as Layout, args.NewValue as Layout);
}
#if USE_INTERNAL_SDK
else if (dependencyProperty == s_borderBrushProperty)
{
if (var panelProtected = try_as<Microsoft.UI.Xaml.Controls.IPanelProtectedFeature_WUXCPreviewTypes>())
{
panelProtected.BorderBrushProtected(Brush>(args.NewValue()));
}
}
else if (dependencyProperty == s_borderThicknessProperty)
{
if (var panelProtected = try_as<Microsoft.UI.Xaml.Controls.IPanelProtectedFeature_WUXCPreviewTypes>())
{
panelProtected.BorderThicknessProtected((Thickness)(args.NewValue()));
}
}
else if (dependencyProperty == s_cornerRadiusProperty)
{
if (var panelProtected = try_as<Microsoft.UI.Xaml.Controls.IPanelProtectedFeature_WUXCPreviewTypes>())
{
panelProtected.CornerRadiusProtected((CornerRadius)(args.NewValue()));
}
}
#endif
else if (dependencyProperty == PaddingProperty)
{
InvalidateMeasure();
}
}


protected override Size MeasureOverride(Size availableSize)
{
Size desiredSize;

// We adjust availableSize based on our Padding and BorderThickness:
var padding = Padding;
var borderThickness = BorderThickness;
var effectiveHorizontalPadding =
(padding.Left + padding.Right + borderThickness.Left + borderThickness.Right);
var effectiveVerticalPadding =
(padding.Top + padding.Bottom + borderThickness.Top + borderThickness.Bottom);

var adjustedSize = availableSize;
adjustedSize.Width -= effectiveHorizontalPadding;
adjustedSize.Height -= effectiveVerticalPadding;

adjustedSize.Width = Math.Max(0.0d, adjustedSize.Width);
adjustedSize.Height = Math.Max(0.0d, adjustedSize.Height);

var layout = Layout;

if (layout is { })
{
var layoutDesiredSize = layout.Measure(m_layoutContext, adjustedSize);
layoutDesiredSize.Width += effectiveHorizontalPadding;
layoutDesiredSize.Height += effectiveVerticalPadding;
desiredSize = layoutDesiredSize;
}
else
{
Size desiredSizeUnpadded = new Size();
foreach (UIElement child in Children)
{
child.Measure(adjustedSize);
var childDesiredSize = child.DesiredSize;
desiredSizeUnpadded.Width = Math.Max(desiredSizeUnpadded.Width, childDesiredSize.Width);
desiredSizeUnpadded.Height = Math.Max(desiredSizeUnpadded.Height, childDesiredSize.Height);
}
desiredSize = desiredSizeUnpadded;
desiredSize.Width += effectiveHorizontalPadding;
desiredSize.Height += effectiveVerticalPadding;
}
return desiredSize;
}

protected override Size ArrangeOverride(Size finalSize)
{
Size result = finalSize;

var padding = Padding;
var borderThickness = BorderThickness;

var effectiveHorizontalPadding =
(float)(padding.Left + padding.Right + borderThickness.Left + borderThickness.Right);
var effectiveVerticalPadding =
(float)(padding.Top + padding.Bottom + borderThickness.Top + borderThickness.Bottom);
var leftAdjustment = (float)(padding.Left + borderThickness.Left);
var topAdjustment = (float)(padding.Top + borderThickness.Top);

var adjustedSize = finalSize;
adjustedSize.Width -= effectiveHorizontalPadding;
adjustedSize.Height -= effectiveVerticalPadding;

adjustedSize.Width = Math.Max(0.0f, adjustedSize.Width);
adjustedSize.Height = Math.Max(0.0f, adjustedSize.Height);

var layout = Layout;

if (layout is { })
{
var layoutSize = layout.Arrange(m_layoutContext, adjustedSize);
layoutSize.Width += effectiveHorizontalPadding;
layoutSize.Height += effectiveVerticalPadding;

// We need to reposition the child elements if we have top or left padding:
if (leftAdjustment != 0 || topAdjustment != 0)
{
foreach (UIElement child in Children)
{
if (child is FrameworkElement childAsFe)
{
var layoutSlot = LayoutInformation.GetLayoutSlot(childAsFe);
layoutSlot.X += leftAdjustment;
layoutSlot.Y += topAdjustment;
childAsFe.Arrange(layoutSlot);
}
}
}

result = layoutSize;
}
else
{
Rect arrangeRect = new Rect(leftAdjustment, topAdjustment, adjustedSize.Width, adjustedSize.Height);
foreach (UIElement child in Children)
{
child.Arrange(arrangeRect);
}
}

return result;
}

void OnLayoutChanged(Layout oldValue, Layout newValue)
{
m_layoutContext ??= new LayoutPanelLayoutContext(this);

if (oldValue is { })
{
oldValue.UninitializeForContext(m_layoutContext);
oldValue.MeasureInvalidated -= InvalidateMeasureForLayout;
oldValue.ArrangeInvalidated -= InvalidateArrangeForLayout;
}

if (newValue is { })
{
newValue.InitializeForContext(m_layoutContext);
newValue.MeasureInvalidated += InvalidateMeasureForLayout;
newValue.ArrangeInvalidated += InvalidateArrangeForLayout;
}

InvalidateMeasure();
}

void InvalidateMeasureForLayout(Layout sender, object o) => InvalidateMeasure();

void InvalidateArrangeForLayout(Layout sender, object o) => InvalidateArrange();
}
}
40 changes: 40 additions & 0 deletions src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanel.h.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.


using Windows.UI.Xaml.Controls;

namespace Microsoft.UI.Xaml.Controls
{

public partial class LayoutPanel : Panel
{
// public

//IInspectable LayoutState() { return m_layoutState.get(); }
//void LayoutState(IInspectable value) { m_layoutState.set(value); }
public object LayoutState { get; set; }

//void OnPropertyChanged(DependencyPropertyChangedEventArgs args);

//Size MeasureOverride(Size availableSize);
//Size ArrangeOverride(Size finalSize);

// private
LayoutContext m_layoutContext;

//Layout.MeasureInvalidated_revoker m_measureInvalidated
//{
//}

//Layout.ArrangeInvalidated_revoker m_arrangeInvalidated
//{
//}

//void OnLayoutChanged(Layout oldValue, Layout newValue);

//void InvalidateMeasureForLayout(Layout sender, IInspectable args);
//void InvalidateArrangeForLayout(Layout sender, IInspectable args);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.


using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;

namespace Microsoft.UI.Xaml.Controls
{
internal partial class LayoutPanelLayoutContext : NonVirtualizingLayoutContext
{
private LayoutPanel m_owner;

internal LayoutPanelLayoutContext(LayoutPanel owner)
{
m_owner = owner;
}

protected internal override IReadOnlyList<UIElement> GetChildrenCore() => m_owner.Children.ToArray();

protected internal override object LayoutStateCore
{
get => m_owner.LayoutState;
set => m_owner.LayoutState = value;
}
}
}

0 comments on commit f2380ef

Please sign in to comment.