Skip to content

Commit

Permalink
feat: Column spans
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustl22 committed Sep 8, 2024
1 parent 6be38a9 commit a893e72
Showing 1 changed file with 63 additions and 19 deletions.
82 changes: 63 additions & 19 deletions pdf/lib/src/widgets/table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TableRow {
this.repeat = false,
this.verticalAlignment,
this.decoration,
this.columnSpans,
});

/// The widgets that comprise the cells in this row.
Expand All @@ -41,6 +42,8 @@ class TableRow {
final BoxDecoration? decoration;

final TableCellVerticalAlignment? verticalAlignment;

final Map<int, int>? columnSpans;
}

enum TableCellVerticalAlignment { bottom, middle, top, full }
Expand Down Expand Up @@ -334,69 +337,103 @@ class Table extends Widget with SpanningWidget {
_context.firstLine = _context.lastLine;
}

List<Widget> _getFilledChildrenFromColumnSpans(TableRow row) {
if (row.columnSpans == null) {
return row.children;
}
final filledChildren = <Widget>[];
var n = 0;
// TODO(Gustl22): Handle intrinsic column widths
for (final child in row.children) {
// Columns, which are currently spanned.
final columnSpan = row.columnSpans![n] ?? 1;
filledChildren.add(child);
if (columnSpan > 1) {
filledChildren
.addAll(Iterable.generate(columnSpan - 1, (index) => Container()));
}
n += columnSpan;
}
return filledChildren;
}

List<double> _getSpannedWidths(List<double?> widths, TableRow row) {
final spannedWidths = <double>[];
var n = 0;
for (var i = 0; i < row.children.length; i++) {
final columnSpan = row.columnSpans?[n] ?? 1;
final indices = Iterable.generate(columnSpan, (span) => n + span);
final width =
indices.fold(0.0, (prev, curIndex) => prev + (widths[curIndex] ?? 0));
spannedWidths.add(width);
n += columnSpan;
}
return spannedWidths;
}

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

for (final row in children) {
var n = 0;
for (final child in row.children) {
for (final child in _getFilledChildrenFromColumnSpans(row)) {
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);
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!);
widths[n] = math.max(widths[n]!, columnLayout.width!);
}
n++;
}
}

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

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

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

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

// Compute final widths
var totalHeight = 0.0;
Expand All @@ -406,17 +443,21 @@ class Table extends Widget with SpanningWidget {
continue;
}

final spannedWidths = _getSpannedWidths(widths, row);

var n = 0;
var x = 0.0;

var lineHeight = 0.0;

for (final child in row.children) {
final childConstraints = BoxConstraints.tightFor(width: _widths[n]);
final childConstraints =
BoxConstraints.tightFor(width: spannedWidths[n]);
child.layout(context, childConstraints);
assert(child.box != null);
child.box =
PdfRect(x, totalHeight, child.box!.width, child.box!.height);
x += _widths[n]!;
x += spannedWidths[n];
lineHeight = math.max(lineHeight, child.box!.height);
n++;
}
Expand All @@ -428,13 +469,13 @@ class Table extends Widget with SpanningWidget {
n = 0;
x = 0;
for (final child in row.children) {
final childConstraints =
BoxConstraints.tightFor(width: _widths[n], height: lineHeight);
final childConstraints = BoxConstraints.tightFor(
width: spannedWidths[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]!;
x += spannedWidths[n];
n++;
}
}
Expand Down Expand Up @@ -491,6 +532,9 @@ class Table extends Widget with SpanningWidget {
}

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

_widths.clear();
_widths.addAll(widths);
}

@override
Expand Down

0 comments on commit a893e72

Please sign in to comment.