Skip to content

Commit

Permalink
feat(effectiveviewport): Move the UIElement's layout properties to th…
Browse files Browse the repository at this point in the history
…e LayoutInformation

This gives us the ability to also use the LayoutSlot on native elements (Like the ScrollContentPresenter).
There is still backing field on the UIElement for perf considerations, but it's almost readonly from the element perspective
(we used custom interface implementation in order to encourage the use the unified solution of the LayoutInformation).
  • Loading branch information
Dr.Rx authored and dr1rrb committed Nov 16, 2020
1 parent d2861ff commit e98a417
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 149 deletions.
31 changes: 0 additions & 31 deletions src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,6 @@ public static void SetMeasuredDimensions(View view, int width, int height)
LayouterHelper.SetMeasuredDimensions(view, new object[] { width, height });
}

partial void SetDesiredChildSize(View view, Size desiredSize)
{
var uiElement = view as UIElement;

if (uiElement != null)
{
uiElement.DesiredSize = desiredSize;
}
else
{
LayouterHelper.LayoutProperties.SetValue(view, "desiredSize", desiredSize);
}
}

/// <summary>
/// Provides the desired size of the element, from the last measure phase.
/// </summary>
/// <param name="view">The element to get the measured with</param>
/// <returns>The measured size</returns>
Size ILayouter.GetDesiredSize(View view)
{
return DesiredChildSize(view);
}

protected Size DesiredChildSize(View view)
{
var uiElement = view as UIElement;

return uiElement?.DesiredSize ?? LayouterHelper.LayoutProperties.GetValue(view, "desiredSize", () => default(Size));
}

protected Size MeasureChildOverride(View view, Size slotSize)
{
var widthSpec = ViewHelper.SpecFromLogicalSize(slotSize.Width);
Expand Down
30 changes: 18 additions & 12 deletions src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
#if !NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;
using Uno;
using Uno.Extensions;
Expand All @@ -17,7 +19,6 @@
using static System.Double;
using static System.Math;
using static Uno.UI.LayoutHelper;
using System.Diagnostics.Contracts;

#if XAMARIN_ANDROID
using Android.Views;
Expand Down Expand Up @@ -106,6 +107,7 @@ public Size Measure(Size availableSize)
.AtLeastZero()
.AtMost(maxSize);

LayoutInformation.SetAvailableSize(this, frameworkAvailableSize);
var desiredSize = MeasureOverride(frameworkAvailableSize);

_logDebug?.LogTrace($"{this}.MeasureOverride(availableSize={frameworkAvailableSize}): desiredSize={desiredSize}");
Expand Down Expand Up @@ -134,7 +136,7 @@ public Size Measure(Size availableSize)

// DesiredSize must include margins
// TODO: on UWP, it's not clipped. See test When_MinWidth_SmallerThan_AvailableSize
SetDesiredChildSize(Panel as View, clippedDesiredSize);
LayoutInformation.SetDesiredSize(Panel, clippedDesiredSize);

// We return "clipped" desiredSize to caller... the unclipped version stays internal
return clippedDesiredSize;
Expand All @@ -159,12 +161,9 @@ private static bool IsLessThanAndNotCloseTo(double a, double b)
/// </summary>
public void Arrange(Rect finalRect)
{
var uiElement = Panel as UIElement;
LayoutInformation.SetLayoutSlot(Panel, finalRect);

if (uiElement != null)
{
uiElement.LayoutSlot = finalRect;
}
var uiElement = Panel as UIElement;

IDisposable traceActivity = null;
if (_trace.IsEnabled)
Expand Down Expand Up @@ -257,6 +256,10 @@ public void Arrange(Rect finalRect)
fe.OnLayoutUpdated();
}
}
else if (Panel is IFrameworkElement_EffectiveViewport evp)
{
evp.OnLayoutUpdated();
}
}
}

Expand All @@ -274,9 +277,12 @@ public void Arrange(Rect finalRect)
protected abstract Size ArrangeOverride(Size finalSize);

/// <summary>
/// Sets the desired child size back on the view. (Used in iOS which does not store measured size)
/// Provides the desired size of the element, from the last measure phase.
/// </summary>
partial void SetDesiredChildSize(View view, Size desiredSize);
/// <param name="view">The element to get the measured with</param>
/// <returns>The measured size</returns>
Size ILayouter.GetDesiredSize(View view)
=> LayoutInformation.GetDesiredSize(view);

protected Size MeasureChild(View view, Size slotSize)
{
Expand All @@ -292,7 +298,7 @@ protected Size MeasureChild(View view, Size slotSize)
// We want the collapsed behavior, so we return a 0,0 size instead.

// Note: Visibility is checked in both Measure and MeasureChild, since some IFrameworkElement children may not have their own Layouter
SetDesiredChildSize(view, ret);
LayoutInformation.SetDesiredSize(view, ret);

if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
Expand Down Expand Up @@ -418,7 +424,7 @@ protected Size MeasureChild(View view, Size slotSize)
{
// For native controls only - because it's already set in Layouter.Measure()
// for Uno's managed controls
SetDesiredChildSize(view, ret);
LayoutInformation.SetDesiredSize(view, ret);
}


Expand Down Expand Up @@ -521,7 +527,7 @@ protected Thickness MarginChild(View view)
|| hasChildMinHeight
)
{
var desiredSize = DesiredChildSize(view);
var desiredSize = LayoutInformation.GetDesiredSize(view);

// Apply vertical alignment
if (
Expand Down
41 changes: 0 additions & 41 deletions src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Uno.Collections;
using Windows.UI.Xaml.Media;
using Windows.Foundation;

using View = UIKit.UIView;
using UIKit;
using CoreGraphics;
Expand All @@ -24,46 +23,6 @@ public IEnumerable<View> GetChildren()
return (Panel as UIView).GetChildren();
}

/// <summary>
/// Provides the desired size of the element, from the last measure phase.
/// </summary>
/// <param name="view">The element to get the measured with</param>
/// <returns>The measured size</returns>
Size ILayouter.GetDesiredSize(View view)
{
return DesiredChildSize(view);
}

protected Size DesiredChildSize(View view)
{
var uiElement = view as UIElement;

if (uiElement != null)
{
return uiElement.DesiredSize;
}
else
{
return _layoutProperties.GetValue(view, "desiredSize", () => default(Size));
}
}

partial void SetDesiredChildSize(View view, Size desiredSize)
{
var uiElement = view as UIElement;

if (uiElement != null)
{
uiElement.DesiredSize = desiredSize;
}
else
{
_layoutProperties.SetValue(view, "desiredSize", desiredSize);
}
}

private static readonly UnsafeWeakAttachedDictionary<View, string> _layoutProperties = new UnsafeWeakAttachedDictionary<View, string>();

protected Size MeasureChildOverride(View view, Size slotSize)
{
var ret = view
Expand Down
40 changes: 0 additions & 40 deletions src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,46 +25,6 @@ public IEnumerable<View> GetChildren()
return (Panel as NSView).GetChildren();
}

/// <summary>
/// Provides the desired size of the element, from the last measure phase.
/// </summary>
/// <param name="view">The element to get the measured with</param>
/// <returns>The measured size</returns>
Size ILayouter.GetDesiredSize(View view)
{
return DesiredChildSize(view);
}

protected Size DesiredChildSize(View view)
{
var uiElement = view as UIElement;

if (uiElement != null)
{
return uiElement.DesiredSize;
}
else
{
return _layoutProperties.GetValue(view, "desiredSize", () => default(Size));
}
}

partial void SetDesiredChildSize(View view, Size desiredSize)
{
var uiElement = view as UIElement;

if (uiElement != null)
{
uiElement.DesiredSize = desiredSize;
}
else
{
_layoutProperties.SetValue(view, "desiredSize", desiredSize);
}
}

private static UnsafeWeakAttachedDictionary<View, string> _layoutProperties = new UnsafeWeakAttachedDictionary<View, string>();

protected Size MeasureChildOverride(View view, Size slotSize)
{
var ret = view
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ private void UpdateContentLayoutSlots(Rect frame)
var content = Content;
if (content != null)
{
content.LayoutSlot = frame;
LayoutInformation.SetLayoutSlot(content, frame);
content.LayoutSlotWithMarginsAndAlignments = frame;
}
}
Expand Down
74 changes: 71 additions & 3 deletions src/Uno.UI/UI/Xaml/Controls/Primitives/LayoutInformation.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,83 @@
using Windows.Foundation;
using Uno.Collections;

namespace Windows.UI.Xaml.Controls.Primitives
{
partial class LayoutInformation
{
private static readonly UnsafeWeakAttachedDictionary<object, string> _layoutProperties = new UnsafeWeakAttachedDictionary<object, string>();

#region AvailableSize
public static Size GetAvailableSize(UIElement element)
=> element.LastAvailableSize;

internal static Size GetAvailableSize(object view)
=> view is IUIElementInternal iue
? iue.LastAvailableSize
: _layoutProperties.GetValue(view, "availablesize", () => default(Size));

internal static void SetAvailableSize(object view, Size value)
{
if (view is IUIElementInternal iue)
{
iue.LastAvailableSize = value;
}
else
{
_layoutProperties.SetValue(view, "availablesize", value);
}
}
#endregion

#region LayoutSlot
public static Rect GetLayoutSlot(FrameworkElement element)
=> element.LayoutSlot;

internal static Rect GetLayoutSlot(object view)
=> view is IUIElementInternal iue
? iue.LayoutSlot
: _layoutProperties.GetValue(view, "layoutslot", () => default(Rect));

internal static void SetLayoutSlot(object view, Rect value)
{
return element.LayoutSlot;
if (view is IUIElementInternal iue)
{
iue.LayoutSlot = value;
}
else
{
_layoutProperties.SetValue(view, "layoutslot", value);
}
}
#endregion

public static Size GetAvailableSize(UIElement element)
=> element.LastAvailableSize;
#region DesiredSize
internal static Size GetDesiredSize(UIElement element)
=> element.DesiredSize;

internal static Size GetDesiredSize(object view)
{
switch (view)
{
case IUIElementInternal iue:
return iue.DesiredSize;
default:
return _layoutProperties.GetValue(view, "desiredSize", () => default(Size));
}
}

internal static void SetDesiredSize(object view, Size desiredSize)
{
switch (view)
{
case IUIElementInternal iue:
iue.DesiredSize = desiredSize;
break;
default:
_layoutProperties.GetValue(view, "desiredSize", () => default(Size));
break;
}
}
#endregion
}
}
4 changes: 0 additions & 4 deletions src/Uno.UI/UI/Xaml/FrameworkElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,6 @@ public bool IsParsing
/// <returns>The size that this object determines it needs during layout, based on its calculations of the allocated sizes for child objects or based on other considerations such as a fixed container size.</returns>
protected virtual Size MeasureOverride(Size availableSize)
{
#if !NETSTANDARD2_0
LastAvailableSize = availableSize;
#endif

var child = this.FindFirstChild();
return child != null ? MeasureElement(child, availableSize) : new Size(0, 0);
}
Expand Down
28 changes: 28 additions & 0 deletions src/Uno.UI/UI/Xaml/IUIElement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Controls.Primitives;

namespace Windows.UI.Xaml
{
internal interface IUIElementInternal : IUIElement
{
/// <summary>
/// The 'availableSize' provided for the last Measure
/// </summary>
/// <remarks>This is the backing flied for <see cref="LayoutInformation.GetAvailableSize"/></remarks>
Size LastAvailableSize { get; set; }

/// <summary>
/// The 'return' size produced by the last Measure
/// </summary>
/// <remarks>This is the backing flied for the **internal** <see cref="LayoutInformation.GetDesiredSize"/></remarks>
Size DesiredSize { get; set; }

/// <summary>
/// The 'finalSize' provided for the last Arrange
/// </summary>
/// <remarks>This is the backing flied for <see cref="LayoutInformation.GetLayoutSlot"/></remarks>
Rect LayoutSlot { get; set; }
}
}

Loading

0 comments on commit e98a417

Please sign in to comment.