-
Notifications
You must be signed in to change notification settings - Fork 743
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(layoutpanel): Implementation of LayoutPanel
- Loading branch information
1 parent
7f0a361
commit f2380ef
Showing
4 changed files
with
272 additions
and
0 deletions.
There are no files selected for viewing
16 changes: 16 additions & 0 deletions
16
src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanel.Properties.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
188
src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
40
src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanel.h.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
|
28 changes: 28 additions & 0 deletions
28
src/Uno.UI/Microsoft/UI/Xaml/Controls/LayoutPanel/LayoutPanelLayoutContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |