List <CellPos> GetCells(CGSize cellSize) { int nexpands = 0; double requiredSize = 0; double availableSize = cellSize.Width; var cellFrames = new List <CellPos> (cells.Count); // Get the natural size of each child foreach (var cell in cells) { if (!cell.Backend.Frontend.Visible) { continue; } var cellPos = new CellPos { Cell = (NSView)cell, Frame = CGRect.Empty }; cellFrames.Add(cellPos); var size = cellPos.Cell.FittingSize; cellPos.Frame.Width = size.Width; requiredSize += size.Width; if (cell.Backend.Frontend.Expands) { nexpands++; } } double remaining = availableSize - requiredSize; if (remaining > 0) { var expandRemaining = new SizeSplitter(remaining, nexpands); foreach (var cellFrame in cellFrames) { if (((ICellRenderer)cellFrame.Cell).Backend.Frontend.Expands) { cellFrame.Frame.Width += (nfloat)expandRemaining.NextSizePart(); } } } double x = 0; foreach (var cellFrame in cellFrames) { var width = cellFrame.Frame.Width; var canvas = cellFrame.Cell as ICanvasCellRenderer; var height = (canvas != null) ? canvas.GetRequiredSize(SizeConstraint.WithSize(width)).Height : cellFrame.Cell.FittingSize.Height; // y-align only if the cell has a valid height, otherwise we're just recalculating the required size var y = cellSize.Height > 0 ? (cellSize.Height - height) / 2 : 0; cellFrame.Frame = new CGRect(x, y, width, height); x += width; } return(cellFrames); }
IEnumerable <CellPos> GetCells(CGRect cellFrame) { int nexpands = 0; double requiredSize = 0; double availableSize = cellFrame.Width; var visibleCells = VisibleCells.ToArray(); var sizes = new double [visibleCells.Length]; // Get the natural size of each child for (int i = 0; i < visibleCells.Length; i++) { var v = visibleCells[i] as NSView; var s = v.FittingSize; if (s.IsEmpty && SizeToFit(v)) { s = v.Frame.Size; } sizes [i] = s.Width; requiredSize += s.Width; if (visibleCells [i].Backend.Frontend.Expands) { nexpands++; } } double remaining = availableSize - requiredSize; if (remaining > 0) { var expandRemaining = new SizeSplitter(remaining, nexpands); for (int i = 0; i < visibleCells.Length; i++) { if (visibleCells [i].Backend.Frontend.Expands) { sizes [i] += (nfloat)expandRemaining.NextSizePart(); } } } double x = cellFrame.X; for (int i = 0; i < visibleCells.Length; i++) { var cell = (NSView)visibleCells [i]; var height = cell.FittingSize.Height; var y = (cellFrame.Height - height) / 2; yield return(new CellPos { Cell = cell, Frame = new CGRect(x, y, sizes [i], height) }); x += sizes [i]; } }
/// <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.GetAlignmentForOrientation (orientation); if (!double.IsNaN (al)) { double s = sizes[n]; if (s < allocatedSize) { cellOffset = (allocatedSize - s) * al; 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; } } }
IEnumerable <CellPos> GetCells(CGRect cellFrame) { if (direction == Orientation.Horizontal) { int nexpands = 0; double requiredSize = 0; double availableSize = cellFrame.Width; var sizes = new Dictionary <ICellRenderer, double> (); // Get the natural size of each child foreach (var bp in VisibleCells) { var s = ((NSCell)bp).CellSize; sizes [bp] = s.Width; requiredSize += s.Width; if (bp.Backend.Frontend.Expands) { nexpands++; } } double remaining = availableSize - requiredSize; if (remaining > 0) { var expandRemaining = new SizeSplitter(remaining, nexpands); foreach (var bp in VisibleCells) { if (bp.Backend.Frontend.Expands) { sizes [bp] += (nfloat)expandRemaining.NextSizePart(); } } } double x = cellFrame.X; foreach (var s in sizes) { yield return(new CellPos() { Cell = (NSCell)s.Key, Frame = new CGRect(x, cellFrame.Y, s.Value, cellFrame.Height) }); x += s.Value; } } else { nfloat y = cellFrame.Y; foreach (NSCell c in VisibleCells) { var s = c.CellSize; var f = new CGRect(cellFrame.X, y, s.Width, cellFrame.Height); y += s.Height; yield return(new CellPos() { Cell = c, Frame = f }); } } }