From 27e9a16e83fbaf28dc47ff92b076c5739574fa5d Mon Sep 17 00:00:00 2001 From: MathanM Date: Sun, 11 Aug 2024 16:54:01 +0530 Subject: [PATCH 1/2] Fix Mid-word line break inside table --- pdf/lib/src/pdf/rect.dart | 20 ++++++++++------- pdf/lib/src/widgets/basic.dart | 24 +++++++++++++------- pdf/lib/src/widgets/geometry.dart | 10 ++++++--- pdf/lib/src/widgets/table.dart | 37 +++++++++++++++++++++++++++++-- pdf/lib/src/widgets/text.dart | 5 ++++- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/pdf/lib/src/pdf/rect.dart b/pdf/lib/src/pdf/rect.dart index 91f4e71e..962e1741 100644 --- a/pdf/lib/src/pdf/rect.dart +++ b/pdf/lib/src/pdf/rect.dart @@ -20,18 +20,20 @@ import 'point.dart'; @immutable class PdfRect { - const PdfRect(this.x, this.y, this.width, this.height); + const PdfRect(this.x, this.y, this.width, this.height, [this.minWidth]); - factory PdfRect.fromLTRB( - double left, double top, double right, double bottom) { - return PdfRect(left, top, right - left, bottom - top); + factory PdfRect.fromLTRB(double left, double top, double right, double bottom, + [double? minWidth]) { + return PdfRect(left, top, right - left, bottom - top, minWidth); } - factory PdfRect.fromPoints(PdfPoint offset, PdfPoint size) { - return PdfRect(offset.x, offset.y, size.x, size.y); + factory PdfRect.fromPoints(PdfPoint offset, PdfPoint size, + [double? minWidth]) { + return PdfRect(offset.x, offset.y, size.x, size.y, minWidth); } final double x, y, width, height; + final double? minWidth; static const PdfRect zero = PdfRect(0, 0, 0, 0); @@ -70,9 +72,9 @@ class PdfRect { PdfPoint get bottomRight => PdfPoint(right, top); /// Returns a new rectangle with edges moved outwards by the given delta. - PdfRect inflate(double delta) { + PdfRect inflate(double delta, [double? minWidth]) { return PdfRect.fromLTRB( - left - delta, top - delta, right + delta, bottom + delta); + left - delta, top - delta, right + delta, bottom + delta, minWidth); } /// Returns a new rectangle with edges moved inwards by the given delta. @@ -83,12 +85,14 @@ class PdfRect { double? y, double? width, double? height, + double? minWidth, }) { return PdfRect( x ?? this.x, y ?? this.y, width ?? this.width, height ?? this.height, + minWidth ?? this.minWidth, ); } } diff --git a/pdf/lib/src/widgets/basic.dart b/pdf/lib/src/widgets/basic.dart index 02f439e9..2d18ae38 100644 --- a/pdf/lib/src/widgets/basic.dart +++ b/pdf/lib/src/widgets/basic.dart @@ -87,8 +87,12 @@ class Padding extends SingleChildWidget { child!.layout(context, childConstraints, parentUsesSize: parentUsesSize); assert(child!.box != null); box = constraints.constrainRect( - width: child!.box!.width + resolvedPadding.horizontal, - height: child!.box!.height + resolvedPadding.vertical); + width: child!.box!.width + resolvedPadding.horizontal, + height: child!.box!.height + resolvedPadding.vertical, + minWidth: child!.box!.minWidth != null + ? child!.box!.minWidth! + resolvedPadding.horizontal + : null, + ); } else { box = constraints.constrainRect( width: resolvedPadding.horizontal, height: resolvedPadding.vertical); @@ -323,12 +327,16 @@ class Align extends SingleChildWidget { assert(child!.box != null); box = constraints.constrainRect( - width: shrinkWrapWidth - ? child!.box!.width * (widthFactor ?? 1.0) - : double.infinity, - height: shrinkWrapHeight - ? child!.box!.height * (heightFactor ?? 1.0) - : double.infinity); + width: shrinkWrapWidth + ? child!.box!.width * (widthFactor ?? 1.0) + : double.infinity, + height: shrinkWrapHeight + ? child!.box!.height * (heightFactor ?? 1.0) + : double.infinity, + minWidth: child!.box!.minWidth != null && shrinkWrapWidth + ? child!.box!.minWidth! * (widthFactor ?? 1.0) + : null, + ); final resolvedAlignment = alignment.resolve(Directionality.of(context)); child!.box = resolvedAlignment.inscribe(child!.box!.size, box!); } else { diff --git a/pdf/lib/src/widgets/geometry.dart b/pdf/lib/src/widgets/geometry.dart index a1f25718..0c4c8572 100644 --- a/pdf/lib/src/widgets/geometry.dart +++ b/pdf/lib/src/widgets/geometry.dart @@ -104,10 +104,13 @@ class BoxConstraints { return result; } - PdfRect constrainRect( - {double width = double.infinity, double height = double.infinity}) { + PdfRect constrainRect({ + double width = double.infinity, + double height = double.infinity, + double? minWidth, + }) { final result = PdfPoint(constrainWidth(width), constrainHeight(height)); - return PdfRect.fromPoints(PdfPoint.zero, result); + return PdfRect.fromPoints(PdfPoint.zero, result, minWidth); } double constrainWidth([double width = double.infinity]) { @@ -672,6 +675,7 @@ class Alignment extends AlignmentGeometry { rect.y + halfHeightDelta + y * halfHeightDelta, size.x, size.y, + rect.minWidth, ); } diff --git a/pdf/lib/src/widgets/table.dart b/pdf/lib/src/widgets/table.dart index 38df5d9f..dfb9dbfa 100644 --- a/pdf/lib/src/widgets/table.dart +++ b/pdf/lib/src/widgets/table.dart @@ -147,10 +147,11 @@ class TableContext extends WidgetContext { } class ColumnLayout { - ColumnLayout(this.width, this.flex); + ColumnLayout(this.width, this.flex, [this.minWidth]); final double? width; final double? flex; + final double? minWidth; } abstract class TableColumnWidth { @@ -180,7 +181,7 @@ class IntrinsicColumnWidth extends TableColumnWidth { (child is Expanded ? child.flex.toDouble() : (child.box!.width == double.infinity ? 1 : 0)); - return ColumnLayout(calculatedWidth, childFlex); + return ColumnLayout(calculatedWidth, childFlex, child.box!.minWidth); } } @@ -317,6 +318,7 @@ class Table extends Widget with SpanningWidget { final List _widths = []; final List _heights = []; + final List _minWidths = []; final TableContext _context = TableContext(); @@ -341,6 +343,7 @@ class Table extends Widget with SpanningWidget { final flex = []; _widths.clear(); _heights.clear(); + _minWidths.clear(); var index = 0; for (final row in children) { @@ -353,11 +356,13 @@ class Table extends Widget with SpanningWidget { if (flex.length < n + 1) { flex.add(columnLayout.flex); _widths.add(columnLayout.width); + _minWidths.add(columnLayout.minWidth ?? 0); } else { if (columnLayout.flex! > 0) { flex[n] = math.max(flex[n]!, columnLayout.flex!); } _widths[n] = math.max(_widths[n]!, columnLayout.width!); + _minWidths[n] = math.max(_minWidths[n]!, columnLayout.minWidth ?? 0); } n++; } @@ -380,10 +385,38 @@ class Table extends Widget with SpanningWidget { if ((tableWidth == TableWidth.max && totalFlex == 0.0) || newWidth < _widths[n]!) { _widths[n] = newWidth; + _widths[n] = math.max(newWidth, _minWidths[n]!); } flexSpace += _widths[n]!; } } + + if (tableWidth == TableWidth.max && totalFlex == 0.0) { + final totalWidth = flexSpace; + final remainingSpace = constraints.maxWidth - totalWidth; + flexSpace = 0.0; + + if (remainingSpace != 0) { + // Calculate the total adjustable width + final adjustableWidth = _widths + .asMap() + .entries + .where((entry) => entry.value! > _minWidths[entry.key]!) + .map((entry) => entry.value! - _minWidths[entry.key]!) + .reduce((a, b) => a + b); + + for (var i = 0; i < _widths.length; i++) { + if (_widths[i]! > _minWidths[i]!) { + final proportion = + (_widths[i]! - _minWidths[i]!) / adjustableWidth; + final adjustment = remainingSpace * proportion; + _widths[i] = math.max(_minWidths[i]!, _widths[i]! + adjustment); + } + flexSpace += _widths[i]!; + } + } + } + final spacePerFlex = totalFlex > 0.0 ? ((constraints.maxWidth - flexSpace) / totalFlex) : double.nan; diff --git a/pdf/lib/src/widgets/text.dart b/pdf/lib/src/widgets/text.dart index 96d49d0f..925d850f 100644 --- a/pdf/lib/src/widgets/text.dart +++ b/pdf/lib/src/widgets/text.dart @@ -907,6 +907,7 @@ class RichText extends Widget with SpanningWidget { var top = 0.0; var bottom = 0.0; + var minWidth = 0.0; final lines = <_Line>[]; var spanCount = 0; @@ -953,6 +954,8 @@ class RichText extends Widget with SpanningWidget { (style.fontSize! * textScaleFactor)) * (style.fontSize! * textScaleFactor); + minWidth = math.max(minWidth, metrics.width); + if (_softWrap && offsetX + metrics.width > constraintWidth + 0.00001) { if (hyphenation != null) { @@ -1200,7 +1203,7 @@ class RichText extends Widget with SpanningWidget { } box = PdfRect(0, 0, constraints.constrainWidth(width), - constraints.constrainHeight(offsetY)); + constraints.constrainHeight(offsetY), minWidth); _context ..endOffset = offsetY - _context.startOffset From f4e42fa8d102a3037cde8c3ce196d0bde57971ea Mon Sep 17 00:00:00 2001 From: MathanM Date: Sat, 28 Sep 2024 08:23:12 +0530 Subject: [PATCH 2/2] Refactor flex column width to accomodate minWidth --- pdf/lib/src/widgets/table.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdf/lib/src/widgets/table.dart b/pdf/lib/src/widgets/table.dart index dfb9dbfa..f702bfe7 100644 --- a/pdf/lib/src/widgets/table.dart +++ b/pdf/lib/src/widgets/table.dart @@ -205,7 +205,9 @@ class FlexColumnWidth extends TableColumnWidth { @override ColumnLayout layout( Widget child, Context context, BoxConstraints? constraints) { - return ColumnLayout(0, flex); + child.layout(context, const BoxConstraints()); + assert(child.box != null); + return ColumnLayout(0, flex, child.box!.minWidth); } } @@ -424,7 +426,7 @@ class Table extends Widget with SpanningWidget { for (var n = 0; n < _widths.length; n++) { if (flex[n]! > 0.0) { final newWidth = spacePerFlex * flex[n]!; - _widths[n] = newWidth; + _widths[n] = math.max(newWidth, _minWidths[n]!); } } }