Пример #1
0
 internal protected virtual void OnReplaceChild(TablePlacement placement, Widget oldWidget, Widget newWidget)
 {
     if (oldWidget != null)
     {
         OnRemove(oldWidget);
     }
     OnAdd(newWidget, placement);
 }
Пример #2
0
 int GetEndAttach(TablePlacement tp, bool calcHeight)
 {
     if (calcHeight)
     {
         return(tp.Bottom);
     }
     else
     {
         return(tp.Right);
     }
 }
Пример #3
0
 int GetEndAttach(TablePlacement tp, Orientation orientation)
 {
     if (orientation == Orientation.Vertical)
     {
         return(tp.Bottom);
     }
     else
     {
         return(tp.Right);
     }
 }
Пример #4
0
 int GetStartAttach(TablePlacement tp, bool calcHeight)
 {
     if (calcHeight)
     {
         return(tp.Top);
     }
     else
     {
         return(tp.Left);
     }
 }
Пример #5
0
 int GetStartAttach(TablePlacement tp, Orientation orientation)
 {
     if (orientation == Orientation.Vertical)
     {
         return(tp.Top);
     }
     else
     {
         return(tp.Left);
     }
 }
Пример #6
0
        public void Attach(Widget widget, int left, int right, int top, int bottom, AttachOptions xOptions, AttachOptions yOptions)
        {
            var p = new TablePlacement((EventSink)WidgetEventSink, widget)
            {
                Left     = left,
                Right    = right,
                Top      = top,
                Bottom   = bottom,
                XOptions = xOptions,
                YOptions = yOptions
            };

            children.Add(p);
        }
Пример #7
0
        public void Add(Widget widget, int left, int top, int rowspan = 1, int colspan = 1, bool hexpand = false, bool vexpand = false, WidgetPlacement hpos = WidgetPlacement.Fill, WidgetPlacement vpos = WidgetPlacement.Fill, double marginLeft = -1, double marginTop = -1, double marginRight = -1, double marginBottom = -1, double margin = -1)
        {
            if (vpos != default(WidgetPlacement))
            {
                widget.VerticalPlacement = vpos;
            }
            if (hpos != default(WidgetPlacement))
            {
                widget.HorizontalPlacement = hpos;
            }

            widget.ExpandHorizontal = hexpand;
            widget.ExpandVertical   = vexpand;

            if (margin != -1)
            {
                widget.Margin = margin;
            }
            if (marginLeft != -1)
            {
                widget.MarginLeft = marginLeft;
            }
            if (marginTop != -1)
            {
                widget.MarginTop = marginTop;
            }
            if (marginTop != -1)
            {
                widget.MarginRight = marginRight;
            }
            if (marginBottom != -1)
            {
                widget.MarginBottom = marginBottom;
            }

            var p = new TablePlacement((WidgetBackendHost)BackendHost, widget)
            {
                Left   = left,
                Right  = left + colspan,
                Top    = top,
                Bottom = top + rowspan
            };

            placements.Add(p);
        }
Пример #8
0
        TablePlacement[] VisibleChildren()
        {
            TablePlacement[] result = new TablePlacement[children.Count];

            int j = 0;

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

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

            return(result);
        }
Пример #9
0
        public void Attach(Widget widget, int left, int right, int top, int bottom, AttachOptions?xOptions = null, AttachOptions?yOptions = null)
        {
            if (xOptions != null)
            {
                widget.ExpandHorizontal = (xOptions.Value & AttachOptions.Expand) != 0;
                if ((xOptions.Value & AttachOptions.Fill) != 0)
                {
                    widget.HorizontalPlacement = WidgetPlacement.Fill;
                }
                else
                {
                    widget.HorizontalPlacement = WidgetPlacement.Center;
                }
            }
            if (yOptions != null)
            {
                widget.ExpandVertical = (yOptions.Value & AttachOptions.Expand) != 0;
                if ((yOptions.Value & AttachOptions.Fill) != 0)
                {
                    widget.VerticalPlacement = WidgetPlacement.Fill;
                }
                else
                {
                    widget.VerticalPlacement = WidgetPlacement.Center;
                }
            }

            var p = new TablePlacement((WidgetBackendHost)BackendHost, widget)
            {
                Left   = left,
                Right  = right,
                Top    = top,
                Bottom = bottom
            };

            placements.Add(p);
        }
Пример #10
0
 void OnChildChanged(TablePlacement placement, object hint)
 {
     OnPreferredSizeChanged();
 }
Пример #11
0
 void OnAdd(Widget child, TablePlacement placement)
 {
     RegisterChild(child);
     Backend.Add((IWidgetBackend)GetBackend(child));
     OnPreferredSizeChanged();
 }
Пример #12
0
        void CalcDefaultSizes(SizeRequestMode mode, bool calcHeights, out TablePlacement[] visibleChildren, out Dictionary <int, WidgetSize> fixedSizesByCell, out HashSet <int> cellsWithExpand, out WidgetSize[] sizes, out double spacing)
        {
            bool useLengthConstraint = mode == SizeRequestMode.HeightForWidth && calcHeights || mode == SizeRequestMode.WidthForHeight && !calcHeights;

            visibleChildren = children.Where(b => b.Child.Visible).ToArray();
            int lastCell = 0;

            fixedSizesByCell = new Dictionary <int, WidgetSize> ();
            cellsWithExpand  = new HashSet <int> ();
            HashSet <int> cellsWithWidget = new HashSet <int> ();

            sizes = new WidgetSize [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, calcHeights);
                int end   = GetEndAttach(bp, calcHeights);

                if (end > lastCell)
                {
                    lastCell = end;
                }

                // Check if the cell is expandable and store the value
                AttachOptions ops = calcHeights ? bp.YOptions : bp.XOptions;
                for (int i = start; i < end; i++)
                {
                    cellsWithWidget.Add(i);
                    if ((ops & AttachOptions.Expand) != 0)
                    {
                        cellsWithExpand.Add(i);
                    }
                }

                WidgetSize s;
                if (useLengthConstraint)
                {
                    s = GetPreferredLengthForSize(mode, bp.Child, calcHeights ? bp.NextWidth : bp.NextHeight);
                }
                else
                {
                    s = GetPreferredSize(calcHeights, bp.Child);
                }
                sizes [n] = s;

                if (end == start + 1)
                {
                    // The widget only takes one cell. Store its size if it is the biggest
                    bool       changed = false;
                    WidgetSize fs;
                    fixedSizesByCell.TryGetValue(start, out fs);
                    if (s.MinSize > fs.MinSize)
                    {
                        fs.MinSize = s.MinSize;
                        changed    = true;
                    }
                    if (s.NaturalSize > fs.NaturalSize)
                    {
                        fs.NaturalSize = s.NaturalSize;
                        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, WidgetSize[]> growSizes = new Dictionary <TablePlacement, WidgetSize[]> ();

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

                WidgetSize fixedSize = new WidgetSize(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++)
                {
                    WidgetSize fs;
                    fixedSizesByCell.TryGetValue(c, out fs);
                    fixedSize += fs;
                    if (c != start && c != end)
                    {
                        spanSpacing += GetSpacing(c, calcHeights);
                    }
                }

                // 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

                WidgetSize sizeToGrow = sizes [n] - fixedSize - new WidgetSize(spanSpacing);

                WidgetSize sizeToGrowPart = new WidgetSize(sizeToGrow.MinSize / (end - start), sizeToGrow.NaturalSize / (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.

                WidgetSize[] widgetGrowSizes = new WidgetSize [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)
            {
                // Get a list of all widgets that cover this cell
                var            colCells    = widgetsToAdjust.Where(bp => GetStartAttach(bp, calcHeights) <= n && GetEndAttach(bp, calcHeights) > n).ToArray();
                WidgetSize     maxv        = new WidgetSize(0);
                TablePlacement maxtMin     = null;
                TablePlacement maxtNatural = null;

                // Find the widget that requires the maximum size for this cell
                foreach (var bp in colCells)
                {
                    WidgetSize cv = growSizes[bp][n - GetStartAttach(bp, calcHeights)];
                    if (cv.MinSize > maxv.MinSize)
                    {
                        maxv.MinSize = cv.MinSize;
                        maxtMin      = bp;
                    }
                    if (cv.NaturalSize > maxv.NaturalSize)
                    {
                        maxv.NaturalSize = cv.NaturalSize;
                        maxtNatural      = bp;
                    }
                }

                // Adjust the required size of all widgets of the cell (excluding the widget with the max size)
                foreach (var bp in colCells)
                {
                    WidgetSize[] widgetGrows = growSizes[bp];
                    int          cellIndex   = n - GetStartAttach(bp, calcHeights);
                    if (bp != maxtMin)
                    {
                        double cv = widgetGrows[cellIndex].MinSize;
                        // splitExtraSpace is the additional space that the widget can take from this cell (because there is a widget
                        // that is requiring more space), split among all other cells of the widget
                        double splitExtraSpace = (maxv.MinSize - cv) / (widgetGrows.Length - 1);
                        for (int i = 0; i < widgetGrows.Length; i++)
                        {
                            widgetGrows[i].MinSize -= splitExtraSpace;
                        }
                    }
                    if (bp != maxtNatural)
                    {
                        double cv = widgetGrows[cellIndex].NaturalSize;
                        double splitExtraSpace = (maxv.NaturalSize - cv) / (widgetGrows.Length - 1);
                        for (int i = 0; i < widgetGrows.Length; i++)
                        {
                            widgetGrows[i].NaturalSize -= splitExtraSpace;
                        }
                    }
                }
            }

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

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

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

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

            foreach (var it in finalGrowTable)
            {
                WidgetSize 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, calcHeights);
                }
            }
        }
Пример #13
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.Child.ExpandsForOrientation(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
            });
        }