Showing
4 changed files
with
302 additions
and
93 deletions
@@ -18,25 +18,85 @@ part of widget; | @@ -18,25 +18,85 @@ part of widget; | ||
18 | 18 | ||
19 | enum TextAlign { left, right, center, justify } | 19 | enum TextAlign { left, right, center, justify } |
20 | 20 | ||
21 | -class _Word { | ||
22 | - _Word(this.text, this.style, this.metrics, this.annotation); | ||
23 | - | ||
24 | - final String text; | 21 | +abstract class _Span { |
22 | + _Span(this.style, this.annotation); | ||
25 | 23 | ||
26 | final TextStyle style; | 24 | final TextStyle style; |
27 | 25 | ||
28 | - final PdfFontMetrics metrics; | 26 | + final AnnotationBuilder annotation; |
29 | 27 | ||
30 | PdfPoint offset = PdfPoint.zero; | 28 | PdfPoint offset = PdfPoint.zero; |
31 | 29 | ||
32 | - final AnnotationBuilder annotation; | 30 | + double left; |
31 | + double top; | ||
32 | + double width; | ||
33 | + double height; | ||
34 | + | ||
35 | + @override | ||
36 | + String toString() { | ||
37 | + return 'Span "offset:$offset'; | ||
38 | + } | ||
39 | + | ||
40 | + void debugPaint( | ||
41 | + Context context, | ||
42 | + double textScaleFactor, | ||
43 | + PdfRect globalBox, | ||
44 | + ) {} | ||
45 | + | ||
46 | + void paint( | ||
47 | + Context context, | ||
48 | + TextStyle style, | ||
49 | + double textScaleFactor, | ||
50 | + PdfPoint point, | ||
51 | + ); | ||
52 | +} | ||
53 | + | ||
54 | +class _Word extends _Span { | ||
55 | + _Word(this.text, TextStyle style, this.metrics, AnnotationBuilder annotation) | ||
56 | + : super(style, annotation); | ||
57 | + | ||
58 | + final String text; | ||
59 | + | ||
60 | + final PdfFontMetrics metrics; | ||
61 | + | ||
62 | + @override | ||
63 | + double get left => metrics.left; | ||
64 | + | ||
65 | + @override | ||
66 | + double get top => metrics.top; | ||
67 | + | ||
68 | + @override | ||
69 | + double get width => metrics.width; | ||
70 | + | ||
71 | + @override | ||
72 | + double get height => metrics.height; | ||
33 | 73 | ||
34 | @override | 74 | @override |
35 | String toString() { | 75 | String toString() { |
36 | return 'Word "$text" offset:$offset metrics:$metrics style:$style'; | 76 | return 'Word "$text" offset:$offset metrics:$metrics style:$style'; |
37 | } | 77 | } |
38 | 78 | ||
39 | - void debugPaint(Context context, double textScaleFactor, PdfRect globalBox) { | 79 | + @override |
80 | + void paint( | ||
81 | + Context context, | ||
82 | + TextStyle style, | ||
83 | + double textScaleFactor, | ||
84 | + PdfPoint point, | ||
85 | + ) { | ||
86 | + context.canvas.drawString( | ||
87 | + style.font.getFont(context), | ||
88 | + style.fontSize * textScaleFactor, | ||
89 | + text, | ||
90 | + point.x + offset.x, | ||
91 | + point.y + offset.y); | ||
92 | + } | ||
93 | + | ||
94 | + @override | ||
95 | + void debugPaint( | ||
96 | + Context context, | ||
97 | + double textScaleFactor, | ||
98 | + PdfRect globalBox, | ||
99 | + ) { | ||
40 | const double deb = 5; | 100 | const double deb = 5; |
41 | 101 | ||
42 | context.canvas | 102 | context.canvas |
@@ -54,27 +114,122 @@ class _Word { | @@ -54,27 +114,122 @@ class _Word { | ||
54 | } | 114 | } |
55 | } | 115 | } |
56 | 116 | ||
57 | -class TextSpan { | ||
58 | - const TextSpan({this.style, this.text, this.children, this.annotation}); | 117 | +class _WidgetSpan extends _Span { |
118 | + _WidgetSpan(this.widget, TextStyle style, AnnotationBuilder annotation) | ||
119 | + : assert(widget != null), | ||
120 | + assert(style != null), | ||
121 | + super(style, annotation); | ||
59 | 122 | ||
60 | - final TextStyle style; | 123 | + final Widget widget; |
61 | 124 | ||
62 | - final String text; | 125 | + @override |
126 | + double get left => 0; | ||
127 | + | ||
128 | + @override | ||
129 | + double get top => 0; | ||
130 | + | ||
131 | + @override | ||
132 | + double get width => widget.box.width; | ||
133 | + | ||
134 | + @override | ||
135 | + double get height => widget.box.height; | ||
136 | + | ||
137 | + @override | ||
138 | + PdfPoint get offset => widget.box.offset; | ||
139 | + | ||
140 | + @override | ||
141 | + set offset(PdfPoint value) { | ||
142 | + widget.box = PdfRect.fromPoints(value, widget.box.size); | ||
143 | + } | ||
144 | + | ||
145 | + @override | ||
146 | + String toString() { | ||
147 | + return 'Widget "$widget" offset:$offset'; | ||
148 | + } | ||
149 | + | ||
150 | + @override | ||
151 | + void paint( | ||
152 | + Context context, | ||
153 | + TextStyle style, | ||
154 | + double textScaleFactor, | ||
155 | + PdfPoint point, | ||
156 | + ) { | ||
157 | + widget.box = PdfRect.fromPoints( | ||
158 | + PdfPoint(point.x + widget.box.offset.x, point.y + widget.box.offset.y), | ||
159 | + widget.box.size); | ||
160 | + widget.paint(context); | ||
161 | + } | ||
162 | +} | ||
163 | + | ||
164 | +@immutable | ||
165 | +abstract class InlineSpan { | ||
166 | + const InlineSpan({this.style, this.baseline, this.annotation}); | ||
167 | + | ||
168 | + final TextStyle style; | ||
63 | 169 | ||
64 | - final List<TextSpan> children; | 170 | + final double baseline; |
65 | 171 | ||
66 | final AnnotationBuilder annotation; | 172 | final AnnotationBuilder annotation; |
67 | 173 | ||
68 | String toPlainText() { | 174 | String toPlainText() { |
69 | final StringBuffer buffer = StringBuffer(); | 175 | final StringBuffer buffer = StringBuffer(); |
70 | - visitTextSpan((TextSpan span, TextStyle style) { | ||
71 | - buffer.write(span.text); | 176 | + visitChildren((InlineSpan span, TextStyle style) { |
177 | + if (span is TextSpan) { | ||
178 | + buffer.write(span.text); | ||
179 | + } | ||
72 | return true; | 180 | return true; |
73 | }, null); | 181 | }, null); |
74 | return buffer.toString(); | 182 | return buffer.toString(); |
75 | } | 183 | } |
76 | 184 | ||
77 | - bool visitTextSpan(bool visitor(TextSpan span, TextStyle parentStyle), | 185 | + bool visitChildren(bool visitor(InlineSpan span, TextStyle parentStyle), |
186 | + TextStyle parentStyle); | ||
187 | +} | ||
188 | + | ||
189 | +class WidgetSpan extends InlineSpan { | ||
190 | + /// Creates a [WidgetSpan] with the given values. | ||
191 | + const WidgetSpan({ | ||
192 | + @required this.child, | ||
193 | + double baseline = 0, | ||
194 | + TextStyle style, | ||
195 | + AnnotationBuilder annotation, | ||
196 | + }) : assert(child != null), | ||
197 | + super(style: style, baseline: baseline, annotation: annotation); | ||
198 | + | ||
199 | + /// The widget to embed inline within text. | ||
200 | + final Widget child; | ||
201 | + | ||
202 | + /// Calls `visitor` on this [WidgetSpan]. There are no children spans to walk. | ||
203 | + @override | ||
204 | + bool visitChildren(bool visitor(InlineSpan span, TextStyle parentStyle), | ||
205 | + TextStyle parentStyle) { | ||
206 | + final TextStyle _style = parentStyle?.merge(style); | ||
207 | + | ||
208 | + if (child != null) { | ||
209 | + if (!visitor(this, _style)) { | ||
210 | + return false; | ||
211 | + } | ||
212 | + } | ||
213 | + | ||
214 | + return true; | ||
215 | + } | ||
216 | +} | ||
217 | + | ||
218 | +class TextSpan extends InlineSpan { | ||
219 | + const TextSpan({ | ||
220 | + TextStyle style, | ||
221 | + this.text, | ||
222 | + double baseline = 0, | ||
223 | + this.children, | ||
224 | + AnnotationBuilder annotation, | ||
225 | + }) : super(style: style, baseline: baseline, annotation: annotation); | ||
226 | + | ||
227 | + final String text; | ||
228 | + | ||
229 | + final List<InlineSpan> children; | ||
230 | + | ||
231 | + @override | ||
232 | + bool visitChildren(bool visitor(InlineSpan span, TextStyle parentStyle), | ||
78 | TextStyle parentStyle) { | 233 | TextStyle parentStyle) { |
79 | final TextStyle _style = parentStyle?.merge(style); | 234 | final TextStyle _style = parentStyle?.merge(style); |
80 | 235 | ||
@@ -84,8 +239,8 @@ class TextSpan { | @@ -84,8 +239,8 @@ class TextSpan { | ||
84 | } | 239 | } |
85 | } | 240 | } |
86 | if (children != null) { | 241 | if (children != null) { |
87 | - for (TextSpan child in children) { | ||
88 | - if (!child.visitTextSpan(visitor, _style)) { | 242 | + for (InlineSpan child in children) { |
243 | + if (!child.visitChildren(visitor, _style)) { | ||
89 | return false; | 244 | return false; |
90 | } | 245 | } |
91 | } | 246 | } |
@@ -105,7 +260,7 @@ class RichText extends Widget { | @@ -105,7 +260,7 @@ class RichText extends Widget { | ||
105 | 260 | ||
106 | static bool debug = false; | 261 | static bool debug = false; |
107 | 262 | ||
108 | - final TextSpan text; | 263 | + final InlineSpan text; |
109 | 264 | ||
110 | final TextAlign textAlign; | 265 | final TextAlign textAlign; |
111 | 266 | ||
@@ -115,9 +270,9 @@ class RichText extends Widget { | @@ -115,9 +270,9 @@ class RichText extends Widget { | ||
115 | 270 | ||
116 | final int maxLines; | 271 | final int maxLines; |
117 | 272 | ||
118 | - final List<_Word> _words = <_Word>[]; | 273 | + final List<_Span> _spans = <_Span>[]; |
119 | 274 | ||
120 | - double _realignLine(List<_Word> words, double totalWidth, double wordsWidth, | 275 | + double _realignLine(List<_Span> spans, double totalWidth, double wordsWidth, |
121 | bool last, double baseline) { | 276 | bool last, double baseline) { |
122 | double delta = 0; | 277 | double delta = 0; |
123 | switch (textAlign) { | 278 | switch (textAlign) { |
@@ -135,17 +290,17 @@ class RichText extends Widget { | @@ -135,17 +290,17 @@ class RichText extends Widget { | ||
135 | totalWidth = wordsWidth; | 290 | totalWidth = wordsWidth; |
136 | break; | 291 | break; |
137 | } | 292 | } |
138 | - delta = (totalWidth - wordsWidth) / (words.length - 1); | 293 | + delta = (totalWidth - wordsWidth) / (spans.length - 1); |
139 | double x = 0; | 294 | double x = 0; |
140 | - for (_Word word in words) { | ||
141 | - word.offset = word.offset.translate(x, -baseline); | 295 | + for (_Span span in spans) { |
296 | + span.offset = span.offset.translate(x, -baseline); | ||
142 | x += delta; | 297 | x += delta; |
143 | } | 298 | } |
144 | return totalWidth; | 299 | return totalWidth; |
145 | } | 300 | } |
146 | 301 | ||
147 | - for (_Word word in words) { | ||
148 | - word.offset = word.offset.translate(delta, -baseline); | 302 | + for (_Span span in spans) { |
303 | + span.offset = span.offset.translate(delta, -baseline); | ||
149 | } | 304 | } |
150 | return totalWidth; | 305 | return totalWidth; |
151 | } | 306 | } |
@@ -153,7 +308,7 @@ class RichText extends Widget { | @@ -153,7 +308,7 @@ class RichText extends Widget { | ||
153 | @override | 308 | @override |
154 | void layout(Context context, BoxConstraints constraints, | 309 | void layout(Context context, BoxConstraints constraints, |
155 | {bool parentUsesSize = false}) { | 310 | {bool parentUsesSize = false}) { |
156 | - _words.clear(); | 311 | + _spans.clear(); |
157 | 312 | ||
158 | final TextStyle defaultstyle = Theme.of(context).defaultTextStyle; | 313 | final TextStyle defaultstyle = Theme.of(context).defaultTextStyle; |
159 | 314 | ||
@@ -174,32 +329,75 @@ class RichText extends Widget { | @@ -174,32 +329,75 @@ class RichText extends Widget { | ||
174 | int wCount = 0; | 329 | int wCount = 0; |
175 | int lineStart = 0; | 330 | int lineStart = 0; |
176 | 331 | ||
177 | - text.visitTextSpan((TextSpan span, TextStyle style) { | ||
178 | - if (span.text == null) { | ||
179 | - return true; | ||
180 | - } | 332 | + text.visitChildren((InlineSpan span, TextStyle style) { |
333 | + if (span is TextSpan) { | ||
334 | + if (span.text == null) { | ||
335 | + return true; | ||
336 | + } | ||
181 | 337 | ||
182 | - final PdfFont font = style.font.getFont(context); | 338 | + final PdfFont font = style.font.getFont(context); |
183 | 339 | ||
184 | - final PdfFontMetrics space = | ||
185 | - font.stringMetrics(' ') * (style.fontSize * textScaleFactor); | 340 | + final PdfFontMetrics space = |
341 | + font.stringMetrics(' ') * (style.fontSize * textScaleFactor); | ||
186 | 342 | ||
187 | - final List<String> spanLines = span.text.split('\n'); | ||
188 | - for (int line = 0; line < spanLines.length; line++) { | ||
189 | - for (String word in spanLines[line].split(RegExp(r'\s'))) { | ||
190 | - if (word.isEmpty) { | ||
191 | - offsetX += space.advanceWidth * style.wordSpacing; | ||
192 | - continue; | ||
193 | - } | 343 | + final List<String> spanLines = span.text.split('\n'); |
344 | + for (int line = 0; line < spanLines.length; line++) { | ||
345 | + for (String word in spanLines[line].split(RegExp(r'\s'))) { | ||
346 | + if (word.isEmpty) { | ||
347 | + offsetX += space.advanceWidth * style.wordSpacing; | ||
348 | + continue; | ||
349 | + } | ||
194 | 350 | ||
195 | - final PdfFontMetrics metrics = | ||
196 | - font.stringMetrics(word) * (style.fontSize * textScaleFactor); | 351 | + final PdfFontMetrics metrics = |
352 | + font.stringMetrics(word) * (style.fontSize * textScaleFactor); | ||
353 | + | ||
354 | + if (offsetX + metrics.width > constraintWidth && wCount > 0) { | ||
355 | + width = math.max( | ||
356 | + width, | ||
357 | + _realignLine( | ||
358 | + _spans.sublist(lineStart), | ||
359 | + constraintWidth, | ||
360 | + offsetX - space.advanceWidth * style.wordSpacing, | ||
361 | + false, | ||
362 | + bottom)); | ||
363 | + | ||
364 | + lineStart += wCount; | ||
365 | + | ||
366 | + if (maxLines != null && ++lines > maxLines) { | ||
367 | + break; | ||
368 | + } | ||
369 | + | ||
370 | + offsetX = 0.0; | ||
371 | + offsetY += bottom - top + style.lineSpacing; | ||
372 | + top = null; | ||
373 | + bottom = null; | ||
374 | + | ||
375 | + if (offsetY > constraintHeight) { | ||
376 | + return false; | ||
377 | + } | ||
378 | + wCount = 0; | ||
379 | + } | ||
197 | 380 | ||
198 | - if (offsetX + metrics.width > constraintWidth && wCount > 0) { | 381 | + final double baseline = span.baseline * textScaleFactor; |
382 | + top = | ||
383 | + math.min(top ?? metrics.top + baseline, metrics.top + baseline); | ||
384 | + bottom = math.max( | ||
385 | + bottom ?? metrics.bottom + baseline, metrics.bottom + baseline); | ||
386 | + | ||
387 | + final _Word wd = _Word(word, style, metrics, span.annotation); | ||
388 | + wd.offset = PdfPoint(offsetX, -offsetY + baseline); | ||
389 | + | ||
390 | + _spans.add(wd); | ||
391 | + wCount++; | ||
392 | + offsetX += | ||
393 | + metrics.advanceWidth + space.advanceWidth * style.wordSpacing; | ||
394 | + } | ||
395 | + | ||
396 | + if (softWrap && line < spanLines.length - 1) { | ||
199 | width = math.max( | 397 | width = math.max( |
200 | width, | 398 | width, |
201 | _realignLine( | 399 | _realignLine( |
202 | - _words.sublist(lineStart), | 400 | + _spans.sublist(lineStart), |
203 | constraintWidth, | 401 | constraintWidth, |
204 | offsetX - space.advanceWidth * style.wordSpacing, | 402 | offsetX - space.advanceWidth * style.wordSpacing, |
205 | false, | 403 | false, |
@@ -212,7 +410,11 @@ class RichText extends Widget { | @@ -212,7 +410,11 @@ class RichText extends Widget { | ||
212 | } | 410 | } |
213 | 411 | ||
214 | offsetX = 0.0; | 412 | offsetX = 0.0; |
215 | - offsetY += bottom - top + style.lineSpacing; | 413 | + if (wCount > 0) { |
414 | + offsetY += bottom - top + style.lineSpacing; | ||
415 | + } else { | ||
416 | + offsetY += space.ascent + space.descent + style.lineSpacing; | ||
417 | + } | ||
216 | top = null; | 418 | top = null; |
217 | bottom = null; | 419 | bottom = null; |
218 | 420 | ||
@@ -221,41 +423,32 @@ class RichText extends Widget { | @@ -221,41 +423,32 @@ class RichText extends Widget { | ||
221 | } | 423 | } |
222 | wCount = 0; | 424 | wCount = 0; |
223 | } | 425 | } |
224 | - | ||
225 | - top = math.min(top ?? metrics.top, metrics.top); | ||
226 | - bottom = math.max(bottom ?? metrics.bottom, metrics.bottom); | ||
227 | - | ||
228 | - final _Word wd = _Word(word, style, metrics, span.annotation); | ||
229 | - wd.offset = PdfPoint(offsetX, -offsetY); | ||
230 | - | ||
231 | - _words.add(wd); | ||
232 | - wCount++; | ||
233 | - offsetX += | ||
234 | - metrics.advanceWidth + space.advanceWidth * style.wordSpacing; | ||
235 | } | 426 | } |
236 | 427 | ||
237 | - if (softWrap && line < spanLines.length - 1) { | 428 | + offsetX -= space.advanceWidth * style.wordSpacing; |
429 | + } else if (span is WidgetSpan) { | ||
430 | + span.child.layout( | ||
431 | + context, | ||
432 | + BoxConstraints.tight(PdfPoint( | ||
433 | + double.infinity, | ||
434 | + style.fontSize * textScaleFactor, | ||
435 | + ))); | ||
436 | + final _WidgetSpan ws = _WidgetSpan(span.child, style, span.annotation); | ||
437 | + | ||
438 | + if (offsetX + ws.width > constraintWidth && wCount > 0) { | ||
238 | width = math.max( | 439 | width = math.max( |
239 | width, | 440 | width, |
240 | - _realignLine( | ||
241 | - _words.sublist(lineStart), | ||
242 | - constraintWidth, | ||
243 | - offsetX - space.advanceWidth * style.wordSpacing, | ||
244 | - false, | ||
245 | - bottom)); | 441 | + _realignLine(_spans.sublist(lineStart), constraintWidth, offsetX, |
442 | + false, bottom)); | ||
246 | 443 | ||
247 | lineStart += wCount; | 444 | lineStart += wCount; |
248 | 445 | ||
249 | if (maxLines != null && ++lines > maxLines) { | 446 | if (maxLines != null && ++lines > maxLines) { |
250 | - break; | 447 | + return false; |
251 | } | 448 | } |
252 | 449 | ||
253 | offsetX = 0.0; | 450 | offsetX = 0.0; |
254 | - if (wCount > 0) { | ||
255 | - offsetY += bottom - top + style.lineSpacing; | ||
256 | - } else { | ||
257 | - offsetY += space.ascent + space.descent + style.lineSpacing; | ||
258 | - } | 451 | + offsetY += bottom - top + style.lineSpacing; |
259 | top = null; | 452 | top = null; |
260 | bottom = null; | 453 | bottom = null; |
261 | 454 | ||
@@ -264,16 +457,24 @@ class RichText extends Widget { | @@ -264,16 +457,24 @@ class RichText extends Widget { | ||
264 | } | 457 | } |
265 | wCount = 0; | 458 | wCount = 0; |
266 | } | 459 | } |
460 | + | ||
461 | + final double baseline = span.baseline * textScaleFactor; | ||
462 | + top = math.min(top ?? baseline, baseline); | ||
463 | + bottom = math.max(bottom ?? ws.height + baseline, ws.height + baseline); | ||
464 | + | ||
465 | + ws.offset = PdfPoint(offsetX, -offsetY + baseline); | ||
466 | + _spans.add(ws); | ||
467 | + wCount++; | ||
468 | + offsetX += ws.left + ws.width; | ||
267 | } | 469 | } |
268 | 470 | ||
269 | - offsetX -= space.advanceWidth * style.wordSpacing; | ||
270 | return true; | 471 | return true; |
271 | }, defaultstyle); | 472 | }, defaultstyle); |
272 | 473 | ||
273 | width = math.max( | 474 | width = math.max( |
274 | width, | 475 | width, |
275 | _realignLine( | 476 | _realignLine( |
276 | - _words.sublist(lineStart), constraintWidth, offsetX, true, bottom)); | 477 | + _spans.sublist(lineStart), constraintWidth, offsetX, true, bottom)); |
277 | 478 | ||
278 | bottom ??= 0.0; | 479 | bottom ??= 0.0; |
279 | top ??= 0.0; | 480 | top ??= 0.0; |
@@ -296,37 +497,34 @@ class RichText extends Widget { | @@ -296,37 +497,34 @@ class RichText extends Widget { | ||
296 | TextStyle currentStyle; | 497 | TextStyle currentStyle; |
297 | PdfColor currentColor; | 498 | PdfColor currentColor; |
298 | 499 | ||
299 | - for (_Word word in _words) { | 500 | + for (_Span span in _spans) { |
300 | assert(() { | 501 | assert(() { |
301 | if (Document.debug && RichText.debug) { | 502 | if (Document.debug && RichText.debug) { |
302 | - word.debugPaint(context, textScaleFactor, box); | 503 | + span.debugPaint(context, textScaleFactor, box); |
303 | } | 504 | } |
304 | return true; | 505 | return true; |
305 | }()); | 506 | }()); |
306 | 507 | ||
307 | - if (word.style != currentStyle) { | ||
308 | - currentStyle = word.style; | 508 | + if (span.style != currentStyle) { |
509 | + currentStyle = span.style; | ||
309 | if (currentStyle.color != currentColor) { | 510 | if (currentStyle.color != currentColor) { |
310 | currentColor = currentStyle.color; | 511 | currentColor = currentStyle.color; |
311 | context.canvas.setFillColor(currentColor); | 512 | context.canvas.setFillColor(currentColor); |
312 | } | 513 | } |
313 | } | 514 | } |
314 | 515 | ||
315 | - if (word.annotation != null) { | ||
316 | - final PdfRect wordBox = PdfRect( | ||
317 | - box.x + word.offset.x + word.metrics.left, | ||
318 | - box.top + word.offset.y + word.metrics.top, | ||
319 | - word.metrics.width, | ||
320 | - word.metrics.height); | ||
321 | - word.annotation.build(context, wordBox); | 516 | + if (span.annotation != null) { |
517 | + final PdfRect spanBox = PdfRect(box.x + span.offset.x + span.left, | ||
518 | + box.top + span.offset.y + span.top, span.width, span.height); | ||
519 | + span.annotation.build(context, spanBox); | ||
322 | } | 520 | } |
323 | 521 | ||
324 | - context.canvas.drawString( | ||
325 | - currentStyle.font.getFont(context), | ||
326 | - currentStyle.fontSize * textScaleFactor, | ||
327 | - word.text, | ||
328 | - box.x + word.offset.x, | ||
329 | - box.top + word.offset.y); | 522 | + span.paint( |
523 | + context, | ||
524 | + currentStyle, | ||
525 | + textScaleFactor, | ||
526 | + PdfPoint(box.left, box.top), | ||
527 | + ); | ||
330 | } | 528 | } |
331 | } | 529 | } |
332 | } | 530 | } |
@@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | ||
4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf | 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf |
5 | repository: https://github.com/DavBfr/dart_pdf | 5 | repository: https://github.com/DavBfr/dart_pdf |
6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
7 | -version: 1.3.17 | 7 | +version: 1.3.18 |
8 | 8 | ||
9 | environment: | 9 | environment: |
10 | sdk: ">=2.1.0 <3.0.0" | 10 | sdk: ">=2.1.0 <3.0.0" |
@@ -169,17 +169,24 @@ void main() { | @@ -169,17 +169,24 @@ void main() { | ||
169 | font: ttf, | 169 | font: ttf, |
170 | fontSize: 20, | 170 | fontSize: 20, |
171 | ), | 171 | ), |
172 | - children: <TextSpan>[ | 172 | + children: <InlineSpan>[ |
173 | TextSpan( | 173 | TextSpan( |
174 | text: 'bold', | 174 | text: 'bold', |
175 | style: TextStyle( | 175 | style: TextStyle( |
176 | - font: ttfBold, | ||
177 | - fontSize: 40, | ||
178 | - color: PdfColors.blue)), | 176 | + font: ttfBold, fontSize: 40, color: PdfColors.blue), |
177 | + children: <InlineSpan>[ | ||
178 | + const TextSpan(text: '*', baseline: 20), | ||
179 | + WidgetSpan(child: PdfLogo(), baseline: -10), | ||
180 | + ]), | ||
179 | TextSpan( | 181 | TextSpan( |
180 | text: ' world!\n', | 182 | text: ' world!\n', |
181 | children: spans, | 183 | children: spans, |
182 | ), | 184 | ), |
185 | + WidgetSpan( | ||
186 | + child: PdfLogo(), | ||
187 | + annotation: AnnotationUrl( | ||
188 | + 'https://github.com/DavBfr/dart_pdf', | ||
189 | + )), | ||
183 | ], | 190 | ], |
184 | ), | 191 | ), |
185 | ), | 192 | ), |
-
Please register or login to post a comment