Committed by
David PHAM-VAN
Add RTL support to EdgeInsets widget
Add RTL support Page and MultiPage
Showing
7 changed files
with
559 additions
and
198 deletions
@@ -22,8 +22,7 @@ import 'point.dart'; | @@ -22,8 +22,7 @@ import 'point.dart'; | ||
22 | class PdfRect { | 22 | class PdfRect { |
23 | const PdfRect(this.x, this.y, this.width, this.height); | 23 | const PdfRect(this.x, this.y, this.width, this.height); |
24 | 24 | ||
25 | - factory PdfRect.fromLTRB( | ||
26 | - double left, double top, double right, double bottom) { | 25 | + factory PdfRect.fromLTRB(double left, double top, double right, double bottom) { |
27 | return PdfRect(left, top, right - left, bottom - top); | 26 | return PdfRect(left, top, right - left, bottom - top); |
28 | } | 27 | } |
29 | 28 | ||
@@ -36,14 +35,18 @@ class PdfRect { | @@ -36,14 +35,18 @@ class PdfRect { | ||
36 | static const PdfRect zero = PdfRect(0, 0, 0, 0); | 35 | static const PdfRect zero = PdfRect(0, 0, 0, 0); |
37 | 36 | ||
38 | double get left => x; | 37 | double get left => x; |
38 | + | ||
39 | double get bottom => y; | 39 | double get bottom => y; |
40 | + | ||
40 | double get right => x + width; | 41 | double get right => x + width; |
42 | + | ||
41 | double get top => y + height; | 43 | double get top => y + height; |
42 | 44 | ||
43 | @Deprecated('type => horizontalCenter') | 45 | @Deprecated('type => horizontalCenter') |
44 | double get horizondalCenter => horizontalCenter; | 46 | double get horizondalCenter => horizontalCenter; |
45 | 47 | ||
46 | double get horizontalCenter => x + width / 2; | 48 | double get horizontalCenter => x + width / 2; |
49 | + | ||
47 | double get verticalCenter => y + height / 2; | 50 | double get verticalCenter => y + height / 2; |
48 | 51 | ||
49 | @override | 52 | @override |
@@ -54,19 +57,36 @@ class PdfRect { | @@ -54,19 +57,36 @@ class PdfRect { | ||
54 | } | 57 | } |
55 | 58 | ||
56 | PdfPoint get offset => PdfPoint(x, y); | 59 | PdfPoint get offset => PdfPoint(x, y); |
60 | + | ||
57 | PdfPoint get size => PdfPoint(width, height); | 61 | PdfPoint get size => PdfPoint(width, height); |
58 | 62 | ||
59 | PdfPoint get topLeft => PdfPoint(x, y); | 63 | PdfPoint get topLeft => PdfPoint(x, y); |
64 | + | ||
60 | PdfPoint get topRight => PdfPoint(right, y); | 65 | PdfPoint get topRight => PdfPoint(right, y); |
66 | + | ||
61 | PdfPoint get bottomLeft => PdfPoint(x, top); | 67 | PdfPoint get bottomLeft => PdfPoint(x, top); |
68 | + | ||
62 | PdfPoint get bottomRight => PdfPoint(right, top); | 69 | PdfPoint get bottomRight => PdfPoint(right, top); |
63 | 70 | ||
64 | /// Returns a new rectangle with edges moved outwards by the given delta. | 71 | /// Returns a new rectangle with edges moved outwards by the given delta. |
65 | PdfRect inflate(double delta) { | 72 | PdfRect inflate(double delta) { |
66 | - return PdfRect.fromLTRB( | ||
67 | - left - delta, top - delta, right + delta, bottom + delta); | 73 | + return PdfRect.fromLTRB(left - delta, top - delta, right + delta, bottom + delta); |
68 | } | 74 | } |
69 | 75 | ||
70 | /// Returns a new rectangle with edges moved inwards by the given delta. | 76 | /// Returns a new rectangle with edges moved inwards by the given delta. |
71 | PdfRect deflate(double delta) => inflate(-delta); | 77 | PdfRect deflate(double delta) => inflate(-delta); |
78 | + | ||
79 | + PdfRect copyWith({ | ||
80 | + double? x, | ||
81 | + double? y, | ||
82 | + double? width, | ||
83 | + double? height, | ||
84 | + }) { | ||
85 | + return PdfRect( | ||
86 | + x ?? this.x, | ||
87 | + y ?? this.y, | ||
88 | + width ?? this.width, | ||
89 | + height ?? this.height, | ||
90 | + ); | ||
91 | + } | ||
72 | } | 92 | } |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | 16 | ||
17 | import 'dart:math' as math; | 17 | import 'dart:math' as math; |
18 | 18 | ||
19 | +import 'package:pdf/widgets.dart'; | ||
19 | import 'package:vector_math/vector_math_64.dart'; | 20 | import 'package:vector_math/vector_math_64.dart'; |
20 | 21 | ||
21 | import '../../pdf.dart'; | 22 | import '../../pdf.dart'; |
@@ -80,46 +81,48 @@ class Padding extends SingleChildWidget { | @@ -80,46 +81,48 @@ class Padding extends SingleChildWidget { | ||
80 | Widget? child, | 81 | Widget? child, |
81 | }) : super(child: child); | 82 | }) : super(child: child); |
82 | 83 | ||
83 | - final EdgeInsets padding; | 84 | + final EdgeInsetsGeometry padding; |
84 | 85 | ||
85 | @override | 86 | @override |
86 | void layout(Context context, BoxConstraints constraints, | 87 | void layout(Context context, BoxConstraints constraints, |
87 | {bool parentUsesSize = false}) { | 88 | {bool parentUsesSize = false}) { |
89 | + final effectivePadding = padding.resolve(Directionality.of(context)); | ||
88 | if (child != null) { | 90 | if (child != null) { |
89 | - final childConstraints = constraints.deflate(padding); | 91 | + final childConstraints = constraints.deflate(effectivePadding); |
90 | child!.layout(context, childConstraints, parentUsesSize: parentUsesSize); | 92 | child!.layout(context, childConstraints, parentUsesSize: parentUsesSize); |
91 | assert(child!.box != null); | 93 | assert(child!.box != null); |
92 | box = constraints.constrainRect( | 94 | box = constraints.constrainRect( |
93 | - width: child!.box!.width + padding.horizontal, | ||
94 | - height: child!.box!.height + padding.vertical); | 95 | + width: child!.box!.width + effectivePadding.horizontal, |
96 | + height: child!.box!.height + effectivePadding.vertical); | ||
95 | } else { | 97 | } else { |
96 | box = constraints.constrainRect( | 98 | box = constraints.constrainRect( |
97 | - width: padding.horizontal, height: padding.vertical); | 99 | + width: effectivePadding.horizontal, height: effectivePadding.vertical); |
98 | } | 100 | } |
99 | } | 101 | } |
100 | 102 | ||
101 | @override | 103 | @override |
102 | void debugPaint(Context context) { | 104 | void debugPaint(Context context) { |
105 | + final effectivePadding = padding.resolve(Directionality.of(context)); | ||
103 | context.canvas | 106 | context.canvas |
104 | ..setFillColor(PdfColors.lime) | 107 | ..setFillColor(PdfColors.lime) |
105 | ..moveTo(box!.x, box!.y) | 108 | ..moveTo(box!.x, box!.y) |
106 | ..lineTo(box!.right, box!.y) | 109 | ..lineTo(box!.right, box!.y) |
107 | ..lineTo(box!.right, box!.top) | 110 | ..lineTo(box!.right, box!.top) |
108 | ..lineTo(box!.x, box!.top) | 111 | ..lineTo(box!.x, box!.top) |
109 | - ..moveTo(box!.x + padding.left, box!.y + padding.bottom) | ||
110 | - ..lineTo(box!.x + padding.left, box!.top - padding.top) | ||
111 | - ..lineTo(box!.right - padding.right, box!.top - padding.top) | ||
112 | - ..lineTo(box!.right - padding.right, box!.y + padding.bottom) | 112 | + ..moveTo(box!.x + effectivePadding.left, box!.y + effectivePadding.bottom) |
113 | + ..lineTo(box!.x + effectivePadding.left, box!.top - effectivePadding.top) | ||
114 | + ..lineTo(box!.right - effectivePadding.right, box!.top - effectivePadding.top) | ||
115 | + ..lineTo(box!.right - effectivePadding.right, box!.y + effectivePadding.bottom) | ||
113 | ..fillPath(); | 116 | ..fillPath(); |
114 | } | 117 | } |
115 | 118 | ||
116 | @override | 119 | @override |
117 | void paint(Context context) { | 120 | void paint(Context context) { |
118 | super.paint(context); | 121 | super.paint(context); |
119 | - | 122 | + final effectivePadding = padding.resolve(Directionality.of(context)); |
120 | if (child != null) { | 123 | if (child != null) { |
121 | final mat = Matrix4.identity(); | 124 | final mat = Matrix4.identity(); |
122 | - mat.translate(box!.x + padding.left, box!.y + padding.bottom); | 125 | + mat.translate(box!.x + effectivePadding.left, box!.y + effectivePadding.bottom); |
123 | context.canvas | 126 | context.canvas |
124 | ..saveContext() | 127 | ..saveContext() |
125 | ..setTransform(mat); | 128 | ..setTransform(mat); |
@@ -20,16 +20,13 @@ import 'package:meta/meta.dart'; | @@ -20,16 +20,13 @@ import 'package:meta/meta.dart'; | ||
20 | import 'package:vector_math/vector_math_64.dart'; | 20 | import 'package:vector_math/vector_math_64.dart'; |
21 | 21 | ||
22 | import '../../pdf.dart'; | 22 | import '../../pdf.dart'; |
23 | -import 'basic.dart'; | 23 | +import '../../widgets.dart'; |
24 | 24 | ||
25 | @immutable | 25 | @immutable |
26 | class BoxConstraints { | 26 | class BoxConstraints { |
27 | /// Creates box constraints with the given constraints. | 27 | /// Creates box constraints with the given constraints. |
28 | const BoxConstraints( | 28 | const BoxConstraints( |
29 | - {this.minWidth = 0.0, | ||
30 | - this.maxWidth = double.infinity, | ||
31 | - this.minHeight = 0.0, | ||
32 | - this.maxHeight = double.infinity}); | 29 | + {this.minWidth = 0.0, this.maxWidth = double.infinity, this.minHeight = 0.0, this.maxHeight = double.infinity}); |
33 | 30 | ||
34 | /// Creates box constraints that require the given width or height. | 31 | /// Creates box constraints that require the given width or height. |
35 | const BoxConstraints.tightFor({double? width, double? height}) | 32 | const BoxConstraints.tightFor({double? width, double? height}) |
@@ -104,8 +101,7 @@ class BoxConstraints { | @@ -104,8 +101,7 @@ class BoxConstraints { | ||
104 | return result; | 101 | return result; |
105 | } | 102 | } |
106 | 103 | ||
107 | - PdfRect constrainRect( | ||
108 | - {double width = double.infinity, double height = double.infinity}) { | 104 | + PdfRect constrainRect({double width = double.infinity, double height = double.infinity}) { |
109 | final result = PdfPoint(constrainWidth(width), constrainHeight(height)); | 105 | final result = PdfPoint(constrainWidth(width), constrainHeight(height)); |
110 | return PdfRect.fromPoints(PdfPoint.zero, result); | 106 | return PdfRect.fromPoints(PdfPoint.zero, result); |
111 | } | 107 | } |
@@ -162,10 +158,8 @@ class BoxConstraints { | @@ -162,10 +158,8 @@ class BoxConstraints { | ||
162 | return BoxConstraints( | 158 | return BoxConstraints( |
163 | minWidth: width == null ? minWidth : width.clamp(minWidth, maxWidth), | 159 | minWidth: width == null ? minWidth : width.clamp(minWidth, maxWidth), |
164 | maxWidth: width == null ? maxWidth : width.clamp(minWidth, maxWidth), | 160 | maxWidth: width == null ? maxWidth : width.clamp(minWidth, maxWidth), |
165 | - minHeight: | ||
166 | - height == null ? minHeight : height.clamp(minHeight, maxHeight), | ||
167 | - maxHeight: | ||
168 | - height == null ? maxHeight : height.clamp(minHeight, maxHeight)); | 161 | + minHeight: height == null ? minHeight : height.clamp(minHeight, maxHeight), |
162 | + maxHeight: height == null ? maxHeight : height.clamp(minHeight, maxHeight)); | ||
169 | } | 163 | } |
170 | 164 | ||
171 | /// Returns new box constraints that are smaller by the given edge dimensions. | 165 | /// Returns new box constraints that are smaller by the given edge dimensions. |
@@ -197,17 +191,11 @@ class BoxConstraints { | @@ -197,17 +191,11 @@ class BoxConstraints { | ||
197 | return BoxConstraints( | 191 | return BoxConstraints( |
198 | minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth), | 192 | minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth), |
199 | maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth), | 193 | maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth), |
200 | - minHeight: | ||
201 | - minHeight.clamp(constraints.minHeight, constraints.maxHeight), | ||
202 | - maxHeight: | ||
203 | - maxHeight.clamp(constraints.minHeight, constraints.maxHeight)); | 194 | + minHeight: minHeight.clamp(constraints.minHeight, constraints.maxHeight), |
195 | + maxHeight: maxHeight.clamp(constraints.minHeight, constraints.maxHeight)); | ||
204 | } | 196 | } |
205 | 197 | ||
206 | - BoxConstraints copyWith( | ||
207 | - {double? minWidth, | ||
208 | - double? maxWidth, | ||
209 | - double? minHeight, | ||
210 | - double? maxHeight}) { | 198 | + BoxConstraints copyWith({double? minWidth, double? maxWidth, double? minHeight, double? maxHeight}) { |
211 | return BoxConstraints( | 199 | return BoxConstraints( |
212 | minWidth: minWidth ?? this.minWidth, | 200 | minWidth: minWidth ?? this.minWidth, |
213 | maxWidth: maxWidth ?? this.maxWidth, | 201 | maxWidth: maxWidth ?? this.maxWidth, |
@@ -222,7 +210,96 @@ class BoxConstraints { | @@ -222,7 +210,96 @@ class BoxConstraints { | ||
222 | } | 210 | } |
223 | 211 | ||
224 | @immutable | 212 | @immutable |
225 | -class EdgeInsets { | 213 | +abstract class EdgeInsetsGeometry { |
214 | + /// Abstract const constructor. This constructor enables subclasses to provide | ||
215 | + /// const constructors so that they can be used in const expressions. | ||
216 | + const EdgeInsetsGeometry(); | ||
217 | + | ||
218 | + double get _bottom; | ||
219 | + | ||
220 | + double get _end; | ||
221 | + | ||
222 | + double get _left; | ||
223 | + | ||
224 | + double get _right; | ||
225 | + | ||
226 | + double get _start; | ||
227 | + | ||
228 | + double get _top; | ||
229 | + | ||
230 | + /// The total offset in the horizontal direction. | ||
231 | + double get horizontal => _left + _right + _start + _end; | ||
232 | + | ||
233 | + /// The total offset in the vertical direction. | ||
234 | + double get vertical => _top + _bottom; | ||
235 | + | ||
236 | + /// Convert this instance into an [EdgeInsets], which uses literal coordinates | ||
237 | + /// (i.e. the `left` coordinate being explicitly a distance from the left, and | ||
238 | + /// the `right` coordinate being explicitly a distance from the right). | ||
239 | + /// | ||
240 | + /// See also: | ||
241 | + /// | ||
242 | + /// * [EdgeInsets], for which this is a no-op (returns itself). | ||
243 | + /// * [EdgeInsetsDirectional], which flips the horizontal direction | ||
244 | + /// based on the `direction` argument. | ||
245 | + EdgeInsets resolve(TextDirection? direction); | ||
246 | + | ||
247 | + /// Returns the sum of two [EdgeInsetsGeometry] objects. | ||
248 | + /// | ||
249 | + /// If you know you are adding two [EdgeInsets] or two [EdgeInsetsDirectional] | ||
250 | + /// objects, consider using the `+` operator instead, which always returns an | ||
251 | + /// object of the same type as the operands, and is typed accordingly. | ||
252 | + /// | ||
253 | + /// If [add] is applied to two objects of the same type ([EdgeInsets] or | ||
254 | + /// [EdgeInsetsDirectional]), an object of that type will be returned (though | ||
255 | + /// this is not reflected in the type system). Otherwise, an object | ||
256 | + /// representing a combination of both is returned. That object can be turned | ||
257 | + /// into a concrete [EdgeInsets] using [resolve]. | ||
258 | + EdgeInsetsGeometry add(EdgeInsetsGeometry other) { | ||
259 | + return _MixedEdgeInsets.fromLRSETB( | ||
260 | + _left + other._left, | ||
261 | + _right + other._right, | ||
262 | + _start + other._start, | ||
263 | + _end + other._end, | ||
264 | + _top + other._top, | ||
265 | + _bottom + other._bottom, | ||
266 | + ); | ||
267 | + } | ||
268 | + | ||
269 | + @override | ||
270 | + String toString() { | ||
271 | + if (_start == 0.0 && _end == 0.0) { | ||
272 | + if (_left == 0.0 && _right == 0.0 && _top == 0.0 && _bottom == 0.0) { | ||
273 | + return 'EdgeInsets.zero'; | ||
274 | + } | ||
275 | + if (_left == _right && _right == _top && _top == _bottom) { | ||
276 | + return 'EdgeInsets.all(${_left.toStringAsFixed(1)})'; | ||
277 | + } | ||
278 | + return 'EdgeInsets(${_left.toStringAsFixed(1)}, ' | ||
279 | + '${_top.toStringAsFixed(1)}, ' | ||
280 | + '${_right.toStringAsFixed(1)}, ' | ||
281 | + '${_bottom.toStringAsFixed(1)})'; | ||
282 | + } | ||
283 | + if (_left == 0.0 && _right == 0.0) { | ||
284 | + return 'EdgeInsetsDirectional(${_start.toStringAsFixed(1)}, ' | ||
285 | + '${_top.toStringAsFixed(1)}, ' | ||
286 | + '${_end.toStringAsFixed(1)}, ' | ||
287 | + '${_bottom.toStringAsFixed(1)})'; | ||
288 | + } | ||
289 | + return 'EdgeInsets(${_left.toStringAsFixed(1)}, ' | ||
290 | + '${_top.toStringAsFixed(1)}, ' | ||
291 | + '${_right.toStringAsFixed(1)}, ' | ||
292 | + '${_bottom.toStringAsFixed(1)})' | ||
293 | + ' + ' | ||
294 | + 'EdgeInsetsDirectional(${_start.toStringAsFixed(1)}, ' | ||
295 | + '0.0, ' | ||
296 | + '${_end.toStringAsFixed(1)}, ' | ||
297 | + '0.0)'; | ||
298 | + } | ||
299 | +} | ||
300 | + | ||
301 | +@immutable | ||
302 | +class EdgeInsets extends EdgeInsetsGeometry { | ||
226 | const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom); | 303 | const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom); |
227 | 304 | ||
228 | const EdgeInsets.all(double value) | 305 | const EdgeInsets.all(double value) |
@@ -231,8 +308,7 @@ class EdgeInsets { | @@ -231,8 +308,7 @@ class EdgeInsets { | ||
231 | right = value, | 308 | right = value, |
232 | bottom = value; | 309 | bottom = value; |
233 | 310 | ||
234 | - const EdgeInsets.only( | ||
235 | - {this.left = 0.0, this.top = 0.0, this.right = 0.0, this.bottom = 0.0}); | 311 | + const EdgeInsets.only({this.left = 0.0, this.top = 0.0, this.right = 0.0, this.bottom = 0.0}); |
236 | 312 | ||
237 | const EdgeInsets.symmetric({double vertical = 0.0, double horizontal = 0.0}) | 313 | const EdgeInsets.symmetric({double vertical = 0.0, double horizontal = 0.0}) |
238 | : left = horizontal, | 314 | : left = horizontal, |
@@ -242,19 +318,45 @@ class EdgeInsets { | @@ -242,19 +318,45 @@ class EdgeInsets { | ||
242 | 318 | ||
243 | static const EdgeInsets zero = EdgeInsets.only(); | 319 | static const EdgeInsets zero = EdgeInsets.only(); |
244 | 320 | ||
321 | + /// The offset from the left. | ||
245 | final double left; | 322 | final double left; |
246 | 323 | ||
324 | + @override | ||
325 | + double get _left => left; | ||
326 | + | ||
327 | + /// The offset from the top. | ||
247 | final double top; | 328 | final double top; |
248 | 329 | ||
330 | + @override | ||
331 | + double get _top => top; | ||
332 | + | ||
333 | + /// The offset from the right. | ||
249 | final double right; | 334 | final double right; |
250 | 335 | ||
336 | + @override | ||
337 | + double get _right => right; | ||
338 | + | ||
339 | + /// The offset from the bottom. | ||
251 | final double bottom; | 340 | final double bottom; |
252 | 341 | ||
253 | - /// The total offset in the horizontal direction. | ||
254 | - double get horizontal => left + right; | 342 | + @override |
343 | + double get _bottom => bottom; | ||
255 | 344 | ||
256 | - /// The total offset in the vertical direction. | ||
257 | - double get vertical => top + bottom; | 345 | + @override |
346 | + double get _start => 0.0; | ||
347 | + | ||
348 | + @override | ||
349 | + double get _end => 0.0; | ||
350 | + | ||
351 | + /// Returns the sum of two [EdgeInsets]. | ||
352 | + EdgeInsets operator +(EdgeInsets other) { | ||
353 | + return EdgeInsets.fromLTRB( | ||
354 | + left + other.left, | ||
355 | + top + other.top, | ||
356 | + right + other.right, | ||
357 | + bottom + other.bottom, | ||
358 | + ); | ||
359 | + } | ||
258 | 360 | ||
259 | EdgeInsets copyWith({ | 361 | EdgeInsets copyWith({ |
260 | double? left, | 362 | double? left, |
@@ -270,18 +372,198 @@ class EdgeInsets { | @@ -270,18 +372,198 @@ class EdgeInsets { | ||
270 | ); | 372 | ); |
271 | } | 373 | } |
272 | 374 | ||
273 | - /// Returns the sum of two [EdgeInsets] objects. | ||
274 | - EdgeInsets add(EdgeInsets other) { | ||
275 | - return EdgeInsets.fromLTRB( | ||
276 | - left + other.left, | 375 | + @override |
376 | + EdgeInsetsGeometry add(EdgeInsetsGeometry other) { | ||
377 | + if (other is EdgeInsets) { | ||
378 | + return this + other; | ||
379 | + } | ||
380 | + return super.add(other); | ||
381 | + } | ||
382 | + | ||
383 | + @override | ||
384 | + EdgeInsets resolve(TextDirection? direction) => this; | ||
385 | +} | ||
386 | + | ||
387 | +class _MixedEdgeInsets extends EdgeInsetsGeometry { | ||
388 | + const _MixedEdgeInsets.fromLRSETB(this._left, this._right, this._start, this._end, this._top, this._bottom); | ||
389 | + | ||
390 | + @override | ||
391 | + final double _left; | ||
392 | + | ||
393 | + @override | ||
394 | + final double _right; | ||
395 | + | ||
396 | + @override | ||
397 | + final double _start; | ||
398 | + | ||
399 | + @override | ||
400 | + final double _end; | ||
401 | + | ||
402 | + @override | ||
403 | + final double _top; | ||
404 | + | ||
405 | + @override | ||
406 | + final double _bottom; | ||
407 | + | ||
408 | + @override | ||
409 | + EdgeInsets resolve(TextDirection? direction) { | ||
410 | + assert(direction != null); | ||
411 | + switch (direction!) { | ||
412 | + case TextDirection.rtl: | ||
413 | + return EdgeInsets.fromLTRB(_end + _left, _top, _start + _right, _bottom); | ||
414 | + case TextDirection.ltr: | ||
415 | + return EdgeInsets.fromLTRB(_start + _left, _top, _end + _right, _bottom); | ||
416 | + } | ||
417 | + } | ||
418 | +} | ||
419 | + | ||
420 | +/// An immutable set of offsets in each of the four cardinal directions, but | ||
421 | +/// whose horizontal components are dependent on the writing direction. | ||
422 | +/// | ||
423 | +/// This can be used to indicate padding from the left in [TextDirection.ltr] | ||
424 | +/// text and padding from the right in [TextDirection.rtl] text without having | ||
425 | +/// to be aware of the current text direction. | ||
426 | +/// | ||
427 | +/// See also: | ||
428 | +/// | ||
429 | +/// * [EdgeInsets], a variant that uses physical labels (left and right instead | ||
430 | +/// of start and end). | ||
431 | +class EdgeInsetsDirectional extends EdgeInsetsGeometry { | ||
432 | + /// Creates insets from offsets from the start, top, end, and bottom. | ||
433 | + const EdgeInsetsDirectional.fromSTEB(this.start, this.top, this.end, this.bottom); | ||
434 | + | ||
435 | + /// Creates insets with only the given values non-zero. | ||
436 | + /// | ||
437 | + /// {@tool snippet} | ||
438 | + /// | ||
439 | + /// A margin indent of 40 pixels on the leading side: | ||
440 | + /// | ||
441 | + /// ```dart | ||
442 | + /// const EdgeInsetsDirectional.only(start: 40.0) | ||
443 | + /// ``` | ||
444 | + /// {@end-tool} | ||
445 | + const EdgeInsetsDirectional.only({ | ||
446 | + this.start = 0.0, | ||
447 | + this.top = 0.0, | ||
448 | + this.end = 0.0, | ||
449 | + this.bottom = 0.0, | ||
450 | + }); | ||
451 | + | ||
452 | + /// Creates insets with symmetric vertical and horizontal offsets. | ||
453 | + /// | ||
454 | + /// This is equivalent to [EdgeInsets.symmetric], since the inset is the same | ||
455 | + /// with either [TextDirection]. This constructor is just a convenience for | ||
456 | + /// type compatibility. | ||
457 | + /// | ||
458 | + /// {@tool snippet} | ||
459 | + /// Eight pixel margin above and below, no horizontal margins: | ||
460 | + /// | ||
461 | + /// ```dart | ||
462 | + /// const EdgeInsetsDirectional.symmetric(vertical: 8.0) | ||
463 | + /// ``` | ||
464 | + /// {@end-tool} | ||
465 | + const EdgeInsetsDirectional.symmetric({ | ||
466 | + double horizontal = 0.0, | ||
467 | + double vertical = 0.0, | ||
468 | + }) : start = horizontal, | ||
469 | + end = horizontal, | ||
470 | + top = vertical, | ||
471 | + bottom = vertical; | ||
472 | + | ||
473 | + /// Creates insets where all the offsets are `value`. | ||
474 | + /// | ||
475 | + /// {@tool snippet} | ||
476 | + /// | ||
477 | + /// Typical eight-pixel margin on all sides: | ||
478 | + /// | ||
479 | + /// ```dart | ||
480 | + /// const EdgeInsetsDirectional.all(8.0) | ||
481 | + /// ``` | ||
482 | + /// {@end-tool} | ||
483 | + const EdgeInsetsDirectional.all(double value) | ||
484 | + : start = value, | ||
485 | + top = value, | ||
486 | + end = value, | ||
487 | + bottom = value; | ||
488 | + | ||
489 | + /// An [EdgeInsetsDirectional] with zero offsets in each direction. | ||
490 | + /// | ||
491 | + /// Consider using [EdgeInsets.zero] instead, since that object has the same | ||
492 | + /// effect, but will be cheaper to [resolve]. | ||
493 | + static const EdgeInsetsDirectional zero = EdgeInsetsDirectional.only(); | ||
494 | + | ||
495 | + /// The offset from the start side, the side from which the user will start | ||
496 | + /// reading text. | ||
497 | + /// | ||
498 | + /// This value is normalized into an [EdgeInsets.left] or [EdgeInsets.right] | ||
499 | + /// value by the [resolve] method. | ||
500 | + final double start; | ||
501 | + | ||
502 | + @override | ||
503 | + double get _start => start; | ||
504 | + | ||
505 | + /// The offset from the top. | ||
506 | + /// | ||
507 | + /// This value is passed through to [EdgeInsets.top] unmodified by the | ||
508 | + /// [resolve] method. | ||
509 | + final double top; | ||
510 | + | ||
511 | + @override | ||
512 | + double get _top => top; | ||
513 | + | ||
514 | + /// The offset from the end side, the side on which the user ends reading | ||
515 | + /// text. | ||
516 | + /// | ||
517 | + /// This value is normalized into an [EdgeInsets.left] or [EdgeInsets.right] | ||
518 | + /// value by the [resolve] method. | ||
519 | + final double end; | ||
520 | + | ||
521 | + @override | ||
522 | + double get _end => end; | ||
523 | + | ||
524 | + /// The offset from the bottom. | ||
525 | + /// | ||
526 | + /// This value is passed through to [EdgeInsets.bottom] unmodified by the | ||
527 | + /// [resolve] method. | ||
528 | + final double bottom; | ||
529 | + | ||
530 | + @override | ||
531 | + double get _bottom => bottom; | ||
532 | + | ||
533 | + @override | ||
534 | + double get _left => 0.0; | ||
535 | + | ||
536 | + @override | ||
537 | + double get _right => 0.0; | ||
538 | + | ||
539 | + @override | ||
540 | + EdgeInsetsGeometry add(EdgeInsetsGeometry other) { | ||
541 | + if (other is EdgeInsetsDirectional) { | ||
542 | + return this + other; | ||
543 | + } | ||
544 | + return super.add(other); | ||
545 | + } | ||
546 | + | ||
547 | + /// Returns the sum of two [EdgeInsetsDirectional] objects. | ||
548 | + EdgeInsetsDirectional operator +(EdgeInsetsDirectional other) { | ||
549 | + return EdgeInsetsDirectional.fromSTEB( | ||
550 | + start + other.start, | ||
277 | top + other.top, | 551 | top + other.top, |
278 | - right + other.right, | 552 | + end + other.end, |
279 | bottom + other.bottom, | 553 | bottom + other.bottom, |
280 | ); | 554 | ); |
281 | } | 555 | } |
282 | 556 | ||
283 | @override | 557 | @override |
284 | - String toString() => 'EdgeInsets $left, $top, $right, $bottom'; | 558 | + EdgeInsets resolve(TextDirection? direction) { |
559 | + assert(direction != null); | ||
560 | + switch (direction!) { | ||
561 | + case TextDirection.rtl: | ||
562 | + return EdgeInsets.fromLTRB(end, top, start, bottom); | ||
563 | + case TextDirection.ltr: | ||
564 | + return EdgeInsets.fromLTRB(start, top, end, bottom); | ||
565 | + } | ||
566 | + } | ||
285 | } | 567 | } |
286 | 568 | ||
287 | class Alignment { | 569 | class Alignment { |
@@ -374,10 +656,7 @@ class FittedSizes { | @@ -374,10 +656,7 @@ class FittedSizes { | ||
374 | } | 656 | } |
375 | 657 | ||
376 | FittedSizes applyBoxFit(BoxFit fit, PdfPoint inputSize, PdfPoint outputSize) { | 658 | FittedSizes applyBoxFit(BoxFit fit, PdfPoint inputSize, PdfPoint outputSize) { |
377 | - if (inputSize.y <= 0.0 || | ||
378 | - inputSize.x <= 0.0 || | ||
379 | - outputSize.y <= 0.0 || | ||
380 | - outputSize.x <= 0.0) { | 659 | + if (inputSize.y <= 0.0 || inputSize.x <= 0.0 || outputSize.y <= 0.0 || outputSize.x <= 0.0) { |
381 | return const FittedSizes(PdfPoint.zero, PdfPoint.zero); | 660 | return const FittedSizes(PdfPoint.zero, PdfPoint.zero); |
382 | } | 661 | } |
383 | 662 | ||
@@ -390,38 +669,29 @@ FittedSizes applyBoxFit(BoxFit fit, PdfPoint inputSize, PdfPoint outputSize) { | @@ -390,38 +669,29 @@ FittedSizes applyBoxFit(BoxFit fit, PdfPoint inputSize, PdfPoint outputSize) { | ||
390 | case BoxFit.contain: | 669 | case BoxFit.contain: |
391 | sourceSize = inputSize; | 670 | sourceSize = inputSize; |
392 | if (outputSize.x / outputSize.y > sourceSize.x / sourceSize.y) { | 671 | if (outputSize.x / outputSize.y > sourceSize.x / sourceSize.y) { |
393 | - destinationSize = | ||
394 | - PdfPoint(sourceSize.x * outputSize.y / sourceSize.y, outputSize.y); | 672 | + destinationSize = PdfPoint(sourceSize.x * outputSize.y / sourceSize.y, outputSize.y); |
395 | } else { | 673 | } else { |
396 | - destinationSize = | ||
397 | - PdfPoint(outputSize.x, sourceSize.y * outputSize.x / sourceSize.x); | 674 | + destinationSize = PdfPoint(outputSize.x, sourceSize.y * outputSize.x / sourceSize.x); |
398 | } | 675 | } |
399 | break; | 676 | break; |
400 | case BoxFit.cover: | 677 | case BoxFit.cover: |
401 | if (outputSize.x / outputSize.y > inputSize.x / inputSize.y) { | 678 | if (outputSize.x / outputSize.y > inputSize.x / inputSize.y) { |
402 | - sourceSize = | ||
403 | - PdfPoint(inputSize.x, inputSize.x * outputSize.y / outputSize.x); | 679 | + sourceSize = PdfPoint(inputSize.x, inputSize.x * outputSize.y / outputSize.x); |
404 | } else { | 680 | } else { |
405 | - sourceSize = | ||
406 | - PdfPoint(inputSize.y * outputSize.x / outputSize.y, inputSize.y); | 681 | + sourceSize = PdfPoint(inputSize.y * outputSize.x / outputSize.y, inputSize.y); |
407 | } | 682 | } |
408 | destinationSize = outputSize; | 683 | destinationSize = outputSize; |
409 | break; | 684 | break; |
410 | case BoxFit.fitWidth: | 685 | case BoxFit.fitWidth: |
411 | - sourceSize = | ||
412 | - PdfPoint(inputSize.x, inputSize.x * outputSize.y / outputSize.x); | ||
413 | - destinationSize = | ||
414 | - PdfPoint(outputSize.x, sourceSize.y * outputSize.x / sourceSize.x); | 686 | + sourceSize = PdfPoint(inputSize.x, inputSize.x * outputSize.y / outputSize.x); |
687 | + destinationSize = PdfPoint(outputSize.x, sourceSize.y * outputSize.x / sourceSize.x); | ||
415 | break; | 688 | break; |
416 | case BoxFit.fitHeight: | 689 | case BoxFit.fitHeight: |
417 | - sourceSize = | ||
418 | - PdfPoint(inputSize.y * outputSize.x / outputSize.y, inputSize.y); | ||
419 | - destinationSize = | ||
420 | - PdfPoint(sourceSize.x * outputSize.y / sourceSize.y, outputSize.y); | 690 | + sourceSize = PdfPoint(inputSize.y * outputSize.x / outputSize.y, inputSize.y); |
691 | + destinationSize = PdfPoint(sourceSize.x * outputSize.y / sourceSize.y, outputSize.y); | ||
421 | break; | 692 | break; |
422 | case BoxFit.none: | 693 | case BoxFit.none: |
423 | - sourceSize = PdfPoint(math.min(inputSize.x, outputSize.x), | ||
424 | - math.min(inputSize.y, outputSize.y)); | 694 | + sourceSize = PdfPoint(math.min(inputSize.x, outputSize.x), math.min(inputSize.y, outputSize.y)); |
425 | destinationSize = sourceSize; | 695 | destinationSize = sourceSize; |
426 | break; | 696 | break; |
427 | case BoxFit.scaleDown: | 697 | case BoxFit.scaleDown: |
@@ -61,14 +61,12 @@ mixin SpanningWidget on Widget { | @@ -61,14 +61,12 @@ mixin SpanningWidget on Widget { | ||
61 | /// Called before relayout to restore the saved state and | 61 | /// Called before relayout to restore the saved state and |
62 | /// restart the layout in the same conditions | 62 | /// restart the layout in the same conditions |
63 | @protected | 63 | @protected |
64 | - void applyContext(covariant WidgetContext context) => | ||
65 | - saveContext().apply(context); | 64 | + void applyContext(covariant WidgetContext context) => saveContext().apply(context); |
66 | } | 65 | } |
67 | 66 | ||
68 | class NewPage extends Widget { | 67 | class NewPage extends Widget { |
69 | @override | 68 | @override |
70 | - void layout(Context context, BoxConstraints constraints, | ||
71 | - {bool parentUsesSize = false}) { | 69 | + void layout(Context context, BoxConstraints constraints, {bool parentUsesSize = false}) { |
72 | box = PdfRect.zero; | 70 | box = PdfRect.zero; |
73 | } | 71 | } |
74 | } | 72 | } |
@@ -151,7 +149,7 @@ class MultiPage extends Page { | @@ -151,7 +149,7 @@ class MultiPage extends Page { | ||
151 | ThemeData? theme, | 149 | ThemeData? theme, |
152 | this.maxPages = 20, | 150 | this.maxPages = 20, |
153 | PageOrientation? orientation, | 151 | PageOrientation? orientation, |
154 | - EdgeInsets? margin, | 152 | + EdgeInsetsGeometry? margin, |
155 | TextDirection? textDirection, | 153 | TextDirection? textDirection, |
156 | }) : _buildList = build, | 154 | }) : _buildList = build, |
157 | assert(maxPages > 0), | 155 | assert(maxPages > 0), |
@@ -185,10 +183,9 @@ class MultiPage extends Page { | @@ -185,10 +183,9 @@ class MultiPage extends Page { | ||
185 | /// This is not checked with a Release build. | 183 | /// This is not checked with a Release build. |
186 | final int maxPages; | 184 | final int maxPages; |
187 | 185 | ||
188 | - void _paintChild( | ||
189 | - Context context, Widget child, double x, double y, double pageHeight) { | 186 | + void _paintChild(Context context, Widget child, double x, double y, double pageHeight) { |
190 | if (mustRotate) { | 187 | if (mustRotate) { |
191 | - final _margin = margin!; | 188 | + final _margin = resolvedMargin!; |
192 | context.canvas | 189 | context.canvas |
193 | ..saveContext() | 190 | ..saveContext() |
194 | ..setTransform(Matrix4.identity() | 191 | ..setTransform(Matrix4.identity() |
@@ -198,10 +195,21 @@ class MultiPage extends Page { | @@ -198,10 +195,21 @@ class MultiPage extends Page { | ||
198 | y + _margin.left - _margin.bottom, | 195 | y + _margin.left - _margin.bottom, |
199 | )); | 196 | )); |
200 | 197 | ||
198 | + final availableWidth = pageHeight - resolvedMargin!.vertical; | ||
199 | + if (pageTheme.textDirection == TextDirection.rtl) { | ||
200 | + child.box = child.box!.copyWith( | ||
201 | + x: (availableWidth - child.box!.width) + child.box!.x, | ||
202 | + ); | ||
203 | + } | ||
201 | child.paint(context); | 204 | child.paint(context); |
202 | context.canvas.restoreContext(); | 205 | context.canvas.restoreContext(); |
203 | } else { | 206 | } else { |
204 | - child.box = PdfRect(x, y, child.box!.width, child.box!.height); | 207 | + var childXPos = x; |
208 | + if (pageTheme.textDirection == TextDirection.rtl) { | ||
209 | + final availableWidth = pageFormat.width - resolvedMargin!.horizontal; | ||
210 | + childXPos = (availableWidth - child.box!.width) + x; | ||
211 | + } | ||
212 | + child.box = child.box!.copyWith(x: childXPos, y: y); | ||
205 | child.paint(context); | 213 | child.paint(context); |
206 | } | 214 | } |
207 | } | 215 | } |
@@ -211,33 +219,26 @@ class MultiPage extends Page { | @@ -211,33 +219,26 @@ class MultiPage extends Page { | ||
211 | assert(pageFormat.width > 0 && pageFormat.width < double.infinity); | 219 | assert(pageFormat.width > 0 && pageFormat.width < double.infinity); |
212 | assert(pageFormat.height > 0 && pageFormat.height < double.infinity); | 220 | assert(pageFormat.height > 0 && pageFormat.height < double.infinity); |
213 | 221 | ||
214 | - final _margin = margin; | 222 | + final _margin = resolvedMargin!; |
215 | final _mustRotate = mustRotate; | 223 | final _mustRotate = mustRotate; |
216 | final pageHeight = _mustRotate ? pageFormat.width : pageFormat.height; | 224 | final pageHeight = _mustRotate ? pageFormat.width : pageFormat.height; |
217 | - final pageHeightMargin = | ||
218 | - _mustRotate ? _margin!.horizontal : _margin!.vertical; | 225 | + final pageHeightMargin = _mustRotate ? _margin.horizontal : _margin.vertical; |
219 | final constraints = BoxConstraints( | 226 | final constraints = BoxConstraints( |
220 | - maxWidth: _mustRotate | ||
221 | - ? (pageFormat.height - _margin.vertical) | ||
222 | - : (pageFormat.width - _margin.horizontal)); | 227 | + maxWidth: _mustRotate ? (pageFormat.height - _margin.vertical) : (pageFormat.width - _margin.horizontal)); |
223 | final fullConstraints = mustRotate | 228 | final fullConstraints = mustRotate |
224 | ? BoxConstraints( | 229 | ? BoxConstraints( |
225 | - maxWidth: pageFormat.height - _margin.vertical, | ||
226 | - maxHeight: pageFormat.width - _margin.horizontal) | 230 | + maxWidth: pageFormat.height - _margin.vertical, maxHeight: pageFormat.width - _margin.horizontal) |
227 | : BoxConstraints( | 231 | : BoxConstraints( |
228 | - maxWidth: pageFormat.width - _margin.horizontal, | ||
229 | - maxHeight: pageFormat.height - _margin.vertical); | 232 | + maxWidth: pageFormat.width - _margin.horizontal, maxHeight: pageFormat.height - _margin.vertical); |
230 | final calculatedTheme = theme ?? document.theme ?? ThemeData.base(); | 233 | final calculatedTheme = theme ?? document.theme ?? ThemeData.base(); |
231 | Context? context; | 234 | Context? context; |
232 | late double offsetEnd; | 235 | late double offsetEnd; |
233 | double? offsetStart; | 236 | double? offsetStart; |
234 | var _index = 0; | 237 | var _index = 0; |
235 | var sameCount = 0; | 238 | var sameCount = 0; |
236 | - final baseContext = | ||
237 | - Context(document: document.document).inheritFromAll(<Inherited>[ | 239 | + final baseContext = Context(document: document.document).inheritFromAll(<Inherited>[ |
238 | calculatedTheme, | 240 | calculatedTheme, |
239 | - if (pageTheme.textDirection != null) | ||
240 | - InheritedDirectionality(pageTheme.textDirection), | 241 | + if (pageTheme.textDirection != null) InheritedDirectionality(pageTheme.textDirection), |
241 | ]); | 242 | ]); |
242 | final children = _buildList(baseContext); | 243 | final children = _buildList(baseContext); |
243 | WidgetContext? widgetContext; | 244 | WidgetContext? widgetContext; |
@@ -272,10 +273,8 @@ class MultiPage extends Page { | @@ -272,10 +273,8 @@ class MultiPage extends Page { | ||
272 | return true; | 273 | return true; |
273 | }()); | 274 | }()); |
274 | 275 | ||
275 | - offsetStart = pageHeight - | ||
276 | - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); | ||
277 | - offsetEnd = | ||
278 | - _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; | 276 | + offsetStart = pageHeight - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); |
277 | + offsetEnd = _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; | ||
279 | 278 | ||
280 | _pages.add(_MultiPageInstance( | 279 | _pages.add(_MultiPageInstance( |
281 | context: context, | 280 | context: context, |
@@ -327,8 +326,7 @@ class MultiPage extends Page { | @@ -327,8 +326,7 @@ class MultiPage extends Page { | ||
327 | 326 | ||
328 | // Else we crash if the widget is too big and cannot be separated | 327 | // Else we crash if the widget is too big and cannot be separated |
329 | if (!canSpan) { | 328 | if (!canSpan) { |
330 | - throw Exception( | ||
331 | - 'Widget won\'t fit into the page as its height (${child.box!.height}) ' | 329 | + throw Exception('Widget won\'t fit into the page as its height (${child.box!.height}) ' |
332 | 'exceed a page height (${pageHeight - pageHeightMargin}). ' | 330 | 'exceed a page height (${pageHeight - pageHeightMargin}). ' |
333 | 'You probably need a SpanningWidget or use a single page layout'); | 331 | 'You probably need a SpanningWidget or use a single page layout'); |
334 | } | 332 | } |
@@ -340,8 +338,7 @@ class MultiPage extends Page { | @@ -340,8 +338,7 @@ class MultiPage extends Page { | ||
340 | span.applyContext(savedContext); | 338 | span.applyContext(savedContext); |
341 | } | 339 | } |
342 | 340 | ||
343 | - final localConstraints = | ||
344 | - constraints.copyWith(maxHeight: offsetStart - offsetEnd); | 341 | + final localConstraints = constraints.copyWith(maxHeight: offsetStart - offsetEnd); |
345 | span.layout(context, localConstraints, parentUsesSize: false); | 342 | span.layout(context, localConstraints, parentUsesSize: false); |
346 | assert(span.box != null); | 343 | assert(span.box != null); |
347 | widgetContext = span.saveContext(); | 344 | widgetContext = span.saveContext(); |
@@ -368,8 +365,7 @@ class MultiPage extends Page { | @@ -368,8 +365,7 @@ class MultiPage extends Page { | ||
368 | _MultiPageWidget( | 365 | _MultiPageWidget( |
369 | child: child, | 366 | child: child, |
370 | constraints: constraints, | 367 | constraints: constraints, |
371 | - widgetContext: | ||
372 | - child is SpanningWidget && canSpan ? child.cloneContext() : null, | 368 | + widgetContext: child is SpanningWidget && canSpan ? child.cloneContext() : null, |
373 | ), | 369 | ), |
374 | ); | 370 | ); |
375 | 371 | ||
@@ -381,28 +377,24 @@ class MultiPage extends Page { | @@ -381,28 +377,24 @@ class MultiPage extends Page { | ||
381 | 377 | ||
382 | @override | 378 | @override |
383 | void postProcess(Document document) { | 379 | void postProcess(Document document) { |
384 | - final _margin = margin; | 380 | + final _margin = resolvedMargin!; |
385 | final _mustRotate = mustRotate; | 381 | final _mustRotate = mustRotate; |
386 | final pageHeight = _mustRotate ? pageFormat.width : pageFormat.height; | 382 | final pageHeight = _mustRotate ? pageFormat.width : pageFormat.height; |
387 | final pageWidth = _mustRotate ? pageFormat.height : pageFormat.width; | 383 | final pageWidth = _mustRotate ? pageFormat.height : pageFormat.width; |
388 | - final pageHeightMargin = | ||
389 | - _mustRotate ? _margin!.horizontal : _margin!.vertical; | 384 | + final pageHeightMargin = _mustRotate ? _margin.horizontal : _margin.vertical; |
390 | final pageWidthMargin = _mustRotate ? _margin.vertical : _margin.horizontal; | 385 | final pageWidthMargin = _mustRotate ? _margin.vertical : _margin.horizontal; |
391 | final availableWidth = pageWidth - pageWidthMargin; | 386 | final availableWidth = pageWidth - pageWidthMargin; |
392 | 387 | ||
393 | for (final page in _pages) { | 388 | for (final page in _pages) { |
394 | - var offsetStart = pageHeight - | ||
395 | - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); | ||
396 | - var offsetEnd = | ||
397 | - _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; | 389 | + var offsetStart = pageHeight - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); |
390 | + var offsetEnd = _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; | ||
398 | 391 | ||
399 | if (pageTheme.buildBackground != null) { | 392 | if (pageTheme.buildBackground != null) { |
400 | final child = pageTheme.buildBackground!(page.context); | 393 | final child = pageTheme.buildBackground!(page.context); |
401 | 394 | ||
402 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); | 395 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); |
403 | assert(child.box != null); | 396 | assert(child.box != null); |
404 | - _paintChild(page.context, child, _margin.left, _margin.bottom, | ||
405 | - pageFormat.height); | 397 | + _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); |
406 | } | 398 | } |
407 | 399 | ||
408 | var totalFlex = 0; | 400 | var totalFlex = 0; |
@@ -428,23 +420,20 @@ class MultiPage extends Page { | @@ -428,23 +420,20 @@ class MultiPage extends Page { | ||
428 | if (header != null) { | 420 | if (header != null) { |
429 | final headerWidget = header!(page.context); | 421 | final headerWidget = header!(page.context); |
430 | 422 | ||
431 | - headerWidget.layout(page.context, page.constraints, | ||
432 | - parentUsesSize: false); | 423 | + headerWidget.layout(page.context, page.constraints, parentUsesSize: false); |
433 | assert(headerWidget.box != null); | 424 | assert(headerWidget.box != null); |
434 | offsetStart -= headerWidget.box!.height; | 425 | offsetStart -= headerWidget.box!.height; |
435 | - _paintChild(page.context, headerWidget, _margin.left, | ||
436 | - page.offsetStart! - headerWidget.box!.height, pageFormat.height); | 426 | + _paintChild( |
427 | + page.context, headerWidget, _margin.left, page.offsetStart! - headerWidget.box!.height, pageFormat.height); | ||
437 | } | 428 | } |
438 | 429 | ||
439 | if (footer != null) { | 430 | if (footer != null) { |
440 | final footerWidget = footer!(page.context); | 431 | final footerWidget = footer!(page.context); |
441 | 432 | ||
442 | - footerWidget.layout(page.context, page.constraints, | ||
443 | - parentUsesSize: false); | 433 | + footerWidget.layout(page.context, page.constraints, parentUsesSize: false); |
444 | assert(footerWidget.box != null); | 434 | assert(footerWidget.box != null); |
445 | offsetEnd += footerWidget.box!.height; | 435 | offsetEnd += footerWidget.box!.height; |
446 | - _paintChild(page.context, footerWidget, _margin.left, _margin.bottom, | ||
447 | - pageFormat.height); | 436 | + _paintChild(page.context, footerWidget, _margin.left, _margin.bottom, pageFormat.height); |
448 | } | 437 | } |
449 | 438 | ||
450 | final freeSpace = math.max(0.0, offsetStart - offsetEnd - allocatedSize); | 439 | final freeSpace = math.max(0.0, offsetStart - offsetEnd - allocatedSize); |
@@ -473,16 +462,14 @@ class MultiPage extends Page { | @@ -473,16 +462,14 @@ class MultiPage extends Page { | ||
473 | break; | 462 | break; |
474 | case MainAxisAlignment.spaceBetween: | 463 | case MainAxisAlignment.spaceBetween: |
475 | leadingSpace = 0.0; | 464 | leadingSpace = 0.0; |
476 | - betweenSpace = | ||
477 | - totalChildren > 1 ? freeSpace / (totalChildren - 1) : 0.0; | 465 | + betweenSpace = totalChildren > 1 ? freeSpace / (totalChildren - 1) : 0.0; |
478 | break; | 466 | break; |
479 | case MainAxisAlignment.spaceAround: | 467 | case MainAxisAlignment.spaceAround: |
480 | betweenSpace = totalChildren > 0 ? freeSpace / totalChildren : 0.0; | 468 | betweenSpace = totalChildren > 0 ? freeSpace / totalChildren : 0.0; |
481 | leadingSpace = betweenSpace / 2.0; | 469 | leadingSpace = betweenSpace / 2.0; |
482 | break; | 470 | break; |
483 | case MainAxisAlignment.spaceEvenly: | 471 | case MainAxisAlignment.spaceEvenly: |
484 | - betweenSpace = | ||
485 | - totalChildren > 0 ? freeSpace / (totalChildren + 1) : 0.0; | 472 | + betweenSpace = totalChildren > 0 ? freeSpace / (totalChildren + 1) : 0.0; |
486 | leadingSpace = betweenSpace; | 473 | leadingSpace = betweenSpace; |
487 | break; | 474 | break; |
488 | } | 475 | } |
@@ -494,11 +481,8 @@ class MultiPage extends Page { | @@ -494,11 +481,8 @@ class MultiPage extends Page { | ||
494 | final flex = child is Flexible ? child.flex : 0; | 481 | final flex = child is Flexible ? child.flex : 0; |
495 | final fit = child is Flexible ? child.fit : FlexFit.loose; | 482 | final fit = child is Flexible ? child.fit : FlexFit.loose; |
496 | if (flex > 0) { | 483 | if (flex > 0) { |
497 | - assert(child is! SpanningWidget || child.canSpan == false, | ||
498 | - 'Cannot have a spanning widget flexible'); | ||
499 | - final maxChildExtent = child == lastFlexChild | ||
500 | - ? (freeSpace - allocatedFlexSpace) | ||
501 | - : spacePerFlex * flex; | 484 | + assert(child is! SpanningWidget || child.canSpan == false, 'Cannot have a spanning widget flexible'); |
485 | + final maxChildExtent = child == lastFlexChild ? (freeSpace - allocatedFlexSpace) : spacePerFlex * flex; | ||
502 | late double minChildExtent; | 486 | late double minChildExtent; |
503 | switch (fit) { | 487 | switch (fit) { |
504 | case FlexFit.tight: | 488 | case FlexFit.tight: |
@@ -547,8 +531,7 @@ class MultiPage extends Page { | @@ -547,8 +531,7 @@ class MultiPage extends Page { | ||
547 | if (child is SpanningWidget && child.canSpan) { | 531 | if (child is SpanningWidget && child.canSpan) { |
548 | child.applyContext(widget.widgetContext!); | 532 | child.applyContext(widget.widgetContext!); |
549 | } | 533 | } |
550 | - _paintChild(page.context, widget.child, _margin.left + x, pos, | ||
551 | - pageFormat.height); | 534 | + _paintChild(page.context, widget.child, _margin.left + x, pos, pageFormat.height); |
552 | pos -= betweenSpace; | 535 | pos -= betweenSpace; |
553 | } | 536 | } |
554 | 537 | ||
@@ -557,8 +540,7 @@ class MultiPage extends Page { | @@ -557,8 +540,7 @@ class MultiPage extends Page { | ||
557 | 540 | ||
558 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); | 541 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); |
559 | assert(child.box != null); | 542 | assert(child.box != null); |
560 | - _paintChild(page.context, child, _margin.left, _margin.bottom, | ||
561 | - pageFormat.height); | 543 | + _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); |
562 | } | 544 | } |
563 | } | 545 | } |
564 | } | 546 | } |
@@ -40,7 +40,7 @@ class Page { | @@ -40,7 +40,7 @@ class Page { | ||
40 | required BuildCallback build, | 40 | required BuildCallback build, |
41 | ThemeData? theme, | 41 | ThemeData? theme, |
42 | PageOrientation? orientation, | 42 | PageOrientation? orientation, |
43 | - EdgeInsets? margin, | 43 | + EdgeInsetsGeometry? margin, |
44 | bool clip = false, | 44 | bool clip = false, |
45 | TextDirection? textDirection, | 45 | TextDirection? textDirection, |
46 | }) : assert( | 46 | }) : assert( |
@@ -77,11 +77,14 @@ class Page { | @@ -77,11 +77,14 @@ class Page { | ||
77 | 77 | ||
78 | PdfPage? _pdfPage; | 78 | PdfPage? _pdfPage; |
79 | 79 | ||
80 | - EdgeInsets? get margin => pageTheme.margin; | 80 | + EdgeInsetsGeometry? get margin => pageTheme.margin; |
81 | + | ||
82 | + EdgeInsets? get resolvedMargin => margin?.resolve(pageTheme.textDirection); | ||
81 | 83 | ||
82 | @protected | 84 | @protected |
83 | void debugPaint(Context context) { | 85 | void debugPaint(Context context) { |
84 | - final _margin = margin!; | 86 | + final _margin = resolvedMargin!; |
87 | + | ||
85 | context.canvas | 88 | context.canvas |
86 | ..setFillColor(PdfColors.lightGreen) | 89 | ..setFillColor(PdfColors.lightGreen) |
87 | ..moveTo(0, 0) | 90 | ..moveTo(0, 0) |
@@ -90,8 +93,7 @@ class Page { | @@ -90,8 +93,7 @@ class Page { | ||
90 | ..lineTo(0, pageFormat.height) | 93 | ..lineTo(0, pageFormat.height) |
91 | ..moveTo(_margin.left, _margin.bottom) | 94 | ..moveTo(_margin.left, _margin.bottom) |
92 | ..lineTo(_margin.left, pageFormat.height - _margin.top) | 95 | ..lineTo(_margin.left, pageFormat.height - _margin.top) |
93 | - ..lineTo( | ||
94 | - pageFormat.width - _margin.right, pageFormat.height - _margin.top) | 96 | + ..lineTo(pageFormat.width - _margin.right, pageFormat.height - _margin.top) |
95 | ..lineTo(pageFormat.width - _margin.right, _margin.bottom) | 97 | ..lineTo(pageFormat.width - _margin.right, _margin.bottom) |
96 | ..fillPath(); | 98 | ..fillPath(); |
97 | } | 99 | } |
@@ -99,8 +101,7 @@ class Page { | @@ -99,8 +101,7 @@ class Page { | ||
99 | void generate(Document document, {bool insert = true, int? index}) { | 101 | void generate(Document document, {bool insert = true, int? index}) { |
100 | if (index != null) { | 102 | if (index != null) { |
101 | if (insert) { | 103 | if (insert) { |
102 | - _pdfPage = | ||
103 | - PdfPage(document.document, pageFormat: pageFormat, index: index); | 104 | + _pdfPage = PdfPage(document.document, pageFormat: pageFormat, index: index); |
104 | } else { | 105 | } else { |
105 | _pdfPage = document.document.page(index); | 106 | _pdfPage = document.document.page(index); |
106 | } | 107 | } |
@@ -112,14 +113,12 @@ class Page { | @@ -112,14 +113,12 @@ class Page { | ||
112 | void postProcess(Document document) { | 113 | void postProcess(Document document) { |
113 | final canvas = _pdfPage!.getGraphics(); | 114 | final canvas = _pdfPage!.getGraphics(); |
114 | canvas.reset(); | 115 | canvas.reset(); |
115 | - final _margin = margin; | 116 | + final _margin = resolvedMargin; |
116 | var constraints = mustRotate | 117 | var constraints = mustRotate |
117 | ? BoxConstraints( | 118 | ? BoxConstraints( |
118 | - maxWidth: pageFormat.height - _margin!.vertical, | ||
119 | - maxHeight: pageFormat.width - _margin.horizontal) | 119 | + maxWidth: pageFormat.height - _margin!.vertical, maxHeight: pageFormat.width - _margin.horizontal) |
120 | : BoxConstraints( | 120 | : BoxConstraints( |
121 | - maxWidth: pageFormat.width - _margin!.horizontal, | ||
122 | - maxHeight: pageFormat.height - _margin.vertical); | 121 | + maxWidth: pageFormat.width - _margin!.horizontal, maxHeight: pageFormat.height - _margin.vertical); |
123 | 122 | ||
124 | final calculatedTheme = theme ?? document.theme ?? ThemeData.base(); | 123 | final calculatedTheme = theme ?? document.theme ?? ThemeData.base(); |
125 | final context = Context( | 124 | final context = Context( |
@@ -128,8 +127,7 @@ class Page { | @@ -128,8 +127,7 @@ class Page { | ||
128 | canvas: canvas, | 127 | canvas: canvas, |
129 | ).inheritFromAll(<Inherited>[ | 128 | ).inheritFromAll(<Inherited>[ |
130 | calculatedTheme, | 129 | calculatedTheme, |
131 | - if (pageTheme.textDirection != null) | ||
132 | - InheritedDirectionality(pageTheme.textDirection), | 130 | + if (pageTheme.textDirection != null) InheritedDirectionality(pageTheme.textDirection), |
133 | ]); | 131 | ]); |
134 | 132 | ||
135 | Widget? background; | 133 | Widget? background; |
@@ -141,8 +139,7 @@ class Page { | @@ -141,8 +139,7 @@ class Page { | ||
141 | final size = layout(content, context, constraints); | 139 | final size = layout(content, context, constraints); |
142 | 140 | ||
143 | if (_pdfPage!.pageFormat.height == double.infinity) { | 141 | if (_pdfPage!.pageFormat.height == double.infinity) { |
144 | - _pdfPage!.pageFormat = | ||
145 | - _pdfPage!.pageFormat.copyWith(width: size.x, height: size.y); | 142 | + _pdfPage!.pageFormat = _pdfPage!.pageFormat.copyWith(width: size.x, height: size.y); |
146 | constraints = mustRotate | 143 | constraints = mustRotate |
147 | ? BoxConstraints( | 144 | ? BoxConstraints( |
148 | maxWidth: _pdfPage!.pageFormat.height - _margin.vertical, | 145 | maxWidth: _pdfPage!.pageFormat.height - _margin.vertical, |
@@ -181,43 +178,49 @@ class Page { | @@ -181,43 +178,49 @@ class Page { | ||
181 | } | 178 | } |
182 | 179 | ||
183 | @protected | 180 | @protected |
184 | - PdfPoint layout(Widget child, Context context, BoxConstraints constraints, | ||
185 | - {bool parentUsesSize = false}) { | ||
186 | - final _margin = margin!; | 181 | + PdfPoint layout(Widget child, Context context, BoxConstraints constraints, {bool parentUsesSize = false}) { |
182 | + final _margin = resolvedMargin!; | ||
187 | child.layout(context, constraints, parentUsesSize: parentUsesSize); | 183 | child.layout(context, constraints, parentUsesSize: parentUsesSize); |
188 | assert(child.box != null); | 184 | assert(child.box != null); |
189 | 185 | ||
190 | - final width = pageFormat.width == double.infinity | ||
191 | - ? child.box!.width + _margin.left + _margin.right | ||
192 | - : pageFormat.width; | 186 | + final width = |
187 | + pageFormat.width == double.infinity ? child.box!.width + _margin.left + _margin.right : pageFormat.width; | ||
193 | 188 | ||
194 | - final height = pageFormat.height == double.infinity | ||
195 | - ? child.box!.height + _margin.top + _margin.bottom | ||
196 | - : pageFormat.height; | 189 | + final height = |
190 | + pageFormat.height == double.infinity ? child.box!.height + _margin.top + _margin.bottom : pageFormat.height; | ||
197 | 191 | ||
198 | - child.box = PdfRect(_margin.left, height - child.box!.height - _margin.top, | ||
199 | - child.box!.width, child.box!.height); | 192 | + child.box = PdfRect(_margin.left, height - child.box!.height - _margin.top, child.box!.width, child.box!.height); |
200 | 193 | ||
201 | return PdfPoint(width, height); | 194 | return PdfPoint(width, height); |
202 | } | 195 | } |
203 | 196 | ||
204 | @protected | 197 | @protected |
205 | void paint(Widget child, Context context) { | 198 | void paint(Widget child, Context context) { |
199 | + final _margin = resolvedMargin!; | ||
200 | + final box = PdfRect( | ||
201 | + _margin.left, | ||
202 | + _margin.bottom, | ||
203 | + pageFormat.width - _margin.horizontal, | ||
204 | + pageFormat.height - _margin.vertical, | ||
205 | + ); | ||
206 | if (pageTheme.clip) { | 206 | if (pageTheme.clip) { |
207 | - final _margin = margin!; | ||
208 | context.canvas | 207 | context.canvas |
209 | ..saveContext() | 208 | ..saveContext() |
210 | - ..drawRect( | ||
211 | - _margin.left, | ||
212 | - _margin.bottom, | ||
213 | - pageFormat.width - _margin.horizontal, | ||
214 | - pageFormat.height - _margin.vertical, | ||
215 | - ) | 209 | + ..drawRect(box.x, box.y, box.width, box.height) |
216 | ..clipPath(); | 210 | ..clipPath(); |
217 | } | 211 | } |
218 | 212 | ||
213 | + if (pageTheme.textDirection == TextDirection.rtl) { | ||
214 | + child.box = PdfRect( | ||
215 | + ((mustRotate ? box.height : box.width) - child.box!.width) + child.box!.x, | ||
216 | + child.box!.y, | ||
217 | + child.box!.width, | ||
218 | + child.box!.height, | ||
219 | + ); | ||
220 | + } | ||
221 | + | ||
219 | if (mustRotate) { | 222 | if (mustRotate) { |
220 | - final _margin = margin!; | 223 | + final _margin = resolvedMargin!; |
221 | context.canvas | 224 | context.canvas |
222 | ..saveContext() | 225 | ..saveContext() |
223 | ..setTransform(Matrix4.identity() | 226 | ..setTransform(Matrix4.identity() |
@@ -30,7 +30,7 @@ class PageTheme { | @@ -30,7 +30,7 @@ class PageTheme { | ||
30 | this.buildForeground, | 30 | this.buildForeground, |
31 | this.theme, | 31 | this.theme, |
32 | PageOrientation? orientation, | 32 | PageOrientation? orientation, |
33 | - EdgeInsets? margin, | 33 | + EdgeInsetsGeometry? margin, |
34 | this.clip = false, | 34 | this.clip = false, |
35 | this.textDirection, | 35 | this.textDirection, |
36 | }) : pageFormat = pageFormat ?? PdfPageFormat.standard, | 36 | }) : pageFormat = pageFormat ?? PdfPageFormat.standard, |
@@ -41,7 +41,7 @@ class PageTheme { | @@ -41,7 +41,7 @@ class PageTheme { | ||
41 | 41 | ||
42 | final PageOrientation orientation; | 42 | final PageOrientation orientation; |
43 | 43 | ||
44 | - final EdgeInsets? _margin; | 44 | + final EdgeInsetsGeometry? _margin; |
45 | 45 | ||
46 | final BuildCallback? buildBackground; | 46 | final BuildCallback? buildBackground; |
47 | 47 | ||
@@ -54,27 +54,30 @@ class PageTheme { | @@ -54,27 +54,30 @@ class PageTheme { | ||
54 | final TextDirection? textDirection; | 54 | final TextDirection? textDirection; |
55 | 55 | ||
56 | bool get mustRotate => | 56 | bool get mustRotate => |
57 | - (orientation == PageOrientation.landscape && | ||
58 | - pageFormat.height > pageFormat.width) || | ||
59 | - (orientation == PageOrientation.portrait && | ||
60 | - pageFormat.width > pageFormat.height); | 57 | + (orientation == PageOrientation.landscape && pageFormat.height > pageFormat.width) || |
58 | + (orientation == PageOrientation.portrait && pageFormat.width > pageFormat.height); | ||
61 | 59 | ||
62 | - EdgeInsets? get margin { | 60 | + EdgeInsetsGeometry? get margin { |
63 | if (_margin != null) { | 61 | if (_margin != null) { |
62 | + final effectiveMargin = _margin!.resolve(textDirection); | ||
64 | if (mustRotate) { | 63 | if (mustRotate) { |
65 | return EdgeInsets.fromLTRB( | 64 | return EdgeInsets.fromLTRB( |
66 | - _margin!.bottom, _margin!.left, _margin!.top, _margin!.right); | 65 | + effectiveMargin.bottom, |
66 | + effectiveMargin.left, | ||
67 | + effectiveMargin.top, | ||
68 | + effectiveMargin.right, | ||
69 | + ); | ||
67 | } else { | 70 | } else { |
68 | return _margin; | 71 | return _margin; |
69 | } | 72 | } |
70 | } | 73 | } |
71 | 74 | ||
72 | if (mustRotate) { | 75 | if (mustRotate) { |
73 | - return EdgeInsets.fromLTRB(pageFormat.marginBottom, pageFormat.marginLeft, | ||
74 | - pageFormat.marginTop, pageFormat.marginRight); | 76 | + return EdgeInsets.fromLTRB( |
77 | + pageFormat.marginBottom, pageFormat.marginLeft, pageFormat.marginTop, pageFormat.marginRight); | ||
75 | } else { | 78 | } else { |
76 | - return EdgeInsets.fromLTRB(pageFormat.marginLeft, pageFormat.marginTop, | ||
77 | - pageFormat.marginRight, pageFormat.marginBottom); | 79 | + return EdgeInsets.fromLTRB( |
80 | + pageFormat.marginLeft, pageFormat.marginTop, pageFormat.marginRight, pageFormat.marginBottom); | ||
78 | } | 81 | } |
79 | } | 82 | } |
80 | 83 |
@@ -40,11 +40,7 @@ final _yellowBox = Container( | @@ -40,11 +40,7 @@ final _yellowBox = Container( | ||
40 | color: PdfColors.yellow, | 40 | color: PdfColors.yellow, |
41 | ); | 41 | ); |
42 | 42 | ||
43 | -final _greenBox = Container( | ||
44 | - width: 50, | ||
45 | - height: 50, | ||
46 | - color: PdfColors.green, | ||
47 | -); | 43 | + |
48 | void main() { | 44 | void main() { |
49 | setUpAll(() { | 45 | setUpAll(() { |
50 | Document.debug = true; | 46 | Document.debug = true; |
@@ -143,10 +139,9 @@ void main() { | @@ -143,10 +139,9 @@ void main() { | ||
143 | build: (Context context) => SizedBox( | 139 | build: (Context context) => SizedBox( |
144 | width: 150, | 140 | width: 150, |
145 | height: 150, | 141 | height: 150, |
146 | - child: Wrap( | ||
147 | - children: [_blueBox, _redBox,_yellowBox], | ||
148 | - ) | ||
149 | - ), | 142 | + child: Wrap( |
143 | + children: [_blueBox, _redBox, _yellowBox], | ||
144 | + )), | ||
150 | ), | 145 | ), |
151 | ); | 146 | ); |
152 | }); | 147 | }); |
@@ -160,9 +155,8 @@ void main() { | @@ -160,9 +155,8 @@ void main() { | ||
160 | width: 150, | 155 | width: 150, |
161 | height: 150, | 156 | height: 150, |
162 | child: Wrap( | 157 | child: Wrap( |
163 | - children: [_blueBox, _redBox,_yellowBox], | ||
164 | - ) | ||
165 | - ), | 158 | + children: [_blueBox, _redBox, _yellowBox], |
159 | + )), | ||
166 | ), | 160 | ), |
167 | ); | 161 | ); |
168 | }); | 162 | }); |
@@ -178,9 +172,8 @@ void main() { | @@ -178,9 +172,8 @@ void main() { | ||
178 | spacing: 10, | 172 | spacing: 10, |
179 | runSpacing: 10, | 173 | runSpacing: 10, |
180 | runAlignment: WrapAlignment.center, | 174 | runAlignment: WrapAlignment.center, |
181 | - children: [_blueBox, _redBox,_yellowBox], | ||
182 | - ) | ||
183 | - ), | 175 | + children: [_blueBox, _redBox, _yellowBox], |
176 | + )), | ||
184 | ), | 177 | ), |
185 | ); | 178 | ); |
186 | }); | 179 | }); |
@@ -197,9 +190,96 @@ void main() { | @@ -197,9 +190,96 @@ void main() { | ||
197 | spacing: 10, | 190 | spacing: 10, |
198 | runSpacing: 10, | 191 | runSpacing: 10, |
199 | runAlignment: WrapAlignment.end, | 192 | runAlignment: WrapAlignment.end, |
200 | - children: [_blueBox, _redBox,_yellowBox], | ||
201 | - ) | ||
202 | - ), | 193 | + children: [_blueBox, _redBox, _yellowBox], |
194 | + )), | ||
195 | + ), | ||
196 | + ); | ||
197 | + }); | ||
198 | + | ||
199 | + test('RTL Page Should render child aligned right', () { | ||
200 | + pdf.addPage( | ||
201 | + Page( | ||
202 | + textDirection: TextDirection.rtl, | ||
203 | + pageFormat: const PdfPageFormat(150, 150), | ||
204 | + build: (Context context) { | ||
205 | + return _blueBox; | ||
206 | + }, | ||
207 | + ), | ||
208 | + ); | ||
209 | + }); | ||
210 | + | ||
211 | + test('LTR Page Should render child aligned left', () { | ||
212 | + pdf.addPage( | ||
213 | + Page( | ||
214 | + textDirection: TextDirection.ltr, | ||
215 | + pageFormat: const PdfPageFormat(150, 150), | ||
216 | + build: (Context context) { | ||
217 | + return _blueBox; | ||
218 | + }, | ||
219 | + ), | ||
220 | + ); | ||
221 | + }); | ||
222 | + | ||
223 | + test('RTL Multi Page Should render child aligned right', () { | ||
224 | + pdf.addPage( | ||
225 | + MultiPage( | ||
226 | + textDirection: TextDirection.rtl, | ||
227 | + pageFormat: const PdfPageFormat(150, 150), | ||
228 | + build: (Context context) { | ||
229 | + return [ | ||
230 | + ListView(children: [ | ||
231 | + for(int i = 0; i < 30; i++) | ||
232 | + Text('Hello World') | ||
233 | + ]), | ||
234 | + ]; | ||
235 | + }, | ||
236 | + ), | ||
237 | + ); | ||
238 | + }); | ||
239 | + | ||
240 | + test('LTR Multi Page Should render child aligned left', () { | ||
241 | + pdf.addPage( | ||
242 | + MultiPage( | ||
243 | + textDirection: TextDirection.ltr, | ||
244 | + pageFormat: const PdfPageFormat(150, 150), | ||
245 | + build: (Context context) { | ||
246 | + return [ | ||
247 | + ListView(children: [ | ||
248 | + for(int i = 0; i < 30; i++) | ||
249 | + Text('Hello World') | ||
250 | + ]), | ||
251 | + ]; | ||
252 | + }, | ||
253 | + ), | ||
254 | + ); | ||
255 | + }); | ||
256 | + | ||
257 | + test('Should render a blue box padded from right', () { | ||
258 | + pdf.addPage( | ||
259 | + Page( | ||
260 | + textDirection: TextDirection.rtl, | ||
261 | + pageFormat: const PdfPageFormat(150, 150), | ||
262 | + build: (Context context) { | ||
263 | + return Padding( | ||
264 | + padding: const EdgeInsetsDirectional.only(start: 20), | ||
265 | + child: _blueBox, | ||
266 | + ); | ||
267 | + }, | ||
268 | + ), | ||
269 | + ); | ||
270 | + }); | ||
271 | + | ||
272 | + test('Should render a blue box padded from left', () { | ||
273 | + pdf.addPage( | ||
274 | + Page( | ||
275 | + textDirection: TextDirection.ltr, | ||
276 | + pageFormat: const PdfPageFormat(150, 150), | ||
277 | + build: (Context context) { | ||
278 | + return Padding( | ||
279 | + padding: const EdgeInsetsDirectional.only(start: 20), | ||
280 | + child: _blueBox, | ||
281 | + ); | ||
282 | + }, | ||
203 | ), | 283 | ), |
204 | ); | 284 | ); |
205 | }); | 285 | }); |
-
Please register or login to post a comment