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>
55 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
59 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
63 /// At the horizontal center of the container
65 CenterHorizontal = 0x4,
67 /// At the top edge of the container
71 /// At the bottom edge of the container
75 /// At the vertical center of the container
77 CenterVertical = 0x20,
79 /// At the vertical and horizontal center of the container
84 struct HeightAndWidthState
86 public MeasuredSize.StateType widthState;
87 public MeasuredSize.StateType heightState;
89 public HeightAndWidthState(MeasuredSize.StateType width, MeasuredSize.StateType height)
97 /// [Draft] Get/Set the orientation in the layout
99 /// <since_tizen> 6 </since_tizen>
100 public LinearLayout.Orientation LinearOrientation
104 return linearOrientation;
108 linearOrientation = value;
114 /// [Draft] Get/Set the padding between cells in the layout
116 /// <since_tizen> 6 </since_tizen>
117 public Size2D CellPadding
121 if (cellPadding == null)
123 cellPadding = new Size2D(0, 0);
137 /// [Draft] Get/Set the alignment in the layout
139 /// <since_tizen> 6 </since_tizen>
140 public LinearLayout.Alignment LinearAlignment
144 return linearAlignment;
149 if (linearAlignment == value)
154 linearAlignment = value;
156 switch (linearAlignment)
158 case Alignment.Begin:
159 HorizontalAlignment = HorizontalAlignment.Begin;
162 HorizontalAlignment = HorizontalAlignment.End;
164 case Alignment.CenterHorizontal:
165 HorizontalAlignment = HorizontalAlignment.Center;
168 VerticalAlignment = VerticalAlignment.Top;
170 case Alignment.Bottom:
171 VerticalAlignment = VerticalAlignment.Bottom;
173 case Alignment.CenterVertical:
174 VerticalAlignment = VerticalAlignment.Center;
176 case Alignment.Center:
177 HorizontalAlignment = HorizontalAlignment.Center;
178 VerticalAlignment = VerticalAlignment.Center;
187 /// Get/Set the horizontal alignment in the layout
189 [EditorBrowsable(EditorBrowsableState.Never)]
190 public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Begin;
193 /// Get/Set the vertical alignment in the layout
195 [EditorBrowsable(EditorBrowsableState.Never)]
196 public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top;
198 private float totalLength = 0.0f;
199 private Size2D cellPadding = new Size2D(0, 0);
200 private Orientation linearOrientation = Orientation.Horizontal;
203 /// [Draft] Constructor
205 /// <since_tizen> 6 </since_tizen>
206 public LinearLayout()
211 /// Measure the layout and its content to determine the measured width and the measured height.
213 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
214 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
215 /// <since_tizen> 6 </since_tizen>
216 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
218 if (linearOrientation == Orientation.Horizontal)
220 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
224 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
229 /// Layout should assign a size and position to each of its children.<br />
231 /// <param name="changed">This is a new size or position for this layout.</param>
232 /// <param name="left">Left position, relative to parent.</param>
233 /// <param name="top"> Top position, relative to parent.</param>
234 /// <param name="right">Right position, relative to parent.</param>
235 /// <param name="bottom">Bottom position, relative to parent.</param>
236 /// <since_tizen> 6 </since_tizen>
237 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
239 if (linearOrientation == Orientation.Horizontal)
241 LayoutHorizontal(left, top, right, bottom);
245 LayoutVertical(left, top, right, bottom);
250 private void MeasureWeightedChild(LayoutItem childLayout, float totalWeightLength, float totalWeight, float childWeight,
251 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
252 HeightAndWidthState childState, Orientation orientation)
254 bool horizontal = false;
255 if (orientation == Orientation.Horizontal)
260 float childsShare = totalWeightLength * (childWeight / totalWeight);
261 float desiredWidth = childLayout.Owner.WidthSpecification;
262 float desiredHeight = childLayout.Owner.HeightSpecification;
264 MeasureSpecification childWidthMeasureSpec;
265 MeasureSpecification childHeightMeasureSpec;
269 childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Start + childLayout.Margin.End)), MeasureSpecification.ModeType.Exactly);
271 childHeightMeasureSpec = GetChildMeasureSpecification(
272 new MeasureSpecification(
273 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
274 heightMeasureSpec.Mode),
275 new LayoutLength(Padding.Top + Padding.Bottom),
276 new LayoutLength(desiredHeight));
280 childWidthMeasureSpec = GetChildMeasureSpecification(
281 new MeasureSpecification(
282 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
283 widthMeasureSpec.Mode),
284 new LayoutLength(Padding.Start + Padding.End),
285 new LayoutLength(desiredWidth));
287 childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Top + childLayout.Margin.Bottom)), MeasureSpecification.ModeType.Exactly);
290 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
292 // Child may now not fit in horizontal dimension.
293 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
295 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
298 // Child may now not fit in vertical dimension.
299 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
301 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
305 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
307 var widthMode = widthMeasureSpec.Mode;
308 var heightMode = heightMeasureSpec.Mode;
309 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
310 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
311 float maxHeight = 0.0f;
312 float totalWeight = 0.0f;
313 int childrenCount = IterateLayoutChildren().Count();
315 // Child layout, which wants to match its width to its parent's remaining width, is either following 1 or 2.
316 // 1. Child layout whose Owner.WidthSpecification is LayoutParamPolicies.MatchParent.
317 // 2. Child layout whose Owner.WidthSpecification is 0 and Owner.Weight is greater than 0.
318 // The number of child layout which wants to match its width to its parent's remaining width.
319 int childrenMatchParentCount = 0;
321 // Reset measure variable
324 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
325 MeasuredSize.StateType.MeasuredSizeOK);
329 // We measure all children whose width specification policy is WrapContent without weight.
330 // After 1st phase, remaining width of parent is accumulated to calculate width of children
331 // whose width specification policy is MatchParent.
332 foreach (var childLayout in LayoutChildren)
334 if (!childLayout.SetPositionByLayout)
338 int childDesiredWidth = childLayout.Owner.WidthSpecification;
339 int childDesiredHeight = childLayout.Owner.HeightSpecification;
340 float childWeight = childLayout.Owner.Weight;
341 Extents childMargin = childLayout.Margin;
342 float childMarginWidth = childMargin.Start + childMargin.End;
343 float childMarginHeight = childMargin.Top + childMargin.Bottom;
344 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
346 totalWeight += childWeight;
348 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
350 childrenMatchParentCount++;
353 // MatchParent child layout's margin is not added to totalLength.
354 // Consequently, MatchParent child layout's margin is added to remaining size,
355 // so the margin is not shared with other MatchParent child layouts.
357 // LinearLayout has size 100.
358 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
359 // Child layout2 is MatchParent and its margin is 0.
360 // Then, child layout1's size is 30 and child layout2's size is 50.
361 if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
363 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
365 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
367 if (childMeasuredWidth < 0)
369 totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
373 totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
377 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
379 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
381 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
383 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
386 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
387 if (childMeasuredHeight < 0)
389 maxHeight = Math.Max(maxHeight, childMarginHeight);
393 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
395 } // 1ST PHASE foreach
397 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
398 float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
399 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
400 widthSize = widthSizeAndState.Size.AsDecimal();
402 float remainingWidth = widthSize - totalLength;
403 float totalWeightLength = 0.0f;
405 // Up to now, only WrapContent children's sizes are added to the totalLength.
406 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
407 // the layout size is assigned to the totalLength if MatchParent child exists.
408 if (childrenMatchParentCount > 0)
410 totalLength = widthSize;
415 // We measure all children whose width specification policy is MatchParent without weight.
416 // After 2nd phase, all children's widths are calculated without considering weight.
417 // And the widths of all weighted children are accumulated to calculate weighted width.
418 foreach (var childLayout in LayoutChildren)
420 if (!childLayout.SetPositionByLayout)
424 int childDesiredWidth = childLayout.Owner.WidthSpecification;
425 int childDesiredHeight = childLayout.Owner.HeightSpecification;
426 float childWeight = childLayout.Owner.Weight;
427 Extents childMargin = childLayout.Margin;
428 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
429 bool needToMeasure = false;
431 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
435 needToMeasure = true;
437 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
438 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
439 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
441 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
442 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
444 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
446 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!");
450 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!");
455 if (remainingWidth > 0)
457 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
461 // In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
462 // Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.Size before it is passed to MeasureChildWithMargins().
463 widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
464 needToMeasure = true;
466 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
467 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
468 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
470 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
471 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
473 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
475 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!");
479 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!");
485 if (needToMeasure == true)
487 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
491 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
493 if (childMeasuredWidth < 0)
495 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Start + childMargin.End);
499 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredWidth + childMargin.Start + childMargin.End);
503 } // 2ND PHASE foreach
507 // We measure all weighted children whose owner has weight greater than 0.
508 // After 3rd phase, all weighted children has width which is proportional to their weights
509 // in remaining width of parent.
510 if (totalWeight > 0.0f)
512 foreach (LayoutItem childLayout in LayoutChildren)
514 if (!childLayout.SetPositionByLayout)
518 int childDesiredWidth = childLayout.Owner.WidthSpecification;
519 float childWeight = childLayout.Owner.Weight;
521 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
525 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
526 widthMeasureSpec, heightMeasureSpec, childState,
527 Orientation.Horizontal);
529 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
530 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
531 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
533 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
534 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
536 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
538 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!");
542 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!");
546 } // 3RD PHASE foreach
549 maxHeight = Math.Max(maxHeight, maxHeight + (Padding.Top + Padding.Bottom));
550 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
552 widthSizeAndState.State = childState.widthState;
554 SetMeasuredDimensions(widthSizeAndState,
555 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
556 } // MeasureHorizontal
558 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
560 var widthMode = widthMeasureSpec.Mode;
561 var heightMode = heightMeasureSpec.Mode;
562 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
563 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
564 float maxWidth = 0.0f;
565 float totalWeight = 0.0f;
566 int childrenCount = IterateLayoutChildren().Count();
568 // Child layout, which wants to match its height to its parent's remaining height, is either following 1 or 2.
569 // 1. Child layout whose Owner.HeightSpecification is LayoutParamPolicies.MatchParent.
570 // 2. Child layout whose Owner.HeightSpecification is 0 and Owner.Weight is greater than 0.
571 // The number of child layout which wants to match its height to its parent's remaining height.
572 int childrenMatchParentCount = 0;
574 // Reset measure variable
577 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
578 MeasuredSize.StateType.MeasuredSizeOK);
582 // We measure all children whose height specification policy is WrapContent without weight.
583 // After 1st phase, remaining height of parent is accumulated to calculate height of children
584 // whose height specification policy is MatchParent.
585 foreach (var childLayout in LayoutChildren)
587 if (!childLayout.SetPositionByLayout)
591 int childDesiredWidth = childLayout.Owner.WidthSpecification;
592 int childDesiredHeight = childLayout.Owner.HeightSpecification;
593 float childWeight = childLayout.Owner.Weight;
594 Extents childMargin = childLayout.Margin;
595 float childMarginWidth = childMargin.Start + childMargin.End;
596 float childMarginHeight = childMargin.Top + childMargin.Bottom;
597 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
599 totalWeight += childWeight;
601 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
603 childrenMatchParentCount++;
606 // MatchParent child layout's margin is not added to totalLength.
607 // Consequently, MatchParent child layout's margin is added to remaining size,
608 // so the margin is not shared with other MatchParent child layouts.
610 // LinearLayout has size 100.
611 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
612 // Child layout2 is MatchParent and its margin is 0.
613 // Then, child layout1's size is 30 and child layout2's size is 50.
614 if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight > 0) && (!useRemainingHeight)))
616 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
618 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
620 if (childMeasuredHeight < 0)
622 totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
626 totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
630 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
632 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
634 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
636 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
639 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
640 if (childMeasuredWidth < 0)
642 maxWidth = Math.Max(maxWidth, childMarginWidth);
646 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
648 } // 1ST PHASE foreach
650 totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
651 float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
652 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
653 heightSize = heightSizeAndState.Size.AsDecimal();
655 float remainingHeight = heightSize - totalLength;
656 float totalWeightLength = 0.0f;
658 // Up to now, only WrapContent children's sizes are added to the totalLength.
659 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
660 // the layout size is assigned to the totalLength if MatchParent child exists.
661 if (childrenMatchParentCount > 0)
663 totalLength = heightSize;
668 // We measure all children whose height specification policy is MatchParent without weight.
669 // After 2nd phase, all children's heights are calculated without considering weight.
670 // And the heights of all weighted children are accumulated to calculate weighted height.
671 foreach (var childLayout in LayoutChildren)
673 if (!childLayout.SetPositionByLayout)
677 int childDesiredWidth = childLayout.Owner.WidthSpecification;
678 int childDesiredHeight = childLayout.Owner.HeightSpecification;
679 float childWeight = childLayout.Owner.Weight;
680 Extents childMargin = childLayout.Margin;
681 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
682 bool needToMeasure = false;
684 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
688 needToMeasure = true;
690 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
691 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
692 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
694 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
695 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
697 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
699 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!");
703 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!");
708 if (remainingHeight > 0)
710 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
714 // In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
715 // Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.Size before it is passed to MeasureChildWithMargins().
716 heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
717 needToMeasure = true;
719 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
720 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
721 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
723 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
724 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
726 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
728 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!");
732 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!");
738 if (needToMeasure == true)
740 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
745 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
747 if (childMeasuredHeight < 0)
749 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Top + childMargin.Bottom);
753 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredHeight + childMargin.Top + childMargin.Bottom);
756 } // 2ND PHASE foreach
760 // We measure all weighted children whose owner has weight greater than 0.
761 // After 3rd phase, all weighted children has height which is proportional to their weights
762 // in remaining height of parent.
765 foreach (var childLayout in LayoutChildren)
767 if (!childLayout.SetPositionByLayout)
771 int childDesiredHeight = childLayout.Owner.HeightSpecification;
772 float childWeight = childLayout.Owner.Weight;
774 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
778 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
779 widthMeasureSpec, heightMeasureSpec, childState,
780 Orientation.Vertical);
782 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
783 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
784 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
786 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
787 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
789 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
791 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!");
795 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!");
799 } // 3RD PHASE foreach
802 maxWidth = Math.Max(maxWidth, maxWidth + (Padding.Start + Padding.End));
803 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
805 heightSizeAndState.State = childState.heightState;
807 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
811 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
813 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
815 LayoutLength childTop = new LayoutLength(Padding.Top);
816 LayoutLength childLeft = new LayoutLength(Padding.Start);
818 // Where bottom of child should go
819 LayoutLength height = new LayoutLength(bottom - top);
821 // Space available for child
822 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
824 var LinearChildren = IterateLayoutChildren();
825 int count = LinearChildren.Count<LayoutItem>();
827 switch (HorizontalAlignment)
829 case HorizontalAlignment.End:
830 // totalLength contains the padding already
831 // In case of RTL map END alignment to the left edge
834 childLeft = new LayoutLength(Padding.Start);
838 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
841 case HorizontalAlignment.Center:
842 // totalLength contains the padding already
843 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f);
845 case HorizontalAlignment.Begin: // FALL THROUGH (default)
847 // totalLength contains the padding already
848 // In case of RTL map BEGIN alignment to the right edge
851 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
855 childLeft = new LayoutLength(Padding.Start);
863 // In case of RTL, start drawing from the last child.
870 for (int i = 0; i < count; i++)
872 int childIndex = start + dir * i;
873 // Get a reference to the childLayout at the given index
874 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
876 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
877 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
878 Extents childMargin = childLayout.Margin;
880 switch (VerticalAlignment)
882 case VerticalAlignment.Bottom:
883 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
885 case VerticalAlignment.Center:
886 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
888 case VerticalAlignment.Top: // FALLTHROUGH default
890 childTop = new LayoutLength(Padding.Top + childMargin.Top);
893 childLeft += (isLayoutRtl ? childMargin.End : childMargin.Start);
894 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
895 childLeft += childWidth + (isLayoutRtl ? childMargin.Start : childMargin.End) + ((i < count - 1) ? CellPadding.Width : 0);
897 } // LayoutHorizontally
899 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
901 LayoutLength childTop = new LayoutLength(Padding.Top);
902 LayoutLength childLeft = new LayoutLength(Padding.Start);
904 // Where end of child should go
905 LayoutLength width = new LayoutLength(right - left);
907 // Space available for child
908 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
910 var LinearChildren = IterateLayoutChildren();
911 int count = LinearChildren.Count<LayoutItem>();
913 switch (VerticalAlignment)
915 case VerticalAlignment.Bottom:
916 // totalLength contains the padding already
917 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength);
919 case VerticalAlignment.Center:
920 // totalLength contains the padding already
921 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f);
923 case VerticalAlignment.Top: // FALL THROUGH (default)
925 // totalLength contains the padding already
926 childTop = new LayoutLength(Padding.Top);
930 for (int i = 0; i < count; i++)
932 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
934 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
935 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
936 Extents childMargin = childLayout.Margin;
938 childTop += childMargin.Top;
939 switch (HorizontalAlignment)
941 case HorizontalAlignment.Begin:
944 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
947 case HorizontalAlignment.End:
949 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
952 case HorizontalAlignment.Center:
954 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
958 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
959 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
963 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
965 // Pretend that the linear layout has an exact size. This is the measured height of
966 // ourselves. The measured height should be the max height of the children, changed
967 // to accommodate the heightMeasureSpec from the parent
968 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
969 foreach (var childLayout in LayoutChildren)
971 if (!childLayout.SetPositionByLayout)
975 int desiredChildHeight = childLayout.Owner.HeightSpecification;
976 int desiredChildWidth = childLayout.Owner.WidthSpecification;
978 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
980 // Temporarily force children to reuse their original measured width
981 int originalWidth = desiredChildWidth;
982 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
983 // Remeasure with new dimensions
984 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
985 uniformMeasureSpec, new LayoutLength(0));
986 // Restore width specification
987 childLayout.Owner.WidthSpecification = originalWidth;