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 (var childLayout in LayoutChildren)
275 if (!childLayout.SetPositionByLayout)
279 int childDesiredWidth = childLayout.Owner.WidthSpecification;
280 int childDesiredHeight = childLayout.Owner.HeightSpecification;
281 float childWeight = childLayout.Owner.Weight;
282 Extents childMargin = childLayout.Margin;
283 float childMarginWidth = childMargin.Start + childMargin.End;
284 float childMarginHeight = childMargin.Top + childMargin.Bottom;
285 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
287 totalWeight += childWeight;
289 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
291 childrenMatchParentCount++;
294 // MatchParent child layout's margin is not added to totalLength.
295 // Consequently, MatchParent child layout's margin is added to remaining size,
296 // so the margin is not shared with other MatchParent child layouts.
298 // LinearLayout has size 100.
299 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
300 // Child layout2 is MatchParent and its margin is 0.
301 // Then, child layout1's size is 30 and child layout2's size is 50.
302 if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
304 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
306 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
308 if (childMeasuredWidth < 0)
310 totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
314 totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
318 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
320 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
322 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
324 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
327 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
328 if (childMeasuredHeight < 0)
330 maxHeight = Math.Max(maxHeight, childMarginHeight);
334 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
336 } // 1ST PHASE foreach
338 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
339 float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
340 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
341 widthSize = widthSizeAndState.Size.AsDecimal();
343 float remainingWidth = widthSize - totalLength;
344 float totalWeightLength = 0.0f;
346 // Up to now, only WrapContent children's sizes are added to the totalLength.
347 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
348 // the layout size is assigned to the totalLength if MatchParent child exists.
349 if (childrenMatchParentCount > 0)
351 totalLength = widthSize;
356 // We measure all children whose width specification policy is MatchParent without weight.
357 // After 2nd phase, all children's widths are calculated without considering weight.
358 // And the widths of all weighted children are accumulated to calculate weighted width.
359 foreach (var childLayout in LayoutChildren)
361 if (!childLayout.SetPositionByLayout)
365 int childDesiredWidth = childLayout.Owner.WidthSpecification;
366 int childDesiredHeight = childLayout.Owner.HeightSpecification;
367 float childWeight = childLayout.Owner.Weight;
368 Extents childMargin = childLayout.Margin;
369 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
370 bool needToMeasure = false;
372 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
376 needToMeasure = true;
378 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
379 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
380 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
382 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
383 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
385 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
387 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!");
391 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!");
396 if (remainingWidth > 0)
398 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
402 // In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
403 // Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.Size before it is passed to MeasureChildWithMargins().
404 widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
405 needToMeasure = true;
407 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
408 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
409 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
411 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
412 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
414 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
416 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!");
420 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!");
426 if (needToMeasure == true)
428 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
432 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
434 if (childMeasuredWidth < 0)
436 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Start + childMargin.End);
440 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredWidth + childMargin.Start + childMargin.End);
444 } // 2ND PHASE foreach
448 // We measure all weighted children whose owner has weight greater than 0.
449 // After 3rd phase, all weighted children has width which is proportional to their weights
450 // in remaining width of parent.
451 if (totalWeight > 0.0f)
453 foreach (LayoutItem childLayout in LayoutChildren)
455 if (!childLayout.SetPositionByLayout)
459 int childDesiredWidth = childLayout.Owner.WidthSpecification;
460 float childWeight = childLayout.Owner.Weight;
462 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
466 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
467 widthMeasureSpec, heightMeasureSpec, childState,
468 Orientation.Horizontal);
470 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
471 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
472 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
474 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
475 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
477 if (childDesiredWidth == LayoutParamPolicies.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 MatchParent!");
483 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 } // 3RD PHASE foreach
490 maxHeight = Math.Max(maxHeight, maxHeight + (Padding.Top + Padding.Bottom));
491 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
493 widthSizeAndState.State = childState.widthState;
495 SetMeasuredDimensions(widthSizeAndState,
496 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
497 } // MeasureHorizontal
499 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
501 var widthMode = widthMeasureSpec.Mode;
502 var heightMode = heightMeasureSpec.Mode;
503 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
504 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
505 float maxWidth = 0.0f;
506 float totalWeight = 0.0f;
507 int childrenCount = IterateLayoutChildren().Count();
509 // Child layout, which wants to match its height to its parent's remaining height, is either following 1 or 2.
510 // 1. Child layout whose Owner.HeightSpecification is LayoutParamPolicies.MatchParent.
511 // 2. Child layout whose Owner.HeightSpecification is 0 and Owner.Weight is greater than 0.
512 // The number of child layout which wants to match its height to its parent's remaining height.
513 int childrenMatchParentCount = 0;
515 // Reset measure variable
518 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
519 MeasuredSize.StateType.MeasuredSizeOK);
523 // We measure all children whose height specification policy is WrapContent without weight.
524 // After 1st phase, remaining height of parent is accumulated to calculate height of children
525 // whose height specification policy is MatchParent.
526 foreach (var childLayout in LayoutChildren)
528 if (!childLayout.SetPositionByLayout)
532 int childDesiredWidth = childLayout.Owner.WidthSpecification;
533 int childDesiredHeight = childLayout.Owner.HeightSpecification;
534 float childWeight = childLayout.Owner.Weight;
535 Extents childMargin = childLayout.Margin;
536 float childMarginWidth = childMargin.Start + childMargin.End;
537 float childMarginHeight = childMargin.Top + childMargin.Bottom;
538 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
540 totalWeight += childWeight;
542 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
544 childrenMatchParentCount++;
547 // MatchParent child layout's margin is not added to totalLength.
548 // Consequently, MatchParent child layout's margin is added to remaining size,
549 // so the margin is not shared with other MatchParent child layouts.
551 // LinearLayout has size 100.
552 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
553 // Child layout2 is MatchParent and its margin is 0.
554 // Then, child layout1's size is 30 and child layout2's size is 50.
555 if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight > 0) && (!useRemainingHeight)))
557 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
559 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
561 if (childMeasuredHeight < 0)
563 totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
567 totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
571 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
573 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
575 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
577 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
580 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
581 if (childMeasuredWidth < 0)
583 maxWidth = Math.Max(maxWidth, childMarginWidth);
587 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
589 } // 1ST PHASE foreach
591 totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
592 float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
593 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
594 heightSize = heightSizeAndState.Size.AsDecimal();
596 float remainingHeight = heightSize - totalLength;
597 float totalWeightLength = 0.0f;
599 // Up to now, only WrapContent children's sizes are added to the totalLength.
600 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
601 // the layout size is assigned to the totalLength if MatchParent child exists.
602 if (childrenMatchParentCount > 0)
604 totalLength = heightSize;
609 // We measure all children whose height specification policy is MatchParent without weight.
610 // After 2nd phase, all children's heights are calculated without considering weight.
611 // And the heights of all weighted children are accumulated to calculate weighted height.
612 foreach (var childLayout in LayoutChildren)
614 if (!childLayout.SetPositionByLayout)
618 int childDesiredWidth = childLayout.Owner.WidthSpecification;
619 int childDesiredHeight = childLayout.Owner.HeightSpecification;
620 float childWeight = childLayout.Owner.Weight;
621 Extents childMargin = childLayout.Margin;
622 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
623 bool needToMeasure = false;
625 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
629 needToMeasure = true;
631 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
632 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
633 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
635 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
636 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
638 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
640 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!");
644 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!");
649 if (remainingHeight > 0)
651 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
655 // In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
656 // Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.Size before it is passed to MeasureChildWithMargins().
657 heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
658 needToMeasure = true;
660 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
661 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
662 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
664 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
665 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
667 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
669 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!");
673 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!");
679 if (needToMeasure == true)
681 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
686 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
688 if (childMeasuredHeight < 0)
690 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Top + childMargin.Bottom);
694 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredHeight + childMargin.Top + childMargin.Bottom);
697 } // 2ND PHASE foreach
701 // We measure all weighted children whose owner has weight greater than 0.
702 // After 3rd phase, all weighted children has height which is proportional to their weights
703 // in remaining height of parent.
706 foreach (var childLayout in LayoutChildren)
708 if (!childLayout.SetPositionByLayout)
712 int childDesiredHeight = childLayout.Owner.HeightSpecification;
713 float childWeight = childLayout.Owner.Weight;
715 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
719 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
720 widthMeasureSpec, heightMeasureSpec, childState,
721 Orientation.Vertical);
723 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
724 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
725 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
727 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
728 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
730 if (childDesiredHeight == LayoutParamPolicies.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 MatchParent!");
736 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!");
740 } // 3RD PHASE foreach
743 maxWidth = Math.Max(maxWidth, maxWidth + (Padding.Start + Padding.End));
744 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
746 heightSizeAndState.State = childState.heightState;
748 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
752 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
754 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
756 LayoutLength childTop = new LayoutLength(Padding.Top);
757 LayoutLength childLeft = new LayoutLength(Padding.Start);
759 // Where bottom of child should go
760 LayoutLength height = new LayoutLength(bottom - top);
762 // Space available for child
763 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
765 var LinearChildren = IterateLayoutChildren();
766 int count = LinearChildren.Count<LayoutItem>();
768 switch (LinearAlignment)
771 // totalLength contains the padding already
772 // In case of RTL map END alignment to the left edge
775 childLeft = new LayoutLength(Padding.Start);
779 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
782 case Alignment.CenterHorizontal: // FALL THROUGH
783 case Alignment.Center:
784 // totalLength contains the padding already
785 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f);
787 case Alignment.Begin: // FALL THROUGH (default)
789 // totalLength contains the padding already
790 // In case of RTL map BEGIN alignment to the right edge
793 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
797 childLeft = new LayoutLength(Padding.Start);
805 // In case of RTL, start drawing from the last child.
812 for (int i = 0; i < count; i++)
814 int childIndex = start + dir * i;
815 // Get a reference to the childLayout at the given index
816 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
818 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
819 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
820 Extents childMargin = childLayout.Margin;
822 switch (LinearAlignment)
824 case Alignment.Bottom:
825 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
827 case Alignment.CenterVertical:
828 case Alignment.Center: // FALLTHROUGH
829 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
831 case Alignment.Top: // FALLTHROUGH default
833 childTop = new LayoutLength(Padding.Top + childMargin.Top);
836 childLeft += (isLayoutRtl ? childMargin.End : childMargin.Start);
837 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
838 childLeft += childWidth + (isLayoutRtl ? childMargin.Start : childMargin.End) + ((i < count - 1) ? CellPadding.Width : 0);
840 } // LayoutHorizontally
842 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
844 LayoutLength childTop = new LayoutLength(Padding.Top);
845 LayoutLength childLeft = new LayoutLength(Padding.Start);
847 // Where end of child should go
848 LayoutLength width = new LayoutLength(right - left);
850 // Space available for child
851 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
853 var LinearChildren = IterateLayoutChildren();
854 int count = LinearChildren.Count<LayoutItem>();
856 switch (LinearAlignment)
858 case Alignment.Bottom:
859 // totalLength contains the padding already
860 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength);
862 case Alignment.CenterVertical: // FALL THROUGH
863 case Alignment.Center:
864 // totalLength contains the padding already
865 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f);
867 case Alignment.Top: // FALL THROUGH (default)
869 // totalLength contains the padding already
870 childTop = new LayoutLength(Padding.Top);
874 for (int i = 0; i < count; i++)
876 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
878 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
879 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
880 Extents childMargin = childLayout.Margin;
882 childTop += childMargin.Top;
883 switch (LinearAlignment)
885 case Alignment.Begin:
888 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
893 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
896 case Alignment.CenterHorizontal:
897 case Alignment.Center: // FALL THROUGH
899 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
903 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
904 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
908 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
910 // Pretend that the linear layout has an exact size. This is the measured height of
911 // ourselves. The measured height should be the max height of the children, changed
912 // to accommodate the heightMeasureSpec from the parent
913 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
914 foreach (var childLayout in LayoutChildren)
916 if (!childLayout.SetPositionByLayout)
920 int desiredChildHeight = childLayout.Owner.HeightSpecification;
921 int desiredChildWidth = childLayout.Owner.WidthSpecification;
923 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
925 // Temporarily force children to reuse their original measured width
926 int originalWidth = desiredChildWidth;
927 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
928 // Remeasure with new dimensions
929 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
930 uniformMeasureSpec, new LayoutLength(0));
931 // Restore width specification
932 childLayout.Owner.WidthSpecification = originalWidth;