Skip to content

Commit 7cf1462

Browse files
committed
[NUI] Fix LinearLayout to support negative CellPadding
LinearLayout is fixed to support negative CellPadding. If LinearLayout items are overlapped by negative CellPadding, then LinearLayout size becomes smaller to bound its items. e.g. LinearLayout has Wrap size, Item size is 100, CellPadding is -50. If negative CellPadding's absolute value is bigger than item size, then items may be displayed outside of LinearLayout. In this case, LinearLayout size bounds its items but items may not be inside the LinearLayout. e.g. LinearLayout has Wrap size, Item size is 100, CellPadding is -200.
1 parent 1eca014 commit 7cf1462

File tree

1 file changed

+58
-18
lines changed

1 file changed

+58
-18
lines changed

src/Tizen.NUI/src/public/Layouting/LinearLayout.cs

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpe
343343
// We measure all children whose width specification policy is WrapContent without weight.
344344
// After 1st phase, remaining width of parent is accumulated to calculate width of children
345345
// whose width specification policy is MatchParent.
346+
widthSpecSize = widthMeasureSpec.GetSize().AsDecimal();
347+
float lastEnd = 0f;
348+
float beginBound = 0f;
349+
float endBound = 0f;
346350
foreach (var childLayout in LayoutChildren)
347351
{
348352
if (!childLayout.SetPositionByLayout || !(childLayout.Owner.Visibility))
@@ -372,21 +376,26 @@ private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpe
372376
// Then, child layout1's size is 30 and child layout2's size is 50.
373377
if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
374378
{
375-
var measurableWidth = Math.Max(widthMeasureSpec.GetSize().AsDecimal() - (totalLength + CellPadding.Width * childrenWrapContentCount), 0);
379+
var lastEndPlusCellPadding = lastEnd + (childrenWrapContentCount == 0 ? 0 : CellPadding.Width);
380+
var measurableWidth = Math.Max(Math.Min(widthSpecSize, widthSpecSize - lastEndPlusCellPadding), 0);
376381
var measurableWidthSpec = new MeasureSpecification(new LayoutLength(measurableWidth), widthMeasureSpec.GetMode());
377382
MeasureChildWithMargins(childLayout, measurableWidthSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
378383

379384
float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
380385

386+
beginBound = Math.Min(beginBound, lastEndPlusCellPadding);
387+
381388
if (childMeasuredWidth < 0)
382389
{
383-
totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
390+
lastEnd = lastEndPlusCellPadding + childMarginWidth;
384391
}
385392
else
386393
{
387-
totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
394+
lastEnd = lastEndPlusCellPadding + childMeasuredWidth + childMarginWidth;
388395
}
389396

397+
endBound = Math.Max(endBound, lastEnd);
398+
390399
childrenWrapContentCount++;
391400
}
392401

@@ -400,14 +409,18 @@ private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpe
400409
}
401410
} // 1ST PHASE foreach
402411

403-
totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
412+
// If childrenWrapContentCount is less than 2, then CellPadding is not added to endBound and beginBound.
413+
// So Math.Max(childrenWrapContentCount - 1, 0) is used to be multiplied to CellPadding.
414+
totalLength = endBound - beginBound + CellPadding.Width * (childrenCount - 1 - Math.Max(childrenWrapContentCount - 1, 0));
415+
totalLength = Math.Max(totalLength, totalLength + Padding.Start + Padding.End);
404416
float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
405417
MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
406418
widthSize = widthSizeAndState.Size.AsDecimal();
407419

408420
float remainingWidth = widthSize - totalLength;
409421
float totalWeightLength = 0.0f;
410422

423+
var childWidthMeasureSpec = new MeasureSpecification(widthMeasureSpec.GetSize(), widthMeasureSpec.GetMode());
411424
if (remainingWidth > 0)
412425
{
413426
// 2ND PHASE:
@@ -434,7 +447,9 @@ private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpe
434447
{
435448
// In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
436449
// Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.GetSize() before it is passed to MeasureChildWithMargins().
437-
widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
450+
// If CellPadding is very big negative value, then remaining / childrenMatchParentCount may exceed constraint.
451+
// So use the minimum between constraint and remaining / childrenMatchParentCount + padding.
452+
childWidthMeasureSpec.SetSize(new LayoutLength(Math.Min(widthMeasureSpec.GetSize().AsDecimal(), (int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End)));
438453
needToMeasure = true;
439454
}
440455
// RelativeLayout's MatchParent children should not fill to the RelativeLayout.
@@ -457,7 +472,7 @@ private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpe
457472

458473
if (needToMeasure == true)
459474
{
460-
MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
475+
MeasureChildWithMargins(childLayout, childWidthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
461476
}
462477

463478
if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
@@ -593,6 +608,10 @@ private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpeci
593608
// We measure all children whose height specification policy is WrapContent without weight.
594609
// After 1st phase, remaining height of parent is accumulated to calculate height of children
595610
// whose height specification policy is MatchParent.
611+
heightSpecSize = heightMeasureSpec.GetSize().AsDecimal();
612+
float lastEnd = 0f;
613+
float beginBound = 0f;
614+
float endBound = 0f;
596615
foreach (var childLayout in LayoutChildren)
597616
{
598617
if (!childLayout.SetPositionByLayout || !(childLayout.Owner.Visibility))
@@ -622,21 +641,26 @@ private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpeci
622641
// Then, child layout1's size is 30 and child layout2's size is 50.
623642
if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight >= 0) && (!useRemainingHeight)))
624643
{
625-
var measurableHeight = Math.Max(heightMeasureSpec.GetSize().AsDecimal() - (totalLength + CellPadding.Height * childrenWrapContentCount), 0);
644+
var lastEndPlusCellPadding = lastEnd + (childrenWrapContentCount == 0 ? 0 : CellPadding.Height);
645+
var measurableHeight = Math.Max(Math.Min(heightSpecSize, heightSpecSize - lastEndPlusCellPadding), 0);
626646
var measurableHeightSpec = new MeasureSpecification(new LayoutLength(measurableHeight), heightMeasureSpec.GetMode());
627647
MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), measurableHeightSpec, new LayoutLength(0));
628648

629649
float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
630650

651+
beginBound = Math.Min(beginBound, lastEndPlusCellPadding);
652+
631653
if (childMeasuredHeight < 0)
632654
{
633-
totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
655+
lastEnd = lastEndPlusCellPadding + childMarginHeight;
634656
}
635657
else
636658
{
637-
totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
659+
lastEnd = lastEndPlusCellPadding + childMeasuredHeight + childMarginHeight;
638660
}
639661

662+
endBound = Math.Max(endBound, lastEnd);
663+
640664
childrenWrapContentCount++;
641665
}
642666

@@ -650,14 +674,18 @@ private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpeci
650674
}
651675
} // 1ST PHASE foreach
652676

653-
totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
677+
// If childrenWrapContentCount is less than 2, then CellPadding is not added to endBound and beginBound.
678+
// So Math.Max(childrenWrapContentCount - 1, 0) is used to be multiplied to CellPadding.
679+
totalLength = endBound - beginBound + CellPadding.Height * (childrenCount - 1 - Math.Max(childrenWrapContentCount - 1, 0));
680+
totalLength = Math.Max(totalLength, totalLength + Padding.Top + Padding.Bottom);
654681
float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
655682
MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
656683
heightSize = heightSizeAndState.Size.AsDecimal();
657684

658685
float remainingHeight = heightSize - totalLength;
659686
float totalWeightLength = 0.0f;
660687

688+
var childHeightMeasureSpec = new MeasureSpecification(heightMeasureSpec.GetSize(), heightMeasureSpec.GetMode());
661689
if (remainingHeight > 0)
662690
{
663691
// 2ND PHASE:
@@ -684,7 +712,9 @@ private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpeci
684712
{
685713
// In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
686714
// Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.GetSize() before it is passed to MeasureChildWithMargins().
687-
heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
715+
// If CellPadding is very big negative value, then remaining / childrenMatchParentCount may exceed constraint.
716+
// So use the minimum between constraint and remaining / childrenMatchParentCount + padding.
717+
childHeightMeasureSpec.SetSize(new LayoutLength(Math.Min(heightMeasureSpec.GetSize().AsDecimal(), (int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom)));
688718
needToMeasure = true;
689719
}
690720
// RelativeLayout's MatchParent children should not fill to the RelativeLayout.
@@ -707,7 +737,7 @@ private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpeci
707737

708738
if (needToMeasure == true)
709739
{
710-
MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
740+
MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), childHeightMeasureSpec, new LayoutLength(0));
711741
}
712742

713743
if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
@@ -819,7 +849,9 @@ private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength
819849
var LinearChildren = IterateLayoutChildren();
820850
int count = LinearChildren.Count();
821851

822-
float totalLength = 0;
852+
float lastEnd = 0f;
853+
float beginBound = 0f;
854+
float endBound = 0f;
823855
int validChildCount = 0;
824856
foreach (var childLayout in LayoutChildren)
825857
{
@@ -831,11 +863,14 @@ private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength
831863
var childWidthSize = childLayout.MeasuredWidth.Size.AsDecimal();
832864
if (childWidthSize > 0)
833865
{
866+
var lastEndPlusCellPadding = lastEnd + (validChildCount == 0 ? 0 : CellPadding.Width);
867+
beginBound = Math.Min(beginBound, lastEndPlusCellPadding);
868+
lastEnd = lastEndPlusCellPadding + childWidthSize + childLayout.Margin.Start + childLayout.Margin.End;
869+
endBound = Math.Max(endBound, lastEnd);
834870
validChildCount++;
835-
totalLength += childWidthSize + childLayout.Margin.Start + childLayout.Margin.End;
836871
}
837872
}
838-
totalLength += CellPadding.Width * (validChildCount - 1);
873+
float totalLength = endBound - beginBound;
839874

840875
var leftPadding = isLayoutRtl ? Padding.End : Padding.Start;
841876

@@ -933,7 +968,9 @@ private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength ri
933968
var LinearChildren = IterateLayoutChildren();
934969
int count = LinearChildren.Count<LayoutItem>();
935970

936-
float totalLength = 0;
971+
float lastEnd = 0f;
972+
float beginBound = 0f;
973+
float endBound = 0f;
937974
int validChildCount = 0;
938975
foreach (var childLayout in LayoutChildren)
939976
{
@@ -945,11 +982,14 @@ private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength ri
945982
var childHeightSize = childLayout.MeasuredHeight.Size.AsDecimal();
946983
if (childHeightSize > 0)
947984
{
985+
var lastEndPlusCellPadding = lastEnd + (validChildCount == 0 ? 0 : CellPadding.Height);
986+
beginBound = Math.Min(beginBound, lastEndPlusCellPadding);
987+
lastEnd = lastEndPlusCellPadding + childHeightSize + childLayout.Margin.Top + childLayout.Margin.Bottom;
988+
endBound = Math.Max(endBound, lastEnd);
948989
validChildCount++;
949-
totalLength += childHeightSize + childLayout.Margin.Top + childLayout.Margin.Bottom;
950990
}
951991
}
952-
totalLength += CellPadding.Height * (validChildCount - 1);
992+
float totalLength = endBound - beginBound;
953993

954994
switch (VerticalAlignment)
955995
{

0 commit comments

Comments
 (0)