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 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);
185 private void MeasureWeightedChild( LayoutItem childLayout, float remainingExcess, float remainingWeight, float childWeight,
186 MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec,
187 HeightAndWidthState childState, Orientation orientation )
189 bool horizontal = false;
190 if (orientation == Orientation.Horizontal)
195 float childsShare = ( childWeight * remainingExcess ) / remainingWeight;
196 remainingExcess -= childsShare;
197 remainingWeight -= childWeight;
199 float desiredWidth = childLayout.Owner.WidthSpecification;
200 float desiredHeight = childLayout.Owner.HeightSpecification;
201 float childLength = 0;
203 Extents layoutPadding = Padding;
205 // Always lay out weighted elements with intrinsic size regardless of the parent spec.
206 // for consistency between specs.
207 if( ( horizontal && ( desiredWidth == 0 )) || ( !horizontal && ( desiredHeight == 0 )) )
209 // This child needs to be laid out from scratch using
210 // only its share of excess space.
211 childLength = childsShare;
215 // This child had some intrinsic width to which we
216 // need to add its share of excess space.
219 childLength = childLayout.MeasuredWidth.Size.AsDecimal() + childsShare;
223 childLength = childLayout.MeasuredHeight.Size.AsDecimal() + childsShare;
227 MeasureSpecification childWidthMeasureSpec;
228 MeasureSpecification childHeightMeasureSpec;
232 childWidthMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly );
233 childHeightMeasureSpec = GetChildMeasureSpecification( heightMeasureSpec,
234 new LayoutLength(layoutPadding.Top + layoutPadding.Bottom),
235 new LayoutLength(desiredHeight) );
239 childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
240 new LayoutLength(Padding.Start + Padding.End),
241 new LayoutLength(desiredWidth) );
243 childHeightMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly);
246 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
248 // Child may now not fit in horizontal dimension.
249 if( childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
251 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
254 // Child may now not fit in vertical dimension.
255 if( childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
257 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
261 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
263 var widthMode = widthMeasureSpec.Mode;
264 var heightMode = heightMeasureSpec.Mode;
265 bool isExactly = ( widthMode == MeasureSpecification.ModeType.Exactly );
266 bool matchHeight = false;
267 bool allFillParent = true;
268 float maxHeight = 0.0f;
269 float alternativeMaxHeight = 0.0f;
270 float weightedMaxHeight = 0.0f;
271 float totalWeight = 0.0f;
273 // Reset measure variables
275 float usedExcessSpace = 0.0f;
276 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
277 MeasuredSize.StateType.MeasuredSizeOK);
280 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
281 // to accumulate total used space in totalLength based on measured sizes and margins.
282 // Weighted children are not measured at this phase.
283 // Available space for weighted children will be calculated in the phase 2 based on totalLength value.
284 // Max height of children is stored.
285 foreach( LayoutItem childLayout in LayoutChildren )
287 int childDesiredHeight = childLayout.Owner.HeightSpecification;
288 float childWeight = childLayout.Owner.Weight;
289 Extents childMargin = childLayout.Margin;
290 totalWeight += childWeight;
292 bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0 ) && (childWeight > 0);
293 if( isExactly && useExcessSpace )
295 // Children to be laid out with excess space can be measured later
296 _totalLength += childMargin.Start + childMargin.End;
302 // The widthMode is either Unspecified or AtMost, and
303 // this child is only laid out using excess space. Measure
304 // using WrapContent so that we can find out the view's
306 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec,
307 new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
308 new LayoutLength(LayoutParamPolicies.WrapContent));
310 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(heightMeasureSpec,
311 new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
312 new LayoutLength(childDesiredHeight));
314 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec);
315 usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal();
319 MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
322 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
323 LayoutLength length = childWidth + childMargin.Start + childMargin.End;
327 _totalLength += length.AsDecimal();
331 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Width);
335 bool matchHeightLocally = false;
336 if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent)
338 // A child has set to MatchParent on it's height.
339 // Will have to re-measure at least this child when we know exact height.
341 matchHeightLocally = true;
344 float marginHeight = childMargin.Top + childMargin.Bottom;
345 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
347 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
349 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
351 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
353 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
356 maxHeight = Math.Max( maxHeight, childHeight);
357 allFillParent = ( allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent);
361 // Heights of weighted Views are invalid if we end up remeasuring, so store them separately.
362 weightedMaxHeight = Math.Max( weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight);
366 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
370 Extents padding = Padding;
371 _totalLength += padding.Start + padding.End;
373 float widthSize = _totalLength;
374 widthSize = Math.Max( widthSize, SuggestedMinimumWidth.AsDecimal());
375 MeasuredSize widthSizeAndState = ResolveSizeAndState( new LayoutLength(widthSize), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
376 widthSize = widthSizeAndState.Size.AsDecimal();
379 // Expand children with weight to take up available space
380 // We cycle through weighted children now (children with weight > 0).
381 // The children are measured with exact size equal to their share of the available space based on their weights.
382 // _totalLength is updated to include weighted children measured sizes.
383 float remainingExcess = widthSize - _totalLength + usedExcessSpace;
384 if( remainingExcess != 0 && totalWeight > 0 )
386 float remainingWeight = totalWeight;
390 int numberOfChildren = LayoutChildren.Count;
391 for( int i = 0; i < numberOfChildren; ++i )
393 LayoutItem childLayout = LayoutChildren[i];
395 float desiredChildHeight = childLayout.Owner.HeightSpecification;
397 float childWeight = childLayout.Owner.Weight;
398 Extents childMargin = childLayout.Margin;
400 if( childWeight > 0 )
402 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
403 widthMeasureSpec, heightMeasureSpec, childState,
404 Orientation.Horizontal );
407 float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End;
408 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0;
411 _totalLength += length;
415 float totalLength = _totalLength;
416 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
419 bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent);
420 float marginHeight = childMargin.Top + childMargin.Bottom;
421 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
423 maxHeight = Math.Max( maxHeight, childHeight );
424 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
425 allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent);
427 _totalLength += padding.Start + padding.End;
432 // No excess space or no weighted children
433 alternativeMaxHeight = Math.Max( alternativeMaxHeight, weightedMaxHeight );
436 if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
438 maxHeight = alternativeMaxHeight;
441 maxHeight += padding.Top + padding.Bottom;
442 maxHeight = Math.Max( maxHeight, SuggestedMinimumHeight.AsRoundedValue() );
444 widthSizeAndState.State = childState.widthState;
446 SetMeasuredDimensions(widthSizeAndState,
447 ResolveSizeAndState( new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState ));
451 ForceUniformHeight(widthMeasureSpec);
453 } // MeasureHorizontal
455 private void MeasureVertical( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
457 var widthMode = widthMeasureSpec.Mode;
458 var heightMode = heightMeasureSpec.Mode;
459 bool isExactly = ( heightMode == MeasureSpecification.ModeType.Exactly);
460 bool matchWidth = false;
461 bool allFillParent = true;
462 float maxWidth = 0.0f;
463 float alternativeMaxWidth = 0.0f;
464 float weightedMaxWidth = 0.0f;
465 float totalWeight = 0.0f;
467 // Reset total length
469 float usedExcessSpace =0.0f;
471 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
472 MeasuredSize.StateType.MeasuredSizeTooSmall);
475 // measure children, and determine if further resolution is required
478 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
479 // to accumulate total used space in _totalLength.
480 // Weighted children are not measured in this phase.
481 // Available space for weighted children will be calculated in the phase 2 based on _totalLength value.
483 foreach( LayoutItem childLayout in LayoutChildren )
485 int childDesiredWidth = childLayout.Owner.WidthSpecification;
486 int childDesiredHeight = childLayout.Owner.HeightSpecification;
487 float childWeight = childLayout.Owner.Weight;
488 Extents childMargin = childLayout.Margin;
489 totalWeight += childWeight;
491 bool useExcessSpace = (childDesiredHeight == 0) && (childWeight > 0);
493 if( isExactly && useExcessSpace )
495 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Top + childMargin.Bottom) );
499 float childHeight = 0.0f;
502 // The heightMode is either Unspecified or AtMost, and
503 // this child is only laid out using excess space. Measure
504 // using WrapContent so that we can find out the view's
506 // We'll restore the original height of 0 after measurement.
507 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
508 new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
509 new LayoutLength(childDesiredWidth) );
510 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( heightMeasureSpec,
511 new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
512 new LayoutLength(LayoutParamPolicies.WrapContent) );
513 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
514 childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
515 usedExcessSpace += childHeight;
519 MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
520 childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
523 float length = childHeight + childMargin.Top + childMargin.Bottom;
524 float cellPadding = CellPadding.Height;
525 // No need to add cell padding to the end of last item.
526 if (index>=LayoutChildren.Count-1)
530 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
533 bool matchWidthLocally = false;
534 if( widthMode != MeasureSpecification.ModeType.Exactly && (childDesiredWidth == LayoutParamPolicies.MatchParent) )
536 // Will have to re-measure at least this child when we know exact height.
538 matchWidthLocally = true;
541 float marginWidth = (childLayout.Margin.Start) + (childLayout.Margin.End);
542 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
544 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
546 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
548 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
550 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
553 maxWidth = Math.Max( maxWidth, childWidth);
554 allFillParent = (allFillParent && (childDesiredWidth == LayoutParamPolicies.MatchParent));
556 float widthforWeight = childWidth;
557 if (matchWidthLocally)
559 widthforWeight = marginWidth;
564 // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
565 weightedMaxWidth = Math.Max( weightedMaxWidth, widthforWeight);
569 alternativeMaxWidth = Math.Max( alternativeMaxWidth, widthforWeight);
575 Extents padding = Padding;
576 _totalLength += padding.Top + padding.Bottom;
577 LayoutLength heightSize = new LayoutLength(_totalLength);
578 heightSize = new LayoutLength(Math.Max( heightSize.AsDecimal(), SuggestedMinimumHeight.AsDecimal() ));
579 MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
580 heightSize = heightSizeAndState.Size;
583 // We cycle through weighted children now (children with weight > 0).
584 // The children are measured with exact size equal to their share of the available space based on their weights.
585 // _totalLength is updated to include weighted children measured sizes.
586 float remainingExcess = heightSize.AsDecimal() - _totalLength + usedExcessSpace;
588 if( remainingExcess != 0 && totalWeight > 0.0f )
590 float remainingWeight = totalWeight;
594 int numberOfChildren = LayoutChildren.Count;
595 for( int i = 0; i < numberOfChildren; ++i )
597 LayoutItem childLayout = LayoutChildren[i];
599 float desiredChildWidth = childLayout.Owner.WidthSpecification;
601 float childWeight = childLayout.Owner.Weight;
602 Extents childMargin = childLayout.Margin;
604 if( childWeight > 0 )
606 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
607 widthMeasureSpec, heightMeasureSpec, childState,
608 Orientation.Vertical);
611 bool matchWidthLocally = false;
612 if( widthMode != MeasureSpecification.ModeType.Exactly && desiredChildWidth == LayoutParamPolicies.MatchParent)
614 // Will have to re-measure at least this child when we know exact height.
616 matchWidthLocally = true;
619 float marginWidth = childMargin.Start + childMargin.End;
620 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
621 maxWidth = Math.Max( maxWidth, childWidth );
622 allFillParent = allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent;
624 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
625 float childLength = childHeight + childMargin.Top + childMargin.Bottom;
626 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0.0f;
627 _totalLength = _totalLength + childLength + cellPadding;
628 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
631 // Add in our padding
632 _totalLength += padding.Top + padding.Bottom;
636 alternativeMaxWidth = Math.Max( alternativeMaxWidth, weightedMaxWidth );
639 if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
641 maxWidth = alternativeMaxWidth;
643 maxWidth += padding.Start + padding.End;
644 maxWidth = Math.Max( maxWidth, SuggestedMinimumWidth.AsRoundedValue());
646 heightSizeAndState.State = childState.heightState;
648 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState ),
649 heightSizeAndState );
653 ForceUniformWidth(heightMeasureSpec );
657 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
659 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
661 LayoutLength childTop = new LayoutLength(Padding.Top);
662 LayoutLength childLeft = new LayoutLength(Padding.Start);
664 // Where bottom of child should go
665 LayoutLength height = new LayoutLength(bottom - top);
667 // Space available for child
668 LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
670 int count = LayoutChildren.Count;
672 switch (LinearAlignment)
675 // totalLength contains the padding already
676 // In case of RTL map END alignment to the left edge
679 childLeft = new LayoutLength(Padding.Start);
683 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
686 case Alignment.CenterHorizontal: // FALL THROUGH
687 case Alignment.Center:
688 // totalLength contains the padding already
689 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
691 case Alignment.Begin: // FALL THROUGH (default)
693 // totalLength contains the padding already
694 // In case of RTL map BEGIN alignment to the right edge
697 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
701 childLeft = new LayoutLength(Padding.Start);
709 // In case of RTL, start drawing from the last child.
716 for( int i = 0; i < count; i++)
718 int childIndex = start + dir * i;
719 // Get a reference to the childLayout at the given index
720 LayoutItem childLayout = LayoutChildren[childIndex];
721 if( childLayout != null )
723 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
724 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
725 Extents childMargin = childLayout.Margin;
727 switch ( LinearAlignment )
729 case Alignment.Bottom:
730 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
732 case Alignment.CenterVertical:
733 case Alignment.Center: // FALLTHROUGH
734 childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
736 case Alignment.Top: // FALLTHROUGH default
738 childTop = new LayoutLength(Padding.Top + childMargin.Top);
741 childLeft += childMargin.Start;
742 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
743 childLeft += childWidth + childMargin.End + CellPadding.Width;
746 } // LayoutHorizontally
748 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
750 LayoutLength childTop = new LayoutLength(Padding.Top);
751 LayoutLength childLeft = new LayoutLength(Padding.Start);
753 // Where end of child should go
754 LayoutLength width = new LayoutLength(right - left);
756 // Space available for child
757 LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
759 int count = LayoutChildren.Count;
761 switch (LinearAlignment)
763 case Alignment.Bottom:
764 // totalLength contains the padding already
765 childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
767 case Alignment.CenterVertical: // FALL THROUGH
768 case Alignment.Center:
769 // totalLength contains the padding already
770 childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
772 case Alignment.Top: // FALL THROUGH (default)
774 // totalLength contains the padding already
775 childTop = new LayoutLength( Padding.Top );
779 for( int i = 0; i < count; i++)
781 LayoutItem childLayout = LayoutChildren[i];
782 if( childLayout != null )
784 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
785 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
786 Extents childMargin = childLayout.Margin;
788 childTop += childMargin.Top;
789 switch ( LinearAlignment )
791 case Alignment.Begin:
794 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
799 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
802 case Alignment.CenterHorizontal:
803 case Alignment.Center: // FALL THROUGH
805 childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
809 childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
810 childTop += childHeight + childMargin.Bottom + CellPadding.Height;
815 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
817 // Pretend that the linear layout has an exact size. This is the measured height of
818 // ourselves. The measured height should be the max height of the children, changed
819 // to accommodate the heightMeasureSpec from the parent
820 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
821 foreach (LayoutItem childLayout in LayoutChildren)
823 int desiredChildHeight = childLayout.Owner.HeightSpecification;
824 int desiredChildWidth = childLayout.Owner.WidthSpecification;
826 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
828 // Temporarily force children to reuse their original measured width
829 int originalWidth = desiredChildWidth;
830 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
831 // Remeasure with new dimensions
832 MeasureChildWithMargins( childLayout, widthMeasureSpec, new LayoutLength(0),
833 uniformMeasureSpec, new LayoutLength(0) );
834 // Restore width specification
835 childLayout.Owner.WidthSpecification = originalWidth;
840 private void ForceUniformWidth(MeasureSpecification heightMeasureSpec)
842 // Pretend that the linear layout has an exact size.
843 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
844 foreach (LayoutItem childLayout in LayoutChildren)
846 int desiredChildWidth = childLayout.Owner.WidthSpecification;
847 int desiredChildHeight = childLayout.Owner.WidthSpecification;
849 if (desiredChildWidth == LayoutParamPolicies.MatchParent)
851 // Temporarily force children to reuse their original measured height
852 int originalHeight = desiredChildHeight;
853 childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
855 // Remeasure with new dimensions
856 MeasureChildWithMargins( childLayout, uniformMeasureSpec, new LayoutLength(0),
857 heightMeasureSpec, new LayoutLength(0));
858 // Restore height specification
859 childLayout.Owner.HeightSpecification = originalHeight;