Ejemplo n.º 1
0
        //TODO: optimise performance for single slot case
        private Size CalculateLayout(Size areaSize, Rect[] slotPositions)
        {
            int[]  columnSizes        = new int[currentLayout.ColumnCount];
            int[]  rowSizes           = new int[currentLayout.RowCount];
            bool[] stretchableRows    = new bool[currentLayout.RowCount];
            TableLayoutPosition[] pss = new TableLayoutPosition[WaveChildren.Count];
            bool relayoutNeeded       = false;

            // all rows are stretchable by default
            for (int i = 0; i < stretchableRows.Length; i++)
            {
                stretchableRows[i] = true;
            }

            // retrieve all stored slot position data and discover all stretchable rows
            for (int i = 0; i < WaveChildren.Count; i++)
            {
                pss[i] = TableLayout.GetSlotPosition(WaveChildren[i]);

                if ((((RendererBase)WaveChildren[i]).Crop & CropStrategy.Stretch) != CropStrategy.Stretch)
                {
                    stretchableRows[pss[i].Row] = false;
                }
            }

            // size fixed-size columns based on single-column slots
            for (int i = 0; i < WaveChildren.Count; i++)
            {
                if ((pss[i].ColumnSpan == 0) && (currentLayout.RelativeSizes[pss[i].Column] == 0))
                {
                    WaveChildren[i].Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

                    if ((int)WaveChildren[i].DesiredSize.Width > columnSizes[pss[i].Column])
                    {
                        if (columnSizes[pss[i].Column] > 0)
                        {
                            relayoutNeeded = true;
                        }

                        columnSizes[pss[i].Column] = (int)WaveChildren[i].DesiredSize.Width;
                    }
                }
            }

            // if width is undefined, we do not calculate relative columns - only absolute ones
            if (!Double.IsInfinity(areaSize.Width))
            {
                // calculate total remaining width for relative columns
                int remainingWidthForRelativeColumns = (int)areaSize.Width;

                foreach (int columnSize in columnSizes)
                {
                    remainingWidthForRelativeColumns -= columnSize;
                }

                // allocate remaining width to relative columns
                if (remainingWidthForRelativeColumns > 0)
                {
                    int totalFractions = 0;

                    for (int i = 0; i < currentLayout.RelativeSizes.Length; i++)
                    {
                        if (currentLayout.RelativeSizes[i] > 0)
                        {
                            totalFractions += currentLayout.RelativeSizes[i];
                        }
                    }

                    if (totalFractions > 0)
                    {
                        int fraction = remainingWidthForRelativeColumns / totalFractions;

                        if (fraction > 0)
                        {
                            for (int i = 0; i < currentLayout.RelativeSizes.Length; i++)
                            {
                                if (currentLayout.RelativeSizes[i] > 0)
                                {
                                    columnSizes[i] = fraction * currentLayout.RelativeSizes[i];
                                }
                            }
                        }
                    }
                }

                // add remaining width to last relative column
                remainingWidthForRelativeColumns = (int)areaSize.Width;

                for (int i = 0; i < columnSizes.Length; i++)
                {
                    remainingWidthForRelativeColumns -= columnSizes[i];
                }

                if (remainingWidthForRelativeColumns > 0)
                {
                    for (int i = currentLayout.RelativeSizes.Length - 1; i == 0; i--)
                    {
                        if (currentLayout.RelativeSizes[i] > 0)
                        {
                            columnSizes[i] += remainingWidthForRelativeColumns;
                            remainingWidthForRelativeColumns = 0;

                            break;
                        }
                    }
                }

                // if there are no relative columns, update the block width to match the combined fixed-size column widths
                if (remainingWidthForRelativeColumns > 0)
                {
                    //TODO: update the block width to match the combined fixed-size column widths
                }
            }

            // layout single-cell slots (both width and height)
            for (int i = 0; i < WaveChildren.Count; i++)
            {
                if ((pss[i].ColumnSpan == 0) && (pss[i].RowSpan == 0))
                {
                    if (columnSizes[pss[i].Column] > 0)
                    {
                        WaveChildren[i].Measure(new Size(columnSizes[pss[i].Column], Double.PositiveInfinity));

                        if (WaveChildren[i].DesiredSize.Height > rowSizes[pss[i].Row])
                        {
                            rowSizes[pss[i].Row] = (int)WaveChildren[i].DesiredSize.Height;
                        }
                    }
                }
            }

            // layout single row multi column slots
            for (int i = 0; i < WaveChildren.Count; i++)
            {
                if ((pss[i].ColumnSpan > 0) && (pss[i].RowSpan == 0))
                {
                    int startColumnIndex = pss[i].Column;
                    int endColumnIndex   = startColumnIndex + pss[i].ColumnSpan;
                    int childWidth       = 0;

                    for (int j = startColumnIndex; j <= endColumnIndex; j++)
                    {
                        childWidth += columnSizes[j];
                    }

                    childWidth += pss[i].ColumnSpan * currentLayout.Spacing;

                    if (childWidth > 0)
                    {
                        WaveChildren[i].Measure(new Size(childWidth, Double.PositiveInfinity));

                        if ((int)WaveChildren[i].DesiredSize.Height > rowSizes[pss[i].Row])
                        {
                            if (rowSizes[pss[i].Row] > 0)
                            {
                                relayoutNeeded = true;
                            }

                            rowSizes[pss[i].Row] = (int)WaveChildren[i].DesiredSize.Height;
                        }
                    }
                }
            }

            // layout multi row slots
            for (int i = 0; i < WaveChildren.Count; i++)
            {
                if (pss[i].RowSpan > 0)
                {
                    // calculate width for the slot
                    int slotWidth = 0;

                    if (pss[i].ColumnSpan > 0)
                    {
                        int startColumnIndex = pss[i].Column;
                        int endColumnIndex   = startColumnIndex + pss[i].ColumnSpan;

                        for (int j = startColumnIndex; j <= endColumnIndex; j++)
                        {
                            slotWidth += columnSizes[j];
                        }

                        slotWidth += pss[i].ColumnSpan * currentLayout.Spacing;
                    }
                    else
                    {
                        slotWidth = columnSizes[pss[i].Column];
                    }

                    // calculate space available for the slot
                    int startRowIndex          = pss[i].Row;
                    int endRowIndex            = startRowIndex + pss[i].RowSpan;
                    int availableHeightForSlot = 0;

                    for (int j = startRowIndex; j <= endRowIndex; j++)
                    {
                        availableHeightForSlot += rowSizes[j];
                    }

                    // get slot's preferred height
                    WaveChildren[i].Measure(new Size(slotWidth, Double.PositiveInfinity));

                    // make adjustments
                    if (WaveChildren[i].DesiredSize.Height > availableHeightForSlot)
                    {
                        relayoutNeeded = true;

                        int numberOfStretchableRows = 0;

                        for (int j = startRowIndex; j <= endRowIndex; j++)
                        {
                            if (stretchableRows[j])
                            {
                                numberOfStretchableRows++;
                            }
                        }

                        if (numberOfStretchableRows > 0)
                        {
                            int[] stretchableRowIndices = new int[numberOfStretchableRows];
                            int[] stretchableRowWeights = new int[numberOfStretchableRows];
                            int   stretchableWeightsSum = 0;

                            for (int j = startRowIndex; j <= endRowIndex; j++)
                            {
                                if (stretchableRows[j])
                                {
                                    stretchableRowIndices[j - startRowIndex] = j;
                                    stretchableRowWeights[j - startRowIndex] = (currentLayout.StretchWeights != null) ? currentLayout.StretchWeights[j] : 1;

                                    stretchableWeightsSum += stretchableRowWeights[j - startRowIndex];
                                }
                            }

                            if ((WaveChildren[i].DesiredSize.Height - availableHeightForSlot) >= 1)
                            {
                                int sizeToRedistribute = (int)(WaveChildren[i].DesiredSize.Height - availableHeightForSlot);
                                int singleAddonUnit    = 0;

                                if (stretchableWeightsSum == 0)
                                {
                                    singleAddonUnit = sizeToRedistribute / numberOfStretchableRows;

                                    if (singleAddonUnit > 0)
                                    {
                                        for (int k = 0; k < stretchableRowIndices.Length; k++)
                                        {
                                            rowSizes[stretchableRowIndices[k]] += singleAddonUnit;
                                        }
                                    }
                                }
                                else
                                {
                                    singleAddonUnit = sizeToRedistribute / stretchableWeightsSum;

                                    if (singleAddonUnit > 0)
                                    {
                                        for (int k = 0; k < stretchableRowIndices.Length; k++)
                                        {
                                            if (stretchableRowWeights[k] > 0)
                                            {
                                                rowSizes[stretchableRowIndices[k]] += stretchableRowWeights[k] * singleAddonUnit;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //TODO: if in any of the previous 3 steps stretch happened - relayout all slots
            if (relayoutNeeded)
            {
                /////////////
            }

            // prepare slot positions if requested
            if (slotPositions != null)
            {
                int   x = Padding.Left, y = Padding.Top;
                int[] columnXs = new int[currentLayout.ColumnCount];
                int[] rowYs    = new int[currentLayout.RowCount];

                // calculate column X coordinates
                for (int i = 0; i < columnXs.Length; i++)
                {
                    columnXs[i] = x;

                    x += columnSizes[i];
                    x += currentLayout.Spacing;
                }

                // calculate row Y coordinates
                for (int i = 0; i < rowYs.Length; i++)
                {
                    rowYs[i] = y;

                    y += rowSizes[i];
                    y += currentLayout.Spacing;
                }

                // calculate actual slot positions
                for (int i = 0; i < WaveChildren.Count; i++)
                {
                    double slotWidth = 0, slotHeight = 0;

                    if (pss[i].ColumnSpan > 0)
                    {
                        int startColumnIndex = pss[i].Column;
                        int endColumnIndex   = startColumnIndex + pss[i].ColumnSpan;

                        for (int j = startColumnIndex; j <= endColumnIndex; j++)
                        {
                            slotWidth += columnSizes[j];
                        }

                        slotWidth += pss[i].ColumnSpan * currentLayout.Spacing;
                    }
                    else
                    {
                        slotWidth = columnSizes[pss[i].Column];
                    }

                    if (pss[i].RowSpan > 0)
                    {
                        int startRowIndex = pss[i].Row;
                        int endRowIndex   = startRowIndex + pss[i].RowSpan;

                        for (int j = startRowIndex; j <= endRowIndex; j++)
                        {
                            slotHeight += rowSizes[j];
                        }

                        slotHeight += pss[i].RowSpan * currentLayout.Spacing;
                    }
                    else
                    {
                        slotHeight = rowSizes[pss[i].Row];
                    }

                    slotPositions[i] = new Rect(
                        columnXs[pss[i].Column], rowYs[pss[i].Row],
                        slotWidth, slotHeight);
                }
            }

            // calculate final control size
            double finalWidth = 0, finalHeight = 0;

            foreach (int columnSize in columnSizes)
            {
                finalWidth += columnSize;
            }

            finalWidth += (columnSizes.Length - 1) * currentLayout.Spacing;
            finalWidth += Padding.Left;
            finalWidth += Padding.Right;

            foreach (int rowSize in rowSizes)
            {
                finalHeight += rowSize;
            }

            finalHeight += (rowSizes.Length - 1) * currentLayout.Spacing;
            finalHeight += Padding.Top;
            finalHeight += Padding.Bottom;

            if (!Double.IsInfinity(areaSize.Width) && (finalWidth > areaSize.Width))
            {
                finalWidth = areaSize.Width;
            }

            if (!Double.IsInfinity(areaSize.Height) && (finalHeight > areaSize.Height))
            {
                finalHeight = areaSize.Height;
            }

            return(new Size(finalWidth, finalHeight));
        }
Ejemplo n.º 2
0
 public static void SetSlotPosition(UIElement element, TableLayoutPosition value)
 {
     element.SetValue(SlotPositionProperty, value);
 }