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 - (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 - (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 for (int i = 0; i < LayoutChildren.Count; i++)
291 LayoutItem childLayout = LayoutChildren[i];
292 int childDesiredHeight = childLayout.Owner.HeightSpecification;
293 float childWeight = childLayout.Owner.Weight;
294 Extents childMargin = childLayout.Margin;
295 totalWeight += childWeight;
297 bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0 ) && (childWeight > 0);
298 if( isExactly && useExcessSpace )
300 // Children to be laid out with excess space can be measured later
301 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Start + childMargin.End) );
307 // Parent is not defiend!!!
308 // The widthMode is either Unspecified or AtMost, and
309 // this child is only laid out using excess space. Measure
310 // using WrapContent so that we can find out the view's
312 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
313 new MeasureSpecification(
314 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
315 widthMeasureSpec.Mode),
316 new LayoutLength(Padding.Start + Padding.End),
317 new LayoutLength(LayoutParamPolicies.WrapContent));
319 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
320 new MeasureSpecification(
321 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
322 heightMeasureSpec.Mode),
323 new LayoutLength(Padding.Top + Padding.Bottom),
324 new LayoutLength(childDesiredHeight));
326 childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec);
327 usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal();
331 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
334 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
335 LayoutLength length = childWidth + childMargin.Start + childMargin.End;
339 _totalLength += length.AsDecimal();
343 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Width : 0));
347 bool matchHeightLocally = false;
348 if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent)
350 // A child has set to MatchParent on it's height.
351 // Will have to re-measure at least this child when we know exact height.
353 matchHeightLocally = true;
356 float marginHeight = childMargin.Top + childMargin.Bottom;
357 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
359 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
361 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
363 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
365 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
368 maxHeight = Math.Max( maxHeight, childHeight);
369 allFillParent = ( allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent);
373 // Heights of weighted Views are invalid if we end up remeasuring, so store them separately.
374 weightedMaxHeight = Math.Max( weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight);
378 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
382 float widthSize = _totalLength;
383 widthSize = Math.Max( widthSize, SuggestedMinimumWidth.AsDecimal());
384 MeasuredSize widthSizeAndState = ResolveSizeAndState( new LayoutLength(widthSize + Padding.Start + Padding.End), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
385 widthSize = widthSizeAndState.Size.AsDecimal();
388 // Expand children with weight to take up available space
389 // We cycle through weighted children now (children with weight > 0).
390 // The children are measured with exact size equal to their share of the available space based on their weights.
391 // _totalLength is updated to include weighted children measured sizes.
392 float remainingExcess = widthSize - _totalLength + usedExcessSpace - (Padding.Start + Padding.End);
393 if( remainingExcess != 0 && totalWeight > 0 )
395 float remainingWeight = totalWeight;
399 int numberOfChildren = LayoutChildren.Count;
400 for( int i = 0; i < numberOfChildren; ++i )
402 LayoutItem childLayout = LayoutChildren[i];
404 float desiredChildHeight = childLayout.Owner.HeightSpecification;
406 float childWeight = childLayout.Owner.Weight;
407 Extents childMargin = childLayout.Margin;
409 if( childWeight > 0 )
411 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
412 widthMeasureSpec, heightMeasureSpec, childState,
413 Orientation.Horizontal );
416 float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End;
417 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0;
420 _totalLength += length;
424 float totalLength = _totalLength;
425 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
428 bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent);
429 float marginHeight = childMargin.Top + childMargin.Bottom;
430 float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight;
432 maxHeight = Math.Max( maxHeight, childHeight );
433 alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
434 allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent);
439 // No excess space or no weighted children
440 alternativeMaxHeight = Math.Max( alternativeMaxHeight, weightedMaxHeight );
443 if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
445 maxHeight = alternativeMaxHeight;
450 // Padding should be concerned when specification is Wrapcontent.
451 maxHeight += (Owner.HeightSpecification == LayoutParamPolicies.WrapContent)?(Padding.Top + Padding.Bottom):0;
452 maxHeight = Math.Max( maxHeight, SuggestedMinimumHeight.AsRoundedValue() );
454 widthSizeAndState.State = childState.widthState;
456 SetMeasuredDimensions(widthSizeAndState,
457 ResolveSizeAndState( new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState ));
461 ForceUniformHeight(widthMeasureSpec);
463 } // MeasureHorizontal
465 private void MeasureVertical( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
467 var widthMode = widthMeasureSpec.Mode;
468 var heightMode = heightMeasureSpec.Mode;
469 bool isExactly = ( heightMode == MeasureSpecification.ModeType.Exactly);
470 bool matchWidth = false;
471 bool allFillParent = true;
472 float maxWidth = 0.0f;
473 float alternativeMaxWidth = 0.0f;
474 float weightedMaxWidth = 0.0f;
475 float totalWeight = 0.0f;
477 // Reset total length
479 float usedExcessSpace =0.0f;
480 HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
481 MeasuredSize.StateType.MeasuredSizeOK);
484 // measure children, and determine if further resolution is required
487 // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
488 // to accumulate total used space in _totalLength.
489 // Weighted children are not measured in this phase.
490 // Available space for weighted children will be calculated in the phase 2 based on _totalLength value.
491 for (int i = 0; i < LayoutChildren.Count; i++)
493 LayoutItem childLayout = LayoutChildren[i];
494 int childDesiredWidth = childLayout.Owner.WidthSpecification;
495 float childWeight = childLayout.Owner.Weight;
496 Extents childMargin = childLayout.Margin;
497 totalWeight += childWeight;
499 bool useExcessSpace = (childLayout.Owner.HeightSpecification == 0) && (childWeight > 0);
500 if( isExactly && useExcessSpace )
502 _totalLength = Math.Max( _totalLength, (_totalLength + childMargin.Top + childMargin.Bottom) );
508 // The heightMode is either Unspecified or AtMost, and
509 // this child is only laid out using excess space. Measure
510 // using WrapContent so that we can find out the view's
512 // We'll restore the original height of 0 after measurement.
513 MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(
514 new MeasureSpecification(
515 new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)),
516 widthMeasureSpec.Mode),
517 new LayoutLength(Padding.Start + Padding.End),
518 new LayoutLength(childDesiredWidth));
520 MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(
521 new MeasureSpecification(
522 new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)),
523 heightMeasureSpec.Mode),
524 new LayoutLength(Padding.Top + Padding.Bottom),
525 new LayoutLength(LayoutParamPolicies.WrapContent));
527 childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec);
528 usedExcessSpace += childLayout.MeasuredHeight.Size.AsDecimal();
532 MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0));
535 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
536 LayoutLength length = childHeight + childMargin.Top + childMargin.Bottom;
541 _totalLength += length.AsDecimal();
545 _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Height : 0));
549 bool matchWidthLocally = false;
550 if( widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth == LayoutParamPolicies.MatchParent)
552 // Will have to re-measure at least this child when we know exact height.
554 matchWidthLocally = true;
557 float marginWidth = childLayout.Margin.Start + childLayout.Margin.End;
558 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
560 if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
562 childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
564 if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
566 childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
569 maxWidth = Math.Max( maxWidth, childWidth);
570 allFillParent = ( allFillParent && childDesiredWidth == LayoutParamPolicies.MatchParent);
574 // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
575 weightedMaxWidth = Math.Max( weightedMaxWidth, matchWidthLocally ? marginWidth : childWidth);
579 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth);
584 float heightSize = _totalLength;
585 heightSize = Math.Max( heightSize, SuggestedMinimumHeight.AsDecimal());
586 MeasuredSize heightSizeAndState = ResolveSizeAndState( new LayoutLength(heightSize + Padding.Top + Padding.Bottom), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK );
587 heightSize = heightSizeAndState.Size.AsDecimal();
590 // We cycle through weighted children now (children with weight > 0).
591 // The children are measured with exact size equal to their share of the available space based on their weights.
592 // _totalLength is updated to include weighted children measured sizes.
593 float remainingExcess = heightSize - _totalLength + usedExcessSpace - (Padding.Top + Padding.Bottom);
594 if( remainingExcess != 0 && totalWeight > 0.0f )
596 float remainingWeight = totalWeight;
600 int numberOfChildren = LayoutChildren.Count;
601 for( int i = 0; i < numberOfChildren; ++i )
603 LayoutItem childLayout = LayoutChildren[i];
605 float desiredChildWidth = childLayout.Owner.WidthSpecification;
607 float childWeight = childLayout.Owner.Weight;
608 Extents childMargin = childLayout.Margin;
610 if( childWeight > 0 )
612 MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight,
613 widthMeasureSpec, heightMeasureSpec, childState,
614 Orientation.Vertical);
617 float length = childLayout.MeasuredHeight.Size.AsDecimal() + childMargin.Top + childMargin.Bottom;
618 float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0;
622 _totalLength += length;
626 float totalLength = _totalLength;
627 _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
630 bool matchWidthLocally = (widthMode != MeasureSpecification.ModeType.Exactly) && (desiredChildWidth == LayoutParamPolicies.MatchParent);
631 float marginWidth = childMargin.Start + childMargin.End;
632 float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
634 maxWidth = Math.Max( maxWidth, childWidth );
635 alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
636 allFillParent = (allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent);
641 alternativeMaxWidth = Math.Max( alternativeMaxWidth, weightedMaxWidth );
644 if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
646 maxWidth = alternativeMaxWidth;
649 maxWidth += (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)?(Padding.Start + Padding.End):0;
650 maxWidth = Math.Max( maxWidth, SuggestedMinimumWidth.AsRoundedValue());
652 heightSizeAndState.State = childState.heightState;
654 SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState ),
655 heightSizeAndState );
659 ForceUniformWidth(heightMeasureSpec );
663 private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
665 bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
667 LayoutLength childTop = new LayoutLength(Padding.Top);
668 LayoutLength childLeft = new LayoutLength(Padding.Start);
670 // Where bottom of child should go
671 LayoutLength height = new LayoutLength(bottom - top);
673 // Space available for child
674 LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
676 int count = LayoutChildren.Count;
678 switch (LinearAlignment)
681 // totalLength contains the padding already
682 // In case of RTL map END alignment to the left edge
685 childLeft = new LayoutLength(Padding.Start);
689 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
692 case Alignment.CenterHorizontal: // FALL THROUGH
693 case Alignment.Center:
694 // totalLength contains the padding already
695 childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
697 case Alignment.Begin: // FALL THROUGH (default)
699 // totalLength contains the padding already
700 // In case of RTL map BEGIN alignment to the right edge
703 childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
707 childLeft = new LayoutLength(Padding.Start);
715 // In case of RTL, start drawing from the last child.
722 for( int i = 0; i < count; i++)
724 int childIndex = start + dir * i;
725 // Get a reference to the childLayout at the given index
726 LayoutItem childLayout = LayoutChildren[childIndex];
727 if( childLayout != null )
729 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
730 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
731 Extents childMargin = childLayout.Margin;
733 switch ( LinearAlignment )
735 case Alignment.Bottom:
736 childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
738 case Alignment.CenterVertical:
739 case Alignment.Center: // FALLTHROUGH
740 childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
742 case Alignment.Top: // FALLTHROUGH default
744 childTop = new LayoutLength(Padding.Top + childMargin.Top);
747 childLeft += childMargin.Start;
748 childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
749 childLeft += childWidth + childMargin.End + ((i < count - 1) ? CellPadding.Width : 0);
752 } // LayoutHorizontally
754 private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
756 LayoutLength childTop = new LayoutLength(Padding.Top);
757 LayoutLength childLeft = new LayoutLength(Padding.Start);
759 // Where end of child should go
760 LayoutLength width = new LayoutLength(right - left);
762 // Space available for child
763 LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
765 int count = LayoutChildren.Count;
767 switch (LinearAlignment)
769 case Alignment.Bottom:
770 // totalLength contains the padding already
771 childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
773 case Alignment.CenterVertical: // FALL THROUGH
774 case Alignment.Center:
775 // totalLength contains the padding already
776 childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
778 case Alignment.Top: // FALL THROUGH (default)
780 // totalLength contains the padding already
781 childTop = new LayoutLength( Padding.Top );
785 for( int i = 0; i < count; i++)
787 LayoutItem childLayout = LayoutChildren[i];
788 if( childLayout != null )
790 LayoutLength childWidth = childLayout.MeasuredWidth.Size;
791 LayoutLength childHeight = childLayout.MeasuredHeight.Size;
792 Extents childMargin = childLayout.Margin;
794 childTop += childMargin.Top;
795 switch ( LinearAlignment )
797 case Alignment.Begin:
800 childLeft = new LayoutLength(Padding.Start + childMargin.Start);
805 childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
808 case Alignment.CenterHorizontal:
809 case Alignment.Center: // FALL THROUGH
811 childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
815 childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
816 childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0);
821 private void ForceUniformHeight(MeasureSpecification widthMeasureSpec)
823 // Pretend that the linear layout has an exact size. This is the measured height of
824 // ourselves. The measured height should be the max height of the children, changed
825 // to accommodate the heightMeasureSpec from the parent
826 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
827 foreach (LayoutItem childLayout in LayoutChildren)
829 int desiredChildHeight = childLayout.Owner.HeightSpecification;
830 int desiredChildWidth = childLayout.Owner.WidthSpecification;
832 if (desiredChildHeight == LayoutParamPolicies.MatchParent)
834 // Temporarily force children to reuse their original measured width
835 int originalWidth = desiredChildWidth;
836 childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
837 // Remeasure with new dimensions
838 MeasureChildWithMargins( childLayout, widthMeasureSpec, new LayoutLength(0),
839 uniformMeasureSpec, new LayoutLength(0) );
840 // Restore width specification
841 childLayout.Owner.WidthSpecification = originalWidth;
846 private void ForceUniformWidth(MeasureSpecification heightMeasureSpec)
848 // Pretend that the linear layout has an exact size.
849 MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
850 foreach (LayoutItem childLayout in LayoutChildren)
852 int desiredChildWidth = childLayout.Owner.WidthSpecification;
853 int desiredChildHeight = childLayout.Owner.WidthSpecification;
855 if (desiredChildWidth == LayoutParamPolicies.MatchParent)
857 // Temporarily force children to reuse their original measured height
858 int originalHeight = desiredChildHeight;
859 childLayout.Owner.HeightSpecification = (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
861 // Remeasure with new dimensions
862 MeasureChildWithMargins( childLayout, uniformMeasureSpec, new LayoutLength(0),
863 heightMeasureSpec, new LayoutLength(0));
864 // Restore height specification
865 childLayout.Owner.HeightSpecification = originalHeight;