Exemple #1
0
        TablePlacement[] VisibleChildren()
        {
            TablePlacement[] result = new TablePlacement[placements.Count];

            int j = 0;
            for (int i = 0; i < placements.Count; i++) {
                var item = placements[i];
                if (item.Child.Visible) {
                    result[j] = item;
                    j++;
                }
            }

            if (j != placements.Count) {
                Array.Resize (ref result, j);
            }

            return result;
        }
Exemple #2
0
 int GetStartAttach(TablePlacement tp, Orientation orientation)
 {
     if (orientation == Orientation.Vertical)
         return tp.Top;
     else
         return tp.Left;
 }
Exemple #3
0
 int GetEndAttach(TablePlacement tp, Orientation orientation)
 {
     if (orientation == Orientation.Vertical)
         return tp.Bottom;
     else
         return tp.Right;
 }
Exemple #4
0
 // Get the preferred size of each child widget, including the margins
 Size[] GetPreferredChildrenSizes(TablePlacement[] visibleChildren, bool useWidthConstraint, bool useHeightConstraint)
 {
     var sizes = new Size [visibleChildren.Length];
     for (int n=0; n<visibleChildren.Length; n++) {
         var bp = visibleChildren[n];
         Size s;
         if (useWidthConstraint)
             s = bp.GetPreferredSize (bp.NextWidth - bp.LeftMargin - bp.RightMargin, double.PositiveInfinity);
         else if (useHeightConstraint)
             s = bp.GetPreferredSize (double.PositiveInfinity, bp.NextHeight - bp.TopMargin - bp.BottomMargin);
         else
             s = bp.GetPreferredSize (double.PositiveInfinity, double.PositiveInfinity);
         s.Width += bp.LeftMargin + bp.RightMargin;
         s.Height += bp.TopMargin + bp.BottomMargin;
         sizes [n] = s;
     }
     return sizes;
 }
Exemple #5
0
        /// <summary>
        /// Calculates the preferred size of each cell (either height or width, depending on the provided orientation) 
        /// </summary>
        /// <param name="mode">Mode.</param>
        /// <param name="orientation">Wether we are calculating the vertical size or the horizontal size</param>
        /// <param name="visibleChildren">List of children that are visible, and for which the size is being calculated.</param>
        /// <param name="fixedSizesByCell">Cells which have a fixed size</param>
        /// <param name="cellsWithExpand">Cells which are expandable.</param>
        /// <param name="sizes">Calculated size of each cell</param>
        /// <param name="spacing">Spacing to use for each cell</param>
        CellSizeVector CalcPreferredCellSizes(TablePlacement[] visibleChildren, Size[] childrenSizes, Orientation orientation)
        {
            Dictionary<int,double> fixedSizesByCell;
            HashSet<int> cellsWithExpand;
            double[] sizes;
            double spacing;

            int lastCell = 0;

            fixedSizesByCell = new Dictionary<int, double> ();
            cellsWithExpand = new HashSet<int> ();
            HashSet<int> cellsWithWidget = new HashSet<int> ();
            sizes = new double [visibleChildren.Length];

            // Get the size of each widget and store the fixed sizes for widgets which don't span more than one cell

            for (int n=0; n<visibleChildren.Length; n++) {
                var bp = visibleChildren[n];
                int start = GetStartAttach (bp, orientation);
                int end = GetEndAttach (bp, orientation);

                if (end > lastCell)
                    lastCell = end;

                // Check if the cell is expandable and store the value
                bool expand = bp.GetExpandsForOrientation (orientation);
                for (int i=start; i < end; i++) {
                    cellsWithWidget.Add (i);
                    if (expand)
                        cellsWithExpand.Add (i);
                }

                double s = orientation == Orientation.Vertical ? childrenSizes[n].Height : childrenSizes[n].Width;
                sizes [n] = s;

                if (end == start + 1) {
                    // The widget only takes one cell. Store its size if it is the biggest
                    bool changed = false;
                    double fs;
                    if (!fixedSizesByCell.TryGetValue (start, out fs))
                        changed = true;
                    if (s > fs) {
                        fs = s;
                        changed = true;
                    }
                    if (changed)
                        fixedSizesByCell [start] = fs;
                }
            }

            // For widgets that span more than one cell, calculate the floating size, that is, the size
            // which is not taken by other fixed size widgets

            List<TablePlacement> widgetsToAdjust = new List<TablePlacement> ();
            Dictionary<TablePlacement,double[]> growSizes = new Dictionary<TablePlacement, double[]> ();

            for (int n=0; n<visibleChildren.Length; n++) {
                var bp = visibleChildren[n];
                int start = GetStartAttach (bp, orientation);
                int end = GetEndAttach (bp, orientation);
                if (end == start + 1)
                    continue;
                widgetsToAdjust.Add (bp);

                double fixedSize = 0;

                // We are going to calculate the spacing included in the widget's span of cells
                // (there is spacing between each cell)
                double spanSpacing = 0;

                for (int c = start; c < end; c++) {
                    double fs;
                    fixedSizesByCell.TryGetValue (c, out fs);
                    fixedSize += fs;
                    if (c != start && c != end)
                        spanSpacing += GetSpacing (c, orientation);
                }

                // sizeToGrow is the size that the whole cell span has to grow in order to fit
                // this widget. We substract the spacing between cells because that space will
                // be used by the widget, so we don't need to allocate more size for it

                double sizeToGrow = sizes [n] - fixedSize - spanSpacing;

                double sizeToGrowPart = sizeToGrow / (end - start);

                // Split the size to grow between the cells of the widget. We need to know how much size the widget
                // requires for each cell it covers.

                double[] widgetGrowSizes = new double [end - start];
                for (int i=0; i<widgetGrowSizes.Length; i++)
                    widgetGrowSizes [i] = sizeToGrowPart;
                growSizes[bp] = widgetGrowSizes;
            }

            // Now size-to-grow values have to be adjusted. For example, let's say widget A requires 100px for column 1 and 100px for column 2, and widget B requires
            // 60px for column 2 and 60px for column 3. So the widgets are overlapping at column 2. Since A requires at least 100px in column 2, it means that B can assume
            // that it will have 100px available in column 2, which means 40px more than it requested. Those extra 40px can then be substracted from the 60px that
            // it required for column 3.

            foreach (var n in cellsWithWidget) {
                double maxv = 0;
                TablePlacement maxtNatural = null;

                // Find the widget that requires the maximum size for this cell
                foreach (var bp in widgetsToAdjust) {
                    // could be expressed as where clause, but this is faster and performance matters here
                    if (GetStartAttach (bp, orientation) <= n && GetEndAttach (bp, orientation) > n) {
                        double cv = growSizes[bp][n - GetStartAttach (bp, orientation)];
                        if (cv > maxv) {
                            maxv = cv;
                            maxtNatural = bp;
                        }
                    }
                }

                // Adjust the required size of all widgets of the cell (excluding the widget with the max size)
                foreach (var bp in widgetsToAdjust) {
                    if (GetStartAttach (bp, orientation) <= n && GetEndAttach (bp, orientation) > n) {
                        double[] widgetGrows = growSizes[bp];
                        int cellIndex = n - GetStartAttach (bp, orientation);
                        if (bp != maxtNatural) {
                            double cv = widgetGrows[cellIndex];
                            double splitExtraSpace = (maxv - cv) / (widgetGrows.Length - 1);
                            for (int i=0; i<widgetGrows.Length; i++)
                                widgetGrows[i] -= splitExtraSpace;
                        }
                    }
                }
            }

            // Find the maximum size-to-grow for each cell

            Dictionary<int,double> finalGrowTable = new Dictionary<int, double> ();

            foreach (var bp in widgetsToAdjust) {
                int start = GetStartAttach (bp, orientation);
                int end = GetEndAttach (bp, orientation);
                double[] widgetGrows = growSizes[bp];
                for (int n=start; n<end; n++) {
                    double curGrow;
                    finalGrowTable.TryGetValue (n, out curGrow);
                    var val = widgetGrows [n - start];
                    if (val > curGrow)
                        curGrow = val;
                    finalGrowTable [n] = curGrow;
                }
            }

            // Add the final size-to-grow to the fixed sizes calculated at the begining

            foreach (var it in finalGrowTable) {
                double ws;
                fixedSizesByCell.TryGetValue (it.Key, out ws);
                fixedSizesByCell [it.Key] = it.Value + ws;
            }

            spacing = 0;
            for (int n=1; n<lastCell; n++) {
                if (cellsWithWidget.Contains (n))
                    spacing += GetSpacing (n, orientation);
            }

            return new CellSizeVector () {
                visibleChildren = visibleChildren,
                fixedSizesByCell = fixedSizesByCell,
                cellsWithExpand = cellsWithExpand,
                sizes = sizes,
                spacing = spacing,
                orientation = orientation
            };
        }