[NUI] Sync dalihub & Fix VD build error (#824)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Layouting / LinearLayout.cs
index 15bad7b..368be21 100755 (executable)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 Samsung Electronics Co., Ltd.
+/* Copyright (c) 2019 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  *
  */
-using System.ComponentModel;
+
+using System;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
 
 namespace Tizen.NUI
 {
     /// <summary>
     /// [Draft] This class implements a linear box layout, automatically handling right to left or left to right direction change.
     /// </summary>
-    internal class LinearLayout : LayoutGroupWrapper
+    internal class LinearLayout : LayoutGroup
     {
-        private global::System.Runtime.InteropServices.HandleRef swigCPtr;
-
-        internal LinearLayout(global::System.IntPtr cPtr, bool cMemoryOwn) : base(Interop.LinearLayout.LinearLayout_SWIGUpcast(cPtr), cMemoryOwn)
+        /// <summary>
+        /// [Draft] Enumeration for the direction in which the content is laid out
+        /// </summary>
+        public enum Orientation
         {
-            swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
+            /// <summary>
+            /// Horizontal (row)
+            /// </summary>
+            Horizontal,
+            /// <summary>
+            /// Vertical (column)
+            /// </summary>
+            Vertical
         }
 
-        internal static global::System.Runtime.InteropServices.HandleRef getCPtr(LinearLayout obj)
+        /// <summary>
+        /// [Draft] Enumeration for the alignment of the linear layout items
+        /// </summary>
+        public enum Alignment
         {
-            return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
+            /// <summary>
+            /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
+            /// </summary>
+            Begin              = 0x1,
+            /// <summary>
+            /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
+            /// </summary>
+            End                = 0x2,
+            /// <summary>
+            /// At the horizontal center of the container
+            /// </summary>
+            CenterHorizontal   = 0x4,
+            /// <summary>
+            /// At the top edge of the container
+            /// </summary>
+            Top                = 0x8,
+            /// <summary>
+            /// At the bottom edge of the container
+            /// </summary>
+            Bottom             = 0x10,
+            /// <summary>
+            /// At the vertical center of the container
+            /// </summary>
+            CenterVertical     = 0x20
         }
 
-        protected override void Dispose(DisposeTypes type)
+        struct HeightAndWidthState
         {
-            if (disposed)
+            public MeasuredSize.StateType widthState;
+            public MeasuredSize.StateType heightState;
+
+            public HeightAndWidthState( MeasuredSize.StateType width, MeasuredSize.StateType height)
             {
-                return;
+                widthState = width;
+                heightState = height;
             }
+        }
 
-            if (type == DisposeTypes.Explicit)
+        /// <summary>
+        /// [Draft] Get/Set the orientation in the layout
+        /// </summary>
+        public LinearLayout.Orientation LinearOrientation
+        {
+            get
             {
-                //Called by User
-                //Release your own managed resources here.
-                //You should release all of your own disposable objects here.
-
+                return _linearOrientation;
             }
-
-            //Release your own unmanaged resources here.
-            //You should not access any managed member here except static instance.
-            //because the execution order of Finalizes is non-deterministic.
-            if (swigCPtr.Handle != global::System.IntPtr.Zero)
+            set
             {
-                if (swigCMemOwn)
-                {
-                    swigCMemOwn = false;
-                    Interop.LinearLayout.delete_LinearLayout(swigCPtr);
-                }
-                swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
+                _linearOrientation = value;
+                RequestLayout();
             }
-            base.Dispose(type);
         }
 
-        internal static new class ChildProperty
-        {
-            internal static readonly int WEIGHT = Interop.LinearLayout.LinearLayout_ChildProperty_WEIGHT_get();
-        }
-        public LinearLayout() : this(Interop.LinearLayout.LinearLayout_New(), true)
+        /// <summary>
+        /// [Draft] Get/Set the padding between cells in the layout
+        /// </summary>
+        public Size2D CellPadding
         {
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            get
+            {
+                return _cellPadding;
+            }
+            set
+            {
+                _cellPadding = value;
+                RequestLayout();
+            }
         }
 
-        public static LinearLayout DownCast(BaseHandle handle)
-        {
-            LinearLayout ret = new LinearLayout(Interop.LinearLayout.LinearLayout_DownCast(BaseHandle.getCPtr(handle)), true);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
-        }
 
-        internal LinearLayout(LinearLayout other) : this(Interop.LinearLayout.new_LinearLayout__SWIG_1(LinearLayout.getCPtr(other)), true)
+        /// <summary>
+        /// [Draft] Get/Set the alignment in the layout
+        /// </summary>
+        public LinearLayout.Alignment LinearAlignment{ get; set; } = Alignment.CenterVertical;
+
+        private float _totalLength = 0.0f;
+        private Size2D _cellPadding  = new Size2D(0,0);
+        private Orientation _linearOrientation = Orientation.Horizontal;
+
+        /// <summary>
+        /// [Draft] Constructor
+        /// </summary>
+        public LinearLayout()
         {
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
         }
 
-        internal LinearLayout Assign(LinearLayout other)
+        protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
         {
-            LinearLayout ret = new LinearLayout(Interop.LinearLayout.LinearLayout_Assign(swigCPtr, LinearLayout.getCPtr(other)), false);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
+            if (_linearOrientation == Orientation.Horizontal)
+            {
+                MeasureHorizontal(widthMeasureSpec, heightMeasureSpec);
+            }
+            else
+            {
+                MeasureVertical(widthMeasureSpec, heightMeasureSpec);
+            }
         }
 
-        internal void SetCellPadding(LayoutSize size)
+        protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
         {
-            Interop.LinearLayout.LinearLayout_SetCellPadding(swigCPtr, LayoutSize.getCPtr(size));
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            if (_linearOrientation == Orientation.Horizontal)
+            {
+                LayoutHorizontal(left, top, right, bottom);
+            }
+            else
+            {
+                LayoutVertical(left, top, right, bottom);
+            }
         }
 
-        internal LayoutSize GetCellPadding()
+        private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
         {
-            LayoutSize ret = new LayoutSize(Interop.LinearLayout.LinearLayout_GetCellPadding(swigCPtr), true);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
-        }
+            var widthMode = widthMeasureSpec.Mode;
+            var heightMode = heightMeasureSpec.Mode;
+            bool isExactly = ( widthMode == MeasureSpecification.ModeType.Exactly );
+            bool matchHeight = false;
+            bool allFillParent = true;
+            float maxHeight = 0.0f;
+            float alternativeMaxHeight = 0.0f;
+            float weightedMaxHeight = 0.0f;
+            float totalWeight = 0.0f;
 
+            // Reset total length
+            _totalLength = 0.0f;
+            LayoutLength usedExcessSpace = new LayoutLength(0);
 
-        internal void SetOrientation(LinearLayout.Orientation orientation)
-        {
-            Interop.LinearLayout.LinearLayout_SetOrientation(swigCPtr, (int)orientation);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-        }
+            HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
+                                                                     MeasuredSize.StateType.MeasuredSizeOK);
 
-        internal LinearLayout.Orientation GetOrientation()
-        {
-            LinearLayout.Orientation ret = (LinearLayout.Orientation)Interop.LinearLayout.LinearLayout_GetOrientation(swigCPtr);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
-        }
+            // Measure children, and determine if further resolution is required
 
-        internal void SetAlignment(LinearLayout.Alignment alignment)
-        {
-            Interop.LinearLayout.LinearLayout_SetAlignment(swigCPtr, (uint)alignment);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-        }
+            // 1st phase:
+            // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
+            // to accumulate total used space in totalLength based on measured sizes and margins.
+            // Weighted children are not measured at this phase.
+            // Available space for weighted children will be calculated in the phase 2 based on totalLength value.
 
-        internal LinearLayout.Alignment GetAlignment()
-        {
-            LinearLayout.Alignment ret = (LinearLayout.Alignment)Interop.LinearLayout.LinearLayout_GetAlignment(swigCPtr);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
-        }
+            foreach( LayoutItem childLayout in _children )
+            {
+                LayoutLength childDesiredWidth = new LayoutLength(childLayout.Owner.WidthSpecification);
+                LayoutLength childDesiredHeight = new LayoutLength(childLayout.Owner.HeightSpecification);
+                float childWeight = childLayout.Owner.Weight;
+                Extents childMargin = childLayout.Margin;
+                totalWeight += childWeight;
 
-        internal enum PropertyRange
-        {
-            CHILD_PROPERTY_START_INDEX = PropertyRanges.CHILD_PROPERTY_REGISTRATION_START_INDEX,
-            CHILD_PROPERTY_END_INDEX = PropertyRanges.CHILD_PROPERTY_REGISTRATION_START_INDEX + 1000
-        }
+                bool useExcessSpace = (childDesiredWidth.AsRoundedValue() == 0 ) && (childWeight > 0);
+                if( isExactly && useExcessSpace )
+                {
+                    _totalLength += childMargin.Start + childMargin.End;
+                }
+                else
+                {
+                    if( useExcessSpace )
+                    {
+                        // The widthMode is either UNSPECIFIED or AT_MOST, and
+                        // this child is only laid out using excess space. Measure
+                        // using WRAP_CONTENT so that we can find out the view's
+                        // optimal width.
+                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(widthMeasureSpec, new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
+                                                                    new LayoutLength(LayoutParamPolicies.WrapContent) );
+                        MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(heightMeasureSpec, new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
+                                                                    childDesiredHeight);
+                        childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec);
+                        usedExcessSpace += childLayout.MeasuredWidth.Size;
+                    }
+                    else
+                    {
+                        MeasureChild(childLayout, widthMeasureSpec, heightMeasureSpec);
+                    }
+                    LayoutLength childWidth = childLayout.MeasuredWidth.Size;
 
-        /// <summary>
-        /// [Draft] Get/Set the orientation in the layout
-        /// </summary>
-        public LinearLayout.Orientation LinearOrientation
+                    LayoutLength length = childWidth + childMargin.Start + childMargin.End;
+                    if( isExactly )
+                    {
+                        _totalLength += length.AsDecimal();
+                    }
+                    else
+                    {
+                        _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + CellPadding.Width);
+                    }
+                }
+
+                bool matchHeightLocally = false;
+                if(heightMode != MeasureSpecification.ModeType.Exactly && (int)childDesiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent)
+                {
+                    // Will have to re-measure at least this child when we know exact height.
+                    matchHeight = true;
+                    matchHeightLocally = true;
+                }
+
+                LayoutLength marginHeight = new LayoutLength(childMargin.Top + childMargin.Bottom);
+                LayoutLength childHeight = childLayout.MeasuredHeight.Size + marginHeight;
+
+                if( childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall )
+                {
+                    childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
+                }
+                if( childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
+                {
+                    childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
+                }
+
+                maxHeight = Math.Max( maxHeight, childHeight.AsDecimal());
+                allFillParent = ( allFillParent && childDesiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent );
+
+                if( childWeight > 0 )
+                {
+                  /*
+                  * Heights of weighted Views are bogus if we end up
+                  * remeasuring, so keep them separate.
+                  */
+                  weightedMaxHeight = Math.Max( weightedMaxHeight, matchHeightLocally ? marginHeight.AsDecimal() : childHeight.AsDecimal());
+                }
+                else
+                {
+                  alternativeMaxHeight = Math.Max( alternativeMaxHeight, matchHeightLocally ? marginHeight.AsDecimal() : childHeight.AsDecimal() );
+                }
+            } // foreach
+
+            Extents padding = Padding;
+            _totalLength += padding.Start + padding.End;
+            LayoutLength widthSize = new LayoutLength(_totalLength);
+            widthSize = new LayoutLength( Math.Max( widthSize.AsDecimal(), SuggestedMinimumWidth.AsDecimal()));
+            MeasuredSize widthSizeAndState = ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
+            widthSize = widthSizeAndState.Size;
+
+            if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly)
+            {
+                maxHeight = alternativeMaxHeight;
+            }
+            maxHeight += padding.Top + padding.Bottom;
+            maxHeight = Math.Max( maxHeight, SuggestedMinimumHeight.AsRoundedValue() );
+
+            widthSizeAndState.State = childState.widthState;
+
+            SetMeasuredDimensions(widthSizeAndState,
+                                  ResolveSizeAndState( new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState ));
+
+            if (matchHeight)
+            {
+                ForceUniformHeight( _children.Count, widthMeasureSpec );
+            }
+        } // MeasureHorizontally
+
+        void MeasureVertical( MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec )
         {
-            get
+            var widthMode = widthMeasureSpec.Mode;
+            var heightMode = heightMeasureSpec.Mode;
+            bool isExactly = ( heightMode == MeasureSpecification.ModeType.Exactly);
+            bool matchWidth = false;
+            bool allFillParent = true;
+            float maxWidth = 0.0f;
+            float alternativeMaxWidth = 0.0f;
+            float weightedMaxWidth = 0.0f;
+            float totalWeight = 0.0f;
+
+            // Reset total length
+            _totalLength = 0.0f;
+            LayoutLength usedExcessSpace = new LayoutLength(0);
+
+            HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK,
+                                                                     MeasuredSize.StateType.MeasuredSizeTooSmall);
+
+
+            // measure children, and determine if further resolution is required
+
+            // 1st phase:
+            // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs
+            // to accumulate total used space in mTotalLength based on measured sizes and margins.
+            // Weighted children are not measured at this phase.
+            // Available space for weighted children will be calculated in the phase 2 based on mTotalLength value.
+            uint index = 0;
+            foreach( LayoutItem childLayout in _children )
             {
-                return GetOrientation();
+                LayoutLength childDesiredWidth = new LayoutLength(childLayout.Owner.WidthSpecification);
+                LayoutLength childDesiredHeight = new LayoutLength(childLayout.Owner.HeightSpecification);
+                float childWeight = childLayout.Owner.Weight;
+                Extents childMargin = childLayout.Margin;
+                totalWeight += childWeight;
+
+                bool useExcessSpace = (childDesiredHeight.AsRoundedValue() == 0) && (childWeight > 0);
+
+                if( isExactly && useExcessSpace )
+                {
+                   LayoutLength totalLength = new LayoutLength(_totalLength);
+                   _totalLength = Math.Max( totalLength.AsDecimal(), (totalLength + childMargin.Top + childMargin.Bottom).AsDecimal() );
+                }
+                else
+                {
+                    LayoutLength childHeight = new LayoutLength(0);
+                    if( useExcessSpace )
+                    {
+                        // The heightMode is either Unspecified or AtMost, and
+                        // this child is only laid out using excess space. Measure
+                        // using WrapContent so that we can find out the view's
+                        // optimal height. We'll restore the original height of 0
+                        // after measurement.
+                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
+                                                                    new LayoutLength(childLayout.Padding.Start + childLayout.Padding.End),
+                                                                    childDesiredWidth);
+                        MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( heightMeasureSpec,
+                                                                      new LayoutLength(childLayout.Padding.Top + childLayout.Padding.Bottom),
+                                                                      new LayoutLength(LayoutParamPolicies.WrapContent) );
+                        childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
+                        childHeight = childLayout.MeasuredHeight.Size;
+                        usedExcessSpace += childHeight;
+                    }
+                    else
+                    {
+                        MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
+                        childHeight = childLayout.MeasuredHeight.Size;
+                    }
+
+                    float length = (childHeight + childMargin.Top + childMargin.Bottom).AsDecimal();
+                    float cellPadding = CellPadding.Height;
+                    // No need to add cell padding to the end of last item.
+                    if (index>=_children.Count-1)
+                    {
+                        cellPadding = 0.0f;
+                    }
+                    _totalLength = Math.Max( _totalLength, _totalLength + length +  cellPadding );
+                }
+
+                bool matchWidthLocally = false;
+                if( widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth ==  new LayoutLength(LayoutParamPolicies.MatchParent) )
+                {
+                    // Will have to re-measure at least this child when we know exact height.
+                    matchWidth = true;
+                    matchWidthLocally = true;
+                }
+
+                float marginWidth = (childLayout.Margin.Start) + (childLayout.Margin.End);
+                LayoutLength childWidth = new LayoutLength(childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth);
+
+                // was combineMeasuredStates()
+                if (childLayout.MeasuredWidthAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
+                {
+                    childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall;
+                }
+                if (childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
+                {
+                    childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
+                }
+
+                maxWidth = (Math.Max( maxWidth, childWidth.AsDecimal()));
+                allFillParent = (allFillParent && (childDesiredWidth == new LayoutLength(LayoutParamPolicies.MatchParent)));
+
+                float widthforWeight = childWidth.AsDecimal();
+                if (matchWidthLocally)
+                {
+                    widthforWeight = marginWidth;
+                }
+
+                if (childWeight > 0)
+                {
+                    /*
+                    * Widths of weighted Views are bogus if we end up remeasuring, so keep them separate.
+                    */
+                    weightedMaxWidth = Math.Max( weightedMaxWidth, widthforWeight);
+                }
+                else
+                {
+                    alternativeMaxWidth = Math.Max( alternativeMaxWidth, widthforWeight);
+                }
+            } // foreach
+
+
+            Extents padding = Padding;
+            _totalLength += padding.Top + padding.Bottom;
+            LayoutLength heightSize = new LayoutLength(_totalLength);
+            heightSize = new LayoutLength(Math.Max( heightSize.AsDecimal(), SuggestedMinimumHeight.AsDecimal() ));
+            MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK);
+            heightSize = heightSizeAndState.Size;
+
+            // Either expand children with weight to take up available space or
+            // shrink them if they extend beyond our current bounds. If we skipped
+            // measurement on any children, we need to measure them now.
+
+            // 2nd phase:
+            // We cycle through weighted children now (children with weight > 0).
+            // The children are measured with exact size equal to their share of the available space based on their weights.
+            // TotalLength is updated to include weighted children measured sizes.
+
+            float remainingExcess = heightSize.AsDecimal() - _totalLength + usedExcessSpace.AsDecimal();
+
+            if( remainingExcess != 0 && totalWeight > 0.0f )
+            {
+                float remainingWeightSum = totalWeight;
+
+                _totalLength = 0;
+
+                foreach( LayoutItem childLayout in _children )
+                {
+                    int desiredWidth = childLayout.Owner.WidthSpecification;
+                    int desiredHeight = childLayout.Owner.HeightSpecification;
+                    float childWeight = childLayout.Owner.Weight;
+                    Extents childMargin = childLayout.Margin;
+
+                    float childHeight = 0;
+                    if( childWeight > 0 )
+                    {
+                        float share = ( childWeight * remainingExcess ) / remainingWeightSum;
+                        remainingExcess -= share;
+                        remainingWeightSum -= childWeight;
+
+                        // Always lay out weighted elements with intrinsic size regardless of the parent spec
+                        // for consistency between specs.
+                        if( desiredHeight == 0 )
+                        {
+                          // This child needs to be laid out from scratch using
+                          // only its share of excess space.
+                          childHeight = share;
+                        }
+                        else
+                        {
+                          // This child had some intrinsic width to which we
+                          // need to add its share of excess space.
+                          childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + share;
+                        }
+
+                        MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( widthMeasureSpec,
+                                            new LayoutLength(Padding.Start + Padding.End),
+                                            new LayoutLength(desiredWidth) );
+
+                        MeasureSpecification childHeightMeasureSpec = new MeasureSpecification( new LayoutLength(childHeight), MeasureSpecification.ModeType.Exactly);
+                        childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec );
+
+                        // Child may now not fit in vertical dimension.
+                        if( childLayout.MeasuredHeightAndState.State == MeasuredSize.StateType.MeasuredSizeTooSmall)
+                        {
+                            childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall;
+                        }
+                    }
+
+                    bool matchWidthLocally = false;
+                    if( widthMode != MeasureSpecification.ModeType.Exactly && desiredWidth == (int)ChildLayoutData.MatchParent )
+                    {
+                        // Will have to re-measure at least this child when we know exact height.
+                        matchWidth = true;
+                        matchWidthLocally = true;
+                    }
+
+                    float marginWidth = childMargin.Start + childMargin.End;
+                    float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth;
+                    maxWidth = Math.Max( maxWidth, childWidth );
+                    allFillParent = allFillParent && desiredWidth == (int)ChildLayoutData.MatchParent;
+
+
+                    alternativeMaxWidth = Math.Max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
+
+                    childHeight = childLayout.MeasuredHeight.Size.AsDecimal();
+                    float length = childHeight + childMargin.Top + childMargin.Bottom;
+                    float cellPadding = CellPadding.Height;
+                    // No need to add cell padding to the end of last item.
+                    if (index>=_children.Count-1)
+                    {
+                        cellPadding = 0.0f;
+                    }
+                    _totalLength = Math.Max( _totalLength, _totalLength + length + cellPadding );
+                } // foreach
+
+                // Add in our padding
+                _totalLength += Padding.Top + Padding.Bottom;
             }
-            set
+            else
             {
-                SetOrientation(value);
+                alternativeMaxWidth = Math.Max( alternativeMaxWidth, weightedMaxWidth );
             }
-        }
 
-        /// <summary>
-        /// [Draft] Get/Set the padding between cells in the layout
-        /// </summary>
-        public LayoutSize CellPadding
+            if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly)
+            {
+                maxWidth = alternativeMaxWidth;
+            }
+            maxWidth += padding.Start + padding.End;
+            maxWidth = Math.Max( maxWidth, SuggestedMinimumWidth.AsRoundedValue());
+
+            heightSizeAndState.State = childState.heightState;
+
+            SetMeasuredDimensions( ResolveSizeAndState( new LayoutLength(maxWidth), widthMeasureSpec, childState.widthState ),
+                                  heightSizeAndState );
+
+            if( matchWidth )
+            {
+                ForceUniformWidth( _children.Count, heightMeasureSpec );
+            }
+        } // MeasureVertically
+
+        void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
         {
-            get
+            bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL;
+
+            LayoutLength childTop = new LayoutLength(Padding.Top);
+            LayoutLength childLeft = new LayoutLength(Padding.Start);
+
+            // Where bottom of child should go
+            LayoutLength height = new LayoutLength(bottom - top);
+
+            // Space available for child
+            LayoutLength childSpace = new LayoutLength( height - Padding.Top - Padding.Bottom);
+
+            int count = _children.Count;
+
+            switch (LinearAlignment)
             {
-                return GetCellPadding();
+                case Alignment.Begin:
+                default:
+                    // totalLength contains the padding already
+                    // In case of RTL map BEGIN alignment to the right edge
+                    if (isLayoutRtl)
+                    {
+                        childLeft = new LayoutLength(Padding.Start  + right.AsDecimal() - left.AsDecimal() - _totalLength);
+                    }
+                    else
+                    {
+                        childLeft = new LayoutLength(Padding.Start);
+                    }
+                    break;
+                case Alignment.End:
+                    // totalLength contains the padding already
+                    // In case of RTL map END alignment to the left edge
+                    if (isLayoutRtl)
+                    {
+                        childLeft = new LayoutLength(Padding.Start);
+                    }
+                    else
+                    {
+                        childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - _totalLength);
+                    }
+                    break;
+                case Alignment.CenterHorizontal:
+                    // totalLength contains the padding already
+                    childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - _totalLength) / 2.0f);
+                    break;
             }
-            set
+
+            int start = 0;
+            int dir = 1;
+
+            // In case of RTL, start drawing from the last child.
+            if (isLayoutRtl)
             {
-                SetCellPadding(value);
+                start = count - 1;
+                dir = -1;
             }
-        }
 
-        /// <summary>
-        /// [Draft] Get/Set the alignment in the layout
-        /// </summary>
-        public LinearLayout.Alignment LinearAlignment
+            for( int i = 0; i < count; i++)
+            {
+                int childIndex = start + dir * i;
+                // Get a reference to the childLayout at the given index
+                LayoutItem childLayout = _children[childIndex];
+                if( childLayout != null )
+                {
+                    LayoutLength childWidth = childLayout.MeasuredWidth.Size;
+                    LayoutLength childHeight = childLayout.MeasuredHeight.Size;
+                    Extents childMargin = childLayout.Margin;
+
+                    switch ( LinearAlignment )
+                    {
+                        case Alignment.Top:
+                            childTop = new LayoutLength(Padding.Top + childMargin.Top);
+                            break;
+                        case Alignment.Bottom:
+                            childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom);
+                            break;
+                        case Alignment.CenterVertical: // FALLTHROUGH
+                        default:
+                            childTop = new LayoutLength(Padding.Top + ( ( childSpace - childHeight ).AsDecimal() / 2.0f ) + childMargin.Top - childMargin.Bottom);
+                            break;
+                    }
+                    childLeft += childMargin.Start;
+                    childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
+                    childLeft += childWidth + childMargin.End + CellPadding.Width;
+                }
+            }
+        } // LayoutHorizontally
+
+        void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
         {
-            get
+            LayoutLength childTop = new LayoutLength(Padding.Top);
+            LayoutLength childLeft = new LayoutLength(Padding.Start);
+
+            // Where end of child should go
+            LayoutLength width = new LayoutLength(right - left);
+
+            // Space available for child
+            LayoutLength childSpace = new LayoutLength( width - Padding.Start - Padding.End);
+
+            int count = _children.Count;
+
+            switch (LinearAlignment)
             {
-                return GetAlignment();
+              case Alignment.Top:
+                // totalLength contains the padding already
+                childTop = new LayoutLength( Padding.Top );
+                break;
+              case Alignment.Bottom:
+                // totalLength contains the padding already
+                childTop = new LayoutLength( Padding.Top + bottom.AsDecimal() - top.AsDecimal() - _totalLength);
+                break;
+              case Alignment.CenterVertical:
+              default:
+                // totalLength contains the padding already
+                childTop = new LayoutLength(Padding.Top + ( bottom.AsDecimal() - top.AsDecimal() - _totalLength ) / 2.0f);
+                break;
             }
-            set
+
+            for( int i = 0; i < count; i++)
             {
-                SetAlignment(value);
+                LayoutItem childLayout = _children[i];
+                if( childLayout != null )
+                {
+                    LayoutLength childWidth = childLayout.MeasuredWidth.Size;
+                    LayoutLength childHeight = childLayout.MeasuredHeight.Size;
+                    Extents childMargin = childLayout.Margin;
+
+                    childTop += childMargin.Top;
+                    switch ( LinearAlignment )
+                    {
+                      case Alignment.Begin:
+                      default:
+                      {
+                        childLeft = new LayoutLength(Padding.Start + childMargin.Start);
+                        break;
+                      }
+                      case Alignment.End:
+                      {
+                        childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End);
+                        break;
+                      }
+                      case Alignment.CenterHorizontal:
+                      {
+                        childLeft = new LayoutLength(Padding.Start + (( childSpace - childWidth ).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End);
+                        break;
+                      }
+                    }
+                    childLayout.Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
+                    childTop += childHeight + childMargin.Bottom + CellPadding.Height;
+                }
             }
-        }
+        } // LayoutVertical
 
-        /// <summary>
-        /// [Draft] Enumeration for the direction in which the content is laid out
-        /// </summary>
-        public enum Orientation
+        void ForceUniformHeight( int count, MeasureSpecification widthMeasureSpec )
         {
-            /// <summary>
-            /// Horizontal (row)
-            /// </summary>
-            Horizontal,
-            /// <summary>
-            /// Vertical (column)
-            /// </summary>
-            Vertical
+          // Pretend that the linear layout has an exact size. This is the measured height of
+          // ourselves. The measured height should be the max height of the children, changed
+          // to accommodate the heightMeasureSpec from the parent
+          MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredHeight.Size, MeasureSpecification.ModeType.Exactly);
+          for (int i = 0; i < count; ++i)
+          {
+            LayoutItem childLayout = _children[i];
+            if (childLayout != null)
+            {
+                LayoutLength desiredWidth = new LayoutLength(childLayout.Owner.WidthSpecification);
+                LayoutLength desiredHeight = new LayoutLength(Owner.WidthSpecification );
+
+                if (desiredHeight.AsRoundedValue() == LayoutParamPolicies.MatchParent)
+                {
+                  // Temporarily force children to reuse their old measured width
+                  LayoutLength oldWidth = desiredWidth;
+                  childLayout.Owner.WidthSpecification = (int)childLayout.MeasuredWidth.Size.AsRoundedValue();
+                  // Remeasure with new dimensions
+                  MeasureChildWithMargins( childLayout, widthMeasureSpec, new LayoutLength(0),
+                                           uniformMeasureSpec, new LayoutLength(0) );
+
+                  childLayout.Owner.WidthSpecification =  (int)oldWidth.AsRoundedValue();
+              }
+            }
+          }
         }
 
-        /// <summary>
-        /// [Draft] Enumeration for the alignment of the linear layout items
-        /// </summary>
-        public enum Alignment
+        void ForceUniformWidth( int count, MeasureSpecification heightMeasureSpec )
         {
-            /// <summary>
-            /// At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
-            /// </summary>
-            Begin              = 0x1,
-            /// <summary>
-            /// At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
-            /// </summary>
-            End                = 0x2,
-            /// <summary>
-            /// At the horizontal center of the container
-            /// </summary>
-            CenterHorizontal   = 0x4,
-            /// <summary>
-            /// At the top edge of the container
-            /// </summary>
-            Top                = 0x8,
-            /// <summary>
-            /// At the bottom edge of the container
-            /// </summary>
-            Bottom             = 0x10,
-            /// <summary>
-            /// At the vertical center of the container
-            /// </summary>
-            CenterVertical     = 0x20
+            // Pretend that the linear layout has an exact size.
+            MeasureSpecification uniformMeasureSpec = new MeasureSpecification( MeasuredWidth.Size, MeasureSpecification.ModeType.Exactly);
+            for (int i = 0; i < count; ++i)
+            {
+                LayoutItem childLayout = _children[i];
+                if (childLayout != null)
+                {
+                    LayoutLength desiredWidth = new LayoutLength(childLayout.Owner.WidthSpecification);
+                    LayoutLength desiredHeight = new LayoutLength(Owner.WidthSpecification );
+
+                    if( desiredWidth.AsRoundedValue()  == LayoutParamPolicies.MatchParent)
+                    {
+                        // Temporarily force children to reuse their old measured height
+                        LayoutLength oldHeight = desiredHeight;
+                        childLayout.Owner.HeightSpecification =  (int)childLayout.MeasuredHeight.Size.AsRoundedValue();
+
+                        // Remeasure with new dimensions
+                        MeasureChildWithMargins( childLayout, uniformMeasureSpec, new LayoutLength(0),
+                                                heightMeasureSpec, new LayoutLength(0));
+
+                        childLayout.Owner.HeightSpecification = (int)oldHeight.AsRoundedValue();
+                    }
+                }
+            }
         }
 
-    }
+    } //LinearLayout
 
-}
+} // namespace