1 /* Copyright (c) 2020 Samsung Electronics Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 using System.ComponentModel;
19 using Tizen.NUI.BaseComponents;
20 using System.Collections.Generic;
26 /// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
28 public class LinearLayout : LayoutGroup
30 private Alignment linearAlignment = Alignment.Top;
33 /// [Draft] Enumeration for the direction in which the content is laid out
35 /// <since_tizen> 6 </since_tizen>
36 public enum Orientation
49 /// [Draft] Enumeration for the alignment of the linear layout items
51 /// <since_tizen> 6 </since_tizen>
52 [Obsolete("Deprecated in API9, will be removed in API11. Please use HorizontalAlignment and VerticalAlignment instead!")]
56 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
60 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
64 /// At the horizontal center of the container
66 CenterHorizontal = 0x4,
68 /// At the top edge of the container
72 /// At the bottom edge of the container
76 /// At the vertical center of the container
78 CenterVertical = 0x20,
80 /// At the vertical and horizontal center of the container
85 struct HeightAndWidthState
87 public MeasuredSize.StateType widthState;
88 public MeasuredSize.StateType heightState;
90 public HeightAndWidthState(MeasuredSize.StateType width, MeasuredSize.StateType height)
98 /// [Draft] Get/Set the orientation in the layout
100 /// <since_tizen> 6 </since_tizen>
101 public LinearLayout.Orientation LinearOrientation
105 return linearOrientation;
109 linearOrientation = value;
115 /// [Draft] Get/Set the padding between cells in the layout
117 /// <since_tizen> 6 </since_tizen>
118 public Size2D CellPadding
122 if (cellPadding == null)
124 cellPadding = new Size2D(0, 0);
138 /// [Draft] Get/Set the alignment in the layout
140 /// <since_tizen> 6 </since_tizen>
141 [Obsolete("Deprecated in API9, will be removed in API11. Please use HorizontalAlignment and VerticalAlignment properties instead!")]
142 public LinearLayout.Alignment LinearAlignment
146 return linearAlignment;
151 if (linearAlignment == value)
156 linearAlignment = value;
158 switch (linearAlignment)
160 case Alignment.Begin:
161 HorizontalAlignment = HorizontalAlignment.Begin;
164 HorizontalAlignment = HorizontalAlignment.End;
166 case Alignment.CenterHorizontal:
167 HorizontalAlignment = HorizontalAlignment.Center;
170 VerticalAlignment = VerticalAlignment.Top;
172 case Alignment.Bottom:
173 VerticalAlignment = VerticalAlignment.Bottom;
175 case Alignment.CenterVertical:
176 VerticalAlignment = VerticalAlignment.Center;
178 case Alignment.Center:
179 HorizontalAlignment = HorizontalAlignment.Center;
180 VerticalAlignment = VerticalAlignment.Center;
189 /// Get/Set the horizontal alignment in the layout
191 /// <since_tizen> 9 </since_tizen>
192 public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Begin;
195 /// Get/Set the vertical alignment in the layout
197 /// <since_tizen> 9 </since_tizen>
198 public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top;
200 private float totalLength = 0.0f;
201 private Size2D cellPadding = new Size2D(0, 0);
202 private Orientation linearOrientation = Orientation.Horizontal;
205 /// [Draft] Constructor
207 /// <since_tizen> 6 </since_tizen>
208 public LinearLayout()
213 [EditorBrowsable(EditorBrowsableState.Never)]
214 public override LayoutItem Clone()
216 var layout = new LinearLayout();
218 foreach (var prop in layout.GetType().GetProperties())
220 if (prop.GetSetMethod() != null)
222 prop.SetValue(layout, this.GetType().GetProperty(prop.Name).GetValue(this));
230 /// Measure the layout and its content to determine the measured width and the measured height.
232 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
233 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
234 /// <since_tizen> 6 </since_tizen>
235 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
237 if (linearOrientation == Orientation.Horizontal)
239 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
243 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
248 /// Layout should assign a size and position to each of its children.<br />
250 /// <param name="changed">This is a new size or position for this layout.</param>
251 /// <param name="left">Left position, relative to parent.</param>
252 /// <param name="top"> Top position, relative to parent.</param>
253 /// <param name="right">Right position, relative to parent.</param>
254 /// <param name="bottom">Bottom position, relative to parent.</param>
255 /// <since_tizen> 6 </since_tizen>
256 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
258 if (linearOrientation == Orientation.Horizontal)
260 LayoutHorizontal(left, top, right, bottom);
264 LayoutVertical(left, top, right, bottom);
269 private void MeasureWeightedChild(LayoutItem childLayout, float totalWeightLength, float totalWeight, float childWeight,
270 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
271 HeightAndWidthState childState, Orientation orientation)
273 bool horizontal = false;
274 if (orientation == Orientation.Horizontal)
279 float childsShare = totalWeightLength * (childWeight / totalWeight);
280 float desiredWidth = childLayout.Owner.WidthSpecification;
281 float desiredHeight = childLayout.Owner.HeightSpecification;
283 MeasureSpecification childWidthMeasureSpec;
284 MeasureSpecification childHeightMeasureSpec;
288 childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Start + childLayout.Margin.End)), MeasureSpecification.ModeType.Exactly);
290 childHeightMeasureSpec = GetChildMeasureSpecification(
291 new MeasureSpecification(
292 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
293 heightMeasureSpec.Mode),
294 new LayoutLength(Padding.Top + Padding.Bottom),
295 new LayoutLength(desiredHeight));
299 childWidthMeasureSpec = GetChildMeasureSpecification(
300 new MeasureSpecification(
301 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
302 widthMeasureSpec.Mode),
303 new LayoutLength(Padding.Start + Padding.End),
304 new LayoutLength(desiredWidth));
306 childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Top + childLayout.Margin.Bottom)), MeasureSpecification.ModeType.Exactly);
309 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
311 // Child may now not fit in horizontal dimension.
312 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
314 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
317 // Child may now not fit in vertical dimension.
318 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
320 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
324 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
326 var widthMode = widthMeasureSpec.Mode;
327 var heightMode = heightMeasureSpec.Mode;
328 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
329 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
330 float maxHeight = 0.0f;
331 float totalWeight = 0.0f;
332 int childrenCount = IterateLayoutChildren().Count();
334 // Child layout, which wants to match its width to its parent's remaining width, is either following 1 or 2.
335 // 1. Child layout whose Owner.WidthSpecification is LayoutParamPolicies.MatchParent.
336 // 2. Child layout whose Owner.WidthSpecification is 0 and Owner.Weight is greater than 0.
337 // The number of child layout which wants to match its width to its parent's remaining width.
338 int childrenMatchParentCount = 0;
340 // Reset measure variable
343 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
344 MeasuredSize.StateType.MeasuredSizeOK);
348 // We measure all children whose width specification policy is WrapContent without weight.
349 // After 1st phase, remaining width of parent is accumulated to calculate width of children
350 // whose width specification policy is MatchParent.
351 foreach (var childLayout in LayoutChildren)
353 if (!childLayout.SetPositionByLayout)
357 int childDesiredWidth = childLayout.Owner.WidthSpecification;
358 int childDesiredHeight = childLayout.Owner.HeightSpecification;
359 float childWeight = childLayout.Owner.Weight;
360 Extents childMargin = childLayout.Margin;
361 float childMarginWidth = childMargin.Start + childMargin.End;
362 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
364 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
366 totalWeight += childWeight;
367 childrenMatchParentCount++;
370 // MatchParent child layout's margin is not added to totalLength.
371 // Consequently, MatchParent child layout's margin is added to remaining size,
372 // so the margin is not shared with other MatchParent child layouts.
374 // LinearLayout has size 100.
375 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
376 // Child layout2 is MatchParent and its margin is 0.
377 // Then, child layout1's size is 30 and child layout2's size is 50.
378 if ((childDesiredWidth == LayoutParamPolicies.WrapContent) || ((childDesiredWidth >= 0) && (!useRemainingWidth)))
380 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
382 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
384 if (childMeasuredWidth < 0)
386 totalLength = Math.Max(totalLength, totalLength + childMarginWidth);
390 totalLength = Math.Max(totalLength, totalLength + childMeasuredWidth + childMarginWidth);
394 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
396 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
398 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
400 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
402 } // 1ST PHASE foreach
404 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1) + Padding.Start + Padding.End);
405 float widthSize = Math.Max(totalLength, SuggestedMinimumWidth.AsDecimal());
406 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
407 widthSize = widthSizeAndState.Size.AsDecimal();
409 float remainingWidth = widthSize - totalLength;
410 float totalWeightLength = 0.0f;
412 // Up to now, only WrapContent children's sizes are added to the totalLength.
413 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
414 // the layout size is assigned to the totalLength if MatchParent child exists.
415 if (childrenMatchParentCount > 0)
417 totalLength = widthSize;
422 // We measure all children whose width specification policy is MatchParent without weight.
423 // After 2nd phase, all children's widths are calculated without considering weight.
424 // And the widths of all weighted children are accumulated to calculate weighted width.
425 foreach (var childLayout in LayoutChildren)
427 if (!childLayout.SetPositionByLayout)
431 int childDesiredWidth = childLayout.Owner.WidthSpecification;
432 int childDesiredHeight = childLayout.Owner.HeightSpecification;
433 float childWeight = childLayout.Owner.Weight;
434 Extents childMargin = childLayout.Margin;
435 bool useRemainingWidth = (childDesiredWidth == 0) && (childWeight > 0);
436 bool needToMeasure = false;
438 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
442 needToMeasure = true;
444 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
445 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
446 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
448 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
449 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
451 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
453 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!");
457 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!");
462 if (remainingWidth > 0)
464 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingWidth))
468 // In MeasureChildWithMargins(), it is assumed that widthMeasureSpec includes Padding.Start and Padding.End.
469 // Therefore, Padding.Start and Padding.End are added to widthMeasureSpec.Size before it is passed to MeasureChildWithMargins().
470 widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End));
471 needToMeasure = true;
473 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
474 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
475 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
477 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
478 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
480 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
482 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!");
486 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!");
492 if (needToMeasure == true)
494 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
497 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
499 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
501 if (childMeasuredWidth < 0)
503 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Start + childMargin.End);
507 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredWidth + childMargin.Start + childMargin.End);
510 } // 2ND PHASE foreach
514 // We measure all weighted children whose owner has weight greater than 0.
515 // After 3rd phase, all weighted children has width which is proportional to their weights
516 // in remaining width of parent.
517 if (totalWeight > 0.0f)
519 foreach (LayoutItem childLayout in LayoutChildren)
521 if (!childLayout.SetPositionByLayout)
525 int childDesiredWidth = childLayout.Owner.WidthSpecification;
526 float childWeight = childLayout.Owner.Weight;
528 if ((childWeight > 0) && ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (childDesiredWidth == 0)))
532 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
533 widthMeasureSpec, heightMeasureSpec, childState,
534 Orientation.Horizontal);
536 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
537 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
538 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
540 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
541 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
543 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
545 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!");
549 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!");
557 // Decide the max height among children.
558 foreach (var childLayout in LayoutChildren)
560 if (!childLayout.SetPositionByLayout)
565 Extents childMargin = childLayout.Margin;
566 float childMarginHeight = childMargin.Top + childMargin.Bottom;
567 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
569 if (childMeasuredHeight < 0)
571 maxHeight = Math.Max(maxHeight, childMarginHeight);
575 maxHeight = Math.Max(maxHeight, childMeasuredHeight + childMarginHeight);
579 // Decide the max height compared with paddings and its suggested height.
580 maxHeight = Math.Max(maxHeight, maxHeight + (Padding.Top + Padding.Bottom));
581 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
583 widthSizeAndState.State = childState.widthState;
585 SetMeasuredDimensions(widthSizeAndState,
586 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
587 } // MeasureHorizontal
589 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
591 var widthMode = widthMeasureSpec.Mode;
592 var heightMode = heightMeasureSpec.Mode;
593 bool isWidthExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
594 bool isHeightExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
595 float maxWidth = 0.0f;
596 float totalWeight = 0.0f;
597 int childrenCount = IterateLayoutChildren().Count();
599 // Child layout, which wants to match its height to its parent's remaining height, is either following 1 or 2.
600 // 1. Child layout whose Owner.HeightSpecification is LayoutParamPolicies.MatchParent.
601 // 2. Child layout whose Owner.HeightSpecification is 0 and Owner.Weight is greater than 0.
602 // The number of child layout which wants to match its height to its parent's remaining height.
603 int childrenMatchParentCount = 0;
605 // Reset measure variable
608 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
609 MeasuredSize.StateType.MeasuredSizeOK);
613 // We measure all children whose height specification policy is WrapContent without weight.
614 // After 1st phase, remaining height of parent is accumulated to calculate height of children
615 // whose height specification policy is MatchParent.
616 foreach (var childLayout in LayoutChildren)
618 if (!childLayout.SetPositionByLayout)
622 int childDesiredWidth = childLayout.Owner.WidthSpecification;
623 int childDesiredHeight = childLayout.Owner.HeightSpecification;
624 float childWeight = childLayout.Owner.Weight;
625 Extents childMargin = childLayout.Margin;
626 float childMarginHeight = childMargin.Top + childMargin.Bottom;
627 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
629 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
631 totalWeight += childWeight;
632 childrenMatchParentCount++;
635 // MatchParent child layout's margin is not added to totalLength.
636 // Consequently, MatchParent child layout's margin is added to remaining size,
637 // so the margin is not shared with other MatchParent child layouts.
639 // LinearLayout has size 100.
640 // Child layout1 is MatchParent and its margin is 20. (This margin is not ad
641 // Child layout2 is MatchParent and its margin is 0.
642 // Then, child layout1's size is 30 and child layout2's size is 50.
643 if ((childDesiredHeight == LayoutParamPolicies.WrapContent) || ((childDesiredHeight > 0) && (!useRemainingHeight)))
645 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
647 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
649 if (childMeasuredHeight < 0)
651 totalLength = Math.Max(totalLength, totalLength + childMarginHeight);
655 totalLength = Math.Max(totalLength, totalLength + childMeasuredHeight + childMarginHeight);
659 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
661 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
663 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
665 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
667 } // 1ST PHASE foreach
669 totalLength = Math.Max(totalLength, totalLength + CellPadding.Height * (childrenCount - 1) + Padding.Top + Padding.Bottom);
670 float heightSize = Math.Max(totalLength, SuggestedMinimumHeight.AsDecimal());
671 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
672 heightSize = heightSizeAndState.Size.AsDecimal();
674 float remainingHeight = heightSize - totalLength;
675 float totalWeightLength = 0.0f;
677 // Up to now, only WrapContent children's sizes are added to the totalLength.
678 // Since the totalLength is used in OnLayout as the sum of all children's sizes,
679 // the layout size is assigned to the totalLength if MatchParent child exists.
680 if (childrenMatchParentCount > 0)
682 totalLength = heightSize;
687 // We measure all children whose height specification policy is MatchParent without weight.
688 // After 2nd phase, all children's heights are calculated without considering weight.
689 // And the heights of all weighted children are accumulated to calculate weighted height.
690 foreach (var childLayout in LayoutChildren)
692 if (!childLayout.SetPositionByLayout)
696 int childDesiredWidth = childLayout.Owner.WidthSpecification;
697 int childDesiredHeight = childLayout.Owner.HeightSpecification;
698 float childWeight = childLayout.Owner.Weight;
699 Extents childMargin = childLayout.Margin;
700 bool useRemainingHeight = (childDesiredHeight == 0) && (childWeight > 0);
701 bool needToMeasure = false;
703 if ((childDesiredWidth == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
707 needToMeasure = true;
709 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
710 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
711 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
713 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
714 else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)
716 if (childDesiredWidth == LayoutParamPolicies.MatchParent)
718 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!");
722 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!");
727 if (remainingHeight > 0)
729 if ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (useRemainingHeight))
733 // In MeasureChildWithMargins(), it is assumed that heightMeasureSpec includes Padding.Top and Padding.Bottom.
734 // Therefore, Padding.Top and Padding.Bottom are added to heightMeasureSpec.Size before it is passed to MeasureChildWithMargins().
735 heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom));
736 needToMeasure = true;
738 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
739 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
740 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
742 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
743 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
745 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
747 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!");
751 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!");
757 if (needToMeasure == true)
759 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
762 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
764 float childMeasuredHeight = childLayout.MeasuredHeight.Size.AsDecimal();
766 if (childMeasuredHeight < 0)
768 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMargin.Top + childMargin.Bottom);
772 totalWeightLength = Math.Max(totalWeightLength, totalWeightLength + childMeasuredHeight + childMargin.Top + childMargin.Bottom);
775 } // 2ND PHASE foreach
779 // We measure all weighted children whose owner has weight greater than 0.
780 // After 3rd phase, all weighted children has height which is proportional to their weights
781 // in remaining height of parent.
784 foreach (var childLayout in LayoutChildren)
786 if (!childLayout.SetPositionByLayout)
790 int childDesiredHeight = childLayout.Owner.HeightSpecification;
791 float childWeight = childLayout.Owner.Weight;
793 if ((childWeight > 0) && ((childDesiredHeight == LayoutParamPolicies.MatchParent) || (childDesiredHeight == 0)))
797 MeasureWeightedChild(childLayout, totalWeightLength, totalWeight, childWeight,
798 widthMeasureSpec, heightMeasureSpec, childState,
799 Orientation.Vertical);
801 // RelativeLayout's MatchParent children should not fill to the RelativeLayout.
802 // Because the children's sizes and positions are calculated by RelativeLayout's APIs.
803 // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost.
805 // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent.
806 else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)
808 if (childDesiredHeight == LayoutParamPolicies.MatchParent)
810 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!");
814 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!");
819 } // 3RD PHASE foreach
821 // Decide the max width among children.
822 foreach (var childLayout in LayoutChildren)
824 if (!childLayout.SetPositionByLayout)
829 Extents childMargin = childLayout.Margin;
830 float childMarginWidth = childMargin.Start + childMargin.End;
831 float childMeasuredWidth = childLayout.MeasuredWidth.Size.AsDecimal();
833 if (childMeasuredWidth < 0)
835 maxWidth = Math.Max(maxWidth, childMarginWidth);
839 maxWidth = Math.Max(maxWidth, childMeasuredWidth + childMarginWidth);
843 // Decide the max width compared with paddings and its suggested width.
844 maxWidth = Math.Max(maxWidth, maxWidth + (Padding.Start + Padding.End));
845 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
847 heightSizeAndState.State = childState.heightState;
849 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
853 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
855 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
857 LayoutLength childTop = new LayoutLength(Padding.Top);
858 LayoutLength childLeft = new LayoutLength(Padding.Start);
860 // Where bottom of child should go
861 LayoutLength height = new LayoutLength(bottom - top);
863 // Space available for child
864 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
866 var LinearChildren = IterateLayoutChildren();
867 int count = LinearChildren.Count<LayoutItem>();
869 switch (HorizontalAlignment)
871 case HorizontalAlignment.End:
872 // totalLength contains the padding already
873 // In case of RTL map END alignment to the left edge
876 childLeft = new LayoutLength(Padding.Start);
880 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
883 case HorizontalAlignment.Center:
884 // totalLength contains the padding already
885 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f);
887 case HorizontalAlignment.Begin: // FALL THROUGH (default)
889 // totalLength contains the padding already
890 // In case of RTL map BEGIN alignment to the right edge
893 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength);
897 childLeft = new LayoutLength(Padding.Start);
905 // In case of RTL, start drawing from the last child.
912 for (int i = 0; i < count; i++)
914 int childIndex = start + dir * i;
915 // Get a reference to the childLayout at the given index
916 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
918 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
919 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
920 Extents childMargin = childLayout.Margin;
922 switch (VerticalAlignment)
924 case VerticalAlignment.Bottom:
925 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
927 case VerticalAlignment.Center:
928 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
930 case VerticalAlignment.Top: // FALLTHROUGH default
932 childTop = new LayoutLength(Padding.Top + childMargin.Top);
935 childLeft += (isLayoutRtl ? childMargin.End : childMargin.Start);
936 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
937 childLeft += childWidth + (isLayoutRtl ? childMargin.Start : childMargin.End) + ((i < count - 1) ? CellPadding.Width : 0);
939 } // LayoutHorizontally
941 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
943 LayoutLength childTop = new LayoutLength(Padding.Top);
944 LayoutLength childLeft = new LayoutLength(Padding.Start);
946 // Where end of child should go
947 LayoutLength width = new LayoutLength(right - left);
949 // Space available for child
950 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
952 var LinearChildren = IterateLayoutChildren();
953 int count = LinearChildren.Count<LayoutItem>();
955 switch (VerticalAlignment)
957 case VerticalAlignment.Bottom:
958 // totalLength contains the padding already
959 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength);
961 case VerticalAlignment.Center:
962 // totalLength contains the padding already
963 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f);
965 case VerticalAlignment.Top: // FALL THROUGH (default)
967 // totalLength contains the padding already
968 childTop = new LayoutLength(Padding.Top);
972 for (int i = 0; i < count; i++)
974 LayoutItem childLayout = LinearChildren.ElementAt<LayoutItem>(i);
976 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
977 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
978 Extents childMargin = childLayout.Margin;
980 childTop += childMargin.Top;
981 switch (HorizontalAlignment)
983 case HorizontalAlignment.Begin:
986 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
989 case HorizontalAlignment.End:
991 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
994 case HorizontalAlignment.Center:
996 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
1000 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
1001 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
1005 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
1007 // Pretend that the linear layout has an exact size. This is the measured height of
1008 // ourselves. The measured height should be the max height of the children, changed
1009 // to accommodate the heightMeasureSpec from the parent
1010 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
1011 foreach (var childLayout in LayoutChildren)
1013 if (!childLayout.SetPositionByLayout)
1017 int desiredChildHeight = childLayout.Owner.HeightSpecification;
1018 int desiredChildWidth = childLayout.Owner.WidthSpecification;
1020 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
1022 // Temporarily force children to reuse their original measured width
1023 int originalWidth = desiredChildWidth;
1024 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
1025 // Remeasure with new dimensions
1026 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
1027 uniformMeasureSpec, new LayoutLength(0));
1028 // Restore width specification
1029 childLayout.Owner.WidthSpecification = originalWidth;