예제 #1
0
파일: Box.cs 프로젝트: wesreid/xwt
        void CalcDefaultSizes(double width, double height)
        {
            bool   vertical      = direction == Orientation.Vertical;
            int    nexpands      = 0;
            double requiredSize  = 0;
            double availableSize = vertical ? height : width;

            var widthConstraint  = vertical ? SizeConstraint.WithSize(width) : SizeConstraint.Unconstrained;
            var heightConstraint = vertical ? SizeConstraint.Unconstrained : SizeConstraint.WithSize(height);

            var visibleChildren = children.Where(b => b.Child.Visible).ToArray();
            var sizes           = new Dictionary <BoxPlacement, double> ();

            // Get the natural size of each child
            foreach (var bp in visibleChildren)
            {
                Size s;
                s             = bp.Child.Surface.GetPreferredSize(widthConstraint, heightConstraint, true);
                bp.NextSize   = vertical ? s.Height : s.Width;
                sizes [bp]    = bp.NextSize;
                requiredSize += bp.NextSize;
                if (bp.Child.ExpandsForOrientation(direction))
                {
                    nexpands++;
                }
            }

            double remaining = availableSize - requiredSize - (spacing * (double)(visibleChildren.Length - 1));

            if (remaining < 0)
            {
                // The box is not big enough to fit the widgets using its natural size.
                // We have to shrink the widgets.

                // The total amount we have to shrink
                double shrinkSize = -remaining;

                var sizePart = new SizeSplitter(shrinkSize, visibleChildren.Length);
                foreach (var bp in visibleChildren)
                {
                    bp.NextSize -= sizePart.NextSizePart();
                }
            }
            else
            {
                var expandRemaining = new SizeSplitter(remaining, nexpands);
                foreach (var bp in visibleChildren)
                {
                    if (bp.Child.ExpandsForOrientation(direction))
                    {
                        bp.NextSize += expandRemaining.NextSizePart();
                    }
                }
            }
        }
예제 #2
0
파일: Box.cs 프로젝트: Clancey/xwt
        void CalcDefaultSizes(SizeRequestMode mode, double totalSize, double lengthConstraint)
        {
            bool   calcHeights         = direction == Orientation.Vertical;
            bool   useLengthConstraint = mode == SizeRequestMode.HeightForWidth && calcHeights || mode == SizeRequestMode.WidthForHeight && !calcHeights;
            int    nexpands            = 0;
            double naturalSize         = 0;

            var visibleChildren = children.Where(b => b.Child.Visible).ToArray();
            var sizes           = new Dictionary <BoxPlacement, WidgetSize> ();

            // Get the natural size of each child
            foreach (var bp in visibleChildren)
            {
                WidgetSize s;
                if (useLengthConstraint)
                {
                    s = GetPreferredLengthForSize(mode, bp.Child, lengthConstraint);
                }
                else
                {
                    s = GetPreferredSize(calcHeights, bp.Child);
                }
                sizes [bp]   = s;
                naturalSize += s.NaturalSize;
                bp.NextSize  = s.NaturalSize;
                if ((bp.BoxMode & BoxMode.Expand) != 0)
                {
                    nexpands++;
                }
            }

            double remaining = totalSize - naturalSize - (spacing * (double)(visibleChildren.Length - 1));

            if (remaining < 0)
            {
                // The box is not big enough to fit the widgets using its natural size.
                // We have to shrink the widgets.

                // List of widgets that we have to shrink
                var toShrink = new List <BoxPlacement> (visibleChildren);

                // The total amount we have to shrink
                double shrinkSize = -remaining;

                while (toShrink.Count > 0 && shrinkSize > 0)
                {
                    SizeSplitter sizePart = new SizeSplitter(shrinkSize, toShrink.Count);
                    shrinkSize = 0;
                    for (int i = 0; i < toShrink.Count; i++)
                    {
                        var bp = toShrink[i];
                        bp.NextSize -= sizePart.NextSizePart();

                        WidgetSize size = sizes [bp];

                        if (bp.NextSize < size.MinSize)
                        {
                            // If the widget can't be shrinked anymore, we remove it from the shrink list
                            // and increment the remaining shrink size. We'll loop again and this size will be
                            // substracted from the cells which can still be reduced
                            shrinkSize += (size.MinSize - bp.NextSize);
                            bp.NextSize = size.MinSize;
                            toShrink.RemoveAt(i);
                            i--;
                        }
                    }
                }
            }
            else
            {
                var expandRemaining = new SizeSplitter(remaining, nexpands);
                foreach (var bp in visibleChildren)
                {
                    if ((bp.BoxMode & BoxMode.Expand) != 0)
                    {
                        bp.NextSize += expandRemaining.NextSizePart();
                    }
                }
            }
        }
예제 #3
0
        void CalcDefaultSizes(SizeRequestMode mode, double totalSize, double lengthConstraint)
        {
            bool   calcHeights         = direction == Orientation.Vertical;
            bool   useLengthConstraint = mode == SizeRequestMode.HeightForWidth && calcHeights || mode == SizeRequestMode.WidthForHeight && !calcHeights;
            int    nexpands            = 0;
            double naturalSize         = 0;

            var visibleChildren = children.Where(b => b.Child.Visible);
            int childrenCount   = 0;

            // Get the natural size of each child
            foreach (var bp in visibleChildren)
            {
                childrenCount++;
                WidgetSize s;
                if (useLengthConstraint)
                {
                    s = GetPreferredLengthForSize(mode, bp.Child, lengthConstraint);
                }
                else
                {
                    s = GetPreferredSize(calcHeights, bp.Child);
                }
                naturalSize += s.NaturalSize;
                bp.NextSize  = s.NaturalSize;
                if ((bp.BoxMode & BoxMode.Expand) != 0)
                {
                    nexpands++;
                }
            }

            double remaining = totalSize - naturalSize - (spacing * (double)(childrenCount - 1));

            if (remaining < 0)
            {
                // The box is not big enough to fit the widgets using its natural size.
                // We have to shrink the widgets.
                var    sizePart   = new SizeSplitter(-remaining, childrenCount);
                var    toAdjust   = new List <BoxPlacement> ();
                double adjustSize = 0;
                foreach (var bp in visibleChildren)
                {
                    WidgetSize s;
                    if (useLengthConstraint)
                    {
                        s = GetPreferredLengthForSize(mode, bp.Child, lengthConstraint);
                    }
                    else
                    {
                        s = GetPreferredSize(calcHeights, bp.Child);
                    }
                    bp.NextSize = s.NaturalSize - sizePart.NextSizePart();
                    if (bp.NextSize < s.MinSize)
                    {
                        adjustSize += (s.MinSize - bp.NextSize);
                        bp.NextSize = s.MinSize;
                    }
                    else
                    {
                        toAdjust.Add(bp);
                    }
                }
                sizePart = new SizeSplitter(adjustSize, toAdjust.Count);
                foreach (var bp in toAdjust)
                {
                    bp.NextSize += sizePart.NextSizePart();
                }
            }
            else
            {
                var expandRemaining = new SizeSplitter(remaining, nexpands);
                foreach (var bp in visibleChildren)
                {
                    if ((bp.BoxMode & BoxMode.Expand) != 0)
                    {
                        bp.NextSize += expandRemaining.NextSizePart();
                    }
                }
            }
        }
예제 #4
0
        void CalcDefaultSizes(SizeRequestMode mode, double totalSize, bool calcHeights, bool calcOffsets)
        {
            TablePlacement[]             visibleChildren;
            Dictionary <int, WidgetSize> fixedSizesByCell;
            HashSet <int> cellsWithExpand;

            WidgetSize[] sizes;
            double       spacing;

            CalcDefaultSizes(mode, calcHeights, out visibleChildren, out fixedSizesByCell, out cellsWithExpand, out sizes, out spacing);

            double naturalSize = 0;

            // Get the total natural size
            foreach (var ws in fixedSizesByCell.Values)
            {
                naturalSize += ws.NaturalSize;
            }

            double remaining = totalSize - naturalSize - spacing;

            if (remaining < 0)
            {
                // The box is not big enough to fit the widgets using its natural size.
                // We have to shrink the cells

                // List of cell indexes that we have to shrink
                var toShrink = new List <int> (fixedSizesByCell.Keys);

                // The total amount we have to shrink
                double shrinkSize = -remaining;

                while (toShrink.Count > 0 && shrinkSize > 0)
                {
                    SizeSplitter sizePart = new SizeSplitter(shrinkSize, toShrink.Count);
                    shrinkSize = 0;
                    for (int i = 0; i < toShrink.Count; i++)
                    {
                        int        n         = toShrink[i];
                        double     reduction = sizePart.NextSizePart();
                        WidgetSize size;
                        fixedSizesByCell.TryGetValue(n, out size);
                        size.NaturalSize -= reduction;

                        if (size.NaturalSize < size.MinSize)
                        {
                            // If the widget can't be shrinked anymore, we remove it from the shrink list
                            // and increment the remaining shrink size. We'll loop again and this size will be
                            // substracted from the cells which can still be reduced
                            shrinkSize      += (size.MinSize - size.NaturalSize);
                            size.NaturalSize = size.MinSize;
                            toShrink.RemoveAt(i);
                            i--;
                        }
                        fixedSizesByCell [n] = size;
                    }
                }
            }
            else
            {
                int nexpands        = cellsWithExpand.Count;
                var expandRemaining = new SizeSplitter(remaining, nexpands);
                foreach (var c in cellsWithExpand)
                {
                    WidgetSize ws;
                    fixedSizesByCell.TryGetValue(c, out ws);
                    ws.NaturalSize      += expandRemaining.NextSizePart();
                    fixedSizesByCell [c] = ws;
                }
            }

            for (int n = 0; n < visibleChildren.Length; n++)
            {
                var           bp            = visibleChildren[n];
                double        allocatedSize = 0;
                double        cellOffset    = 0;
                AttachOptions ops           = calcHeights ? bp.YOptions : bp.XOptions;

                int start = GetStartAttach(bp, calcHeights);
                int end   = GetEndAttach(bp, calcHeights);
                for (int i = start; i < end; i++)
                {
                    WidgetSize ws;
                    fixedSizesByCell.TryGetValue(i, out ws);
                    allocatedSize += ws.NaturalSize;
                    if (i != start)
                    {
                        allocatedSize += GetSpacing(i, calcHeights);
                    }
                }

                if ((ops & AttachOptions.Fill) == 0)
                {
                    double s = sizes[n].NaturalSize;
                    if (s < allocatedSize)
                    {
                        cellOffset    = (allocatedSize - s) / 2;
                        allocatedSize = s;
                    }
                }

                // cellOffset is the offset of the widget inside the cell. We store it in NextX/Y, and
                // will be used below to calculate the total offset of the widget

                if (calcHeights)
                {
                    bp.NextHeight = allocatedSize;
                    bp.NextY      = cellOffset;
                }
                else
                {
                    bp.NextWidth = allocatedSize;
                    bp.NextX     = cellOffset;
                }
            }

            if (calcOffsets)
            {
                var    sortedChildren = visibleChildren.OrderBy(c => GetStartAttach(c, calcHeights)).ToArray();
                var    cells          = fixedSizesByCell.OrderBy(c => c.Key);
                double offset         = 0;
                int    n = 0;
                foreach (var c in cells)
                {
                    if (c.Key > 0)
                    {
                        offset += GetSpacing(c.Key, calcHeights);
                    }
                    while (n < sortedChildren.Length && GetStartAttach(sortedChildren[n], calcHeights) == c.Key)
                    {
                        // In the loop above we store the offset of the widget inside the cell in the NextX/Y field
                        // so now we have to add (not just assign) the offset of the cell to NextX/Y
                        if (calcHeights)
                        {
                            sortedChildren[n].NextY += offset;
                        }
                        else
                        {
                            sortedChildren[n].NextX += offset;
                        }
                        n++;
                    }
                    offset += c.Value.NaturalSize;
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Calculates size of each cell, taking into account their preferred size, expansion/fill requests, and the available space.
        /// Calculation is done only for the provided orientation (either height or width).
        /// </summary>
        /// <param name="mode">Mode.</param>
        /// <param name="availableSize">Total size available</param>
        /// <param name="calcOffsets"></param>
        void CalcCellSizes(CellSizeVector cellSizes, double availableSize, bool calcOffsets)
        {
            TablePlacement[]         visibleChildren  = cellSizes.visibleChildren;
            Dictionary <int, double> fixedSizesByCell = cellSizes.fixedSizesByCell;

            double[]    sizes       = cellSizes.sizes;
            double      spacing     = cellSizes.spacing;
            Orientation orientation = cellSizes.orientation;

            // Get the total natural size
            double naturalSize = fixedSizesByCell.Values.Sum();

            double remaining = availableSize - naturalSize - spacing;

            if (availableSize - spacing <= 0)
            {
                foreach (var i in fixedSizesByCell.Keys.ToArray())
                {
                    fixedSizesByCell [i] = 0;
                }
            }
            else if (remaining < 0)
            {
                // The box is not big enough to fit the widgets using its natural size.
                // We have to shrink the cells. We do a proportional reduction

                // List of cell indexes that we have to shrink
                var toShrink = new List <int> (fixedSizesByCell.Keys);

                // The total amount we have to shrink
                double splitSize = (availableSize - spacing) / toShrink.Count;

                // We have to reduce all cells proportionally, but if a cell is much bigger that
                // its proportionally allocated space, then we reduce this one before the others

                var smallCells     = fixedSizesByCell.Where(c => c.Value < splitSize);
                var belowSplitSize = smallCells.Sum(c => splitSize - c.Value);

                var bigCells      = fixedSizesByCell.Where(c => c.Value > splitSize);
                var overSplitSize = bigCells.Sum(c => c.Value - splitSize);

                ReduceProportional(fixedSizesByCell, bigCells.Select(c => c.Key), overSplitSize - belowSplitSize);

                var newNatural = fixedSizesByCell.Sum(c => c.Value);
                ReduceProportional(fixedSizesByCell, fixedSizesByCell.Keys, (availableSize - spacing) - newNatural);

                RoundSizes(fixedSizesByCell);
            }
            else
            {
                // Distribute remaining space among the extensible widgets
                HashSet <int> cellsWithExpand = cellSizes.cellsWithExpand;
                int           nexpands        = cellsWithExpand.Count;
                var           expandRemaining = new SizeSplitter(remaining, nexpands);
                foreach (var c in cellsWithExpand)
                {
                    double ws;
                    fixedSizesByCell.TryGetValue(c, out ws);
                    ws += expandRemaining.NextSizePart();
                    fixedSizesByCell [c] = ws;
                }
            }

            // Calculate the offset of each widget, relative to the cell (so 0 means at the left/top of the cell).

            for (int n = 0; n < visibleChildren.Length; n++)
            {
                var    bp            = visibleChildren[n];
                double allocatedSize = 0;
                double cellOffset    = 0;

                int start = GetStartAttach(bp, orientation);
                int end   = GetEndAttach(bp, orientation);
                for (int i = start; i < end; i++)
                {
                    double ws;
                    fixedSizesByCell.TryGetValue(i, out ws);
                    allocatedSize += ws;
                    if (i != start)
                    {
                        allocatedSize += GetSpacing(i, orientation);
                    }
                }

                var al = bp.Child.AlignmentForOrientation(orientation);
                if (al != WidgetPlacement.Fill)
                {
                    double s = sizes[n];
                    if (s < allocatedSize)
                    {
                        cellOffset    = (allocatedSize - s) * al.GetValue();
                        allocatedSize = s;
                    }
                }

                // cellOffset is the offset of the widget inside the cell. We store it in NextX/Y, and
                // will be used below to calculate the total offset of the widget

                if (orientation == Orientation.Vertical)
                {
                    bp.NextHeight = allocatedSize;
                    bp.NextY      = cellOffset;
                }
                else
                {
                    bp.NextWidth = allocatedSize;
                    bp.NextX     = cellOffset;
                }
            }

            if (calcOffsets)
            {
                // Calculate the final offset of each widget, relative to the table origin
                var    sortedChildren = visibleChildren.OrderBy(c => GetStartAttach(c, orientation)).ToArray();
                var    cells          = fixedSizesByCell.OrderBy(c => c.Key);
                double offset         = 0;
                int    n = 0;
                foreach (var c in cells)
                {
                    if (c.Key > 0)
                    {
                        offset += GetSpacing(c.Key, orientation);
                    }
                    while (n < sortedChildren.Length && GetStartAttach(sortedChildren[n], orientation) == c.Key)
                    {
                        // In the loop above we store the offset of the widget inside the cell in the NextX/Y field
                        // so now we have to add (not just assign) the offset of the cell to NextX/Y
                        if (orientation == Orientation.Vertical)
                        {
                            sortedChildren[n].NextY += offset;
                        }
                        else
                        {
                            sortedChildren[n].NextX += offset;
                        }
                        n++;
                    }
                    offset += c.Value;
                }
            }
        }