Summary: @public Currently only parent can tell the layout to align its children based on baseline. But if one of the children is a column or row then basealign does not work as expected. We have added an api setReferenceBaseline which when set to true would mean that it's baseline would be considered as the reference baseline for parent amongst its siblings. If there are more than one siblings with referenceBaseline set, the first one would be considered. Reviewed By: davidaurelio Differential Revision: D12883323 fbshipit-source-id: 19beccfc47d98bb38f81f5b66ba764e83680f821
683 lines
17 KiB
C#
683 lines
17 KiB
C#
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
#if __IOS__
|
|
using ObjCRuntime;
|
|
#endif
|
|
#if ENABLE_IL2CPP
|
|
using AOT;
|
|
#endif
|
|
|
|
namespace Facebook.Yoga
|
|
{
|
|
public partial class YogaNode : IEnumerable<YogaNode>
|
|
{
|
|
private readonly YGNodeHandle _ygNode;
|
|
private readonly YogaConfig _config;
|
|
private WeakReference _parent;
|
|
private List<YogaNode> _children;
|
|
private MeasureFunction _measureFunction;
|
|
private BaselineFunction _baselineFunction;
|
|
private YogaMeasureFunc _managedMeasure;
|
|
private YogaBaselineFunc _managedBaseline;
|
|
private object _data;
|
|
|
|
public YogaNode(YogaConfig config = null)
|
|
{
|
|
_config = config == null ? YogaConfig.Default : config;
|
|
_ygNode = Native.YGNodeNewWithConfig(_config.Handle);
|
|
if (_ygNode.IsInvalid)
|
|
{
|
|
throw new InvalidOperationException("Failed to allocate native memory");
|
|
}
|
|
|
|
_ygNode.SetContext(this);
|
|
}
|
|
|
|
public YogaNode(YogaNode srcNode)
|
|
: this(srcNode._config)
|
|
{
|
|
CopyStyle(srcNode);
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
_measureFunction = null;
|
|
_baselineFunction = null;
|
|
_data = null;
|
|
|
|
_ygNode.ReleaseManaged();
|
|
Native.YGNodeReset(_ygNode);
|
|
_ygNode.SetContext(this);
|
|
}
|
|
|
|
public bool IsDirty
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeIsDirty(_ygNode);
|
|
}
|
|
}
|
|
|
|
public virtual void MarkDirty()
|
|
{
|
|
Native.YGNodeMarkDirty(_ygNode);
|
|
}
|
|
|
|
public bool HasNewLayout
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeGetHasNewLayout(_ygNode);
|
|
}
|
|
}
|
|
|
|
public void MarkHasNewLayout()
|
|
{
|
|
Native.YGNodeSetHasNewLayout(_ygNode, true);
|
|
}
|
|
|
|
public YogaNode Parent
|
|
{
|
|
get
|
|
{
|
|
return _parent != null ? _parent.Target as YogaNode : null;
|
|
}
|
|
}
|
|
|
|
public bool IsMeasureDefined
|
|
{
|
|
get
|
|
{
|
|
return _measureFunction != null;
|
|
}
|
|
}
|
|
|
|
public bool IsBaselineDefined
|
|
{
|
|
get
|
|
{
|
|
return _baselineFunction != null;
|
|
}
|
|
}
|
|
|
|
public void CopyStyle(YogaNode srcNode)
|
|
{
|
|
Native.YGNodeCopyStyle(_ygNode, srcNode._ygNode);
|
|
}
|
|
|
|
public YogaDirection StyleDirection
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetDirection(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetDirection(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaFlexDirection FlexDirection
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetFlexDirection(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetFlexDirection(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaJustify JustifyContent
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetJustifyContent(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetJustifyContent(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaDisplay Display
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetDisplay(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetDisplay(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaAlign AlignItems
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetAlignItems(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetAlignItems(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaAlign AlignSelf
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetAlignSelf(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetAlignSelf(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaAlign AlignContent
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetAlignContent(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetAlignContent(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaPositionType PositionType
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetPositionType(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetPositionType(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaWrap Wrap
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetFlexWrap(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetFlexWrap(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public float Flex
|
|
{
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetFlex(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public float FlexGrow
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetFlexGrow(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetFlexGrow(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public float FlexShrink
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetFlexShrink(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetFlexShrink(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public YogaValue FlexBasis
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetFlexBasis(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetFlexBasisPercent(_ygNode, value.Value);
|
|
}
|
|
else if (value.Unit == YogaUnit.Auto)
|
|
{
|
|
Native.YGNodeStyleSetFlexBasisAuto(_ygNode);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetFlexBasis(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue Width
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetWidth(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetWidthPercent(_ygNode, value.Value);
|
|
}
|
|
else if (value.Unit == YogaUnit.Auto)
|
|
{
|
|
Native.YGNodeStyleSetWidthAuto(_ygNode);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetWidth(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue Height
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetHeight(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetHeightPercent(_ygNode, value.Value);
|
|
}
|
|
else if (value.Unit == YogaUnit.Auto)
|
|
{
|
|
Native.YGNodeStyleSetHeightAuto(_ygNode);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetHeight(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue MaxWidth
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetMaxWidth(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetMaxWidthPercent(_ygNode, value.Value);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetMaxWidth(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue MaxHeight
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetMaxHeight(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetMaxHeightPercent(_ygNode, value.Value);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetMaxHeight(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue MinWidth
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetMinWidth(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetMinWidthPercent(_ygNode, value.Value);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetMinWidth(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public YogaValue MinHeight
|
|
{
|
|
get
|
|
{
|
|
return YogaValue.MarshalValue(Native.YGNodeStyleGetMinHeight(_ygNode));
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value.Unit == YogaUnit.Percent)
|
|
{
|
|
Native.YGNodeStyleSetMinHeightPercent(_ygNode, value.Value);
|
|
}
|
|
else
|
|
{
|
|
Native.YGNodeStyleSetMinHeight(_ygNode, value.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public float AspectRatio
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetAspectRatio(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetAspectRatio(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public float LayoutX
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeLayoutGetLeft(_ygNode);
|
|
}
|
|
}
|
|
|
|
public float LayoutY
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeLayoutGetTop(_ygNode);
|
|
}
|
|
}
|
|
|
|
public float LayoutWidth
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeLayoutGetWidth(_ygNode);
|
|
}
|
|
}
|
|
|
|
public float LayoutHeight
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeLayoutGetHeight(_ygNode);
|
|
}
|
|
}
|
|
|
|
public YogaDirection LayoutDirection
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeLayoutGetDirection(_ygNode);
|
|
}
|
|
}
|
|
|
|
public YogaOverflow Overflow
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeStyleGetOverflow(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeStyleSetOverflow(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public object Data
|
|
{
|
|
get
|
|
{
|
|
return _data;
|
|
}
|
|
|
|
set
|
|
{
|
|
_data = value;
|
|
}
|
|
}
|
|
|
|
public YogaNode this[int index]
|
|
{
|
|
get
|
|
{
|
|
return _children[index];
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
return _children != null ? _children.Count : 0;
|
|
}
|
|
}
|
|
|
|
public void MarkLayoutSeen()
|
|
{
|
|
Native.YGNodeSetHasNewLayout(_ygNode, false);
|
|
}
|
|
|
|
public bool IsReferenceBaseline
|
|
{
|
|
get
|
|
{
|
|
return Native.YGNodeIsReferenceBaseline(_ygNode);
|
|
}
|
|
|
|
set
|
|
{
|
|
Native.YGNodeSetIsReferenceBaseline(_ygNode, value);
|
|
}
|
|
}
|
|
|
|
public bool ValuesEqual(float f1, float f2)
|
|
{
|
|
if (float.IsNaN(f1) || float.IsNaN(f2))
|
|
{
|
|
return float.IsNaN(f1) && float.IsNaN(f2);
|
|
}
|
|
|
|
return Math.Abs(f2 - f1) < float.Epsilon;
|
|
}
|
|
|
|
public void Insert(int index, YogaNode node)
|
|
{
|
|
if (_children == null)
|
|
{
|
|
_children = new List<YogaNode>(4);
|
|
}
|
|
_children.Insert(index, node);
|
|
node._parent = new WeakReference(this);
|
|
Native.YGNodeInsertChild(_ygNode, node._ygNode, (uint)index);
|
|
}
|
|
|
|
public void RemoveAt(int index)
|
|
{
|
|
var child = _children[index];
|
|
child._parent = null;
|
|
_children.RemoveAt(index);
|
|
Native.YGNodeRemoveChild(_ygNode, child._ygNode);
|
|
}
|
|
|
|
public void AddChild(YogaNode child)
|
|
{
|
|
Insert(Count, child);
|
|
}
|
|
|
|
public void RemoveChild(YogaNode child)
|
|
{
|
|
int index = IndexOf(child);
|
|
if (index >= 0)
|
|
{
|
|
RemoveAt(index);
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
if (_children != null)
|
|
{
|
|
while (_children.Count > 0)
|
|
{
|
|
RemoveAt(_children.Count-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int IndexOf(YogaNode node)
|
|
{
|
|
return _children != null ? _children.IndexOf(node) : -1;
|
|
}
|
|
|
|
public void SetMeasureFunction(MeasureFunction measureFunction)
|
|
{
|
|
_measureFunction = measureFunction;
|
|
_managedMeasure = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null;
|
|
Native.YGNodeSetMeasureFunc(_ygNode, _managedMeasure);
|
|
}
|
|
|
|
public void SetBaselineFunction(BaselineFunction baselineFunction)
|
|
{
|
|
_baselineFunction = baselineFunction;
|
|
_managedBaseline =
|
|
baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null;
|
|
Native.YGNodeSetBaselineFunc(_ygNode, _managedBaseline);
|
|
}
|
|
|
|
public void CalculateLayout(
|
|
float width = YogaConstants.Undefined,
|
|
float height = YogaConstants.Undefined)
|
|
{
|
|
Native.YGNodeCalculateLayout(
|
|
_ygNode,
|
|
width,
|
|
height,
|
|
Native.YGNodeStyleGetDirection(_ygNode));
|
|
}
|
|
|
|
#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__
|
|
[MonoPInvokeCallback(typeof(YogaMeasureFunc))]
|
|
#endif
|
|
private static YogaSize MeasureInternal(
|
|
IntPtr unmanagedNodePtr,
|
|
float width,
|
|
YogaMeasureMode widthMode,
|
|
float height,
|
|
YogaMeasureMode heightMode)
|
|
{
|
|
var node = YGNodeHandle.GetManaged(unmanagedNodePtr);
|
|
if (node == null || node._measureFunction == null)
|
|
{
|
|
throw new InvalidOperationException("Measure function is not defined.");
|
|
}
|
|
return node._measureFunction(node, width, widthMode, height, heightMode);
|
|
}
|
|
|
|
#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__
|
|
[MonoPInvokeCallback(typeof(YogaBaselineFunc))]
|
|
#endif
|
|
private static float BaselineInternal(
|
|
IntPtr unmanagedNodePtr,
|
|
float width,
|
|
float height)
|
|
{
|
|
var node = YGNodeHandle.GetManaged(unmanagedNodePtr);
|
|
if (node == null || node._baselineFunction == null)
|
|
{
|
|
throw new InvalidOperationException("Baseline function is not defined.");
|
|
}
|
|
return node._baselineFunction(node, width, height);
|
|
}
|
|
|
|
public string Print(YogaPrintOptions options =
|
|
YogaPrintOptions.Layout|YogaPrintOptions.Style|YogaPrintOptions.Children)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
Logger orig = _config.Logger;
|
|
_config.Logger = (config, node, level, message) => {sb.Append(message);};
|
|
Native.YGNodePrint(_ygNode, options);
|
|
_config.Logger = orig;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public IEnumerator<YogaNode> GetEnumerator()
|
|
{
|
|
return _children != null ? ((IEnumerable<YogaNode>)_children).GetEnumerator() :
|
|
System.Linq.Enumerable.Empty<YogaNode>().GetEnumerator();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return _children != null ? ((IEnumerable<YogaNode>)_children).GetEnumerator() :
|
|
System.Linq.Enumerable.Empty<YogaNode>().GetEnumerator();
|
|
}
|
|
|
|
public static int GetInstanceCount()
|
|
{
|
|
return Native.YGNodeGetInstanceCount();
|
|
}
|
|
}
|
|
}
|