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 Tizen.NUI.BaseComponents;
19 using System.Collections.Generic;
25 /// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
27 public class LinearLayout : LayoutGroup
30 /// [Draft] Enumeration for the direction in which the content is laid out
32 /// <since_tizen> 6 </since_tizen>
33 public enum Orientation
46 /// [Draft] Enumeration for the alignment of the linear layout items
48 /// <since_tizen> 6 </since_tizen>
52 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
56 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
60 /// At the horizontal center of the container
62 CenterHorizontal = 0x4,
64 /// At the top edge of the container
68 /// At the bottom edge of the container
72 /// At the vertical center of the container
74 CenterVertical = 0x20,
76 /// At the vertical and horizontal center of the container
81 struct HeightAndWidthState
83 public MeasuredSize.StateType widthState;
84 public MeasuredSize.StateType heightState;
86 public HeightAndWidthState(MeasuredSize.StateType width, MeasuredSize.StateType height)
94 /// [Draft] Get/Set the orientation in the layout
96 /// <since_tizen> 6 </since_tizen>
97 public LinearLayout.Orientation LinearOrientation
101 return linearOrientation;
105 linearOrientation = value;
111 /// [Draft] Get/Set the padding between cells in the layout
113 /// <since_tizen> 6 </since_tizen>
114 public Size2D CellPadding
118 if (cellPadding == null)
120 cellPadding = new Size2D(0, 0);
134 /// [Draft] Get/Set the alignment in the layout
136 /// <since_tizen> 6 </since_tizen>
137 public LinearLayout.Alignment LinearAlignment { get; set; } = Alignment.Top;
139 private float totalLength = 0.0f;
140 private Size2D cellPadding = new Size2D(0, 0);
141 private Orientation linearOrientation = Orientation.Horizontal;
144 /// [Draft] Constructor
146 /// <since_tizen> 6 </since_tizen>
147 public LinearLayout()
152 /// Measure the layout and its content to determine the measured width and the measured height.
154 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
155 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
156 /// <since_tizen> 6 </since_tizen>
157 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
159 if (linearOrientation == Orientation.Horizontal)
161 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
165 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
170 /// Layout should assign a size and position to each of its children.<br />
172 /// <param name="changed">This is a new size or position for this layout.</param>
173 /// <param name="left">Left position, relative to parent.</param>
174 /// <param name="top"> Top position, relative to parent.</param>
175 /// <param name="right">Right position, relative to parent.</param>
176 /// <param name="bottom">Bottom position, relative to parent.</param>
177 /// <since_tizen> 6 </since_tizen>
178 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
180 if (linearOrientation == Orientation.Horizontal)
182 LayoutHorizontal(left, top, right, bottom);
186 LayoutVertical(left, top, right, bottom);
191 private void MeasureWeightedChild(LayoutItem childLayout, float totalWeightLength, float totalWeight, float childWeight,
192 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
193 HeightAndWidthState childState, Orientation orientation)
195 bool horizontal = false;
196 if (orientation == Orientation.Horizontal)
201 float childsShare = totalWeightLength * (childWeight / totalWeight);
202 float desiredWidth = childLayout.Owner.WidthSpecification;
203 float desiredHeight = childLayout.Owner.HeightSpecification;
205 MeasureSpecification childWidthMeasureSpec;
206 MeasureSpecification childHeightMeasureSpec;
210 childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Start + childLayout.Margin.End)), MeasureSpecification.ModeType.Exactly);
212 childHeightMeasureSpec = GetChildMeasureSpecification(
213 new MeasureSpecification(
214 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
215 heightMeasureSpec.Mode),
216 new LayoutLength(Padding.Top + Padding.Bottom),
217 new LayoutLength(desiredHeight));
221 childWidthMeasureSpec = GetChildMeasureSpecification(
222 new MeasureSpecification(
223 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
224 widthMeasureSpec.Mode),
225 new LayoutLength(Padding.Start + Padding.End),
226 new LayoutLength(desiredWidth));
228 childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Top + childLayout.Margin.Bottom)), MeasureSpecification.ModeType.Exactly);
231 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
233 // Child may now not fit in horizontal dimension.
234 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
236 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
239 // Child may now not fit in vertical dimension.
240 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
242 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
246 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
248 var widthMode = widthMeasureSpec.Mode;
249 var heightMode = heightMeasureSpec.Mode;
250 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
251 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
252 float maxHeight = 0.0f;
253 float totalWeight = 0.0f;
254 int childrenCount = IterateLayoutChildren().Count();
256 // Child layout, which wants to match its width to its parent's remaining width, is either following 1 or 2.
257 // 1. Child layout whose Owner.WidthSpecification is LayoutParamPolicies.MatchParent.
258 // 2. Child layout whose Owner.WidthSpecification is 0 and Owner.Weight is greater than 0.
259 // The number of child layout which wants to match its width to its parent's remaining width.
260 int childrenMatchParentCount = 0;
262 // Reset measure variable
265 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
266 MeasuredSize.StateType.MeasuredSizeOK);
270 // We measure all children whose width specification policy is WrapContent without weight.
271 // After 1st phase, remaining width of parent is accumulated to calculate width of children
272 // whose width specification policy is MatchParent.
273 foreach (LayoutItem childLayout in IterateLayoutChildren())
275 int childDesiredWidth = childLayout.Owner.WidthSpecification;
276 int childDesiredHeight = childLayout.Owner.HeightSpecification;
277 float childWeight = childLayout.Owner.Weight;
278 Extents childMargin = childLayout.Margin;
279 float childMarginWidth = childMargin.Start + childMargin.End;
280 float childMarginHeight = childMargin.Top + childMargin.Bottom;
281 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
283 totalWeight += childWeight;
285 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
287 childrenMatchParentCount++;
290 // MatchParent child layout's margin is not added to totalLength.
291 // Consequently, MatchParent child layout's margin is added to remaining size,
292 // so the margin is not shared with other MatchParent child layouts.
294 // LinearLayout has size 100.
295 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
296 // Child layout2 is MatchParent and its margin is 0.
297 // Then, child layout1's size is 30 and child layout2's size is 50.
298 if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
300 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
302 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
304 if (childMeasuredWidth < 0)
306 totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
310 totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
314 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
316 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
318 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
320 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
323 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
324 if (childMeasuredHeight < 0)
326 maxHeight = Math.Max(maxHeight, childMarginHeight);
330 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
332 } // 1ST PHASE foreach
334 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
335 float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
336 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
337 widthSize = widthSizeAndState.Size.AsDecimal();
339 float remainingWidth = widthSize - totalLength;
340 float totalWeightLength = 0.0f;
344 // We measure all children whose width specification policy is MatchParent without weight.
345 // After 2nd phase, all children's widths are calculated without considering weight.
346 // And the widths of all weighted children are accumulated to calculate weighted width.
347 foreach (LayoutItem childLayout in IterateLayoutChildren())
349 int childDesiredWidth = childLayout.Owner.WidthSpecification;
350 int childDesiredHeight = childLayout.Owner.HeightSpecification;
351 float childWeight = childLayout.Owner.Weight;
352 Extents childMargin = childLayout.Margin;
353 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
354 bool needToMeasure = false;
356 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
360 needToMeasure = true;
362 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
363 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
364 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
366 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
367 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
369 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
371 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!");
375 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!");
380 if (remainingWidth > 0)
382 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
386 // In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
387 // Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.Size before it is passed to MeasureChildWithMargins().
388 widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
389 needToMeasure = true;
391 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
392 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
393 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
395 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
396 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
398 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
400 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!");
404 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!");
410 if (needToMeasure == true)
412 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
416 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
418 if (childMeasuredWidth < 0)
420 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Start + childMargin.End);
424 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredWidth + childMargin.Start + childMargin.End);
428 } // 2ND PHASE foreach
432 // We measure all weighted children whose owner has weight greater than 0.
433 // After 3rd phase, all weighted children has width which is proportional to their weights
434 // in remaining width of parent.
435 if (totalWeight > 0.0f)
437 foreach (LayoutItem childLayout in IterateLayoutChildren())
439 int childDesiredWidth = childLayout.Owner.WidthSpecification;
440 float childWeight = childLayout.Owner.Weight;
442 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
446 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
447 widthMeasureSpec, heightMeasureSpec, childState,
448 Orientation.Horizontal);
450 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
451 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
452 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
454 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
455 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
457 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
459 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!");
463 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!");
467 } // 3RD PHASE foreach
470 maxHeight = Math.Max(maxHeight, maxHeight + (Padding.Top + Padding.Bottom));
471 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
473 widthSizeAndState.State = childState.widthState;
475 SetMeasuredDimensions(widthSizeAndState,
476 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
477 } // MeasureHorizontal
479 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
481 var widthMode = widthMeasureSpec.Mode;
482 var heightMode = heightMeasureSpec.Mode;
483 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
484 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
485 float maxWidth = 0.0f;
486 float totalWeight = 0.0f;
487 int childrenCount = IterateLayoutChildren().Count();
489 // Child layout, which wants to match its height to its parent's remaining height, is either following 1 or 2.
490 // 1. Child layout whose Owner.HeightSpecification is LayoutParamPolicies.MatchParent.
491 // 2. Child layout whose Owner.HeightSpecification is 0 and Owner.Weight is greater than 0.
492 // The number of child layout which wants to match its height to its parent's remaining height.
493 int childrenMatchParentCount = 0;
495 // Reset measure variable
498 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
499 MeasuredSize.StateType.MeasuredSizeOK);
503 // We measure all children whose height specification policy is WrapContent without weight.
504 // After 1st phase, remaining height of parent is accumulated to calculate height of children
505 // whose height specification policy is MatchParent.
506 foreach (LayoutItem childLayout in IterateLayoutChildren())
508 int childDesiredWidth = childLayout.Owner.WidthSpecification;
509 int childDesiredHeight = childLayout.Owner.HeightSpecification;
510 float childWeight = childLayout.Owner.Weight;
511 Extents childMargin = childLayout.Margin;
512 float childMarginWidth = childMargin.Start + childMargin.End;
513 float childMarginHeight = childMargin.Top + childMargin.Bottom;
514 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
516 totalWeight += childWeight;
518 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
520 childrenMatchParentCount++;
523 // MatchParent child layout's margin is not added to totalLength.
524 // Consequently, MatchParent child layout's margin is added to remaining size,
525 // so the margin is not shared with other MatchParent child layouts.
527 // LinearLayout has size 100.
528 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
529 // Child layout2 is MatchParent and its margin is 0.
530 // Then, child layout1's size is 30 and child layout2's size is 50.
531 if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight > 0) && (!useRemainingHeight)))
533 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
535 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
537 if (childMeasuredHeight < 0)
539 totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
543 totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
547 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
549 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
551 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
553 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
556 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
557 if (childMeasuredWidth < 0)
559 maxWidth = Math.Max(maxWidth, childMarginWidth);
563 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
565 } // 1ST PHASE foreach
567 totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
568 float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
569 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
570 heightSize = heightSizeAndState.Size.AsDecimal();
572 float remainingHeight = heightSize - totalLength;
573 float totalWeightLength = 0.0f;
577 // We measure all children whose height specification policy is MatchParent without weight.
578 // After 2nd phase, all children's heights are calculated without considering weight.
579 // And the heights of all weighted children are accumulated to calculate weighted height.
580 foreach (LayoutItem childLayout in IterateLayoutChildren())
582 int childDesiredWidth = childLayout.Owner.WidthSpecification;
583 int childDesiredHeight = childLayout.Owner.HeightSpecification;
584 float childWeight = childLayout.Owner.Weight;
585 Extents childMargin = childLayout.Margin;
586 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
587 bool needToMeasure = false;
589 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
593 needToMeasure = true;
595 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
596 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
597 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
599 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
600 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
602 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
604 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!");
608 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!");
613 if (remainingHeight > 0)
615 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
619 // In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
620 // Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.Size before it is passed to MeasureChildWithMargins().
621 heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
622 needToMeasure = true;
624 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
625 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
626 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
628 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
629 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
631 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
633 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!");
637 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!");
643 if (needToMeasure == true)
645 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
650 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
652 if (childMeasuredHeight < 0)
654 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Top + childMargin.Bottom);
658 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredHeight + childMargin.Top + childMargin.Bottom);
661 } // 2ND PHASE foreach
665 // We measure all weighted children whose owner has weight greater than 0.
666 // After 3rd phase, all weighted children has height which is proportional to their weights
667 // in remaining height of parent.
670 foreach (LayoutItem childLayout in IterateLayoutChildren())
672 int childDesiredHeight = childLayout.Owner.HeightSpecification;
673 float childWeight = childLayout.Owner.Weight;
675 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
679 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
680 widthMeasureSpec, heightMeasureSpec, childState,
681 Orientation.Vertical);
683 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
684 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
685 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
687 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
688 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
690 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
692 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!");
696 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!");
700 } // 3RD PHASE foreach
703 maxWidth = Math.Max(maxWidth, maxWidth + (Padding.Start + Padding.End));
704 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
706 heightSizeAndState.State = childState.heightState;
708 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
712 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
714 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
716 LayoutLength childTop = new LayoutLength(Padding.Top);
717 LayoutLength childLeft = new LayoutLength(Padding.Start);
719 // Where bottom of child should go
720 LayoutLength height = new LayoutLength(bottom - top);
722 // Space available for child
723 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
725 List<LayoutItem> LinearChildren = IterateLayoutChildren().ToList();
726 int count = LinearChildren.Count;
728 switch (LinearAlignment)
731 // totalLength contains the padding already
732 // In case of RTL map END alignment to the left edge
735 childLeft = new LayoutLength(Padding.Start);
739 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
742 case Alignment.CenterHorizontal: // FALL THROUGH
743 case Alignment.Center:
744 // totalLength contains the padding already
745 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f);
747 case Alignment.Begin: // FALL THROUGH (default)
749 // totalLength contains the padding already
750 // In case of RTL map BEGIN alignment to the right edge
753 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
757 childLeft = new LayoutLength(Padding.Start);
765 // In case of RTL, start drawing from the last child.
772 for (int i = 0; i < count; i++)
774 int childIndex = start + dir * i;
775 // Get a reference to the childLayout at the given index
776 LayoutItem childLayout = LinearChildren[childIndex];
778 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
779 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
780 Extents childMargin = childLayout.Margin;
782 switch (LinearAlignment)
784 case Alignment.Bottom:
785 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
787 case Alignment.CenterVertical:
788 case Alignment.Center: // FALLTHROUGH
789 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
791 case Alignment.Top: // FALLTHROUGH default
793 childTop = new LayoutLength(Padding.Top + childMargin.Top);
796 childLeft += (isLayoutRtl ? childMargin.End : childMargin.Start);
797 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
798 childLeft += childWidth + (isLayoutRtl ? childMargin.Start : childMargin.End) + ((i < count - 1) ? CellPadding.Width : 0);
800 } // LayoutHorizontally
802 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
804 LayoutLength childTop = new LayoutLength(Padding.Top);
805 LayoutLength childLeft = new LayoutLength(Padding.Start);
807 // Where end of child should go
808 LayoutLength width = new LayoutLength(right - left);
810 // Space available for child
811 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
813 List<LayoutItem> LinearChildren = IterateLayoutChildren().ToList();
814 int count = LinearChildren.Count;
816 switch (LinearAlignment)
818 case Alignment.Bottom:
819 // totalLength contains the padding already
820 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength);
822 case Alignment.CenterVertical: // FALL THROUGH
823 case Alignment.Center:
824 // totalLength contains the padding already
825 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f);
827 case Alignment.Top: // FALL THROUGH (default)
829 // totalLength contains the padding already
830 childTop = new LayoutLength(Padding.Top);
834 for (int i = 0; i < count; i++)
836 LayoutItem childLayout = LinearChildren[i];
838 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
839 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
840 Extents childMargin = childLayout.Margin;
842 childTop += childMargin.Top;
843 switch (LinearAlignment)
845 case Alignment.Begin:
848 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
853 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
856 case Alignment.CenterHorizontal:
857 case Alignment.Center: // FALL THROUGH
859 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
863 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
864 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
868 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
870 // Pretend that the linear layout has an exact size. This is the measured height of
871 // ourselves. The measured height should be the max height of the children, changed
872 // to accommodate the heightMeasureSpec from the parent
873 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
874 foreach (LayoutItem childLayout in IterateLayoutChildren())
876 int desiredChildHeight = childLayout.Owner.HeightSpecification;
877 int desiredChildWidth = childLayout.Owner.WidthSpecification;
879 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
881 // Temporarily force children to reuse their original measured width
882 int originalWidth = desiredChildWidth;
883 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
884 // Remeasure with new dimensions
885 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
886 uniformMeasureSpec, new LayoutLength(0));
887 // Restore width specification
888 childLayout.Owner.WidthSpecification = originalWidth;