/**
         *  
         * 
         *  This function sets the height of each child
         *  so that the heights add up to <code>height</code>. 
         *  Each child is set to its preferred height
         *  if its percentHeight is zero.
         *  If its percentHeight is a positive number,
         *  the child grows (or shrinks) to consume its
         *  share of extra space.
         *  
         *  The return value is any extra space that's left over
         *  after growing all children to their maxHeight.
         */
        private float DistributeWidth(float width, 
                                          float height, 
                                          float restrictedHeight)
        {
            float spaceToDistribute = width;
            float totalPercentWidth = 0;
            System.Collections.Generic.List<FlexChildInfo> childInfoArray = new System.Collections.Generic.List<FlexChildInfo>();
            FlexChildInfo childInfo;
            float newHeight;
            ILayoutElement layoutElement;
            
            // rowHeight can be expensive to compute
            float cw = (_variableColumnWidth) ? 0 : Mathf.Ceil(ColumnWidth);
            int count = Target.NumberOfContentChildren;
            int totalCount = count; // number of elements to use in gap calculation
            
            // If the child is flexible, store information about it in the
            // childInfoArray. For non-flexible children, just set the child's
            // width and height immediately.
            for (int index = 0; index < count; index++)
            {
                layoutElement = (ILayoutElement) Target.GetContentChildAt(index);
                if (null == layoutElement || !layoutElement.IncludeInLayout)
                {
                    totalCount--;
                    continue;
                }

                if (null != layoutElement.PercentWidth && _variableColumnWidth)
                {
                    totalPercentWidth += (float)layoutElement.PercentWidth;

                    childInfo = new FlexChildInfo
                                    {
                                        LayoutElement = layoutElement,
                                        Percent = (float)layoutElement.PercentWidth,
                                        Min = LayoutUtil.GetMinBoundsWidth((InvalidationManagerClient) layoutElement),
                                        Max = LayoutUtil.GetMaxBoundsWidth(((InvalidationManagerClient) layoutElement))
                                    };

                    childInfoArray.Add(childInfo);                
                }
                else
                {
                    SizeLayoutElement(layoutElement, height, _verticalAlign,
                                   restrictedHeight, null, _variableColumnWidth, cw);
                    
                    spaceToDistribute -= Mathf.Ceil(LayoutUtil.GetLayoutBoundsWidth((InvalidationManagerClient) layoutElement));
                } 
            }
            
            if (totalCount > 1)
                spaceToDistribute -= (totalCount-1) * _gap;

            // Distribute the extra space among the flexible children
            if (0 != totalPercentWidth)
            {
                Flex.FlexChildrenProportionally(width,
                                                spaceToDistribute,
                                                totalPercentWidth,
                                                childInfoArray);

                float roundOff = 0;            
                foreach (FlexChildInfo info in childInfoArray)
                {
                    // Make sure the calculated percentages are rounded to pixel boundaries
                    int childSize = (int) Mathf.Round(info.Size + roundOff);
                    roundOff += info.Size - childSize;

                    SizeLayoutElement(info.LayoutElement, height, _verticalAlign, 
                                   restrictedHeight, childSize,
                                   _variableColumnWidth, cw);
                    spaceToDistribute -= childSize;

                    //if (((Component)info.LayoutElement).Id == "test")
                    //{
                    //    Debug.Log("Sized: " + childSize);
                    //}
                    //Debug.Log("Sized: " + childSize);
                }
            }
            return spaceToDistribute;
        }
Exemple #2
0
        /**
         *  This function distributes excess space among the flexible children.
         *  It does so with a view to keep the children's overall size
         *  close the ratios specified by their percent.
         *
         *  Param: spaceForChildren The total space for all children
         *
         *  Param: spaceToDistribute The space that needs to be distributed
         *  among the flexible children.
         *
         *  Param: childInfoArray An array of Objects. When this function
         *  is called, each object should define the following properties:
         *  - percent: the percentWidth or percentHeight of the child (depending
         *  on whether we're growing in a horizontal or vertical direction)
         *  - min: the minimum width (or height) for that child
         *  - max: the maximum width (or height) for that child
         *
         *  Returns: When this function finishes executing, a "size" property
         *  will be defined for each child object. The size property contains
         *  the portion of the spaceToDistribute to be distributed to the child.
         *  Ideally, the sum of all size properties is spaceToDistribute.
         *  If all the children hit their minWidth/maxWidth/minHeight/maxHeight
         *  before the space was distributed, then the remaining unused space
         *  is returned. Otherwise, the return value is zero.
         */
        public static float FlexChildrenProportionally(
            float spaceForChildren,
            float spaceToDistribute,
            float totalPercent,
            List <FlexChildInfo> childInfoArray)
        {
            // The algorithm iterivately attempts to break down the space that
            // is consumed by "flexible" containers into ratios that are related
            // to the percentWidth/percentHeight of the participating containers.

            int   numChildren = childInfoArray.Count;
            float flexConsumed;         // space consumed by flexible compontents
            bool  done;

            // We now do something a little tricky so that we can
            // support partial filling of the space. If our total
            // percent < 100% then we can trim off some space.
            float unused = spaceToDistribute -
                           (spaceForChildren * totalPercent / 100);

            if (unused > 0)
            {
                spaceToDistribute -= unused;
            }

            // Continue as long as there are some remaining flexible children.
            // The "done" flag isn't strictly necessary, except that it catches
            // cases where round-off error causes totalPercent to not exactly
            // equal zero.
            do
            {
                flexConsumed = 0;        // space consumed by flexible compontents
                done         = true;     // we are optimistic

                // Space for flexible children is the total amount of space
                // available minus the amount of space consumed by non-flexible
                // components.Divide that space in proportion to the percent
                // of the child
                float spacePerPercent = spaceToDistribute / totalPercent;

                // Attempt to divide out the space using our percent amounts,
                // if we hit its limit then that control becomes 'non-flexible'
                // and we run the whole space to distribute calculation again.
                for (int i = 0; i < numChildren; i++)
                {
                    FlexChildInfo childInfo = childInfoArray[i];

                    // Set its size in proportion to its percent.
                    float size = childInfo.Percent * spacePerPercent;

                    // If our flexiblity calc say grow/shrink more than we are
                    // allowed, then we grow/shrink whatever we can, remove
                    // ourselves from the array for the next pass, and start
                    // the loop over again so that the space that we weren't
                    // able to consume / release can be re-used by others.
                    if (size < childInfo.Min)
                    {
                        float min = childInfo.Min;
                        childInfo.Size = min;

                        // Move this object to the end of the array
                        // and decrement the length of the array.
                        // This is slightly expensive, but we don't expect
                        // to hit these min/max limits very often.
                        childInfoArray[i]           = childInfoArray[--numChildren];
                        childInfoArray[numChildren] = childInfo;

                        totalPercent      -= childInfo.Percent;
                        spaceToDistribute -= min;
                        done = false;
                        break;
                    }

                    if (size > childInfo.Max)
                    {
                        float max = childInfo.Max;
                        childInfo.Size = max;

                        childInfoArray[i]           = childInfoArray[--numChildren];
                        childInfoArray[numChildren] = childInfo;

                        totalPercent      -= childInfo.Percent;
                        spaceToDistribute -= max;
                        done = false;
                        break;
                    }

                    // All is well, let's carry on...
                    childInfo.Size = size;
                    flexConsumed  += size;
                }
            }while (!done);

            return((float)Math.Max(0, Math.Floor(spaceToDistribute - flexConsumed)));
        }