-/* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+/* Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty FlexGrowProperty = BindableProperty.CreateAttached("FlexGrow", typeof(float), typeof(FlexLayout), FlexUndefined, validateValue: (bindable, value) => (float)value >= 0, propertyChanged: OnChildPropertyChanged);
- private static bool LayoutDebugFlex = false; // Debug flag
-
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
private bool swigCMemOwn;
private bool disposed;
private bool isDisposeQueued = false;
- private bool disposedThis = false;
private MeasureSpecification parentMeasureSpecificationWidth;
private MeasureSpecification parentMeasureSpecificationHeight;
- private IntPtr _rootFlex; // Pointer to the unmanged flex layout class.
+ private IntPtr _rootFlex; // Pointer to the unmanaged flex layout class.
internal const float FlexUndefined = 10E20F; // Auto setting which is equivalent to WrapContent.
[EditorBrowsable(EditorBrowsableState.Never)]
protected override void Dispose(bool disposing)
{
- if (disposedThis)
+ if (disposed)
{
return;
}
// TODO: dispose managed state (managed objects).
// Explicit call. user calls Dispose()
- //Throw excpetion if Dispose() is called in separate thread.
+ //Throw exception if Dispose() is called in separate thread.
if (!Window.IsInstalled())
{
throw new System.InvalidOperationException("This API called from separate thread. This API must be called from MainThread.");
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
- disposedThis = true;
base.Dispose(disposing);
}
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
- internal static FlexLayout DownCast(BaseHandle handle)
- {
- FlexLayout ret = new FlexLayout(Interop.FlexLayout.DownCast(BaseHandle.getCPtr(handle)), true);
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- return ret;
- }
-
- internal FlexLayout(FlexLayout other) : this(Interop.FlexLayout.NewFlexLayout(FlexLayout.getCPtr(other)), true)
- {
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
- }
-
internal FlexLayout.AlignmentType GetFlexAlignment()
{
FlexLayout.AlignmentType ret = (FlexLayout.AlignmentType)Interop.FlexLayout.GetFlexAlignment(swigCPtr);
get => (FlexJustification)Interop.FlexLayout.GetFlexJustification(swigCPtr);
set
{
- if (value < FlexJustification.FlexStart || value > FlexJustification.SpaceAround)
+ if (value < FlexJustification.FlexStart || value > FlexJustification.SpaceEvenly)
throw new InvalidEnumArgumentException(nameof(Justification));
Interop.FlexLayout.SetFlexJustification(swigCPtr, (int)value);
/// </summary>
SpaceBetween,
/// <summary>
+ /// Items are positioned with equal space before, and after the lines.<br/>
+ /// </summary>
+ SpaceAround,
+ /// <summary>
/// Items are positioned with equal space before, between, and after the lines.<br/>
- /// Compared to <see cref="FlexJustification.SpaceBetween"/> using <see cref="FlexJustification.SpaceAround"/>
- /// will result in space being distributed to the beginning of the first child and end of the last child.
+ /// Spaces are distributed equally to the beginning of the first child, between each child, and the end of the last child.
/// </summary>
- SpaceAround
+ /// <since_tizen> 9 </since_tizen>
+ SpaceEvenly
}
/// <summary>
// We need to measure child layout
View child = Registry.GetManagedBaseHandleFromNativePtr(childPtr) as View;
// independent child will be measured in LayoutGroup.OnMeasureIndependentChildren().
- if (child?.ExcludeLayouting ?? true)
+ if ((child == null) || (child?.ExcludeLayouting ?? true))
{
measureSize.width = 0;
measureSize.height = 0;
}
LayoutItem childLayout = child.Layout;
+ Extents margin = child.Margin;
MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
new MeasureSpecification(
- new LayoutLength(parentMeasureSpecificationWidth.Size - (child.Margin.Start + child.Margin.End)),
+ new LayoutLength(parentMeasureSpecificationWidth.Size - (margin.Start + margin.End)),
parentMeasureSpecificationWidth.Mode),
new LayoutLength(Padding.Start + Padding.End),
new LayoutLength(child.WidthSpecification));
MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
new MeasureSpecification(
- new LayoutLength(parentMeasureSpecificationHeight.Size - (child.Margin.Top + child.Margin.Bottom)),
+ new LayoutLength(parentMeasureSpecificationHeight.Size - (margin.Top + margin.Bottom)),
parentMeasureSpecificationHeight.Mode),
new LayoutLength(Padding.Top + Padding.Bottom),
new LayoutLength(child.HeightSpecification));
- childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ childLayout?.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
- measureSize.width = childLayout.MeasuredWidth.Size.AsRoundedValue();
- measureSize.height = childLayout.MeasuredHeight.Size.AsRoundedValue();
+ measureSize.width = (childLayout == null) ? 0 : childLayout.MeasuredWidth.Size.AsRoundedValue();
+ measureSize.height = (childLayout == null) ? 0 : childLayout.MeasuredHeight.Size.AsRoundedValue();
}
void InsertChild(LayoutItem child)
/// Callback when child is removed from container.<br />
/// </summary>
/// <param name="child">The Layout child.</param>
+ /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
/// <since_tizen> 6 </since_tizen>
protected override void OnChildRemove(LayoutItem child)
{
+ if (null == child)
+ {
+ throw new ArgumentNullException(nameof(child));
+ }
// When child View is removed from it's parent View (that is a Layout) then remove it from the layout too.
// FlexLayout refers to the child as a View not LayoutItem.
- Interop.FlexLayout.RemoveChild(swigCPtr, child);
+ Interop.FlexLayout.RemoveChild(swigCPtr, child.Owner.SwigCPtr);
}
/// <summary>
float width = FlexUndefined; // Behaves as WrapContent (Flex Auto)
float height = FlexUndefined; // Behaves as WrapContent (Flex Auto)
- if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || widthMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
+ if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
{
width = widthMeasureSpec.Size.AsDecimal();
}
- if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly || heightMeasureSpec.Mode == MeasureSpecification.ModeType.AtMost)
+ if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
{
height = heightMeasureSpec.Size.AsDecimal();
}
LayoutLength flexLayoutWidth = new LayoutLength(Interop.FlexLayout.GetWidth(swigCPtr));
LayoutLength flexLayoutHeight = new LayoutLength(Interop.FlexLayout.GetHeight(swigCPtr));
- Debug.WriteLineIf(LayoutDebugFlex, "FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue()
- + " height:" + flexLayoutHeight.AsRoundedValue());
+ NUILog.Debug("FlexLayout OnMeasure width:" + flexLayoutWidth.AsRoundedValue() + " height:" + flexLayoutHeight.AsRoundedValue());
SetMeasuredDimensions(GetDefaultSize(flexLayoutWidth, widthMeasureSpec),
GetDefaultSize(flexLayoutHeight, heightMeasureSpec));
{
// Get the frame for the child, start, top, end, bottom.
Vector4 frame = new Vector4(Interop.FlexLayout.GetNodeFrame(swigCPtr, childIndex), true);
+
+ // Child view's size is calculated in OnLayout() without considering child layout's measured size unlike other layouts' OnLayout().
+ // This causes that the grand child view's size is calculated incorrectly if the child and grand child have MatchParent Specification.
+ // e.g. Let parent view's width be 200 and parent has 2 children.
+ // Then, child layout's measured width becomes 200 and child view's width becomes 100. (by dali-toolkit's YOGA APIs)
+ // Then, grand child layout's measured width becomes 200 and grand child view's width becomes 200. (by NUI Layout)
+ //
+ // To resolve the above issue, child layout's measured size is set with the child view's size calculated by dali-toolkit's YOGA APIs.
+ MeasureSpecification widthSpec = new MeasureSpecification(new LayoutLength(frame.Z - frame.X), MeasureSpecification.ModeType.Exactly);
+ MeasureSpecification heightSpec = new MeasureSpecification(new LayoutLength(frame.W - frame.Y), MeasureSpecification.ModeType.Exactly);
+ MeasureChildWithoutPadding(childLayout, widthSpec, heightSpec);
+
childLayout.Layout(new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W));
+ frame.Dispose();
}
}
}