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 // Always lay out weighted elements with intrinsic size regardless of the parent spec.
204 // for consistency between specs.
205 if( ( horizontal && ( desiredWidth == 0 )) || ( !horizontal && ( desiredHeight == 0 )) )
207 // This child needs to be laid out from scratch using
208 // only its share of excess space.
209 childLength = childsShare;
213 // This child had some intrinsic width to which we
214 // need to add its share of excess space.
217 childLength = childLayout.MeasuredWidth.Size.AsDecimal() + childsShare;
221 childLength = childLayout.MeasuredHeight.Size.AsDecimal() + childsShare;
225 MeasureSpecification childWidthMeasureSpec;
226 MeasureSpecification childHeightMeasureSpec;
230 childWidthMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly );
231 childHeightMeasureSpec = GetChildMeasureSpecification(
232 new MeasureSpecification(
233 new LayoutLength(heightMeasureSpec.Size - (Padding.Top + Padding.Bottom + childLayout.Owner.Margin.Top + childLayout.Owner.Margin.Bottom)),
234 heightMeasureSpec.Mode),
235 new LayoutLength(Padding.Top + Padding.Bottom),
236 new LayoutLength(desiredHeight));
240 childWidthMeasureSpec = GetChildMeasureSpecification(
241 new MeasureSpecification(
242 new LayoutLength(widthMeasureSpec.Size - (Padding.Start + Padding.End + childLayout.Owner.Margin.Start + childLayout.Owner.Margin.End)),
243 widthMeasureSpec.Mode),
244 new LayoutLength(Padding.Start + Padding.End),
245 new LayoutLength(desiredWidth));
247 childHeightMeasureSpec = new MeasureSpecification( new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly);
250 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
252 // Child may now not fit in horizontal dimension.
253 if( childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
255 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
258 // Child may now not fit in vertical dimension.
259 if( childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
261 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
265 private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
267 var widthMode = widthMeasureSpec.Mode;
268 var heightMode = heightMeasureSpec.Mode;
269 bool isExactly = ( widthMode == MeasureSpecification.ModeType.Exactly );
270 bool matchHeight = false;
271 bool allFillParent = true;
272 float maxHeight = 0.0f;
273 float alternativeMaxHeight = 0.0f;
274 float weightedMaxHeight = 0.0f;
275 float totalWeight = 0.0f;
277 // Reset measure variables
279 float usedExcessSpace = 0.0f;
280 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
281 MeasuredSize.StateType.MeasuredSizeOK);
284 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
285 // to accumulate total used space in totalLength based on measured sizes and margins.
286 // Weighted children are not measured at this phase.
287 // Available space for weighted children will be calculated in the phase 2 based on totalLength value.
288 // Max height of children is stored.
289 foreach( LayoutItem childLayout in LayoutChildren )
291 int childDesiredHeight = childLayout.Owner.HeightSpecification;
292 float childWeight = childLayout.Owner.Weight;
293 Extents childMargin = childLayout.Margin;
294 totalWeight += childWeight;
296 bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0 ) && (childWeight > 0);
297 if( isExactly && useExcessSpace )
299 // Children to be laid out with excess space can be measured later
300 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Start + childMargin.End) );
306 // Parent is not defiend!!!
307 // The widthMode is either Unspecified or AtMost, and
308 // this child is only laid out using excess space. Measure
309 // using WrapContent so that we can find out the view's
311 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
312 new MeasureSpecification(
313 new LayoutLength(widthMeasureSpec.Size - (Padding.Start + Padding.End + childLayout.Margin.Start + childLayout.Margin.End)),
314 widthMeasureSpec.Mode),
315 new LayoutLength(Padding.Start + Padding.End),
316 new LayoutLength(LayoutParamPolicies.WrapContent));
318 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
319 new MeasureSpecification(
320 new LayoutLength(heightMeasureSpec.Size - (Padding.Top + Padding.Bottom + childLayout.Margin.Top + childLayout.Margin.Bottom)),
321 heightMeasureSpec.Mode),
322 new LayoutLength(Padding.Top + Padding.Bottom),
323 new LayoutLength(childDesiredHeight));
325 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec);
326 usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal();
330 MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
333 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
334 LayoutLength length = childWidth + childMargin.Start + childMargin.End;
338 _totalLength += length.AsDecimal();
342 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Width);
346 bool matchHeightLocally = false;
347 if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent)
349 // A child has set to MatchParent on it's height.
350 // Will have to re-measure at least this child when we know exact height.
352 matchHeightLocally = true;
355 float marginHeight = childMargin.Top + childMargin.Bottom;
356 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
358 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
360 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
362 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
364 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
367 maxHeight = Math.Max( maxHeight, childHeight);
368 allFillParent = ( allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent);
372 // Heights of weighted Views are invalid if we end up remeasuring, so store them separately.
373 weightedMaxHeight = Math.Max( weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight);
377 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
381 float widthSize = _totalLength;
382 widthSize = Math.Max( widthSize, SuggestedMinimumWidth.AsDecimal());
383 MeasuredSize widthSizeAndState = ResolveSizeAndState( new LayoutLength(widthSize + Padding.Start + Padding.End), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
384 widthSize = widthSizeAndState.Size.AsDecimal();
387 // Expand children with weight to take up available space
388 // We cycle through weighted children now (children with weight > 0).
389 // The children are measured with exact size equal to their share of the available space based on their weights.
390 // _totalLength is updated to include weighted children measured sizes.
391 float remainingExcess = widthSize - _totalLength + usedExcessSpace - (Padding.Start + Padding.End);
392 if( remainingExcess != 0 && totalWeight > 0 )
394 float remainingWeight = totalWeight;
398 int numberOfChildren = LayoutChildren.Count;
399 for( int i = 0; i < numberOfChildren; ++i )
401 LayoutItem childLayout = LayoutChildren[i];
403 float desiredChildHeight = childLayout.Owner.HeightSpecification;
405 float childWeight = childLayout.Owner.Weight;
406 Extents childMargin = childLayout.Margin;
408 if( childWeight > 0 )
410 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
411 widthMeasureSpec, heightMeasureSpec, childState,
412 Orientation.Horizontal );
415 float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End;
416 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0;
419 _totalLength += length;
423 float totalLength = _totalLength;
424 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
427 bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent);
428 float marginHeight = childMargin.Top + childMargin.Bottom;
429 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
431 maxHeight = Math.Max( maxHeight, childHeight );
432 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
433 allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent);
438 // No excess space or no weighted children
439 alternativeMaxHeight = Math.Max( alternativeMaxHeight, weightedMaxHeight );
442 if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
444 maxHeight = alternativeMaxHeight;
449 // Padding should be concerned when specification is Wrapcontent.
450 maxHeight += (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)?(Padding.Top + Padding.Bottom):0;
451 maxHeight = Math.Max( maxHeight, SuggestedMinimumHeight.AsRoundedValue() );
453 widthSizeAndState.State = childState.widthState;
455 SetMeasuredDimensions(widthSizeAndState,
456 ResolveSizeAndState( new LayoutLength(maxHeight + Padding.Top + Padding.Bottom), heightMeasureSpec, childState.heightState ));
460 ForceUniformHeight(widthMeasureSpec);
462 } // MeasureHorizontal
464 private void MeasureVertical( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
466 var widthMode = widthMeasureSpec.Mode;
467 var heightMode = heightMeasureSpec.Mode;
468 bool isExactly = ( heightMode == MeasureSpecification.ModeType.Exactly);
469 bool matchWidth = false;
470 bool allFillParent = true;
471 float maxWidth = 0.0f;
472 float alternativeMaxWidth = 0.0f;
473 float weightedMaxWidth = 0.0f;
474 float totalWeight = 0.0f;
476 // Reset total length
478 float usedExcessSpace =0.0f;
479 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
480 MeasuredSize.StateType.MeasuredSizeOK);
483 // measure children, and determine if further resolution is required
486 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
487 // to accumulate total used space in _totalLength.
488 // Weighted children are not measured in this phase.
489 // Available space for weighted children will be calculated in the phase 2 based on _totalLength value.
490 foreach( LayoutItem childLayout in LayoutChildren )
492 int childDesiredWidth = childLayout.Owner.WidthSpecification;
493 float childWeight = childLayout.Owner.Weight;
494 Extents childMargin = childLayout.Margin;
495 totalWeight += childWeight;
497 bool useExcessSpace = (childLayout.Owner.HeightSpecification == 0) && (childWeight > 0);
498 if( isExactly && useExcessSpace )
500 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Top + childMargin.Bottom) );
506 // The heightMode is either Unspecified or AtMost, and
507 // this child is only laid out using excess space. Measure
508 // using WrapContent so that we can find out the view's
510 // We'll restore the original height of 0 after measurement.
511 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
512 new MeasureSpecification(
513 new LayoutLength(widthMeasureSpec.Size - (Padding.Start + Padding.End + childLayout.Margin.Start + childLayout.Margin.End)),
514 widthMeasureSpec.Mode),
515 new LayoutLength(Padding.Start + Padding.End),
516 new LayoutLength(childDesiredWidth));
518 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
519 new MeasureSpecification(
520 new LayoutLength(heightMeasureSpec.Size - (Padding.Top + Padding.Bottom + childLayout.Margin.Top + childLayout.Margin.Bottom)),
521 heightMeasureSpec.Mode),
522 new LayoutLength(Padding.Top + Padding.Bottom),
523 new LayoutLength(LayoutParamPolicies.WrapContent));
525 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
526 usedExcessSpace += childLayout.MeasuredHeight.Size.AsDecimal();
530 MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
533 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
534 LayoutLength length = childHeight + childMargin.Top + childMargin.Bottom;
539 _totalLength += length.AsDecimal();
543 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Height);
547 bool matchWidthLocally = false;
548 if( widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth == LayoutParamPolicies.MatchParent)
550 // Will have to re-measure at least this child when we know exact height.
552 matchWidthLocally = true;
555 float marginWidth = childLayout.Margin.Start + childLayout.Margin.End;
556 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
558 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
560 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
562 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
564 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
567 maxWidth = Math.Max( maxWidth, childWidth);
568 allFillParent = ( allFillParent && childDesiredWidth == LayoutParamPolicies.MatchParent);
572 // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
573 weightedMaxWidth = Math.Max( weightedMaxWidth, matchWidthLocally ? marginWidth : childWidth);
577 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth);
582 float heightSize = _totalLength;
583 heightSize = Math.Max( heightSize, SuggestedMinimumHeight.AsDecimal());
584 MeasuredSize heightSizeAndState = ResolveSizeAndState( new LayoutLength(heightSize + Padding.Top + Padding.Bottom), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK );
585 heightSize = heightSizeAndState.Size.AsDecimal();
588 // We cycle through weighted children now (children with weight > 0).
589 // The children are measured with exact size equal to their share of the available space based on their weights.
590 // _totalLength is updated to include weighted children measured sizes.
591 float remainingExcess = heightSize - _totalLength + usedExcessSpace - (Padding.Top + Padding.Bottom);
592 if( remainingExcess != 0 && totalWeight > 0.0f )
594 float remainingWeight = totalWeight;
598 int numberOfChildren = LayoutChildren.Count;
599 for( int i = 0; i < numberOfChildren; ++i )
601 LayoutItem childLayout = LayoutChildren[i];
603 float desiredChildWidth = childLayout.Owner.WidthSpecification;
605 float childWeight = childLayout.Owner.Weight;
606 Extents childMargin = childLayout.Margin;
608 if( childWeight > 0 )
610 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
611 widthMeasureSpec, heightMeasureSpec, childState,
612 Orientation.Vertical);
615 float length = childLayout.MeasuredHeight.Size.AsDecimal() + childMargin.Top + childMargin.Bottom;
616 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0;
620 _totalLength += length;
624 float totalLength = _totalLength;
625 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
628 bool matchWidthLocally = (widthMode != MeasureSpecification.ModeType.Exactly) && (desiredChildWidth == LayoutParamPolicies.MatchParent);
629 float marginWidth = childMargin.Start + childMargin.End;
630 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
632 maxWidth = Math.Max( maxWidth, childWidth );
633 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
634 allFillParent = (allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent);
639 alternativeMaxWidth = Math.Max( alternativeMaxWidth, weightedMaxWidth );
642 if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
644 maxWidth = alternativeMaxWidth;
647 maxWidth += (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)?(Padding.Start + Padding.End):0;
648 maxWidth = Math.Max( maxWidth, SuggestedMinimumWidth.AsRoundedValue());
650 heightSizeAndState.State = childState.heightState;
652 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(maxWidth + Padding.Top + Padding.Bottom), widthMeasureSpec, childState.widthState ),
653 heightSizeAndState );
657 ForceUniformWidth(heightMeasureSpec );
661 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
663 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
665 LayoutLength childTop = new LayoutLength(Padding.Top);
666 LayoutLength childLeft = new LayoutLength(Padding.Start);
668 // Where bottom of child should go
669 LayoutLength height = new LayoutLength(bottom - top);
671 // Space available for child
672 LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
674 int count = LayoutChildren.Count;
676 switch (LinearAlignment)
679 // totalLength contains the padding already
680 // In case of RTL map END alignment to the left edge
683 childLeft = new LayoutLength(Padding.Start);
687 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
690 case Alignment.CenterHorizontal: // FALL THROUGH
691 case Alignment.Center:
692 // totalLength contains the padding already
693 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
695 case Alignment.Begin: // FALL THROUGH (default)
697 // totalLength contains the padding already
698 // In case of RTL map BEGIN alignment to the right edge
701 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
705 childLeft = new LayoutLength(Padding.Start);
713 // In case of RTL, start drawing from the last child.
720 for( int i = 0; i < count; i++)
722 int childIndex = start + dir * i;
723 // Get a reference to the childLayout at the given index
724 LayoutItem childLayout = LayoutChildren[childIndex];
725 if( childLayout != null )
727 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
728 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
729 Extents childMargin = childLayout.Margin;
731 switch ( LinearAlignment )
733 case Alignment.Bottom:
734 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
736 case Alignment.CenterVertical:
737 case Alignment.Center: // FALLTHROUGH
738 childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
740 case Alignment.Top: // FALLTHROUGH default
742 childTop = new LayoutLength(Padding.Top + childMargin.Top);
745 childLeft += childMargin.Start;
746 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
747 childLeft += childWidth + childMargin.End + CellPadding.Width;
750 } // LayoutHorizontally
752 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
754 LayoutLength childTop = new LayoutLength(Padding.Top);
755 LayoutLength childLeft = new LayoutLength(Padding.Start);
757 // Where end of child should go
758 LayoutLength width = new LayoutLength(right - left);
760 // Space available for child
761 LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
763 int count = LayoutChildren.Count;
765 switch (LinearAlignment)
767 case Alignment.Bottom:
768 // totalLength contains the padding already
769 childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
771 case Alignment.CenterVertical: // FALL THROUGH
772 case Alignment.Center:
773 // totalLength contains the padding already
774 childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
776 case Alignment.Top: // FALL THROUGH (default)
778 // totalLength contains the padding already
779 childTop = new LayoutLength( Padding.Top );
783 for( int i = 0; i < count; i++)
785 LayoutItem childLayout = LayoutChildren[i];
786 if( childLayout != null )
788 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
789 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
790 Extents childMargin = childLayout.Margin;
792 childTop += childMargin.Top;
793 switch ( LinearAlignment )
795 case Alignment.Begin:
798 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
803 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
806 case Alignment.CenterHorizontal:
807 case Alignment.Center: // FALL THROUGH
809 childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
813 childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
814 childTop += childHeight + childMargin.Bottom + CellPadding.Height;
819 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
821 // Pretend that the linear layout has an exact size. This is the measured height of
822 // ourselves. The measured height should be the max height of the children, changed
823 // to accommodate the heightMeasureSpec from the parent
824 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
825 foreach (LayoutItem childLayout in LayoutChildren)
827 int desiredChildHeight = childLayout.Owner.HeightSpecification;
828 int desiredChildWidth = childLayout.Owner.WidthSpecification;
830 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
832 // Temporarily force children to reuse their original measured width
833 int originalWidth = desiredChildWidth;
834 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
835 // Remeasure with new dimensions
836 MeasureChildWithMargins( childLayout, widthMeasureSpec, new LayoutLength(0),
837 uniformMeasureSpec, new LayoutLength(0) );
838 // Restore width specification
839 childLayout.Owner.WidthSpecification = originalWidth;
844 private void ForceUniformWidth(MeasureSpecification heightMeasureSpec)
846 // Pretend that the linear layout has an exact size.
847 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
848 foreach (LayoutItem childLayout in LayoutChildren)
850 int desiredChildWidth = childLayout.Owner.WidthSpecification;
851 int desiredChildHeight = childLayout.Owner.WidthSpecification;
853 if (desiredChildWidth == LayoutParamPolicies.MatchParent)
855 // Temporarily force children to reuse their original measured height
856 int originalHeight = desiredChildHeight;
857 childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
859 // Remeasure with new dimensions
860 MeasureChildWithMargins( childLayout, uniformMeasureSpec, new LayoutLength(0),
861 heightMeasureSpec, new LayoutLength(0));
862 // Restore height specification
863 childLayout.Owner.HeightSpecification = originalHeight;