Showing
9 changed files
with
218 additions
and
173 deletions
@@ -59,12 +59,14 @@ class Calendar extends StatelessWidget { | @@ -59,12 +59,14 @@ class Calendar extends StatelessWidget { | ||
59 | ) { | 59 | ) { |
60 | return Container( | 60 | return Container( |
61 | color: PdfColors.blue200, | 61 | color: PdfColors.blue200, |
62 | - padding: const EdgeInsets.all(8.0), | 62 | + padding: const EdgeInsets.only(top: 8, left: 8, bottom: 8), |
63 | child: Text( | 63 | child: Text( |
64 | DateFormat.EEEE().format(date), | 64 | DateFormat.EEEE().format(date), |
65 | style: const TextStyle( | 65 | style: const TextStyle( |
66 | fontSize: 15, | 66 | fontSize: 15, |
67 | ), | 67 | ), |
68 | + maxLines: 1, | ||
69 | + overflow: TextOverflow.clip, | ||
68 | ), | 70 | ), |
69 | ); | 71 | ); |
70 | } | 72 | } |
@@ -101,6 +101,7 @@ Future<Uint8List> generateCertificate( | @@ -101,6 +101,7 @@ Future<Uint8List> generateCertificate( | ||
101 | ), | 101 | ), |
102 | pw.Text( | 102 | pw.Text( |
103 | data.name, | 103 | data.name, |
104 | + textAlign: pw.TextAlign.center, | ||
104 | style: pw.TextStyle( | 105 | style: pw.TextStyle( |
105 | fontWeight: pw.FontWeight.bold, | 106 | fontWeight: pw.FontWeight.bold, |
106 | fontSize: 20, | 107 | fontSize: 20, |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | 16 | ||
17 | import 'dart:typed_data'; | 17 | import 'dart:typed_data'; |
18 | 18 | ||
19 | +import 'package:flutter/services.dart'; | ||
19 | import 'package:pdf/pdf.dart'; | 20 | import 'package:pdf/pdf.dart'; |
20 | import 'package:pdf/widgets.dart' as pw; | 21 | import 'package:pdf/widgets.dart' as pw; |
21 | 22 | ||
@@ -25,7 +26,14 @@ Future<Uint8List> generateDocument( | @@ -25,7 +26,14 @@ Future<Uint8List> generateDocument( | ||
25 | PdfPageFormat format, CustomData data) async { | 26 | PdfPageFormat format, CustomData data) async { |
26 | final doc = pw.Document(pageMode: PdfPageMode.outlines); | 27 | final doc = pw.Document(pageMode: PdfPageMode.outlines); |
27 | 28 | ||
29 | + final font1 = await rootBundle.load('assets/open-sans.ttf'); | ||
30 | + final font2 = await rootBundle.load('assets/open-sans-bold.ttf'); | ||
31 | + | ||
28 | doc.addPage(pw.MultiPage( | 32 | doc.addPage(pw.MultiPage( |
33 | + theme: pw.ThemeData.withFont( | ||
34 | + base: pw.Font.ttf(font1), | ||
35 | + bold: pw.Font.ttf(font2), | ||
36 | + ), | ||
29 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), | 37 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), |
30 | orientation: pw.PageOrientation.portrait, | 38 | orientation: pw.PageOrientation.portrait, |
31 | crossAxisAlignment: pw.CrossAxisAlignment.start, | 39 | crossAxisAlignment: pw.CrossAxisAlignment.start, |
@@ -222,6 +222,7 @@ class Invoice { | @@ -222,6 +222,7 @@ class Invoice { | ||
222 | child: pw.BarcodeWidget( | 222 | child: pw.BarcodeWidget( |
223 | barcode: pw.Barcode.pdf417(), | 223 | barcode: pw.Barcode.pdf417(), |
224 | data: 'Invoice# $invoiceNumber', | 224 | data: 'Invoice# $invoiceNumber', |
225 | + drawText: false, | ||
225 | ), | 226 | ), |
226 | ), | 227 | ), |
227 | pw.Text( | 228 | pw.Text( |
@@ -55,136 +55,138 @@ Future<Uint8List> generateReport( | @@ -55,136 +55,138 @@ Future<Uint8List> generateReport( | ||
55 | bold: pw.Font.ttf(await rootBundle.load('assets/open-sans-bold.ttf')), | 55 | bold: pw.Font.ttf(await rootBundle.load('assets/open-sans-bold.ttf')), |
56 | ); | 56 | ); |
57 | 57 | ||
58 | + // Top bar chart | ||
59 | + final chart1 = pw.Chart( | ||
60 | + left: pw.Container( | ||
61 | + alignment: pw.Alignment.topCenter, | ||
62 | + margin: const pw.EdgeInsets.only(right: 5, top: 10), | ||
63 | + child: pw.Transform.rotateBox( | ||
64 | + angle: pi / 2, | ||
65 | + child: pw.Text('Amount'), | ||
66 | + ), | ||
67 | + ), | ||
68 | + overlay: pw.ChartLegend( | ||
69 | + position: const pw.Alignment(-.7, 1), | ||
70 | + decoration: pw.BoxDecoration( | ||
71 | + color: PdfColors.white, | ||
72 | + border: pw.Border.all( | ||
73 | + color: PdfColors.black, | ||
74 | + width: .5, | ||
75 | + ), | ||
76 | + ), | ||
77 | + ), | ||
78 | + grid: pw.CartesianGrid( | ||
79 | + xAxis: pw.FixedAxis.fromStrings( | ||
80 | + List<String>.generate( | ||
81 | + dataTable.length, (index) => dataTable[index][0] as String), | ||
82 | + marginStart: 30, | ||
83 | + marginEnd: 30, | ||
84 | + ticks: true, | ||
85 | + ), | ||
86 | + yAxis: pw.FixedAxis( | ||
87 | + [0, 100, 200, 300, 400, 500, 600, 700], | ||
88 | + format: (v) => '\$$v', | ||
89 | + divisions: true, | ||
90 | + ), | ||
91 | + ), | ||
92 | + datasets: [ | ||
93 | + pw.BarDataSet( | ||
94 | + color: PdfColors.blue100, | ||
95 | + legend: tableHeaders[2], | ||
96 | + width: 15, | ||
97 | + offset: -10, | ||
98 | + borderColor: baseColor, | ||
99 | + data: List<pw.LineChartValue>.generate( | ||
100 | + dataTable.length, | ||
101 | + (i) { | ||
102 | + final v = dataTable[i][2] as num; | ||
103 | + return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
104 | + }, | ||
105 | + ), | ||
106 | + ), | ||
107 | + pw.BarDataSet( | ||
108 | + color: PdfColors.amber100, | ||
109 | + legend: tableHeaders[1], | ||
110 | + width: 15, | ||
111 | + offset: 10, | ||
112 | + borderColor: PdfColors.amber, | ||
113 | + data: List<pw.LineChartValue>.generate( | ||
114 | + dataTable.length, | ||
115 | + (i) { | ||
116 | + final v = dataTable[i][1] as num; | ||
117 | + return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
118 | + }, | ||
119 | + ), | ||
120 | + ), | ||
121 | + ], | ||
122 | + ); | ||
123 | + | ||
124 | + // Left curved line chart | ||
125 | + final chart2 = pw.Chart( | ||
126 | + right: pw.ChartLegend(), | ||
127 | + grid: pw.CartesianGrid( | ||
128 | + xAxis: pw.FixedAxis([0, 1, 2, 3, 4, 5, 6]), | ||
129 | + yAxis: pw.FixedAxis( | ||
130 | + [0, 200, 400, 600], | ||
131 | + divisions: true, | ||
132 | + ), | ||
133 | + ), | ||
134 | + datasets: [ | ||
135 | + pw.LineDataSet( | ||
136 | + legend: 'Expense', | ||
137 | + drawSurface: true, | ||
138 | + isCurved: true, | ||
139 | + drawPoints: false, | ||
140 | + color: baseColor, | ||
141 | + data: List<pw.LineChartValue>.generate( | ||
142 | + dataTable.length, | ||
143 | + (i) { | ||
144 | + final v = dataTable[i][2] as num; | ||
145 | + return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
146 | + }, | ||
147 | + ), | ||
148 | + ), | ||
149 | + ], | ||
150 | + ); | ||
151 | + | ||
152 | + // Data table | ||
153 | + final table = pw.Table.fromTextArray( | ||
154 | + border: null, | ||
155 | + headers: tableHeaders, | ||
156 | + data: List<List<dynamic>>.generate( | ||
157 | + dataTable.length, | ||
158 | + (index) => <dynamic>[ | ||
159 | + dataTable[index][0], | ||
160 | + dataTable[index][1], | ||
161 | + dataTable[index][2], | ||
162 | + (dataTable[index][1] as num) - (dataTable[index][2] as num), | ||
163 | + ], | ||
164 | + ), | ||
165 | + headerStyle: pw.TextStyle( | ||
166 | + color: PdfColors.white, | ||
167 | + fontWeight: pw.FontWeight.bold, | ||
168 | + ), | ||
169 | + headerDecoration: pw.BoxDecoration( | ||
170 | + color: baseColor, | ||
171 | + ), | ||
172 | + rowDecoration: pw.BoxDecoration( | ||
173 | + border: pw.Border( | ||
174 | + bottom: pw.BorderSide( | ||
175 | + color: baseColor, | ||
176 | + width: .5, | ||
177 | + ), | ||
178 | + ), | ||
179 | + ), | ||
180 | + cellAlignment: pw.Alignment.centerRight, | ||
181 | + cellAlignments: {0: pw.Alignment.centerLeft}, | ||
182 | + ); | ||
183 | + | ||
58 | // Add page to the PDF | 184 | // Add page to the PDF |
59 | document.addPage( | 185 | document.addPage( |
60 | pw.Page( | 186 | pw.Page( |
61 | pageFormat: pageFormat, | 187 | pageFormat: pageFormat, |
62 | theme: theme, | 188 | theme: theme, |
63 | build: (context) { | 189 | build: (context) { |
64 | - // Top bar chart | ||
65 | - final chart1 = pw.Chart( | ||
66 | - left: pw.Container( | ||
67 | - alignment: pw.Alignment.topCenter, | ||
68 | - margin: const pw.EdgeInsets.only(right: 5, top: 10), | ||
69 | - child: pw.Transform.rotateBox( | ||
70 | - angle: pi / 2, | ||
71 | - child: pw.Text('Amount'), | ||
72 | - ), | ||
73 | - ), | ||
74 | - overlay: pw.ChartLegend( | ||
75 | - position: const pw.Alignment(-.7, 1), | ||
76 | - decoration: pw.BoxDecoration( | ||
77 | - color: PdfColors.white, | ||
78 | - border: pw.Border.all( | ||
79 | - color: PdfColors.black, | ||
80 | - width: .5, | ||
81 | - ), | ||
82 | - ), | ||
83 | - ), | ||
84 | - grid: pw.CartesianGrid( | ||
85 | - xAxis: pw.FixedAxis.fromStrings( | ||
86 | - List<String>.generate( | ||
87 | - dataTable.length, (index) => dataTable[index][0] as String), | ||
88 | - marginStart: 30, | ||
89 | - marginEnd: 30, | ||
90 | - ticks: true, | ||
91 | - ), | ||
92 | - yAxis: pw.FixedAxis( | ||
93 | - [0, 100, 200, 300, 400, 500, 600, 700], | ||
94 | - format: (v) => '\$$v', | ||
95 | - divisions: true, | ||
96 | - ), | ||
97 | - ), | ||
98 | - datasets: [ | ||
99 | - pw.BarDataSet( | ||
100 | - color: PdfColors.blue100, | ||
101 | - legend: tableHeaders[2], | ||
102 | - width: 15, | ||
103 | - offset: -10, | ||
104 | - borderColor: baseColor, | ||
105 | - data: List<pw.LineChartValue>.generate( | ||
106 | - dataTable.length, | ||
107 | - (i) { | ||
108 | - final v = dataTable[i][2] as num; | ||
109 | - return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
110 | - }, | ||
111 | - ), | ||
112 | - ), | ||
113 | - pw.BarDataSet( | ||
114 | - color: PdfColors.amber100, | ||
115 | - legend: tableHeaders[1], | ||
116 | - width: 15, | ||
117 | - offset: 10, | ||
118 | - borderColor: PdfColors.amber, | ||
119 | - data: List<pw.LineChartValue>.generate( | ||
120 | - dataTable.length, | ||
121 | - (i) { | ||
122 | - final v = dataTable[i][1] as num; | ||
123 | - return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
124 | - }, | ||
125 | - ), | ||
126 | - ), | ||
127 | - ], | ||
128 | - ); | ||
129 | - | ||
130 | - // Left curved line chart | ||
131 | - final chart2 = pw.Chart( | ||
132 | - grid: pw.CartesianGrid( | ||
133 | - xAxis: pw.FixedAxis([0, 1, 2, 3, 4, 5, 6]), | ||
134 | - yAxis: pw.FixedAxis( | ||
135 | - [0, 200, 400, 600], | ||
136 | - divisions: true, | ||
137 | - ), | ||
138 | - ), | ||
139 | - datasets: [ | ||
140 | - pw.LineDataSet( | ||
141 | - drawSurface: true, | ||
142 | - isCurved: true, | ||
143 | - drawPoints: false, | ||
144 | - color: baseColor, | ||
145 | - data: List<pw.LineChartValue>.generate( | ||
146 | - dataTable.length, | ||
147 | - (i) { | ||
148 | - final v = dataTable[i][2] as num; | ||
149 | - return pw.LineChartValue(i.toDouble(), v.toDouble()); | ||
150 | - }, | ||
151 | - ), | ||
152 | - ), | ||
153 | - ], | ||
154 | - ); | ||
155 | - | ||
156 | - // Data table | ||
157 | - final table = pw.Table.fromTextArray( | ||
158 | - border: null, | ||
159 | - headers: tableHeaders, | ||
160 | - data: List<List<dynamic>>.generate( | ||
161 | - dataTable.length, | ||
162 | - (index) => <dynamic>[ | ||
163 | - dataTable[index][0], | ||
164 | - dataTable[index][1], | ||
165 | - dataTable[index][2], | ||
166 | - (dataTable[index][1] as num) - (dataTable[index][2] as num), | ||
167 | - ], | ||
168 | - ), | ||
169 | - headerStyle: pw.TextStyle( | ||
170 | - color: PdfColors.white, | ||
171 | - fontWeight: pw.FontWeight.bold, | ||
172 | - ), | ||
173 | - headerDecoration: pw.BoxDecoration( | ||
174 | - color: baseColor, | ||
175 | - ), | ||
176 | - rowDecoration: pw.BoxDecoration( | ||
177 | - border: pw.Border( | ||
178 | - bottom: pw.BorderSide( | ||
179 | - color: baseColor, | ||
180 | - width: .5, | ||
181 | - ), | ||
182 | - ), | ||
183 | - ), | ||
184 | - cellAlignment: pw.Alignment.centerRight, | ||
185 | - cellAlignments: {0: pw.Alignment.centerLeft}, | ||
186 | - ); | ||
187 | - | ||
188 | // Page layout | 190 | // Page layout |
189 | return pw.Column( | 191 | return pw.Column( |
190 | children: [ | 192 | children: [ |
@@ -196,17 +198,7 @@ Future<Uint8List> generateReport( | @@ -196,17 +198,7 @@ Future<Uint8List> generateReport( | ||
196 | pw.Divider(thickness: 4), | 198 | pw.Divider(thickness: 4), |
197 | pw.Expanded(flex: 3, child: chart1), | 199 | pw.Expanded(flex: 3, child: chart1), |
198 | pw.Divider(), | 200 | pw.Divider(), |
199 | - pw.Expanded( | ||
200 | - flex: 2, | ||
201 | - child: pw.Row( | ||
202 | - crossAxisAlignment: pw.CrossAxisAlignment.start, | ||
203 | - children: [ | ||
204 | - pw.Expanded(child: chart2), | ||
205 | - pw.SizedBox(width: 10), | ||
206 | - pw.Expanded(child: table), | ||
207 | - ], | ||
208 | - ), | ||
209 | - ), | 201 | + pw.Expanded(flex: 2, child: chart2), |
210 | pw.SizedBox(height: 10), | 202 | pw.SizedBox(height: 10), |
211 | pw.Row( | 203 | pw.Row( |
212 | crossAxisAlignment: pw.CrossAxisAlignment.start, | 204 | crossAxisAlignment: pw.CrossAxisAlignment.start, |
@@ -275,34 +267,38 @@ Future<Uint8List> generateReport( | @@ -275,34 +267,38 @@ Future<Uint8List> generateReport( | ||
275 | PdfColors.lime300, | 267 | PdfColors.lime300, |
276 | ]; | 268 | ]; |
277 | 269 | ||
278 | - return pw.SizedBox( | ||
279 | - height: 400, | ||
280 | - child: pw.Chart( | ||
281 | - title: pw.Text( | ||
282 | - 'Expense breakdown', | ||
283 | - style: pw.TextStyle( | ||
284 | - color: baseColor, | ||
285 | - fontSize: 20, | ||
286 | - ), | ||
287 | - ), | ||
288 | - grid: pw.PieGrid(), | ||
289 | - datasets: List<pw.Dataset>.generate(dataTable.length, (index) { | ||
290 | - final data = dataTable[index]; | ||
291 | - final color = chartColors[index % chartColors.length]; | ||
292 | - final textColor = | ||
293 | - color.luminance < 0.2 ? PdfColors.white : PdfColors.black; | 270 | + return pw.Column( |
271 | + children: [ | ||
272 | + pw.Flexible( | ||
273 | + child: pw.Chart( | ||
274 | + title: pw.Text( | ||
275 | + 'Expense breakdown', | ||
276 | + style: pw.TextStyle( | ||
277 | + color: baseColor, | ||
278 | + fontSize: 20, | ||
279 | + ), | ||
280 | + ), | ||
281 | + grid: pw.PieGrid(), | ||
282 | + datasets: List<pw.Dataset>.generate(dataTable.length, (index) { | ||
283 | + final data = dataTable[index]; | ||
284 | + final color = chartColors[index % chartColors.length]; | ||
285 | + final textColor = | ||
286 | + color.luminance < 0.2 ? PdfColors.white : PdfColors.black; | ||
294 | 287 | ||
295 | - final value = (data[2] as num).toDouble(); | ||
296 | - final pct = (value / expense * 100).round(); | 288 | + final value = (data[2] as num).toDouble(); |
289 | + final pct = (value / expense * 100).round(); | ||
297 | 290 | ||
298 | - return pw.PieDataSet( | ||
299 | - legend: '${data[0]}\n$pct%', | ||
300 | - value: value, | ||
301 | - color: color, | ||
302 | - legendStyle: pw.TextStyle(fontSize: 10, color: textColor), | ||
303 | - ); | ||
304 | - }), | ||
305 | - ), | 291 | + return pw.PieDataSet( |
292 | + legend: '${data[0]}\n$pct%', | ||
293 | + value: value, | ||
294 | + color: color, | ||
295 | + legendStyle: pw.TextStyle(fontSize: 10, color: textColor), | ||
296 | + ); | ||
297 | + }), | ||
298 | + ), | ||
299 | + ), | ||
300 | + table, | ||
301 | + ], | ||
306 | ); | 302 | ); |
307 | }, | 303 | }, |
308 | ), | 304 | ), |
@@ -141,6 +141,7 @@ Future<Uint8List> generateResume(PdfPageFormat format, CustomData data) async { | @@ -141,6 +141,7 @@ Future<Uint8List> generateResume(PdfPageFormat format, CustomData data) async { | ||
141 | width: 60, | 141 | width: 60, |
142 | height: 60, | 142 | height: 60, |
143 | barcode: pw.Barcode.qrCode(), | 143 | barcode: pw.Barcode.qrCode(), |
144 | + drawText: false, | ||
144 | ), | 145 | ), |
145 | ], | 146 | ], |
146 | ), | 147 | ), |
@@ -11,6 +11,7 @@ | @@ -11,6 +11,7 @@ | ||
11 | - Fix textScalingFactor with lineSpacing | 11 | - Fix textScalingFactor with lineSpacing |
12 | - Implement SpanningWidget on RichText | 12 | - Implement SpanningWidget on RichText |
13 | - Passthrough SpanningWidget on SingleChildWidget and StatelessWidget | 13 | - Passthrough SpanningWidget on SingleChildWidget and StatelessWidget |
14 | +- Improve TextOverflow support | ||
14 | 15 | ||
15 | ## 3.2.0 | 16 | ## 3.2.0 |
16 | 17 |
@@ -33,11 +33,14 @@ enum TextDirection { ltr, rtl } | @@ -33,11 +33,14 @@ enum TextDirection { ltr, rtl } | ||
33 | 33 | ||
34 | /// How overflowing text should be handled. | 34 | /// How overflowing text should be handled. |
35 | enum TextOverflow { | 35 | enum TextOverflow { |
36 | - /// Span to the next page when possible. | ||
37 | - span, | 36 | + /// Clip the overflowing text to fix its container. |
37 | + clip, | ||
38 | 38 | ||
39 | /// Render overflowing text outside of its container. | 39 | /// Render overflowing text outside of its container. |
40 | visible, | 40 | visible, |
41 | + | ||
42 | + /// Span to the next page when possible. | ||
43 | + span, | ||
41 | } | 44 | } |
42 | 45 | ||
43 | abstract class _Span { | 46 | abstract class _Span { |
@@ -611,7 +614,9 @@ class RichText extends Widget with SpanningWidget { | @@ -611,7 +614,9 @@ class RichText extends Widget with SpanningWidget { | ||
611 | 614 | ||
612 | final _context = _RichTextContext(); | 615 | final _context = _RichTextContext(); |
613 | 616 | ||
614 | - final TextOverflow overflow; | 617 | + final TextOverflow? overflow; |
618 | + | ||
619 | + var _mustClip = false; | ||
615 | 620 | ||
616 | void _appendDecoration(bool append, _TextDecoration td) { | 621 | void _appendDecoration(bool append, _TextDecoration td) { |
617 | if (append && _decorations.isNotEmpty) { | 622 | if (append && _decorations.isNotEmpty) { |
@@ -638,6 +643,7 @@ class RichText extends Widget with SpanningWidget { | @@ -638,6 +643,7 @@ class RichText extends Widget with SpanningWidget { | ||
638 | final _maxLines = maxLines ?? theme.maxLines; | 643 | final _maxLines = maxLines ?? theme.maxLines; |
639 | _textAlign = textAlign ?? theme.textAlign; | 644 | _textAlign = textAlign ?? theme.textAlign; |
640 | final _textDirection = textDirection ?? Directionality.of(context); | 645 | final _textDirection = textDirection ?? Directionality.of(context); |
646 | + final _overflow = this.overflow ?? theme.overflow; | ||
641 | 647 | ||
642 | final constraintWidth = constraints.hasBoundedWidth | 648 | final constraintWidth = constraints.hasBoundedWidth |
643 | ? constraints.maxWidth | 649 | ? constraints.maxWidth |
@@ -728,12 +734,14 @@ class RichText extends Widget with SpanningWidget { | @@ -728,12 +734,14 @@ class RichText extends Widget with SpanningWidget { | ||
728 | // One word Overflow, try to split it. | 734 | // One word Overflow, try to split it. |
729 | final pos = _splitWord(word, font, style, constraintWidth); | 735 | final pos = _splitWord(word, font, style, constraintWidth); |
730 | 736 | ||
731 | - words[index] = word.substring(0, pos); | ||
732 | - words.insert(index + 1, word.substring(pos)); | 737 | + if (pos < word.length) { |
738 | + words[index] = word.substring(0, pos); | ||
739 | + words.insert(index + 1, word.substring(pos)); | ||
733 | 740 | ||
734 | - // Try again | ||
735 | - index--; | ||
736 | - continue; | 741 | + // Try again |
742 | + index--; | ||
743 | + continue; | ||
744 | + } | ||
737 | } | 745 | } |
738 | } | 746 | } |
739 | 747 | ||
@@ -910,7 +918,10 @@ class RichText extends Widget with SpanningWidget { | @@ -910,7 +918,10 @@ class RichText extends Widget with SpanningWidget { | ||
910 | ..endOffset = offsetY - _context.startOffset | 918 | ..endOffset = offsetY - _context.startOffset |
911 | ..spanEnd = _spans.length; | 919 | ..spanEnd = _spans.length; |
912 | 920 | ||
913 | - if (this.overflow != TextOverflow.span) { | 921 | + if (_overflow != TextOverflow.span) { |
922 | + if (_overflow != TextOverflow.visible) { | ||
923 | + _mustClip = true; | ||
924 | + } | ||
914 | return; | 925 | return; |
915 | } | 926 | } |
916 | 927 | ||
@@ -949,6 +960,13 @@ class RichText extends Widget with SpanningWidget { | @@ -949,6 +960,13 @@ class RichText extends Widget with SpanningWidget { | ||
949 | TextStyle? currentStyle; | 960 | TextStyle? currentStyle; |
950 | PdfColor? currentColor; | 961 | PdfColor? currentColor; |
951 | 962 | ||
963 | + if (_mustClip) { | ||
964 | + context.canvas | ||
965 | + ..saveContext() | ||
966 | + ..drawBox(box!) | ||
967 | + ..clipPath(); | ||
968 | + } | ||
969 | + | ||
952 | for (var decoration in _decorations) { | 970 | for (var decoration in _decorations) { |
953 | assert(() { | 971 | assert(() { |
954 | if (Document.debug && RichText.debug) { | 972 | if (Document.debug && RichText.debug) { |
@@ -997,6 +1015,10 @@ class RichText extends Widget with SpanningWidget { | @@ -997,6 +1015,10 @@ class RichText extends Widget with SpanningWidget { | ||
997 | _spans, | 1015 | _spans, |
998 | ); | 1016 | ); |
999 | } | 1017 | } |
1018 | + | ||
1019 | + if (_mustClip) { | ||
1020 | + context.canvas.restoreContext(); | ||
1021 | + } | ||
1000 | } | 1022 | } |
1001 | 1023 | ||
1002 | int _splitWord(String word, PdfFont font, TextStyle style, double maxWidth) { | 1024 | int _splitWord(String word, PdfFont font, TextStyle style, double maxWidth) { |
@@ -1019,7 +1041,7 @@ class RichText extends Widget with SpanningWidget { | @@ -1019,7 +1041,7 @@ class RichText extends Widget with SpanningWidget { | ||
1019 | pos = (low + high) ~/ 2; | 1041 | pos = (low + high) ~/ 2; |
1020 | } | 1042 | } |
1021 | 1043 | ||
1022 | - return pos; | 1044 | + return math.max(1, pos); |
1023 | } | 1045 | } |
1024 | 1046 | ||
1025 | @override | 1047 | @override |
@@ -1050,7 +1072,7 @@ class Text extends RichText { | @@ -1050,7 +1072,7 @@ class Text extends RichText { | ||
1050 | bool tightBounds = false, | 1072 | bool tightBounds = false, |
1051 | double textScaleFactor = 1.0, | 1073 | double textScaleFactor = 1.0, |
1052 | int? maxLines, | 1074 | int? maxLines, |
1053 | - TextOverflow overflow = TextOverflow.visible, | 1075 | + TextOverflow? overflow, |
1054 | }) : super( | 1076 | }) : super( |
1055 | text: TextSpan(text: text, style: style), | 1077 | text: TextSpan(text: text, style: style), |
1056 | textAlign: textAlign, | 1078 | textAlign: textAlign, |
@@ -39,6 +39,7 @@ class ThemeData extends Inherited { | @@ -39,6 +39,7 @@ class ThemeData extends Inherited { | ||
39 | TextStyle? tableCell, | 39 | TextStyle? tableCell, |
40 | bool? softWrap, | 40 | bool? softWrap, |
41 | TextAlign? textAlign, | 41 | TextAlign? textAlign, |
42 | + TextOverflow? overflow, | ||
42 | int? maxLines, | 43 | int? maxLines, |
43 | IconThemeData? iconTheme, | 44 | IconThemeData? iconTheme, |
44 | }) { | 45 | }) { |
@@ -56,6 +57,7 @@ class ThemeData extends Inherited { | @@ -56,6 +57,7 @@ class ThemeData extends Inherited { | ||
56 | tableHeader: tableHeader, | 57 | tableHeader: tableHeader, |
57 | tableCell: tableCell, | 58 | tableCell: tableCell, |
58 | softWrap: softWrap, | 59 | softWrap: softWrap, |
60 | + overflow: overflow, | ||
59 | textAlign: textAlign, | 61 | textAlign: textAlign, |
60 | maxLines: maxLines, | 62 | maxLines: maxLines, |
61 | iconTheme: iconTheme, | 63 | iconTheme: iconTheme, |
@@ -75,6 +77,7 @@ class ThemeData extends Inherited { | @@ -75,6 +77,7 @@ class ThemeData extends Inherited { | ||
75 | required this.tableHeader, | 77 | required this.tableHeader, |
76 | required this.tableCell, | 78 | required this.tableCell, |
77 | required this.softWrap, | 79 | required this.softWrap, |
80 | + required this.overflow, | ||
78 | required this.textAlign, | 81 | required this.textAlign, |
79 | required this.iconTheme, | 82 | required this.iconTheme, |
80 | this.maxLines, | 83 | this.maxLines, |
@@ -121,6 +124,7 @@ class ThemeData extends Inherited { | @@ -121,6 +124,7 @@ class ThemeData extends Inherited { | ||
121 | fontSize: fontSize * 0.8, fontWeight: FontWeight.bold), | 124 | fontSize: fontSize * 0.8, fontWeight: FontWeight.bold), |
122 | tableCell: defaultStyle.copyWith(fontSize: fontSize * 0.8), | 125 | tableCell: defaultStyle.copyWith(fontSize: fontSize * 0.8), |
123 | softWrap: true, | 126 | softWrap: true, |
127 | + overflow: TextOverflow.visible, | ||
124 | textAlign: TextAlign.left, | 128 | textAlign: TextAlign.left, |
125 | iconTheme: IconThemeData.fallback(icons), | 129 | iconTheme: IconThemeData.fallback(icons), |
126 | ); | 130 | ); |
@@ -143,6 +147,7 @@ class ThemeData extends Inherited { | @@ -143,6 +147,7 @@ class ThemeData extends Inherited { | ||
143 | bool? softWrap, | 147 | bool? softWrap, |
144 | TextAlign? textAlign, | 148 | TextAlign? textAlign, |
145 | int? maxLines, | 149 | int? maxLines, |
150 | + TextOverflow? overflow, | ||
146 | IconThemeData? iconTheme, | 151 | IconThemeData? iconTheme, |
147 | }) => | 152 | }) => |
148 | ThemeData._( | 153 | ThemeData._( |
@@ -158,6 +163,7 @@ class ThemeData extends Inherited { | @@ -158,6 +163,7 @@ class ThemeData extends Inherited { | ||
158 | tableHeader: this.tableHeader.merge(tableHeader), | 163 | tableHeader: this.tableHeader.merge(tableHeader), |
159 | tableCell: this.tableCell.merge(tableCell), | 164 | tableCell: this.tableCell.merge(tableCell), |
160 | softWrap: softWrap ?? this.softWrap, | 165 | softWrap: softWrap ?? this.softWrap, |
166 | + overflow: overflow ?? this.overflow, | ||
161 | textAlign: textAlign ?? this.textAlign, | 167 | textAlign: textAlign ?? this.textAlign, |
162 | maxLines: maxLines ?? this.maxLines, | 168 | maxLines: maxLines ?? this.maxLines, |
163 | iconTheme: iconTheme ?? this.iconTheme, | 169 | iconTheme: iconTheme ?? this.iconTheme, |
@@ -183,6 +189,7 @@ class ThemeData extends Inherited { | @@ -183,6 +189,7 @@ class ThemeData extends Inherited { | ||
183 | final TextAlign textAlign; | 189 | final TextAlign textAlign; |
184 | final bool softWrap; | 190 | final bool softWrap; |
185 | final int? maxLines; | 191 | final int? maxLines; |
192 | + final TextOverflow overflow; | ||
186 | 193 | ||
187 | final IconThemeData iconTheme; | 194 | final IconThemeData iconTheme; |
188 | } | 195 | } |
@@ -216,6 +223,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | @@ -216,6 +223,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | ||
216 | required this.child, | 223 | required this.child, |
217 | this.textAlign, | 224 | this.textAlign, |
218 | this.softWrap = true, | 225 | this.softWrap = true, |
226 | + this.overflow, | ||
219 | this.maxLines, | 227 | this.maxLines, |
220 | }) : assert(maxLines == null || maxLines > 0); | 228 | }) : assert(maxLines == null || maxLines > 0); |
221 | 229 | ||
@@ -224,6 +232,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | @@ -224,6 +232,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | ||
224 | TextAlign? textAlign, | 232 | TextAlign? textAlign, |
225 | bool? softWrap, | 233 | bool? softWrap, |
226 | int? maxLines, | 234 | int? maxLines, |
235 | + TextOverflow? overflow, | ||
227 | required Widget child, | 236 | required Widget child, |
228 | }) { | 237 | }) { |
229 | return Builder( | 238 | return Builder( |
@@ -234,6 +243,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | @@ -234,6 +243,7 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | ||
234 | style: parent.defaultTextStyle.merge(style), | 243 | style: parent.defaultTextStyle.merge(style), |
235 | textAlign: textAlign ?? parent.textAlign, | 244 | textAlign: textAlign ?? parent.textAlign, |
236 | softWrap: softWrap ?? parent.softWrap, | 245 | softWrap: softWrap ?? parent.softWrap, |
246 | + overflow: overflow ?? parent.overflow, | ||
237 | maxLines: maxLines ?? parent.maxLines, | 247 | maxLines: maxLines ?? parent.maxLines, |
238 | child: child, | 248 | child: child, |
239 | ); | 249 | ); |
@@ -251,12 +261,15 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | @@ -251,12 +261,15 @@ class DefaultTextStyle extends StatelessWidget implements Inherited { | ||
251 | 261 | ||
252 | final int? maxLines; | 262 | final int? maxLines; |
253 | 263 | ||
264 | + final TextOverflow? overflow; | ||
265 | + | ||
254 | @override | 266 | @override |
255 | Widget build(Context context) { | 267 | Widget build(Context context) { |
256 | final theme = Theme.of(context).copyWith( | 268 | final theme = Theme.of(context).copyWith( |
257 | defaultTextStyle: style, | 269 | defaultTextStyle: style, |
258 | textAlign: textAlign, | 270 | textAlign: textAlign, |
259 | softWrap: softWrap, | 271 | softWrap: softWrap, |
272 | + overflow: overflow, | ||
260 | maxLines: maxLines, | 273 | maxLines: maxLines, |
261 | ); | 274 | ); |
262 | 275 |
-
Please register or login to post a comment