1 /* Copyright (c) 2020 Samsung Electronics Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 using System.ComponentModel;
19 using Tizen.NUI.BaseComponents;
20 using System.Collections.Generic;
26 /// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
28 public class LinearLayout : LayoutGroup
30 private Alignment linearAlignment = Alignment.Top;
33 /// [Draft] Enumeration for the direction in which the content is laid out
35 /// <since_tizen> 6 </since_tizen>
36 public enum Orientation
49 /// [Draft] Enumeration for the alignment of the linear layout items
51 /// <since_tizen> 6 </since_tizen>
52 [Obsolete("Deprecated in API9, will be removed in API11. Please use HorizontalAlignment and VerticalAlignment instead!")]
56 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
60 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
64 /// At the horizontal center of the container
66 CenterHorizontal = 0x4,
68 /// At the top edge of the container
72 /// At the bottom edge of the container
76 /// At the vertical center of the container
78 CenterVertical = 0x20,
80 /// At the vertical and horizontal center of the container
85 struct HeightAndWidthState
87 public MeasuredSize.StateType widthState;
88 public MeasuredSize.StateType heightState;
90 public HeightAndWidthState(MeasuredSize.StateType width, MeasuredSize.StateType height)
98 /// [Draft] Get/Set the orientation in the layout
100 /// <since_tizen> 6 </since_tizen>
101 public LinearLayout.Orientation LinearOrientation
105 return linearOrientation;
109 linearOrientation = value;
115 /// [Draft] Get/Set the padding between cells in the layout
117 /// <since_tizen> 6 </since_tizen>
118 public Size2D CellPadding
122 if (cellPadding == null)
124 cellPadding = new Size2D(0, 0);
138 /// [Draft] Get/Set the alignment in the layout
140 /// <since_tizen> 6 </since_tizen>
141 [Obsolete("Deprecated in API9, will be removed in API11. Please use HorizontalAlignment and VerticalAlignment properties instead!")]
142 public LinearLayout.Alignment LinearAlignment
146 return linearAlignment;
151 if (linearAlignment == value)
156 linearAlignment = value;
158 switch (linearAlignment)
160 case Alignment.Begin:
161 HorizontalAlignment = HorizontalAlignment.Begin;
164 HorizontalAlignment = HorizontalAlignment.End;
166 case Alignment.CenterHorizontal:
167 HorizontalAlignment = HorizontalAlignment.Center;
170 VerticalAlignment = VerticalAlignment.Top;
172 case Alignment.Bottom:
173 VerticalAlignment = VerticalAlignment.Bottom;
175 case Alignment.CenterVertical:
176 VerticalAlignment = VerticalAlignment.Center;
178 case Alignment.Center:
179 HorizontalAlignment = HorizontalAlignment.Center;
180 VerticalAlignment = VerticalAlignment.Center;
189 /// Get/Set the horizontal alignment in the layout
191 /// <since_tizen> 9 </since_tizen>
192 public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Begin;
195 /// Get/Set the vertical alignment in the layout
197 /// <since_tizen> 9 </since_tizen>
198 public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top;
200 private float totalLength = 0.0f;
201 private Size2D cellPadding = new Size2D(0, 0);
202 private Orientation linearOrientation = Orientation.Horizontal;
205 /// [Draft] Constructor
207 /// <since_tizen> 6 </since_tizen>
208 public LinearLayout()
213 /// Measure the layout and its content to determine the measured width and the measured height.
215 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
216 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
217 /// <since_tizen> 6 </since_tizen>
218 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
220 if (linearOrientation == Orientation.Horizontal)
222 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
226 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
231 /// Layout should assign a size and position to each of its children.<br />
233 /// <param name="changed">This is a new size or position for this layout.</param>
234 /// <param name="left">Left position, relative to parent.</param>
235 /// <param name="top"> Top position, relative to parent.</param>
236 /// <param name="right">Right position, relative to parent.</param>
237 /// <param name="bottom">Bottom position, relative to parent.</param>
238 /// <since_tizen> 6 </since_tizen>
239 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
241 if (linearOrientation == Orientation.Horizontal)
243 LayoutHorizontal(left, top, right, bottom);
247 LayoutVertical(left, top, right, bottom);
252 private void MeasureWeightedChild(LayoutItem childLayout, float totalWeightLength, float totalWeight, float childWeight,
253 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
254 HeightAndWidthState childState, Orientation orientation)
256 bool horizontal = false;
257 if (orientation == Orientation.Horizontal)
262 float childsShare = totalWeightLength * (childWeight / totalWeight);
263 float desiredWidth = childLayout.Owner.WidthSpecification;
264 float desiredHeight = childLayout.Owner.HeightSpecification;
266 MeasureSpecification childWidthMeasureSpec;
267 MeasureSpecification childHeightMeasureSpec;
271 childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Start + childLayout.Margin.End)), MeasureSpecification.ModeType.Exactly);
273 childHeightMeasureSpec = GetChildMeasureSpecification(
274 new MeasureSpecification(
275 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
276 heightMeasureSpec.Mode),
277 new LayoutLength(Padding.Top + Padding.Bottom),
278 new LayoutLength(desiredHeight));
282 childWidthMeasureSpec = GetChildMeasureSpecification(
283 new MeasureSpecification(
284 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
285 widthMeasureSpec.Mode),
286 new LayoutLength(Padding.Start + Padding.End),
287 new LayoutLength(desiredWidth));
289 childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Top + childLayout.Margin.Bottom)), MeasureSpecification.ModeType.Exactly);
292 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
294 // Child may now not fit in horizontal dimension.
295 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
297 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
300 // Child may now not fit in vertical dimension.
301 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
303 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
307 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
309 var widthMode = widthMeasureSpec.Mode;
310 var heightMode = heightMeasureSpec.Mode;
311 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
312 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
313 float maxHeight = 0.0f;
314 float totalWeight = 0.0f;
315 int childrenCount = IterateLayoutChildren().Count();
317 // Child layout, which wants to match its width to its parent's remaining width, is either following 1 or 2.
318 // 1. Child layout whose Owner.WidthSpecification is LayoutParamPolicies.MatchParent.
319 // 2. Child layout whose Owner.WidthSpecification is 0 and Owner.Weight is greater than 0.
320 // The number of child layout which wants to match its width to its parent's remaining width.
321 int childrenMatchParentCount = 0;
323 // Reset measure variable
326 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
327 MeasuredSize.StateType.MeasuredSizeOK);
331 // We measure all children whose width specification policy is WrapContent without weight.
332 // After 1st phase, remaining width of parent is accumulated to calculate width of children
333 // whose width specification policy is MatchParent.
334 foreach (var childLayout in LayoutChildren)
336 if (!childLayout.SetPositionByLayout)
340 int childDesiredWidth = childLayout.Owner.WidthSpecification;
341 int childDesiredHeight = childLayout.Owner.HeightSpecification;
342 float childWeight = childLayout.Owner.Weight;
343 Extents childMargin = childLayout.Margin;
344 float childMarginWidth = childMargin.Start + childMargin.End;
345 float childMarginHeight = childMargin.Top + childMargin.Bottom;
346 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
348 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
350 totalWeight += childWeight;
351 childrenMatchParentCount++;
354 // MatchParent child layout's margin is not added to totalLength.
355 // Consequently, MatchParent child layout's margin is added to remaining size,
356 // so the margin is not shared with other MatchParent child layouts.
358 // LinearLayout has size 100.
359 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
360 // Child layout2 is MatchParent and its margin is 0.
361 // Then, child layout1's size is 30 and child layout2's size is 50.
362 if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
364 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
366 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
368 if (childMeasuredWidth < 0)
370 totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
374 totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
378 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
380 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
382 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
384 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
387 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
388 if (childMeasuredHeight < 0)
390 maxHeight = Math.Max(maxHeight, childMarginHeight);
394 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
396 } // 1ST PHASE foreach
398 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
399 float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
400 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
401 widthSize = widthSizeAndState.Size.AsDecimal();
403 float remainingWidth = widthSize - totalLength;
404 float totalWeightLength = 0.0f;
406 // Up to now, only WrapContent children's sizes are added to the totalLength.
407 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
408 // the layout size is assigned to the totalLength if MatchParent child exists.
409 if (childrenMatchParentCount > 0)
411 totalLength = widthSize;
416 // We measure all children whose width specification policy is MatchParent without weight.
417 // After 2nd phase, all children's widths are calculated without considering weight.
418 // And the widths of all weighted children are accumulated to calculate weighted width.
419 foreach (var childLayout in LayoutChildren)
421 if (!childLayout.SetPositionByLayout)
425 int childDesiredWidth = childLayout.Owner.WidthSpecification;
426 int childDesiredHeight = childLayout.Owner.HeightSpecification;
427 float childWeight = childLayout.Owner.Weight;
428 Extents childMargin = childLayout.Margin;
429 float childMarginHeight = childMargin.Top + childMargin.Bottom;
430 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
431 bool needToMeasure = false;
433 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
437 needToMeasure = true;
439 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
440 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
441 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
443 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
444 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
446 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
448 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is MatchParent!");
452 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is 0 with positive weight!");
457 if (remainingWidth > 0)
459 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
463 // In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
464 // Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.Size before it is passed to MeasureChildWithMargins().
465 widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
466 needToMeasure = true;
468 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
469 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
470 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
472 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
473 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
475 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
477 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is MatchParent!");
481 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is 0 with positive weight!");
487 if (needToMeasure == true)
489 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
491 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
492 if (childMeasuredHeight < 0)
494 maxHeight = Math.Max(maxHeight, childMarginHeight);
498 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
502 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
504 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
506 if (childMeasuredWidth < 0)
508 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Start + childMargin.End);
512 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredWidth + childMargin.Start + childMargin.End);
515 } // 2ND PHASE foreach
519 // We measure all weighted children whose owner has weight greater than 0.
520 // After 3rd phase, all weighted children has width which is proportional to their weights
521 // in remaining width of parent.
522 if (totalWeight > 0.0f)
524 foreach (LayoutItem childLayout in LayoutChildren)
526 if (!childLayout.SetPositionByLayout)
530 int childDesiredWidth = childLayout.Owner.WidthSpecification;
531 float childWeight = childLayout.Owner.Weight;
533 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
537 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
538 widthMeasureSpec, heightMeasureSpec, childState,
539 Orientation.Horizontal);
541 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
542 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
543 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
545 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
546 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
548 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
550 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is MatchParent!");
554 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is 0 with positive weight!");
558 } // 3RD PHASE foreach
561 maxHeight = Math.Max(maxHeight, maxHeight + (Padding.Top + Padding.Bottom));
562 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
564 widthSizeAndState.State = childState.widthState;
566 SetMeasuredDimensions(widthSizeAndState,
567 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
568 } // MeasureHorizontal
570 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
572 var widthMode = widthMeasureSpec.Mode;
573 var heightMode = heightMeasureSpec.Mode;
574 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
575 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
576 float maxWidth = 0.0f;
577 float totalWeight = 0.0f;
578 int childrenCount = IterateLayoutChildren().Count();
580 // Child layout, which wants to match its height to its parent's remaining height, is either following 1 or 2.
581 // 1. Child layout whose Owner.HeightSpecification is LayoutParamPolicies.MatchParent.
582 // 2. Child layout whose Owner.HeightSpecification is 0 and Owner.Weight is greater than 0.
583 // The number of child layout which wants to match its height to its parent's remaining height.
584 int childrenMatchParentCount = 0;
586 // Reset measure variable
589 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
590 MeasuredSize.StateType.MeasuredSizeOK);
594 // We measure all children whose height specification policy is WrapContent without weight.
595 // After 1st phase, remaining height of parent is accumulated to calculate height of children
596 // whose height specification policy is MatchParent.
597 foreach (var childLayout in LayoutChildren)
599 if (!childLayout.SetPositionByLayout)
603 int childDesiredWidth = childLayout.Owner.WidthSpecification;
604 int childDesiredHeight = childLayout.Owner.HeightSpecification;
605 float childWeight = childLayout.Owner.Weight;
606 Extents childMargin = childLayout.Margin;
607 float childMarginWidth = childMargin.Start + childMargin.End;
608 float childMarginHeight = childMargin.Top + childMargin.Bottom;
609 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
611 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
613 totalWeight += childWeight;
614 childrenMatchParentCount++;
617 // MatchParent child layout's margin is not added to totalLength.
618 // Consequently, MatchParent child layout's margin is added to remaining size,
619 // so the margin is not shared with other MatchParent child layouts.
621 // LinearLayout has size 100.
622 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
623 // Child layout2 is MatchParent and its margin is 0.
624 // Then, child layout1's size is 30 and child layout2's size is 50.
625 if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight > 0) && (!useRemainingHeight)))
627 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
629 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
631 if (childMeasuredHeight < 0)
633 totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
637 totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
641 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
643 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
645 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
647 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
650 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
651 if (childMeasuredWidth < 0)
653 maxWidth = Math.Max(maxWidth, childMarginWidth);
657 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
659 } // 1ST PHASE foreach
661 totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
662 float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
663 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
664 heightSize = heightSizeAndState.Size.AsDecimal();
666 float remainingHeight = heightSize - totalLength;
667 float totalWeightLength = 0.0f;
669 // Up to now, only WrapContent children's sizes are added to the totalLength.
670 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
671 // the layout size is assigned to the totalLength if MatchParent child exists.
672 if (childrenMatchParentCount > 0)
674 totalLength = heightSize;
679 // We measure all children whose height specification policy is MatchParent without weight.
680 // After 2nd phase, all children's heights are calculated without considering weight.
681 // And the heights of all weighted children are accumulated to calculate weighted height.
682 foreach (var childLayout in LayoutChildren)
684 if (!childLayout.SetPositionByLayout)
688 int childDesiredWidth = childLayout.Owner.WidthSpecification;
689 int childDesiredHeight = childLayout.Owner.HeightSpecification;
690 float childWeight = childLayout.Owner.Weight;
691 Extents childMargin = childLayout.Margin;
692 float childMarginWidth = childMargin.Start + childMargin.End;
693 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
694 bool needToMeasure = false;
696 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
700 needToMeasure = true;
702 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
703 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
704 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
706 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
707 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
709 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
711 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is MatchParent!");
715 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s WidthSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s WidthSpecification is 0 with positive weight!");
720 if (remainingHeight > 0)
722 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
726 // In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
727 // Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.Size before it is passed to MeasureChildWithMargins().
728 heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
729 needToMeasure = true;
731 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
732 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
733 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
735 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
736 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
738 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
740 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is MatchParent!");
744 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is 0 with positive weight!");
750 if (needToMeasure == true)
752 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
754 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
755 if (childMeasuredWidth < 0)
757 maxWidth = Math.Max(maxWidth, childMarginWidth);
761 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
765 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
767 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
769 if (childMeasuredHeight < 0)
771 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Top + childMargin.Bottom);
775 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredHeight + childMargin.Top + childMargin.Bottom);
778 } // 2ND PHASE foreach
782 // We measure all weighted children whose owner has weight greater than 0.
783 // After 3rd phase, all weighted children has height which is proportional to their weights
784 // in remaining height of parent.
787 foreach (var childLayout in LayoutChildren)
789 if (!childLayout.SetPositionByLayout)
793 int childDesiredHeight = childLayout.Owner.HeightSpecification;
794 float childWeight = childLayout.Owner.Weight;
796 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
800 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
801 widthMeasureSpec, heightMeasureSpec, childState,
802 Orientation.Vertical);
804 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
805 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
806 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
808 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
809 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
811 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
813 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is MatchParent!");
817 Tizen.Log.Error("NUI", "There is a recursive reference! Parent layout(Owner: " + Owner + ")'s HeightSpecification is WrapContent and child layout(Owner: " + childLayout.Owner + ")'s HeightSpecification is 0 with positive weight!");
821 } // 3RD PHASE foreach
824 maxWidth = Math.Max(maxWidth, maxWidth + (Padding.Start + Padding.End));
825 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
827 heightSizeAndState.State = childState.heightState;
829 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
833 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
835 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
837 LayoutLength childTop = new LayoutLength(Padding.Top);
838 LayoutLength childLeft = new LayoutLength(Padding.Start);
840 // Where bottom of child should go
841 LayoutLength height = new LayoutLength(bottom - top);
843 // Space available for child
844 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
846 var LinearChildren = IterateLayoutChildren();
847 int count = LinearChildren.Count<LayoutItem>();
849 switch (HorizontalAlignment)
851 case HorizontalAlignment.End:
852 // totalLength contains the padding already
853 // In case of RTL map END alignment to the left edge
856 childLeft = new LayoutLength(Padding.Start);
860 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
863 case HorizontalAlignment.Center:
864 // totalLength contains the padding already
865 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f);
867 case HorizontalAlignment.Begin: // FALL THROUGH (default)
869 // totalLength contains the padding already
870 // In case of RTL map BEGIN alignment to the right edge
873 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
877 childLeft = new LayoutLength(Padding.Start);
885 // In case of RTL, start drawing from the last child.
892 for (int i = 0; i < count; i++)
894 int childIndex = start + dir * i;
895 // Get a reference to the childLayout at the given index
896 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
898 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
899 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
900 Extents childMargin = childLayout.Margin;
902 switch (VerticalAlignment)
904 case VerticalAlignment.Bottom:
905 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
907 case VerticalAlignment.Center:
908 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
910 case VerticalAlignment.Top: // FALLTHROUGH default
912 childTop = new LayoutLength(Padding.Top + childMargin.Top);
915 childLeft += (isLayoutRtl ? childMargin.End : childMargin.Start);
916 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
917 childLeft += childWidth + (isLayoutRtl ? childMargin.Start : childMargin.End) + ((i < count - 1) ? CellPadding.Width : 0);
919 } // LayoutHorizontally
921 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
923 LayoutLength childTop = new LayoutLength(Padding.Top);
924 LayoutLength childLeft = new LayoutLength(Padding.Start);
926 // Where end of child should go
927 LayoutLength width = new LayoutLength(right - left);
929 // Space available for child
930 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
932 var LinearChildren = IterateLayoutChildren();
933 int count = LinearChildren.Count<LayoutItem>();
935 switch (VerticalAlignment)
937 case VerticalAlignment.Bottom:
938 // totalLength contains the padding already
939 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength);
941 case VerticalAlignment.Center:
942 // totalLength contains the padding already
943 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f);
945 case VerticalAlignment.Top: // FALL THROUGH (default)
947 // totalLength contains the padding already
948 childTop = new LayoutLength(Padding.Top);
952 for (int i = 0; i < count; i++)
954 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
956 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
957 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
958 Extents childMargin = childLayout.Margin;
960 childTop += childMargin.Top;
961 switch (HorizontalAlignment)
963 case HorizontalAlignment.Begin:
966 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
969 case HorizontalAlignment.End:
971 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
974 case HorizontalAlignment.Center:
976 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
980 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
981 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
985 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
987 // Pretend that the linear layout has an exact size. This is the measured height of
988 // ourselves. The measured height should be the max height of the children, changed
989 // to accommodate the heightMeasureSpec from the parent
990 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
991 foreach (var childLayout in LayoutChildren)
993 if (!childLayout.SetPositionByLayout)
997 int desiredChildHeight = childLayout.Owner.HeightSpecification;
998 int desiredChildWidth = childLayout.Owner.WidthSpecification;
1000 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
1002 // Temporarily force children to reuse their original measured width
1003 int originalWidth = desiredChildWidth;
1004 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
1005 // Remeasure with new dimensions
1006 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
1007 uniformMeasureSpec, new LayoutLength(0));
1008 // Restore width specification
1009 childLayout.Owner.WidthSpecification = originalWidth;