1 /* Copyright (c) 2019 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 internal class LinearLayout : LayoutGroup
29 /// [Draft] Enumeration for the direction in which the content is laid out
31 public enum Orientation
44 /// [Draft] Enumeration for the alignment of the linear layout items
49 /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
53 /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
57 /// At the horizontal center of the container
59 CenterHorizontal = 0x4,
61 /// At the top edge of the container
65 /// At the bottom edge of the container
69 /// At the vertical center of the container
71 CenterVertical = 0x20,
73 /// At the vertical and horizontal center of the container
78 struct HeightAndWidthState
80 public MeasuredSize.StateType widthState;
81 public MeasuredSize.StateType heightState;
83 public HeightAndWidthState( MeasuredSize.StateType width, MeasuredSize.StateType height)
91 /// [Draft] Get/Set the orientation in the layout
93 public LinearLayout.Orientation LinearOrientation
97 return _linearOrientation;
101 _linearOrientation = value;
107 /// [Draft] Get/Set the padding between cells in the layout
109 public Size2D CellPadding
117 _cellPadding = value;
124 /// [Draft] Get/Set the alignment in the layout
126 public LinearLayout.Alignment LinearAlignment{ get; set; } = Alignment.Top;
128 private float _totalLength = 0.0f;
129 private Size2D _cellPadding = new Size2D(0,0);
130 private Orientation _linearOrientation = Orientation.Horizontal;
133 /// [Draft] Constructor
135 public LinearLayout()
139 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
141 if (_linearOrientation == Orientation.Horizontal)
143 MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
147 MeasureVertical(widthMeasureSpec, heightMeasureSpec);
151 protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
153 if (_linearOrientation == Orientation.Horizontal)
155 LayoutHorizontal(left, top, right, bottom);
159 LayoutVertical(left, top, right, bottom);
164 private void MeasureWeightedChild( LayoutItem childLayout, float remainingExcess, float remainingWeight, float childWeight,
165 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
166 HeightAndWidthState childState, Orientation orientation )
168 bool horizontal = false;
169 if (orientation == Orientation.Horizontal)
174 float childsShare = ( childWeight * remainingExcess ) / remainingWeight;
175 remainingExcess -= childsShare;
176 remainingWeight -= childWeight;
178 float desiredWidth = childLayout.Owner.WidthSpecification;
179 float desiredHeight = childLayout.Owner.HeightSpecification;
180 float childLength = 0;
182 Extents layoutPadding = Padding;
184 // Always lay out weighted elements with intrinsic size regardless of the parent spec.
185 // for consistency between specs.
186 if( ( horizontal && ( desiredWidth == 0 )) || ( !horizontal && ( desiredHeight == 0 )) )
188 // This child needs to be laid out from scratch using
189 // only its share of excess space.
190 childLength = childsShare;
194 // This child had some intrinsic width to which we
195 // need to add its share of excess space.
198 childLength = childLayout.MeasuredWidth.Size.AsDecimal() + childsShare;
202 childLength = childLayout.MeasuredHeight.Size.AsDecimal() + childsShare;
206 MeasureSpecification childWidthMeasureSpec;
207 MeasureSpecification childHeightMeasureSpec;
211 childWidthMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly );
212 childHeightMeasureSpec = GetChildMeasureSpecification( heightMeasureSpec,
213 new LayoutLength(layoutPadding.Top + layoutPadding.Bottom),
214 new LayoutLength(desiredHeight) );
218 childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
219 new LayoutLength(Padding.Start + Padding.End),
220 new LayoutLength(desiredWidth) );
222 childHeightMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly);
225 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
227 // Child may now not fit in horizontal dimension.
228 if( childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
230 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
233 // Child may now not fit in vertical dimension.
234 if( childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
236 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
240 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
242 var widthMode = widthMeasureSpec.Mode;
243 var heightMode = heightMeasureSpec.Mode;
244 bool isExactly = ( widthMode == MeasureSpecification.ModeType.Exactly );
245 bool matchHeight = false;
246 bool allFillParent = true;
247 float maxHeight = 0.0f;
248 float alternativeMaxHeight = 0.0f;
249 float weightedMaxHeight = 0.0f;
250 float totalWeight = 0.0f;
252 // Reset measure variables
254 float usedExcessSpace = 0.0f;
255 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
256 MeasuredSize.StateType.MeasuredSizeOK);
259 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
260 // to accumulate total used space in totalLength based on measured sizes and margins.
261 // Weighted children are not measured at this phase.
262 // Available space for weighted children will be calculated in the phase 2 based on totalLength value.
263 // Max height of children is stored.
264 foreach( LayoutItem childLayout in _children )
266 int childDesiredHeight = childLayout.Owner.HeightSpecification;
267 float childWeight = childLayout.Owner.Weight;
268 Extents childMargin = childLayout.Margin;
269 totalWeight += childWeight;
271 bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0 ) && (childWeight > 0);
272 if( isExactly && useExcessSpace )
274 // Children to be laid out with excess space can be measured later
275 _totalLength += childMargin.Start + childMargin.End;
281 // The widthMode is either Unspecified or AtMost, and
282 // this child is only laid out using excess space. Measure
283 // using WrapContent so that we can find out the view's
285 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec,
286 new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
287 new LayoutLength(LayoutParamPolicies.WrapContent));
289 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(heightMeasureSpec,
290 new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
291 new LayoutLength(childDesiredHeight));
293 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec);
294 usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal();
298 MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
301 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
302 LayoutLength length = childWidth + childMargin.Start + childMargin.End;
306 _totalLength += length.AsDecimal();
310 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Width);
314 bool matchHeightLocally = false;
315 if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent)
317 // A child has set to MatchParent on it's height.
318 // Will have to re-measure at least this child when we know exact height.
320 matchHeightLocally = true;
323 float marginHeight = childMargin.Top + childMargin.Bottom;
324 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
326 if (childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
328 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
330 if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
332 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
335 maxHeight = Math.Max( maxHeight, childHeight);
336 allFillParent = ( allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent);
340 // Heights of weighted Views are invalid if we end up remeasuring, so store them separately.
341 weightedMaxHeight = Math.Max( weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight);
345 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
349 Extents padding = Padding;
350 _totalLength += padding.Start + padding.End;
352 float widthSize = _totalLength;
353 widthSize = Math.Max( widthSize, SuggestedMinimumWidth.AsDecimal());
354 MeasuredSize widthSizeAndState = ResolveSizeAndState( new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
355 widthSize = widthSizeAndState.Size.AsDecimal();
358 // Expand children with weight to take up available space
359 // We cycle through weighted children now (children with weight > 0).
360 // The children are measured with exact size equal to their share of the available space based on their weights.
361 // _totalLength is updated to include weighted children measured sizes.
362 float remainingExcess = widthSize - _totalLength + usedExcessSpace;
363 if( remainingExcess != 0 && totalWeight > 0 )
365 float remainingWeight = totalWeight;
369 int numberOfChildren = _children.Count;
370 for( int i = 0; i < numberOfChildren; ++i )
372 LayoutItem childLayout = _children[i];
374 float desiredChildHeight = childLayout.Owner.HeightSpecification;
376 float childWeight = childLayout.Owner.Weight;
377 Extents childMargin = childLayout.Margin;
379 if( childWeight > 0 )
381 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
382 widthMeasureSpec, heightMeasureSpec, childState,
383 Orientation.Horizontal );
386 float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End;
387 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0;
390 _totalLength += length;
394 float totalLength = _totalLength;
395 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
398 bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent);
399 float marginHeight = childMargin.Top + childMargin.Bottom;
400 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
402 maxHeight = Math.Max( maxHeight, childHeight );
403 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
404 allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent);
406 _totalLength += padding.Start + padding.End;
411 // No excess space or no weighted children
412 alternativeMaxHeight = Math.Max( alternativeMaxHeight, weightedMaxHeight );
415 if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
417 maxHeight = alternativeMaxHeight;
420 maxHeight += padding.Top + padding.Bottom;
421 maxHeight = Math.Max( maxHeight, SuggestedMinimumHeight.AsRoundedValue() );
423 widthSizeAndState.State = childState.widthState;
425 SetMeasuredDimensions(widthSizeAndState,
426 ResolveSizeAndState( new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState ));
430 ForceUniformHeight(widthMeasureSpec);
432 } // MeasureHorizontal
434 private void MeasureVertical( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
436 var widthMode = widthMeasureSpec.Mode;
437 var heightMode = heightMeasureSpec.Mode;
438 bool isExactly = ( heightMode == MeasureSpecification.ModeType.Exactly);
439 bool matchWidth = false;
440 bool allFillParent = true;
441 float maxWidth = 0.0f;
442 float alternativeMaxWidth = 0.0f;
443 float weightedMaxWidth = 0.0f;
444 float totalWeight = 0.0f;
446 // Reset total length
448 float usedExcessSpace =0.0f;
450 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
451 MeasuredSize.StateType.MeasuredSizeTooSmall);
454 // measure children, and determine if further resolution is required
457 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
458 // to accumulate total used space in _totalLength.
459 // Weighted children are not measured in this phase.
460 // Available space for weighted children will be calculated in the phase 2 based on _totalLength value.
462 foreach( LayoutItem childLayout in _children )
464 int childDesiredWidth = childLayout.Owner.WidthSpecification;
465 int childDesiredHeight = childLayout.Owner.HeightSpecification;
466 float childWeight = childLayout.Owner.Weight;
467 Extents childMargin = childLayout.Margin;
468 totalWeight += childWeight;
470 bool useExcessSpace = (childDesiredHeight == 0) && (childWeight > 0);
472 if( isExactly && useExcessSpace )
474 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Top + childMargin.Bottom) );
478 float childHeight = 0.0f;
481 // The heightMode is either Unspecified or AtMost, and
482 // this child is only laid out using excess space. Measure
483 // using WrapContent so that we can find out the view's
485 // We'll restore the original height of 0 after measurement.
486 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
487 new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
488 new LayoutLength(childDesiredWidth) );
489 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( heightMeasureSpec,
490 new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
491 new LayoutLength(LayoutParamPolicies.WrapContent) );
492 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
493 childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
494 usedExcessSpace += childHeight;
498 MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
499 childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
502 float length = childHeight + childMargin.Top + childMargin.Bottom;
503 float cellPadding = CellPadding.Height;
504 // No need to add cell padding to the end of last item.
505 if (index>=_children.Count-1)
509 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
512 bool matchWidthLocally = false;
513 if( widthMode != MeasureSpecification.ModeType.Exactly && (childDesiredWidth == LayoutParamPolicies.MatchParent) )
515 // Will have to re-measure at least this child when we know exact height.
517 matchWidthLocally = true;
520 float marginWidth = (childLayout.Margin.Start) + (childLayout.Margin.End);
521 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
523 if (childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
525 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
527 if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
529 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
532 maxWidth = Math.Max( maxWidth, childWidth);
533 allFillParent = (allFillParent && (childDesiredWidth == LayoutParamPolicies.MatchParent));
535 float widthforWeight = childWidth;
536 if (matchWidthLocally)
538 widthforWeight = marginWidth;
543 // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
544 weightedMaxWidth = Math.Max( weightedMaxWidth, widthforWeight);
548 alternativeMaxWidth = Math.Max( alternativeMaxWidth, widthforWeight);
554 Extents padding = Padding;
555 _totalLength += padding.Top + padding.Bottom;
556 LayoutLength heightSize = new LayoutLength(_totalLength);
557 heightSize = new LayoutLength(Math.Max( heightSize.AsDecimal(), SuggestedMinimumHeight.AsDecimal() ));
558 MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
559 heightSize = heightSizeAndState.Size;
562 // We cycle through weighted children now (children with weight > 0).
563 // The children are measured with exact size equal to their share of the available space based on their weights.
564 // _totalLength is updated to include weighted children measured sizes.
565 float remainingExcess = heightSize.AsDecimal() - _totalLength + usedExcessSpace;
567 if( remainingExcess != 0 && totalWeight > 0.0f )
569 float remainingWeight = totalWeight;
573 int numberOfChildren = _children.Count;
574 for( int i = 0; i < numberOfChildren; ++i )
576 LayoutItem childLayout = _children[i];
578 float desiredChildWidth = childLayout.Owner.WidthSpecification;
580 float childWeight = childLayout.Owner.Weight;
581 Extents childMargin = childLayout.Margin;
583 if( childWeight > 0 )
585 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
586 widthMeasureSpec, heightMeasureSpec, childState,
587 Orientation.Vertical);
590 bool matchWidthLocally = false;
591 if( widthMode != MeasureSpecification.ModeType.Exactly && desiredChildWidth == LayoutParamPolicies.MatchParent)
593 // Will have to re-measure at least this child when we know exact height.
595 matchWidthLocally = true;
598 float marginWidth = childMargin.Start + childMargin.End;
599 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
600 maxWidth = Math.Max( maxWidth, childWidth );
601 allFillParent = allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent;
603 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
604 float childLength = childHeight + childMargin.Top + childMargin.Bottom;
605 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0.0f;
606 _totalLength = _totalLength + childLength + cellPadding;
607 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
610 // Add in our padding
611 _totalLength += padding.Top + padding.Bottom;
615 alternativeMaxWidth = Math.Max( alternativeMaxWidth, weightedMaxWidth );
618 if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
620 maxWidth = alternativeMaxWidth;
622 maxWidth += padding.Start + padding.End;
623 maxWidth = Math.Max( maxWidth, SuggestedMinimumWidth.AsRoundedValue());
625 heightSizeAndState.State = childState.heightState;
627 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState ),
628 heightSizeAndState );
632 ForceUniformWidth(heightMeasureSpec );
636 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
638 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
640 LayoutLength childTop = new LayoutLength(Padding.Top);
641 LayoutLength childLeft = new LayoutLength(Padding.Start);
643 // Where bottom of child should go
644 LayoutLength height = new LayoutLength(bottom - top);
646 // Space available for child
647 LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
649 int count = _children.Count;
651 switch (LinearAlignment)
654 // totalLength contains the padding already
655 // In case of RTL map END alignment to the left edge
658 childLeft = new LayoutLength(Padding.Start);
662 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
665 case Alignment.CenterHorizontal: // FALL THROUGH
666 case Alignment.Center:
667 // totalLength contains the padding already
668 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
670 case Alignment.Begin: // FALL THROUGH (default)
672 // totalLength contains the padding already
673 // In case of RTL map BEGIN alignment to the right edge
676 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
680 childLeft = new LayoutLength(Padding.Start);
688 // In case of RTL, start drawing from the last child.
695 for( int i = 0; i < count; i++)
697 int childIndex = start + dir * i;
698 // Get a reference to the childLayout at the given index
699 LayoutItem childLayout = _children[childIndex];
700 if( childLayout != null )
702 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
703 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
704 Extents childMargin = childLayout.Margin;
706 switch ( LinearAlignment )
708 case Alignment.Bottom:
709 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
711 case Alignment.CenterVertical:
712 case Alignment.Center: // FALLTHROUGH
713 childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
715 case Alignment.Top: // FALLTHROUGH default
717 childTop = new LayoutLength(Padding.Top + childMargin.Top);
720 childLeft += childMargin.Start;
721 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
722 childLeft += childWidth + childMargin.End + CellPadding.Width;
725 } // LayoutHorizontally
727 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
729 LayoutLength childTop = new LayoutLength(Padding.Top);
730 LayoutLength childLeft = new LayoutLength(Padding.Start);
732 // Where end of child should go
733 LayoutLength width = new LayoutLength(right - left);
735 // Space available for child
736 LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
738 int count = _children.Count;
740 switch (LinearAlignment)
742 case Alignment.Bottom:
743 // totalLength contains the padding already
744 childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
746 case Alignment.CenterVertical: // FALL THROUGH
747 case Alignment.Center:
748 // totalLength contains the padding already
749 childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
751 case Alignment.Top: // FALL THROUGH (default)
753 // totalLength contains the padding already
754 childTop = new LayoutLength( Padding.Top );
758 for( int i = 0; i < count; i++)
760 LayoutItem childLayout = _children[i];
761 if( childLayout != null )
763 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
764 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
765 Extents childMargin = childLayout.Margin;
767 childTop += childMargin.Top;
768 switch ( LinearAlignment )
770 case Alignment.Begin:
773 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
778 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
781 case Alignment.CenterHorizontal:
782 case Alignment.Center: // FALL THROUGH
784 childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
788 childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
789 childTop += childHeight + childMargin.Bottom + CellPadding.Height;
794 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
796 // Pretend that the linear layout has an exact size. This is the measured height of
797 // ourselves. The measured height should be the max height of the children, changed
798 // to accommodate the heightMeasureSpec from the parent
799 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
800 foreach (LayoutItem childLayout in _children)
802 int desiredChildHeight = childLayout.Owner.HeightSpecification;
803 int desiredChildWidth = childLayout.Owner.WidthSpecification;
805 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
807 // Temporarily force children to reuse their original measured width
808 int originalWidth = desiredChildWidth;
809 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
810 // Remeasure with new dimensions
811 MeasureChildWithMargins( childLayout, widthMeasureSpec, new LayoutLength(0),
812 uniformMeasureSpec, new LayoutLength(0) );
813 // Restore width specification
814 childLayout.Owner.WidthSpecification = originalWidth;
819 private void ForceUniformWidth(MeasureSpecification heightMeasureSpec)
821 // Pretend that the linear layout has an exact size.
822 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
823 foreach (LayoutItem childLayout in _children)
825 int desiredChildWidth = childLayout.Owner.WidthSpecification;
826 int desiredChildHeight = childLayout.Owner.WidthSpecification;
828 if (desiredChildWidth == LayoutParamPolicies.MatchParent)
830 // Temporarily force children to reuse their original measured height
831 int originalHeight = desiredChildHeight;
832 childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
834 // Remeasure with new dimensions
835 MeasureChildWithMargins( childLayout, uniformMeasureSpec, new LayoutLength(0),
836 heightMeasureSpec, new LayoutLength(0));
837 // Restore height specification
838 childLayout.Owner.HeightSpecification = originalHeight;