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;
24 /// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
26 public class LinearLayout : LayoutGroup
29 /// [Draft] Enumeration for the direction in which the content is laid out
31 /// <since_tizen> 6 </since_tizen>
32 public enum Orientation
45 /// [Draft] Enumeration for the alignment of the linear layout items
47 /// <since_tizen> 6 </since_tizen>
51 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
55 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
59 /// At the horizontal center of the container
61 CenterHorizontal = 0x4,
63 /// At the top edge of the container
67 /// At the bottom edge of the container
71 /// At the vertical center of the container
73 CenterVertical = 0x20,
75 /// At the vertical and horizontal center of the container
80 struct HeightAndWidthState
82 public MeasuredSize.StateType widthState;
83 public MeasuredSize.StateType heightState;
85 public HeightAndWidthState(MeasuredSize.StateType width, MeasuredSize.StateType height)
93 /// [Draft] Get/Set the orientation in the layout
95 /// <since_tizen> 6 </since_tizen>
96 public LinearLayout.Orientation LinearOrientation
100 return _linearOrientation;
104 _linearOrientation = value;
110 /// [Draft] Get/Set the padding between cells in the layout
112 /// <since_tizen> 6 </since_tizen>
113 public Size2D CellPadding
121 _cellPadding = value;
128 /// [Draft] Get/Set the alignment in the layout
130 /// <since_tizen> 6 </since_tizen>
131 public LinearLayout.Alignment LinearAlignment { get; set; } = Alignment.Top;
133 private float _totalLength = 0.0f;
134 private Size2D _cellPadding = new Size2D(0, 0);
135 private Orientation _linearOrientation = Orientation.Horizontal;
138 /// [Draft] Constructor
140 /// <since_tizen> 6 </since_tizen>
141 public LinearLayout()
146 /// Measure the layout and its content to determine the measured width and the measured height.
148 /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
149 /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
150 /// <since_tizen> 6 </since_tizen>
151 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
153 if (_linearOrientation == Orientation.Horizontal)
155 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
159 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
164 /// Layout should assign a size and position to each of its children.<br />
166 /// <param name="changed">This is a new size or position for this layout.</param>
167 /// <param name="left">Left position, relative to parent.</param>
168 /// <param name="top"> Top position, relative to parent.</param>
169 /// <param name="right">Right position, relative to parent.</param>
170 /// <param name="bottom">Bottom position, relative to parent.</param>
171 /// <since_tizen> 6 </since_tizen>
172 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
174 if (_linearOrientation == Orientation.Horizontal)
176 LayoutHorizontal(left, top, right, bottom);
180 LayoutVertical(left, top, right, bottom);
182 LayoutForIndependentChild();
186 private void MeasureWeightedChild(LayoutItem childLayout, float remainingExcess, float remainingWeight, float childWeight,
187 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
188 HeightAndWidthState childState, Orientation orientation)
190 bool horizontal = false;
191 if (orientation == Orientation.Horizontal)
196 float childsShare = (childWeight * remainingExcess) / remainingWeight;
197 remainingExcess -= childsShare;
198 remainingWeight -= childWeight;
200 float desiredWidth = childLayout.Owner.WidthSpecification;
201 float desiredHeight = childLayout.Owner.HeightSpecification;
202 float childLength = 0;
204 // Always lay out weighted elements with intrinsic size regardless of the parent spec.
205 // for consistency between specs.
206 if ((horizontal && (desiredWidth == 0)) || (!horizontal && (desiredHeight == 0)))
208 // This child needs to be laid out from scratch using
209 // only its share of excess space.
210 childLength = childsShare;
214 // This child had some intrinsic width to which we
215 // need to add its share of excess space.
218 childLength = childLayout.MeasuredWidth.Size.AsDecimal() + childsShare;
222 childLength = childLayout.MeasuredHeight.Size.AsDecimal() + childsShare;
226 MeasureSpecification childWidthMeasureSpec;
227 MeasureSpecification childHeightMeasureSpec;
231 childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly);
232 childHeightMeasureSpec = GetChildMeasureSpecification(
233 new MeasureSpecification(
234 new LayoutLength(heightMeasureSpec.Size - (childLayout.Owner.Margin.Top + childLayout.Owner.Margin.Bottom)),
235 heightMeasureSpec.Mode),
236 new LayoutLength(Padding.Top + Padding.Bottom),
237 new LayoutLength(desiredHeight));
241 childWidthMeasureSpec = GetChildMeasureSpecification(
242 new MeasureSpecification(
243 new LayoutLength(widthMeasureSpec.Size - (childLayout.Owner.Margin.Start + childLayout.Owner.Margin.End)),
244 widthMeasureSpec.Mode),
245 new LayoutLength(Padding.Start + Padding.End),
246 new LayoutLength(desiredWidth));
248 childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly);
251 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
253 // Child may now not fit in horizontal dimension.
254 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
256 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
259 // Child may now not fit in vertical dimension.
260 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
262 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
266 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
268 var widthMode = widthMeasureSpec.Mode;
269 var heightMode = heightMeasureSpec.Mode;
270 bool isExactly = (widthMode == MeasureSpecification.ModeType.Exactly);
271 bool matchHeight = false;
272 bool allFillParent = true;
273 float maxHeight = 0.0f;
274 float alternativeMaxHeight = 0.0f;
275 float weightedMaxHeight = 0.0f;
276 float totalWeight = 0.0f;
278 // Reset measure variables
280 float usedExcessSpace = 0.0f;
281 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
282 MeasuredSize.StateType.MeasuredSizeOK);
285 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
286 // to accumulate total used space in totalLength based on measured sizes and margins.
287 // Weighted children are not measured at this phase.
288 // Available space for weighted children will be calculated in the phase 2 based on totalLength value.
289 // Max height of children is stored.
290 for (int i = 0; i < LayoutChildren.Count; i++)
292 LayoutItem childLayout = LayoutChildren[i];
293 if (!childLayout.Owner.ExcludeLayouting)
295 MeasureChildWithoutPadding(childLayout, widthMeasureSpec, heightMeasureSpec);
299 int childDesiredHeight = childLayout.Owner.HeightSpecification;
300 float childWeight = childLayout.Owner.Weight;
301 Extents childMargin = childLayout.Margin;
302 totalWeight += childWeight;
304 bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0) && (childWeight > 0);
305 if (isExactly && useExcessSpace)
307 // Children to be laid out with excess space can be measured later
308 _totalLength = Math.Max(_totalLength, (_totalLength + childMargin.Start + childMargin.End));
314 // Parent is not defiend!!!
315 // The widthMode is either Unspecified or AtMost, and
316 // this child is only laid out using excess space. Measure
317 // using WrapContent so that we can find out the view's
319 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
320 new MeasureSpecification(
321 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
322 widthMeasureSpec.Mode),
323 new LayoutLength(Padding.Start + Padding.End),
324 new LayoutLength(LayoutParamPolicies.WrapContent));
326 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
327 new MeasureSpecification(
328 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
329 heightMeasureSpec.Mode),
330 new LayoutLength(Padding.Top + Padding.Bottom),
331 new LayoutLength(childDesiredHeight));
333 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
334 usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal();
338 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
341 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
342 LayoutLength length = childWidth + childMargin.Start + childMargin.End;
346 _totalLength += length.AsDecimal();
350 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Width : 0));
354 bool matchHeightLocally = false;
355 if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent)
357 // A child has set to MatchParent on it's height.
358 // Will have to re-measure at least this child when we know exact height.
360 matchHeightLocally = true;
363 float marginHeight = childMargin.Top + childMargin.Bottom;
364 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
366 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
368 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
370 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
372 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
375 maxHeight = Math.Max(maxHeight, childHeight);
376 allFillParent = (allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent);
380 // Heights of weighted Views are invalid if we end up remeasuring, so store them separately.
381 weightedMaxHeight = Math.Max(weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight);
385 alternativeMaxHeight = Math.Max(alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight);
389 float widthSize = _totalLength;
390 widthSize = Math.Max(widthSize, SuggestedMinimumWidth.AsDecimal());
391 MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize + Padding.Start + Padding.End), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
392 widthSize = widthSizeAndState.Size.AsDecimal();
395 // Expand children with weight to take up available space
396 // We cycle through weighted children now (children with weight > 0).
397 // The children are measured with exact size equal to their share of the available space based on their weights.
398 // _totalLength is updated to include weighted children measured sizes.
399 float remainingExcess = widthSize - _totalLength + usedExcessSpace - (Padding.Start + Padding.End);
400 if (remainingExcess != 0 && totalWeight > 0)
402 float remainingWeight = totalWeight;
406 int numberOfChildren = LayoutChildren.Count;
407 for (int i = 0; i < numberOfChildren; ++i)
409 LayoutItem childLayout = LayoutChildren[i];
410 if (!childLayout.Owner.ExcludeLayouting)
415 float desiredChildHeight = childLayout.Owner.HeightSpecification;
417 float childWeight = childLayout.Owner.Weight;
418 Extents childMargin = childLayout.Margin;
422 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
423 widthMeasureSpec, heightMeasureSpec, childState,
424 Orientation.Horizontal);
427 float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End;
428 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0;
431 _totalLength += length;
435 float totalLength = _totalLength;
436 _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding);
439 bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent);
440 float marginHeight = childMargin.Top + childMargin.Bottom;
441 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
443 maxHeight = Math.Max(maxHeight, childHeight);
444 alternativeMaxHeight = Math.Max(alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight);
445 allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent);
450 // No excess space or no weighted children
451 alternativeMaxHeight = Math.Max(alternativeMaxHeight, weightedMaxHeight);
454 if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
456 maxHeight = alternativeMaxHeight;
461 // Padding should be concerned when specification is Wrapcontent.
462 maxHeight += (Owner.HeightSpecification == LayoutParamPolicies.WrapContent) ? (Padding.Top + Padding.Bottom) : 0;
463 maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue());
465 widthSizeAndState.State = childState.widthState;
467 SetMeasuredDimensions(widthSizeAndState,
468 ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState));
472 ForceUniformHeight(widthMeasureSpec);
474 } // MeasureHorizontal
476 private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
478 var widthMode = widthMeasureSpec.Mode;
479 var heightMode = heightMeasureSpec.Mode;
480 bool isExactly = (heightMode == MeasureSpecification.ModeType.Exactly);
481 bool matchWidth = false;
482 bool allFillParent = true;
483 float maxWidth = 0.0f;
484 float alternativeMaxWidth = 0.0f;
485 float weightedMaxWidth = 0.0f;
486 float totalWeight = 0.0f;
488 // Reset total length
490 float usedExcessSpace = 0.0f;
491 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
492 MeasuredSize.StateType.MeasuredSizeOK);
495 // measure children, and determine if further resolution is required
498 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
499 // to accumulate total used space in _totalLength.
500 // Weighted children are not measured in this phase.
501 // Available space for weighted children will be calculated in the phase 2 based on _totalLength value.
502 for (int i = 0; i < LayoutChildren.Count; i++)
504 LayoutItem childLayout = LayoutChildren[i];
505 if (!childLayout.Owner.ExcludeLayouting)
507 MeasureChildWithoutPadding(childLayout, widthMeasureSpec, heightMeasureSpec);
511 int childDesiredWidth = childLayout.Owner.WidthSpecification;
512 float childWeight = childLayout.Owner.Weight;
513 Extents childMargin = childLayout.Margin;
514 totalWeight += childWeight;
516 bool useExcessSpace = (childLayout.Owner.HeightSpecification == 0) && (childWeight > 0);
517 if (isExactly && useExcessSpace)
519 _totalLength = Math.Max(_totalLength, (_totalLength + childMargin.Top + childMargin.Bottom));
525 // The heightMode is either Unspecified or AtMost, and
526 // this child is only laid out using excess space. Measure
527 // using WrapContent so that we can find out the view's
529 // We'll restore the original height of 0 after measurement.
530 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
531 new MeasureSpecification(
532 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
533 widthMeasureSpec.Mode),
534 new LayoutLength(Padding.Start + Padding.End),
535 new LayoutLength(childDesiredWidth));
537 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
538 new MeasureSpecification(
539 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
540 heightMeasureSpec.Mode),
541 new LayoutLength(Padding.Top + Padding.Bottom),
542 new LayoutLength(LayoutParamPolicies.WrapContent));
544 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
545 usedExcessSpace += childLayout.MeasuredHeight.Size.AsDecimal();
549 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
552 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
553 LayoutLength length = childHeight + childMargin.Top + childMargin.Bottom;
558 _totalLength += length.AsDecimal();
562 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Height : 0));
566 bool matchWidthLocally = false;
567 if (widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth == LayoutParamPolicies.MatchParent)
569 // Will have to re-measure at least this child when we know exact height.
571 matchWidthLocally = true;
574 float marginWidth = childLayout.Margin.Start + childLayout.Margin.End;
575 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
577 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
579 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
581 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
583 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
586 maxWidth = Math.Max(maxWidth, childWidth);
587 allFillParent = (allFillParent && childDesiredWidth == LayoutParamPolicies.MatchParent);
591 // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
592 weightedMaxWidth = Math.Max(weightedMaxWidth, matchWidthLocally ? marginWidth : childWidth);
596 alternativeMaxWidth = Math.Max(alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth);
601 float heightSize = _totalLength;
602 heightSize = Math.Max(heightSize, SuggestedMinimumHeight.AsDecimal());
603 MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize + Padding.Top + Padding.Bottom), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
604 heightSize = heightSizeAndState.Size.AsDecimal();
607 // We cycle through weighted children now (children with weight > 0).
608 // The children are measured with exact size equal to their share of the available space based on their weights.
609 // _totalLength is updated to include weighted children measured sizes.
610 float remainingExcess = heightSize - _totalLength + usedExcessSpace - (Padding.Top + Padding.Bottom);
611 if (remainingExcess != 0 && totalWeight > 0.0f)
613 float remainingWeight = totalWeight;
617 int numberOfChildren = LayoutChildren.Count;
618 for (int i = 0; i < numberOfChildren; ++i)
620 LayoutItem childLayout = LayoutChildren[i];
621 if (!childLayout.Owner.ExcludeLayouting)
626 float desiredChildWidth = childLayout.Owner.WidthSpecification;
628 float childWeight = childLayout.Owner.Weight;
629 Extents childMargin = childLayout.Margin;
633 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
634 widthMeasureSpec, heightMeasureSpec, childState,
635 Orientation.Vertical);
638 float length = childLayout.MeasuredHeight.Size.AsDecimal() + childMargin.Top + childMargin.Bottom;
639 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0;
643 _totalLength += length;
647 float totalLength = _totalLength;
648 _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding);
651 bool matchWidthLocally = (widthMode != MeasureSpecification.ModeType.Exactly) && (desiredChildWidth == LayoutParamPolicies.MatchParent);
652 float marginWidth = childMargin.Start + childMargin.End;
653 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
655 maxWidth = Math.Max(maxWidth, childWidth);
656 alternativeMaxWidth = Math.Max(alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth);
657 allFillParent = (allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent);
662 alternativeMaxWidth = Math.Max(alternativeMaxWidth, weightedMaxWidth);
665 if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
667 maxWidth = alternativeMaxWidth;
670 maxWidth += (Owner.WidthSpecification == LayoutParamPolicies.WrapContent) ? (Padding.Start + Padding.End) : 0;
671 maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue());
673 heightSizeAndState.State = childState.heightState;
675 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState),
680 ForceUniformWidth(heightMeasureSpec);
684 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
686 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
688 LayoutLength childTop = new LayoutLength(Padding.Top);
689 LayoutLength childLeft = new LayoutLength(Padding.Start);
691 // Where bottom of child should go
692 LayoutLength height = new LayoutLength(bottom - top);
694 // Space available for child
695 LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom);
697 int count = LayoutChildren.Count;
699 switch (LinearAlignment)
702 // totalLength contains the padding already
703 // In case of RTL map END alignment to the left edge
706 childLeft = new LayoutLength(Padding.Start);
710 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
713 case Alignment.CenterHorizontal: // FALL THROUGH
714 case Alignment.Center:
715 // totalLength contains the padding already
716 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
718 case Alignment.Begin: // FALL THROUGH (default)
720 // totalLength contains the padding already
721 // In case of RTL map BEGIN alignment to the right edge
724 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
728 childLeft = new LayoutLength(Padding.Start);
736 // In case of RTL, start drawing from the last child.
743 for (int i = 0; i < count; i++)
745 int childIndex = start + dir * i;
746 // Get a reference to the childLayout at the given index
747 LayoutItem childLayout = LayoutChildren[childIndex];
748 if (childLayout != null)
750 if (childLayout.Owner.ExcludeLayouting)
752 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
753 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
754 Extents childMargin = childLayout.Margin;
756 switch (LinearAlignment)
758 case Alignment.Bottom:
759 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
761 case Alignment.CenterVertical:
762 case Alignment.Center: // FALLTHROUGH
763 childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom);
765 case Alignment.Top: // FALLTHROUGH default
767 childTop = new LayoutLength(Padding.Top + childMargin.Top);
770 childLeft += childMargin.Start;
771 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
772 childLeft += childWidth + childMargin.End + ((i < count - 1) ? CellPadding.Width : 0);
776 } // LayoutHorizontally
778 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
780 LayoutLength childTop = new LayoutLength(Padding.Top);
781 LayoutLength childLeft = new LayoutLength(Padding.Start);
783 // Where end of child should go
784 LayoutLength width = new LayoutLength(right - left);
786 // Space available for child
787 LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End);
789 int count = LayoutChildren.Count;
791 switch (LinearAlignment)
793 case Alignment.Bottom:
794 // totalLength contains the padding already
795 childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
797 case Alignment.CenterVertical: // FALL THROUGH
798 case Alignment.Center:
799 // totalLength contains the padding already
800 childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - _totalLength) / 2.0f);
802 case Alignment.Top: // FALL THROUGH (default)
804 // totalLength contains the padding already
805 childTop = new LayoutLength(Padding.Top);
809 for (int i = 0; i < count; i++)
811 LayoutItem childLayout = LayoutChildren[i];
812 if (childLayout != null)
814 if (childLayout.Owner.ExcludeLayouting)
816 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
817 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
818 Extents childMargin = childLayout.Margin;
820 childTop += childMargin.Top;
821 switch (LinearAlignment)
823 case Alignment.Begin:
826 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
831 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
834 case Alignment.CenterHorizontal:
835 case Alignment.Center: // FALL THROUGH
837 childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
841 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
842 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
848 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
850 // Pretend that the linear layout has an exact size. This is the measured height of
851 // ourselves. The measured height should be the max height of the children, changed
852 // to accommodate the heightMeasureSpec from the parent
853 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
854 foreach (LayoutItem childLayout in LayoutChildren)
856 if (!childLayout.Owner.ExcludeLayouting)
860 int desiredChildHeight = childLayout.Owner.HeightSpecification;
861 int desiredChildWidth = childLayout.Owner.WidthSpecification;
863 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
865 // Temporarily force children to reuse their original measured width
866 int originalWidth = desiredChildWidth;
867 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
868 // Remeasure with new dimensions
869 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0),
870 uniformMeasureSpec, new LayoutLength(0));
871 // Restore width specification
872 childLayout.Owner.WidthSpecification = originalWidth;
877 private void ForceUniformWidth(MeasureSpecification heightMeasureSpec)
879 // Pretend that the linear layout has an exact size.
880 MeasureSpecification uniformMeasureSpec = new MeasureSpecification(MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
881 foreach (LayoutItem childLayout in LayoutChildren)
883 if (!childLayout.Owner.ExcludeLayouting)
888 int desiredChildWidth = childLayout.Owner.WidthSpecification;
889 int desiredChildHeight = childLayout.Owner.WidthSpecification;
891 if (desiredChildWidth == LayoutParamPolicies.MatchParent)
893 // Temporarily force children to reuse their original measured height
894 int originalHeight = desiredChildHeight;
895 childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
897 // Remeasure with new dimensions
898 MeasureChildWithMargins(childLayout, uniformMeasureSpec, new LayoutLength(0),
899 heightMeasureSpec, new LayoutLength(0));
900 // Restore height specification
901 childLayout.Owner.HeightSpecification = originalHeight;