David PHAM-VAN

Improve Annotations placement

@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 4
5 - Apply BoxShape and BorderRadius to selected Checkbox [Joseph Grabinger] 5 - Apply BoxShape and BorderRadius to selected Checkbox [Joseph Grabinger]
6 - Fix Color.toHex() 6 - Fix Color.toHex()
  7 +- Improve Annotations placement
7 8
8 ## 3.9.0 9 ## 3.9.0
9 10
@@ -20,7 +20,7 @@ import 'dart:typed_data'; @@ -20,7 +20,7 @@ import 'dart:typed_data';
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 '../priv.dart'; 23 +import '../pdf/data_types.dart';
24 import 'basic.dart'; 24 import 'basic.dart';
25 import 'border_radius.dart'; 25 import 'border_radius.dart';
26 import 'box_border.dart'; 26 import 'box_border.dart';
@@ -32,7 +32,57 @@ import 'text_style.dart'; @@ -32,7 +32,57 @@ import 'text_style.dart';
32 import 'theme.dart'; 32 import 'theme.dart';
33 import 'widget.dart'; 33 import 'widget.dart';
34 34
35 -class ChoiceField extends StatelessWidget { 35 +mixin AnnotationAppearance on Widget {
  36 + void drawAppearance(
  37 + Context context,
  38 + PdfAnnotBase bf,
  39 + Matrix4 mat,
  40 + Widget child, {
  41 + PdfAnnotAppearance type = PdfAnnotAppearance.normal,
  42 + PdfName? tag,
  43 + String? name,
  44 + bool selected = false,
  45 + }) {
  46 + final canvas = bf.appearance(
  47 + context.document,
  48 + type,
  49 + matrix: mat,
  50 + boundingBox: PdfRect(0, 0, box!.width, box!.height),
  51 + name: name,
  52 + selected: selected,
  53 + );
  54 +
  55 + if (tag != null) {
  56 + canvas.markContentBegin(tag);
  57 + }
  58 +
  59 + Widget.draw(
  60 + child,
  61 + offset: PdfPoint.zero,
  62 + canvas: canvas,
  63 + page: context.page,
  64 + constraints:
  65 + BoxConstraints.tightFor(width: box!.width, height: box!.height),
  66 + );
  67 +
  68 + if (tag != null) {
  69 + canvas.markContentEnd();
  70 + }
  71 + }
  72 +
  73 + Matrix4 getAppearanceMatrix(Context context) {
  74 + final translation = Vector3(0, 0, 0);
  75 + final rotation = Quaternion(0, 0, 0, 0);
  76 + final scale = Vector3(0, 0, 0);
  77 +
  78 + return context.canvas.getTransform()
  79 + ..decompose(translation, rotation, scale)
  80 + ..leftTranslate(-translation.x, -translation.y)
  81 + ..translate(box!.x, box!.y);
  82 + }
  83 +}
  84 +
  85 +class ChoiceField extends StatelessWidget with AnnotationAppearance {
36 ChoiceField({ 86 ChoiceField({
37 this.width = 120, 87 this.width = 120,
38 this.height = 13, 88 this.height = 13,
@@ -63,6 +113,19 @@ class ChoiceField extends StatelessWidget { @@ -63,6 +113,19 @@ class ChoiceField extends StatelessWidget {
63 items: items, 113 items: items,
64 rect: pdfRect, 114 rect: pdfRect,
65 ); 115 );
  116 +
  117 + if (value != null) {
  118 + final mat = getAppearanceMatrix(context);
  119 +
  120 + drawAppearance(
  121 + context,
  122 + bf,
  123 + mat,
  124 + Text(value!, style: _textStyle),
  125 + tag: const PdfName('/Tx'),
  126 + );
  127 + }
  128 +
66 PdfAnnot(context.page, bf); 129 PdfAnnot(context.page, bf);
67 } 130 }
68 131
@@ -72,7 +135,7 @@ class ChoiceField extends StatelessWidget { @@ -72,7 +135,7 @@ class ChoiceField extends StatelessWidget {
72 } 135 }
73 } 136 }
74 137
75 -class Checkbox extends SingleChildWidget { 138 +class Checkbox extends SingleChildWidget with AnnotationAppearance {
76 Checkbox({ 139 Checkbox({
77 required this.value, 140 required this.value,
78 this.tristate = false, 141 this.tristate = false,
@@ -82,10 +145,10 @@ class Checkbox extends SingleChildWidget { @@ -82,10 +145,10 @@ class Checkbox extends SingleChildWidget {
82 double width = 13, 145 double width = 13,
83 double height = 13, 146 double height = 13,
84 BoxDecoration? decoration, 147 BoxDecoration? decoration,
85 - }) : radius = decoration?.shape == BoxShape.circle  
86 - ? Radius.circular(math.max(height, width)/2)  
87 - : decoration?.borderRadius?.topLeft ?? Radius.zero,  
88 - super( 148 + }) : radius = decoration?.shape == BoxShape.circle
  149 + ? Radius.circular(math.max(height, width) / 2)
  150 + : decoration?.borderRadius?.topLeft ?? Radius.zero,
  151 + super(
89 child: Container( 152 child: Container(
90 width: width, 153 width: width,
91 height: height, 154 height: height,
@@ -112,7 +175,6 @@ class Checkbox extends SingleChildWidget { @@ -112,7 +175,6 @@ class Checkbox extends SingleChildWidget {
112 @override 175 @override
113 void paint(Context context) { 176 void paint(Context context) {
114 super.paint(context); 177 super.paint(context);
115 - paintChild(context);  
116 178
117 final bf = PdfButtonField( 179 final bf = PdfButtonField(
118 rect: context.localToGlobal(box!), 180 rect: context.localToGlobal(box!),
@@ -122,26 +184,45 @@ class Checkbox extends SingleChildWidget { @@ -122,26 +184,45 @@ class Checkbox extends SingleChildWidget {
122 flags: <PdfAnnotFlags>{PdfAnnotFlags.print}, 184 flags: <PdfAnnotFlags>{PdfAnnotFlags.print},
123 ); 185 );
124 186
125 - final g = bf.appearance(context.document, PdfAnnotAppearance.normal,  
126 - name: '/Yes', selected: value);  
127 - g.drawRRect(0, 0, bf.rect.width, bf.rect.height, radius.y, radius.x);  
128 - g.setFillColor(activeColor);  
129 - g.fillPath();  
130 - g.moveTo(2, bf.rect.height / 2);  
131 - g.lineTo(bf.rect.width / 3, bf.rect.height / 4);  
132 - g.lineTo(bf.rect.width - 2, bf.rect.height / 4 * 3);  
133 - g.setStrokeColor(checkColor);  
134 - g.setLineWidth(2);  
135 - g.strokePath();  
136 -  
137 - bf.appearance(context.document, PdfAnnotAppearance.normal,  
138 - name: '/Off', selected: !value); 187 + final mat = getAppearanceMatrix(context);
  188 +
  189 + drawAppearance(
  190 + context,
  191 + bf,
  192 + mat,
  193 + name: '/Yes',
  194 + selected: value,
  195 + CustomPaint(
  196 + size: bf.rect.size,
  197 + painter: (canvas, size) {
  198 + canvas.drawRRect(
  199 + 0, 0, bf.rect.width, bf.rect.height, radius.y, radius.x);
  200 + canvas.setFillColor(activeColor);
  201 + canvas.fillPath();
  202 + canvas.moveTo(2, bf.rect.height / 2);
  203 + canvas.lineTo(bf.rect.width / 3, bf.rect.height / 4);
  204 + canvas.lineTo(bf.rect.width - 2, bf.rect.height / 4 * 3);
  205 + canvas.setStrokeColor(checkColor);
  206 + canvas.setLineWidth(2);
  207 + canvas.strokePath();
  208 + },
  209 + ),
  210 + );
  211 +
  212 + drawAppearance(
  213 + context,
  214 + bf,
  215 + mat,
  216 + name: '/Off',
  217 + selected: !value,
  218 + child!,
  219 + );
139 220
140 PdfAnnot(context.page, bf); 221 PdfAnnot(context.page, bf);
141 } 222 }
142 } 223 }
143 224
144 -class FlatButton extends SingleChildWidget { 225 +class FlatButton extends SingleChildWidget with AnnotationAppearance {
145 FlatButton({ 226 FlatButton({
146 PdfColor textColor = PdfColors.white, 227 PdfColor textColor = PdfColors.white,
147 PdfColor color = PdfColors.blue, 228 PdfColor color = PdfColors.blue,
@@ -213,53 +294,18 @@ class FlatButton extends SingleChildWidget { @@ -213,53 +294,18 @@ class FlatButton extends SingleChildWidget {
213 fieldFlags: <PdfFieldFlags>{PdfFieldFlags.pushButton}, 294 fieldFlags: <PdfFieldFlags>{PdfFieldFlags.pushButton},
214 ); 295 );
215 296
216 - final mat = context.canvas.getTransform();  
217 - final translation = Vector3(0, 0, 0);  
218 - final rotation = Quaternion(0, 0, 0, 0);  
219 - final scale = Vector3(0, 0, 0);  
220 - mat  
221 - ..decompose(translation, rotation, scale)  
222 - ..leftTranslate(-translation.x, -translation.y)  
223 - ..translate(box!.x, box!.y); 297 + final mat = getAppearanceMatrix(context);
224 298
225 - var canvas = bf.appearance(context.document, PdfAnnotAppearance.normal,  
226 - matrix: mat, boundingBox: box);  
227 - Widget.draw(  
228 - child!,  
229 - offset: PdfPoint.zero,  
230 - canvas: canvas,  
231 - page: context.page,  
232 - constraints:  
233 - BoxConstraints.tightFor(width: box!.width, height: box!.height),  
234 - );  
235 -  
236 - canvas = bf.appearance(context.document, PdfAnnotAppearance.down,  
237 - matrix: mat, boundingBox: box);  
238 - Widget.draw(  
239 - _childDown,  
240 - offset: PdfPoint.zero,  
241 - canvas: canvas,  
242 - page: context.page,  
243 - constraints:  
244 - BoxConstraints.tightFor(width: box!.width, height: box!.height),  
245 - );  
246 -  
247 - canvas = bf.appearance(context.document, PdfAnnotAppearance.rollover,  
248 - matrix: mat, boundingBox: box);  
249 - Widget.draw(  
250 - _childRollover,  
251 - offset: PdfPoint.zero,  
252 - canvas: canvas,  
253 - page: context.page,  
254 - constraints:  
255 - BoxConstraints.tightFor(width: box!.width, height: box!.height),  
256 - ); 299 + drawAppearance(context, bf, mat, child!);
  300 + drawAppearance(context, bf, mat, _childDown, type: PdfAnnotAppearance.down);
  301 + drawAppearance(context, bf, mat, _childRollover,
  302 + type: PdfAnnotAppearance.rollover);
257 303
258 PdfAnnot(context.page, bf); 304 PdfAnnot(context.page, bf);
259 } 305 }
260 } 306 }
261 307
262 -class TextField extends StatelessWidget { 308 +class TextField extends StatelessWidget with AnnotationAppearance {
263 TextField({ 309 TextField({
264 this.child, 310 this.child,
265 this.width = 120, 311 this.width = 120,
@@ -329,35 +375,23 @@ class TextField extends StatelessWidget { @@ -329,35 +375,23 @@ class TextField extends StatelessWidget {
329 textColor: _textStyle.color!, 375 textColor: _textStyle.color!,
330 ); 376 );
331 377
332 - final mat = context.canvas.getTransform();  
333 - final translation = Vector3(0, 0, 0);  
334 - final rotation = Quaternion(0, 0, 0, 0);  
335 - final scale = Vector3(0, 0, 0);  
336 - mat  
337 - ..decompose(translation, rotation, scale)  
338 - ..leftTranslate(-translation.x, -translation.y)  
339 - ..translate(box!.x, box!.y);  
340 -  
341 if (value != null) { 378 if (value != null) {
342 - final canvas = tf.appearance(context.document, PdfAnnotAppearance.normal,  
343 - matrix: mat, boundingBox: box);  
344 - canvas.markContentBegin(const PdfName('/Tx'));  
345 - Widget.draw( 379 + final mat = getAppearanceMatrix(context);
  380 +
  381 + drawAppearance(
  382 + context,
  383 + tf,
  384 + mat,
346 Text(value!, style: _textStyle), 385 Text(value!, style: _textStyle),
347 - offset: PdfPoint.zero,  
348 - canvas: canvas,  
349 - page: context.page,  
350 - constraints:  
351 - BoxConstraints.tightFor(width: box!.width, height: box!.height), 386 + tag: const PdfName('/Tx'),
352 ); 387 );
353 - canvas.markContentEnd();  
354 } 388 }
355 389
356 PdfAnnot(context.page, tf); 390 PdfAnnot(context.page, tf);
357 } 391 }
358 } 392 }
359 393
360 -class Signature extends SingleChildWidget { 394 +class Signature extends SingleChildWidget with AnnotationAppearance {
361 Signature({ 395 Signature({
362 Widget? child, 396 Widget? child,
363 @Deprecated('Use value instead') PdfSignatureBase? crypto, 397 @Deprecated('Use value instead') PdfSignatureBase? crypto,
@@ -438,25 +472,8 @@ class Signature extends SingleChildWidget { @@ -438,25 +472,8 @@ class Signature extends SingleChildWidget {
438 ); 472 );
439 473
440 if (child != null && value != null) { 474 if (child != null && value != null) {
441 - final mat = context.canvas.getTransform();  
442 - final translation = Vector3(0, 0, 0);  
443 - final rotation = Quaternion(0, 0, 0, 0);  
444 - final scale = Vector3(0, 0, 0);  
445 - mat  
446 - ..decompose(translation, rotation, scale)  
447 - ..leftTranslate(-translation.x, -translation.y)  
448 - ..translate(box!.x, box!.y);  
449 -  
450 - final canvas = bf.appearance(context.document, PdfAnnotAppearance.normal,  
451 - matrix: mat);  
452 - Widget.draw(  
453 - child!,  
454 - offset: PdfPoint.zero,  
455 - canvas: canvas,  
456 - page: context.page,  
457 - constraints:  
458 - BoxConstraints.tightFor(width: box!.width, height: box!.height),  
459 - ); 475 + final mat = getAppearanceMatrix(context);
  476 + drawAppearance(context, bf, mat, child!);
460 } 477 }
461 478
462 PdfAnnot(context.page, bf); 479 PdfAnnot(context.page, bf);