@qrcommunication/gigapdf-lib 0.1.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +213 -0
- package/README.md +54 -6
- package/dist/editor.cjs +1153 -0
- package/dist/editor.cjs.map +1 -0
- package/dist/editor.d.cts +96 -0
- package/dist/editor.d.ts +96 -0
- package/dist/editor.js +1126 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.cjs +467 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +203 -5
- package/dist/index.d.ts +203 -5
- package/dist/index.js +467 -7
- package/dist/index.js.map +1 -1
- package/dist/viewer.cjs +526 -0
- package/dist/viewer.cjs.map +1 -0
- package/dist/viewer.d.cts +144 -0
- package/dist/viewer.d.ts +144 -0
- package/dist/viewer.js +501 -0
- package/dist/viewer.js.map +1 -0
- package/gigapdf.wasm +0 -0
- package/package.json +12 -2
package/dist/index.cjs
CHANGED
|
@@ -125,6 +125,10 @@ var GigaPdfEngine = class _GigaPdfEngine {
|
|
|
125
125
|
this._free(ptr, b.length);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
/** Pass an optional string; an absent/empty value runs `fn(0, 0)` (no alloc). */
|
|
129
|
+
_withOptStr(s, fn) {
|
|
130
|
+
return s ? this._withStr(s, fn) : fn(0, 0);
|
|
131
|
+
}
|
|
128
132
|
/** Pass a bytes argument; runs `fn(ptr, len)` then frees. */
|
|
129
133
|
_withBytes(bytes, fn) {
|
|
130
134
|
const ptr = this._toWasm(bytes);
|
|
@@ -206,8 +210,194 @@ var GigaPdfEngine = class _GigaPdfEngine {
|
|
|
206
210
|
parseCssFontUrl(css) {
|
|
207
211
|
return this._withStr(css, (p, l) => this._str((o) => this.ex.gp_parse_css_font_url(p, l, o)));
|
|
208
212
|
}
|
|
213
|
+
// ── JavaScript engine (no headless browser) ────────────────────────────────
|
|
214
|
+
/**
|
|
215
|
+
* Evaluate a JavaScript snippet with the built-in engine and return the
|
|
216
|
+
* result value as a string (or `Uncaught …` / `SyntaxError: …`).
|
|
217
|
+
*/
|
|
218
|
+
evalJs(src) {
|
|
219
|
+
return this._withStr(src, (p, l) => this._str((o) => this.ex.gp_js_eval(p, l, o)));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Run a document's inline `<script>`s and return the resulting HTML. The
|
|
223
|
+
* `htmlRender`/`htmlNeededFonts` paths already do this automatically; use this
|
|
224
|
+
* only when you want the post-script HTML on its own.
|
|
225
|
+
*/
|
|
226
|
+
runInlineScripts(html) {
|
|
227
|
+
return this._withStr(
|
|
228
|
+
html,
|
|
229
|
+
(p, l) => this._str((o) => this.ex.gp_run_inline_scripts(p, l, o))
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
// ── HTML rendering engine (replaces a headless browser for HTML→PDF) ───────
|
|
233
|
+
/**
|
|
234
|
+
* Phase 1 — the Google fonts the document references. Download each `url`
|
|
235
|
+
* (→ TTF) and pass the bytes back to {@link htmlRender} for an identical render.
|
|
236
|
+
*/
|
|
237
|
+
htmlNeededFonts(html) {
|
|
238
|
+
return this._withStr(
|
|
239
|
+
html,
|
|
240
|
+
(p, l) => this._json((o) => this.ex.gp_html_needed_fonts(p, l, o))
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Phase 2 — render HTML + CSS to PDF, with the supplied fonts embedded (real
|
|
245
|
+
* Google fonts, real metrics → identical or nearest match). Block, inline and
|
|
246
|
+
* table layout with pagination. Page size and margin are in points
|
|
247
|
+
* (US-Letter portrait, 0.5in margins by default). JavaScript is not executed.
|
|
248
|
+
*/
|
|
249
|
+
htmlRender(html, fonts = [], pageWidth = 612, pageHeight = 792, margin = 36) {
|
|
250
|
+
const blob = packHtmlFonts(fonts);
|
|
251
|
+
return this._withStr(
|
|
252
|
+
html,
|
|
253
|
+
(hp, hl) => this._withBytes(
|
|
254
|
+
blob,
|
|
255
|
+
(fp, fl) => this._buffer((o) => this.ex.gp_html_render(hp, hl, fp, fl, pageWidth, pageHeight, margin, o))
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Resolve a named paper size — `"A4"`, `"a3-landscape"`, `"letter"`, `"legal"`,
|
|
261
|
+
* `"tabloid"`, `"b5"`, … — to `{ w, h }` in points (portrait unless the name
|
|
262
|
+
* has a `-landscape` suffix). Returns `null` for an unknown name.
|
|
263
|
+
*/
|
|
264
|
+
pageSize(name) {
|
|
265
|
+
const outPtr = this.ex.gp_alloc(16);
|
|
266
|
+
try {
|
|
267
|
+
const ok = this._withStr(
|
|
268
|
+
name,
|
|
269
|
+
(p, l) => this.ex.gp_page_size(p, l, outPtr, outPtr + 8)
|
|
270
|
+
);
|
|
271
|
+
if (!ok) return null;
|
|
272
|
+
const dv = this.dv();
|
|
273
|
+
return { w: dv.getFloat64(outPtr, true), h: dv.getFloat64(outPtr + 8, true) };
|
|
274
|
+
} finally {
|
|
275
|
+
this._free(outPtr, 16);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Phase 1 variant that also scans the running `header`/`footer` HTML, so the
|
|
280
|
+
* Google fonts they reference are requested alongside the body's.
|
|
281
|
+
*/
|
|
282
|
+
htmlNeededFontsWith(html, header, footer) {
|
|
283
|
+
return this._withStr(
|
|
284
|
+
html,
|
|
285
|
+
(hp, hl) => this._withOptStr(
|
|
286
|
+
header,
|
|
287
|
+
(hdp, hdl) => this._withOptStr(
|
|
288
|
+
footer,
|
|
289
|
+
(ftp, ftl) => this._json((o) => this.ex.gp_html_needed_fonts_ex(hp, hl, hdp, hdl, ftp, ftl, o))
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Phase 2 with full page control: named/explicit size, per-side margins, and a
|
|
296
|
+
* running header/footer painted in the page margins. `{{page}}` and `{{pages}}`
|
|
297
|
+
* in the header/footer are replaced with the current / total page number.
|
|
298
|
+
*
|
|
299
|
+
* ```ts
|
|
300
|
+
* const fonts = await fetchFonts(giga.htmlNeededFontsWith(html, header, footer));
|
|
301
|
+
* const pdf = giga.htmlRenderWith(html, fonts, {
|
|
302
|
+
* pageSize: "A4",
|
|
303
|
+
* margin: { top: 72, bottom: 72, left: 54, right: 54 },
|
|
304
|
+
* header: `<div style="text-align:center">My Report</div>`,
|
|
305
|
+
* footer: `<div style="text-align:center">Page {{page}} / {{pages}}</div>`,
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
htmlRenderWith(html, fonts = [], options = {}) {
|
|
310
|
+
let pw = options.pageWidth ?? 612;
|
|
311
|
+
let ph = options.pageHeight ?? 792;
|
|
312
|
+
if (options.pageSize) {
|
|
313
|
+
const sz = this.pageSize(options.pageSize);
|
|
314
|
+
if (!sz) throw new Error(`gigapdf: unknown page size "${options.pageSize}"`);
|
|
315
|
+
pw = sz.w;
|
|
316
|
+
ph = sz.h;
|
|
317
|
+
}
|
|
318
|
+
const m = options.margin ?? 36;
|
|
319
|
+
const mg = typeof m === "number" ? { top: m, right: m, bottom: m, left: m } : { top: m.top ?? 36, right: m.right ?? 36, bottom: m.bottom ?? 36, left: m.left ?? 36 };
|
|
320
|
+
const headerOffset = options.headerOffset ?? 18;
|
|
321
|
+
const footerOffset = options.footerOffset ?? 18;
|
|
322
|
+
const start = options.startPageNumber ?? 1;
|
|
323
|
+
const blob = packHtmlFonts(fonts);
|
|
324
|
+
return this._withStr(
|
|
325
|
+
html,
|
|
326
|
+
(hp, hl) => this._withBytes(
|
|
327
|
+
blob,
|
|
328
|
+
(fp, fl) => this._withOptStr(
|
|
329
|
+
options.header,
|
|
330
|
+
(hdp, hdl) => this._withOptStr(
|
|
331
|
+
options.footer,
|
|
332
|
+
(ftp, ftl) => this._buffer(
|
|
333
|
+
(o) => this.ex.gp_html_render_opts(
|
|
334
|
+
hp,
|
|
335
|
+
hl,
|
|
336
|
+
fp,
|
|
337
|
+
fl,
|
|
338
|
+
pw,
|
|
339
|
+
ph,
|
|
340
|
+
mg.top,
|
|
341
|
+
mg.right,
|
|
342
|
+
mg.bottom,
|
|
343
|
+
mg.left,
|
|
344
|
+
hdp,
|
|
345
|
+
hdl,
|
|
346
|
+
ftp,
|
|
347
|
+
ftl,
|
|
348
|
+
headerOffset,
|
|
349
|
+
footerOffset,
|
|
350
|
+
start,
|
|
351
|
+
o
|
|
352
|
+
)
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
);
|
|
358
|
+
}
|
|
209
359
|
};
|
|
360
|
+
function packHtmlFonts(fonts) {
|
|
361
|
+
let size = 4;
|
|
362
|
+
for (const f of fonts) size += 4 + enc.encode(f.family).length + 2 + 1 + 4 + f.ttf.length;
|
|
363
|
+
const buf = new Uint8Array(size);
|
|
364
|
+
const dv = new DataView(buf.buffer);
|
|
365
|
+
let o = 0;
|
|
366
|
+
dv.setUint32(o, fonts.length, true);
|
|
367
|
+
o += 4;
|
|
368
|
+
for (const f of fonts) {
|
|
369
|
+
const fam = enc.encode(f.family);
|
|
370
|
+
dv.setUint32(o, fam.length, true);
|
|
371
|
+
o += 4;
|
|
372
|
+
buf.set(fam, o);
|
|
373
|
+
o += fam.length;
|
|
374
|
+
dv.setUint16(o, f.weight, true);
|
|
375
|
+
o += 2;
|
|
376
|
+
buf[o] = f.italic ? 1 : 0;
|
|
377
|
+
o += 1;
|
|
378
|
+
dv.setUint32(o, f.ttf.length, true);
|
|
379
|
+
o += 4;
|
|
380
|
+
buf.set(f.ttf, o);
|
|
381
|
+
o += f.ttf.length;
|
|
382
|
+
}
|
|
383
|
+
return buf;
|
|
384
|
+
}
|
|
210
385
|
var RGB = (rgb) => rgb & 16777215;
|
|
386
|
+
function styleArgs(s = {}) {
|
|
387
|
+
const hasBorder = s.border === null ? 0 : 1;
|
|
388
|
+
const borderRgb = s.border == null ? 0 : s.border;
|
|
389
|
+
const hasBg = s.background == null ? 0 : 1;
|
|
390
|
+
const bgRgb = s.background == null ? 0 : s.background;
|
|
391
|
+
return [
|
|
392
|
+
s.fontSize ?? 0,
|
|
393
|
+
RGB(s.color ?? 0),
|
|
394
|
+
RGB(borderRgb),
|
|
395
|
+
hasBorder,
|
|
396
|
+
RGB(bgRgb),
|
|
397
|
+
hasBg,
|
|
398
|
+
s.borderWidth ?? 1
|
|
399
|
+
];
|
|
400
|
+
}
|
|
211
401
|
var GigaPdfDoc = class {
|
|
212
402
|
constructor(g, h) {
|
|
213
403
|
this.g = g;
|
|
@@ -274,7 +464,7 @@ var GigaPdfDoc = class {
|
|
|
274
464
|
* Draw a vector rectangle. Pass an `0xRRGGBB` colour for `stroke`/`fill`, or
|
|
275
465
|
* `null` to omit that paint. 0 → success.
|
|
276
466
|
*/
|
|
277
|
-
addRectangle(page, x, y, w, h, stroke = null, fill = 0, lineWidth = 1) {
|
|
467
|
+
addRectangle(page, x, y, w, h, stroke = null, fill = 0, lineWidth = 1, opacity = 1) {
|
|
278
468
|
return this.ex().gp_add_rectangle(
|
|
279
469
|
this.h,
|
|
280
470
|
page,
|
|
@@ -286,9 +476,99 @@ var GigaPdfDoc = class {
|
|
|
286
476
|
stroke === null ? 0 : 1,
|
|
287
477
|
RGB(fill ?? 0),
|
|
288
478
|
fill === null ? 0 : 1,
|
|
289
|
-
lineWidth
|
|
479
|
+
lineWidth,
|
|
480
|
+
opacity
|
|
481
|
+
) === 0;
|
|
482
|
+
}
|
|
483
|
+
/** Draw a straight line from `(x1,y1)` to `(x2,y2)`. `stroke` is `0xRRGGBB`. */
|
|
484
|
+
drawLine(page, x1, y1, x2, y2, stroke = 0, lineWidth = 1, opacity = 1) {
|
|
485
|
+
return this.ex().gp_draw_line(this.h, page, x1, y1, x2, y2, RGB(stroke), lineWidth, opacity) === 0;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Draw an ellipse (circle when `rx === ry`) centred at `(cx,cy)`. Pass an
|
|
489
|
+
* `0xRRGGBB` colour for `stroke`/`fill`, or `null` to omit that paint.
|
|
490
|
+
*/
|
|
491
|
+
addEllipse(page, cx, cy, rx, ry, stroke = null, fill = 0, lineWidth = 1, opacity = 1) {
|
|
492
|
+
return this.ex().gp_add_ellipse(
|
|
493
|
+
this.h,
|
|
494
|
+
page,
|
|
495
|
+
cx,
|
|
496
|
+
cy,
|
|
497
|
+
rx,
|
|
498
|
+
ry,
|
|
499
|
+
RGB(stroke ?? 0),
|
|
500
|
+
stroke === null ? 0 : 1,
|
|
501
|
+
RGB(fill ?? 0),
|
|
502
|
+
fill === null ? 0 : 1,
|
|
503
|
+
lineWidth,
|
|
504
|
+
opacity
|
|
505
|
+
) === 0;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Draw a polyline/polygon through flat `[x0,y0,x1,y1,…]` points. `close` joins
|
|
509
|
+
* the last vertex back to the first. `0xRRGGBB` colours, or `null` to omit.
|
|
510
|
+
*/
|
|
511
|
+
addPolygon(page, points, close = true, stroke = null, fill = 0, lineWidth = 1, opacity = 1) {
|
|
512
|
+
return this.g._withF64(
|
|
513
|
+
points,
|
|
514
|
+
(p, c) => this.ex().gp_add_polygon(
|
|
515
|
+
this.h,
|
|
516
|
+
page,
|
|
517
|
+
p,
|
|
518
|
+
c,
|
|
519
|
+
close ? 1 : 0,
|
|
520
|
+
RGB(stroke ?? 0),
|
|
521
|
+
stroke === null ? 0 : 1,
|
|
522
|
+
RGB(fill ?? 0),
|
|
523
|
+
fill === null ? 0 : 1,
|
|
524
|
+
lineWidth,
|
|
525
|
+
opacity
|
|
526
|
+
)
|
|
527
|
+
) === 0;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Draw an SVG path (`M`/`L`/`C`/`Q`/`Z`…) anchored so the SVG origin maps to
|
|
531
|
+
* `(ox,oy)` with the Y axis flipped — same convention as `pdf-lib`'s
|
|
532
|
+
* `drawSvgPath`. Covers freeform/polygon/triangle shapes.
|
|
533
|
+
*/
|
|
534
|
+
addPath(page, svgPath, ox, oy, stroke = null, fill = 0, lineWidth = 1, opacity = 1) {
|
|
535
|
+
return this.g._withStr(
|
|
536
|
+
svgPath,
|
|
537
|
+
(p, l) => this.ex().gp_add_path(
|
|
538
|
+
this.h,
|
|
539
|
+
page,
|
|
540
|
+
p,
|
|
541
|
+
l,
|
|
542
|
+
ox,
|
|
543
|
+
oy,
|
|
544
|
+
RGB(stroke ?? 0),
|
|
545
|
+
stroke === null ? 0 : 1,
|
|
546
|
+
RGB(fill ?? 0),
|
|
547
|
+
fill === null ? 0 : 1,
|
|
548
|
+
lineWidth,
|
|
549
|
+
opacity
|
|
550
|
+
)
|
|
551
|
+
) === 0;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Embed a raster image (PNG or JPEG bytes) at `(x,y)` sized `(w,h)` in PDF
|
|
555
|
+
* user space. PNG alpha is honoured; `opacity` (0..1) sets an overall alpha.
|
|
556
|
+
*/
|
|
557
|
+
addImage(page, data, x, y, w, h, opacity = 1) {
|
|
558
|
+
return this.g._withBytes(
|
|
559
|
+
data,
|
|
560
|
+
(p, l) => this.ex().gp_add_image(this.h, page, p, l, x, y, w, h, opacity)
|
|
290
561
|
) === 0;
|
|
291
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Draw SVG markup on a page as **native vector paths** (crisp at any zoom, not
|
|
565
|
+
* rasterized), fitting its `viewBox` into the box `(x, y, w, h)` in PDF points
|
|
566
|
+
* (origin bottom-left). Supports shapes, `<path>`, groups, transforms and
|
|
567
|
+
* fill/stroke/opacity. Returns `false` if the SVG can't be parsed.
|
|
568
|
+
*/
|
|
569
|
+
addSvg(page, svg, x, y, w, h) {
|
|
570
|
+
return this.g._withStr(svg, (p, l) => this.ex().gp_add_svg(this.h, page, p, l, x, y, w, h)) === 0;
|
|
571
|
+
}
|
|
292
572
|
/** True redaction: delete content intersecting the region (no opaque cover by default). */
|
|
293
573
|
redact(page, x, y, w, h, coverRgb = 0, hasCover = false) {
|
|
294
574
|
return this.ex().gp_redact_region(this.h, page, x, y, w, h, RGB(coverRgb), hasCover ? 1 : 0);
|
|
@@ -366,6 +646,10 @@ var GigaPdfDoc = class {
|
|
|
366
646
|
toPptx() {
|
|
367
647
|
return this.g._buffer((o) => this.ex().gp_to_pptx(this.h, o));
|
|
368
648
|
}
|
|
649
|
+
/** Convert to an editable OpenDocument Presentation (`.odp`). */
|
|
650
|
+
toOdp() {
|
|
651
|
+
return this.g._buffer((o) => this.ex().gp_to_odp(this.h, o));
|
|
652
|
+
}
|
|
369
653
|
toOdt() {
|
|
370
654
|
return this.g._buffer((o) => this.ex().gp_to_odt(this.h, o));
|
|
371
655
|
}
|
|
@@ -382,13 +666,54 @@ var GigaPdfDoc = class {
|
|
|
382
666
|
return this.g._buffer((o) => this.ex().gp_to_pdfa(this.h, o));
|
|
383
667
|
}
|
|
384
668
|
// security
|
|
385
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Serialize the document encrypted with the PDF Standard Security Handler.
|
|
671
|
+
* Defaults to **AES-256 (R6)**. `fileId` is the document `/ID` (any stable
|
|
672
|
+
* hex/string). For AES-256 a **secret 32-byte key** is required — it is taken
|
|
673
|
+
* from `opts.keySeed` or generated with Web Crypto; RC4/AES-128 derive their
|
|
674
|
+
* key from the password and ignore it.
|
|
675
|
+
*/
|
|
676
|
+
saveEncrypted(password, fileId, opts = {}) {
|
|
677
|
+
const algo = opts.algorithm ?? "aes256";
|
|
678
|
+
const algoCode = algo === "rc4" ? 0 : algo === "aes128" ? 1 : 2;
|
|
679
|
+
const permissions = opts.permissions ?? -44;
|
|
680
|
+
let key = opts.keySeed ?? new Uint8Array(0);
|
|
681
|
+
if (algoCode === 2 && key.length < 32) {
|
|
682
|
+
const c = globalThis.crypto;
|
|
683
|
+
if (!c?.getRandomValues) {
|
|
684
|
+
throw new Error(
|
|
685
|
+
"AES-256 encryption needs Web Crypto (globalThis.crypto.getRandomValues) or an explicit opts.keySeed"
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
const fresh = new Uint8Array(32);
|
|
689
|
+
c.getRandomValues(fresh);
|
|
690
|
+
key = fresh;
|
|
691
|
+
}
|
|
386
692
|
return this.g._withStr(
|
|
387
693
|
password,
|
|
388
|
-
(pwP, pwL) => this.g.
|
|
389
|
-
|
|
390
|
-
(
|
|
391
|
-
|
|
694
|
+
(pwP, pwL) => this.g._withOptStr(
|
|
695
|
+
opts.ownerPassword,
|
|
696
|
+
(oP, oL) => this.g._withStr(
|
|
697
|
+
fileId,
|
|
698
|
+
(idP, idL) => this.g._withBytes(
|
|
699
|
+
key,
|
|
700
|
+
(kP, kL) => this.g._buffer(
|
|
701
|
+
(o) => this.ex().gp_save_encrypted(
|
|
702
|
+
this.h,
|
|
703
|
+
pwP,
|
|
704
|
+
pwL,
|
|
705
|
+
oP,
|
|
706
|
+
oL,
|
|
707
|
+
idP,
|
|
708
|
+
idL,
|
|
709
|
+
kP,
|
|
710
|
+
kL,
|
|
711
|
+
algoCode,
|
|
712
|
+
permissions,
|
|
713
|
+
o
|
|
714
|
+
)
|
|
715
|
+
)
|
|
716
|
+
)
|
|
392
717
|
)
|
|
393
718
|
)
|
|
394
719
|
);
|
|
@@ -532,6 +857,141 @@ var GigaPdfDoc = class {
|
|
|
532
857
|
(nP, nL) => this.g._withStr(values.join("\n"), (vP, vL) => this.ex().gp_set_choice(this.h, nP, nL, vP, vL))
|
|
533
858
|
) === 0;
|
|
534
859
|
}
|
|
860
|
+
// ── form field creation ──────────────────────────────────────────────────
|
|
861
|
+
/**
|
|
862
|
+
* Create a text field on `page` covering `rect` = `[x0, y0, x1, y1]` (PDF
|
|
863
|
+
* user space). Options: `maxLen` character cap, `multiline`, `password`,
|
|
864
|
+
* and visual `style`.
|
|
865
|
+
*/
|
|
866
|
+
addTextField(page, name, rect, value = "", opts = {}) {
|
|
867
|
+
const st = styleArgs(opts.style);
|
|
868
|
+
return this.g._withStr(
|
|
869
|
+
name,
|
|
870
|
+
(nP, nL) => this.g._withStr(
|
|
871
|
+
value,
|
|
872
|
+
(vP, vL) => this.ex().gp_add_text_field(
|
|
873
|
+
this.h,
|
|
874
|
+
page,
|
|
875
|
+
nP,
|
|
876
|
+
nL,
|
|
877
|
+
rect[0],
|
|
878
|
+
rect[1],
|
|
879
|
+
rect[2],
|
|
880
|
+
rect[3],
|
|
881
|
+
vP,
|
|
882
|
+
vL,
|
|
883
|
+
opts.maxLen ?? -1,
|
|
884
|
+
opts.multiline ? 1 : 0,
|
|
885
|
+
opts.password ? 1 : 0,
|
|
886
|
+
...st
|
|
887
|
+
)
|
|
888
|
+
)
|
|
889
|
+
) === 0;
|
|
890
|
+
}
|
|
891
|
+
/** Create a checkbox. `export` is the on-state name (default `On`). */
|
|
892
|
+
addCheckbox(page, name, rect, checked = false, opts = {}) {
|
|
893
|
+
const st = styleArgs(opts.style);
|
|
894
|
+
return this.g._withStr(
|
|
895
|
+
name,
|
|
896
|
+
(nP, nL) => this.g._withStr(
|
|
897
|
+
opts.export ?? "On",
|
|
898
|
+
(eP, eL) => this.ex().gp_add_checkbox(
|
|
899
|
+
this.h,
|
|
900
|
+
page,
|
|
901
|
+
nP,
|
|
902
|
+
nL,
|
|
903
|
+
rect[0],
|
|
904
|
+
rect[1],
|
|
905
|
+
rect[2],
|
|
906
|
+
rect[3],
|
|
907
|
+
checked ? 1 : 0,
|
|
908
|
+
eP,
|
|
909
|
+
eL,
|
|
910
|
+
...st
|
|
911
|
+
)
|
|
912
|
+
)
|
|
913
|
+
) === 0;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Create a radio-button group: one logical field whose `options` are the
|
|
917
|
+
* individual buttons. `selected` is the initially-chosen export value.
|
|
918
|
+
*/
|
|
919
|
+
addRadioGroup(page, name, options, opts = {}) {
|
|
920
|
+
const st = styleArgs(opts.style);
|
|
921
|
+
const exports2 = options.map((o) => o.export).join("\n");
|
|
922
|
+
const rects = options.flatMap((o) => o.rect).join(",");
|
|
923
|
+
return this.g._withStr(
|
|
924
|
+
name,
|
|
925
|
+
(nP, nL) => this.g._withStr(
|
|
926
|
+
exports2,
|
|
927
|
+
(eP, eL) => this.g._withStr(
|
|
928
|
+
rects,
|
|
929
|
+
(rP, rL) => this.g._withStr(
|
|
930
|
+
opts.selected ?? "",
|
|
931
|
+
(sP, sL) => this.ex().gp_add_radio_group(this.h, page, nP, nL, eP, eL, rP, rL, sP, sL, ...st)
|
|
932
|
+
)
|
|
933
|
+
)
|
|
934
|
+
)
|
|
935
|
+
) === 0;
|
|
936
|
+
}
|
|
937
|
+
/** Create a drop-down combo box. `editable` permits values outside `options`. */
|
|
938
|
+
addComboBox(page, name, rect, options, opts = {}) {
|
|
939
|
+
const st = styleArgs(opts.style);
|
|
940
|
+
return this.g._withStr(
|
|
941
|
+
name,
|
|
942
|
+
(nP, nL) => this.g._withStr(
|
|
943
|
+
options.join("\n"),
|
|
944
|
+
(oP, oL) => this.g._withStr(
|
|
945
|
+
opts.selected ?? "",
|
|
946
|
+
(sP, sL) => this.ex().gp_add_combo_box(
|
|
947
|
+
this.h,
|
|
948
|
+
page,
|
|
949
|
+
nP,
|
|
950
|
+
nL,
|
|
951
|
+
rect[0],
|
|
952
|
+
rect[1],
|
|
953
|
+
rect[2],
|
|
954
|
+
rect[3],
|
|
955
|
+
oP,
|
|
956
|
+
oL,
|
|
957
|
+
sP,
|
|
958
|
+
sL,
|
|
959
|
+
opts.editable ? 1 : 0,
|
|
960
|
+
...st
|
|
961
|
+
)
|
|
962
|
+
)
|
|
963
|
+
)
|
|
964
|
+
) === 0;
|
|
965
|
+
}
|
|
966
|
+
/** Create a scrolling list box. `multi` allows selecting several options. */
|
|
967
|
+
addListBox(page, name, rect, options, opts = {}) {
|
|
968
|
+
const st = styleArgs(opts.style);
|
|
969
|
+
return this.g._withStr(
|
|
970
|
+
name,
|
|
971
|
+
(nP, nL) => this.g._withStr(
|
|
972
|
+
options.join("\n"),
|
|
973
|
+
(oP, oL) => this.g._withStr(
|
|
974
|
+
opts.selected ?? "",
|
|
975
|
+
(sP, sL) => this.ex().gp_add_list_box(
|
|
976
|
+
this.h,
|
|
977
|
+
page,
|
|
978
|
+
nP,
|
|
979
|
+
nL,
|
|
980
|
+
rect[0],
|
|
981
|
+
rect[1],
|
|
982
|
+
rect[2],
|
|
983
|
+
rect[3],
|
|
984
|
+
oP,
|
|
985
|
+
oL,
|
|
986
|
+
sP,
|
|
987
|
+
sL,
|
|
988
|
+
opts.multi ? 1 : 0,
|
|
989
|
+
...st
|
|
990
|
+
)
|
|
991
|
+
)
|
|
992
|
+
)
|
|
993
|
+
) === 0;
|
|
994
|
+
}
|
|
535
995
|
};
|
|
536
996
|
// Annotate the CommonJS export names for ESM import in node:
|
|
537
997
|
0 && (module.exports = {
|