void Grid::Arrange(const Rect finalRect) { Cell* cell; Control* el; for (Grid::CellData& d : els) { cell = GetCell(d.row, d.col); el = d.el; Point pos(GetCellPos(d.row, d.col)); int elDx = el->DesiredSize().Width; int containerDx = 0; for (int i = d.col; i < d.col + d.colSpan; i++) { containerDx += maxColWidth[i]; } int xOff = d.horizAlign.CalcOffset(elDx, containerDx); pos.X += xOff; int elDy = el->DesiredSize().Height; int containerDy = maxRowHeight[d.row]; int yOff = d.vertAlign.CalcOffset(elDy, containerDy); pos.Y += yOff; Rect r(pos, cell->desiredSize); el->Arrange(r); } SetPosition(finalRect); }
Size Grid::Measure(const Size availableSize) { RebuildCellDataIfNeeded(); Size borderSize(GetBorderAndPaddingSize(cachedStyle)); Cell* cell; Control* el; for (Grid::CellData& d : els) { cell = GetCell(d.row, d.col); cell->desiredSize.Width = 0; cell->desiredSize.Height = 0; el = d.el; if (!el->IsVisible()) continue; // calculate max dx of each column (dx of widest cell in the row) // and max dy of each row (dy of tallest cell in the column) el->Measure(availableSize); // TODO: take cell's border and padding into account cell->desiredSize = el->DesiredSize(); // if a cell spans multiple columns, we don't count its size here if (d.colSpan == 1) { if (cell->desiredSize.Width > maxColWidth[d.col]) maxColWidth[d.col] = cell->desiredSize.Width; } if (cell->desiredSize.Height > maxRowHeight[d.row]) maxRowHeight[d.row] = cell->desiredSize.Height; } // account for cells with colSpan > 1. If cell.dx > total dx // of columns it spans, we widen the columns by equally // re-distributing the difference among columns for (Grid::CellData& d : els) { if (d.colSpan == 1) continue; cell = GetCell(d.row, d.col); int totalDx = 0; for (int i = d.col; i < d.col + d.colSpan; i++) { totalDx += maxColWidth[i]; } int diff = cell->desiredSize.Width - totalDx; if (diff > 0) { int diffPerCol = diff / d.colSpan; int rest = diff % d.colSpan; // note: we could try to redistribute rest for ideal sizing instead of // over-sizing but not sure if that would matter in practice if (rest > 0) diffPerCol += 1; CrashIf(diffPerCol * d.colSpan < diff); for (int i = d.col; i < d.col + d.colSpan; i++) { maxColWidth[i] += diffPerCol; } } } int desiredWidth = 0; int desiredHeight = 0; for (int row = 0; row < rows; row++) { desiredHeight += maxRowHeight[row]; } for (int col = 0; col < cols; col++) { desiredWidth += maxColWidth[col]; } // TODO: what to do if desired size is more than availableSize? desiredSize.Width = desiredWidth + borderSize.Width; desiredSize.Height = desiredHeight + borderSize.Height; return desiredSize; }