layout method

  1. @override
void layout(
  1. Context context,
  2. BoxConstraints constraints,
  3. {bool parentUsesSize = false}
)
override

First widget pass to calculate the children layout and bounding box

Implementation

@override
void layout(Context context, BoxConstraints constraints,
    {bool parentUsesSize = false}) {
  // Compute required width for all row/columns width flex
  final flex = <double?>[];
  _widths.clear();
  _heights.clear();
  var index = 0;

  for (final row in children) {
    var n = 0;
    for (final child in row.children) {
      final columnWidth = columnWidths != null && columnWidths![n] != null
          ? columnWidths![n]!
          : defaultColumnWidth;
      final columnLayout = columnWidth.layout(child, context, constraints);
      if (flex.length < n + 1) {
        flex.add(columnLayout.flex);
        _widths.add(columnLayout.width);
      } else {
        if (columnLayout.flex! > 0) {
          flex[n] = math.max(flex[n]!, columnLayout.flex!);
        }
        _widths[n] = math.max(_widths[n]!, columnLayout.width!);
      }
      n++;
    }
  }

  if (_widths.isEmpty) {
    box = PdfRect.fromPoints(PdfPoint.zero, constraints.smallest);
    return;
  }

  final maxWidth = _widths.reduce((double? a, double? b) => a! + b!);

  // Compute column widths using flex and estimated width
  if (constraints.hasBoundedWidth) {
    final totalFlex = flex.reduce((double? a, double? b) => a! + b!)!;
    var flexSpace = 0.0;
    for (var n = 0; n < _widths.length; n++) {
      if (flex[n] == 0.0) {
        final newWidth = _widths[n]! / maxWidth! * constraints.maxWidth;
        if ((tableWidth == TableWidth.max && totalFlex == 0.0) ||
            newWidth < _widths[n]!) {
          _widths[n] = newWidth;
        }
        flexSpace += _widths[n]!;
      }
    }
    final spacePerFlex = totalFlex > 0.0
        ? ((constraints.maxWidth - flexSpace) / totalFlex)
        : double.nan;

    for (var n = 0; n < _widths.length; n++) {
      if (flex[n]! > 0.0) {
        final newWidth = spacePerFlex * flex[n]!;
        _widths[n] = newWidth;
      }
    }
  }

  final totalWidth = _widths.reduce((double? a, double? b) => a! + b!)!;

  // Compute final widths
  var totalHeight = 0.0;
  index = 0;
  for (final row in children) {
    if (index++ < _context.firstLine && !row.repeat) {
      continue;
    }

    var n = 0;
    var x = 0.0;

    var lineHeight = 0.0;
    for (final child in row.children) {
      final childConstraints = BoxConstraints.tightFor(width: _widths[n]);
      child.layout(context, childConstraints);
      assert(child.box != null);
      child.box =
          PdfRect(x, totalHeight, child.box!.width, child.box!.height);
      x += _widths[n]!;
      lineHeight = math.max(lineHeight, child.box!.height);
      n++;
    }

    final align = row.verticalAlignment ?? defaultVerticalAlignment;

    if (align == TableCellVerticalAlignment.full) {
      // Compute the layout again to give the full height to all cells
      n = 0;
      x = 0;
      for (final child in row.children) {
        final childConstraints =
            BoxConstraints.tightFor(width: _widths[n], height: lineHeight);
        child.layout(context, childConstraints);
        assert(child.box != null);
        child.box =
            PdfRect(x, totalHeight, child.box!.width, child.box!.height);
        x += _widths[n]!;
        n++;
      }
    }

    if (totalHeight + lineHeight > constraints.maxHeight) {
      index--;
      break;
    }
    totalHeight += lineHeight;
    _heights.add(lineHeight);
  }
  _context.lastLine = index;

  // Compute final y position
  index = 0;
  var heightIndex = 0;
  for (final row in children) {
    if (index++ < _context.firstLine && !row.repeat) {
      continue;
    }

    final align = row.verticalAlignment ?? defaultVerticalAlignment;

    for (final child in row.children) {
      double? childY;

      switch (align) {
        case TableCellVerticalAlignment.bottom:
          childY = totalHeight - child.box!.y - _getHeight(heightIndex);
          break;
        case TableCellVerticalAlignment.middle:
          childY = totalHeight -
              child.box!.y -
              (_getHeight(heightIndex) + child.box!.height) / 2;
          break;
        case TableCellVerticalAlignment.top:
        case TableCellVerticalAlignment.full:
          childY = totalHeight - child.box!.y - child.box!.height;
          break;
      }

      child.box = PdfRect(
        child.box!.x,
        childY,
        child.box!.width,
        child.box!.height,
      );
    }

    if (index >= _context.lastLine) {
      break;
    }
    heightIndex++;
  }

  box = PdfRect(0, 0, totalWidth, totalHeight);
}