summaryrefslogtreecommitdiff
path: root/appl/charon/paginate.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/charon/paginate.b')
-rw-r--r--appl/charon/paginate.b511
1 files changed, 511 insertions, 0 deletions
diff --git a/appl/charon/paginate.b b/appl/charon/paginate.b
new file mode 100644
index 00000000..31411d30
--- /dev/null
+++ b/appl/charon/paginate.b
@@ -0,0 +1,511 @@
+implement Paginate;
+
+include "common.m";
+include "print.m";
+include "paginate.m";
+
+sys: Sys;
+print: Print;
+L: Layout;
+D: Draw;
+
+Frame, Lay, Line, Control: import Layout;
+Docinfo: import Build;
+Image, Display, Rect, Point: import D;
+Item: import Build;
+MaskedImage: import CharonUtils;
+
+disp: ref Display;
+p0: Point;
+nulimg: ref Image;
+
+DPI: con 110;
+
+init(layout: Layout, draw: Draw, display: ref Draw->Display): string
+{
+ sys = load Sys Sys->PATH;
+ L = layout;
+ D = draw;
+ disp = display;
+ if (L == nil || D == nil || disp == nil)
+ return "bad args";
+ print = load Print Print->PATH;
+ if (print == nil)
+ return sys->sprint("cannot load module %s: %r", Print->PATH);
+ print->init();
+#nullfd := sys->open("/dev/null", Sys->OWRITE);
+#print->set_printfd(nullfd);
+ p0 = Point(0, 0);
+ nulimg = disp.newimage(((0, 0), (1, 1)), 3, 0, 0);
+ return nil;
+}
+
+paginate(frame: ref Layout->Frame, orient: int, pnums, cancel: chan of int, result: chan of (string, ref Pageset))
+{
+ pidc := chan of int;
+ spawn watchdog(pidc, cancel, nil, sys->pctl(0, nil));
+ watchpid := <- pidc;
+
+ if (frame.kids != nil) {
+ result <-= ("cannot print frameset", nil);
+ kill(watchpid);
+ return;
+ }
+
+ defp := print->get_defprinter();
+ if (defp == nil) {
+ result <-= ("no default printer", nil);
+ kill(watchpid);
+ return;
+ }
+
+ # assuming printer's X & Y resolution are the same
+ if (orient == PORTRAIT)
+ defp.popt.orientation = Print->PORTRAIT;
+ else
+ defp.popt.orientation = Print->LANDSCAPE;
+ (dpi, pagew, pageh) := print->get_size(defp);
+ pagew = (DPI * pagew)/dpi;
+ pageh = (DPI * pageh)/dpi;
+
+ pfr := copyframe(frame);
+ pr := Rect(p0, (pagew, pageh));
+ pfr.r = pr;
+ pfr.cr = pr;
+ pfr.viewr = pr;
+ l := pfr.layout;
+ L->relayout(pfr, l, pagew, l.just);
+ maxy := l.height + l.margin; # don't include bottom margin
+ prctxt := ref Layout->Printcontext;
+ pfr.prctxt = prctxt;
+ pfr.cim = nulimg;
+ pnum := 1;
+ startys : list of int;
+
+ for (y := 0; y < maxy;) {
+ startys = y :: startys;
+ pnums <-= pnum++;
+ endy := y + pageh;
+ prctxt.endy = pageh;
+ pfr.viewr.min.y = y;
+ pfr.viewr.max.y = endy;
+ L->drawall(pfr);
+ y += prctxt.endy;
+ }
+
+ # startys are in reverse order
+ ys : list of int;
+ for (; startys != nil; startys = tl startys)
+ ys = hd startys :: ys;
+
+ pageset := ref Pageset(defp, pfr, ys);
+ result <-= (nil, pageset);
+ kill(watchpid);
+}
+
+printpageset(pset: ref Pageset, pnums, cancel: chan of int)
+{
+ pidc := chan of int;
+ stopdog := chan of int;
+ spawn watchdog(pidc, cancel, stopdog, sys->pctl(0, nil));
+ watchpid := <- pidc;
+
+ frame := pset.frame;
+ pageh := frame.cr.dy();
+ white := disp.rgb2cmap(255, 255, 255);
+ prctxt := frame.prctxt;
+ l := frame.layout;
+ maxy := l.height + l.margin; # don't include bottom margin
+ maxy = max(maxy, pageh);
+ pnum := 1;
+
+ for (pages := pset.pages; pages != nil; pages = tl pages) {
+ y := hd pages;
+ if (y + pageh > maxy)
+ pageh = maxy - y;
+ frame.cr.max.y = pageh;
+ frame.cim = disp.newimage(frame.cr, 3, 0, white);
+ if (frame.cim == nil) {
+ pnums <-= -1;
+ kill(watchpid);
+ return;
+ }
+ pnums <-= pnum++;
+ endy := y + pageh;
+ prctxt.endy = pageh;
+ frame.viewr.min.y = y;
+ frame.viewr.max.y = endy;
+ L->drawall(frame);
+ stopdog <-= 1;
+#start := sys->millisec();
+ if (print->print_image(pset.printer, disp, frame.cim, 100, cancel) == -1) {
+ # cancelled
+ kill(watchpid);
+ return;
+ }
+ stopdog <-= 1;
+#sys->print("PAGE %d: %dms\n", pnum -1, sys->millisec()-start);
+ }
+ pnums <-= -1;
+ kill(watchpid);
+}
+
+watchdog(pidc, cancel, pause: chan of int, pid: int)
+{
+ pidc <-= sys->pctl(0, nil);
+ if (pause == nil)
+ pause = chan of int;
+ for (;;) alt {
+ <- cancel =>
+ kill(pid);
+ return;
+ <- pause =>
+ <- pause;
+ }
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("/prog/" + string pid +"/ctl", Sys->OWRITE), "kill");
+}
+
+killgrp(pid: int)
+{
+ sys->fprint(sys->open("/prog/" + string pid +"/ctl", Sys->OWRITE), "killgrp");
+}
+
+max(a, b: int): int
+{
+ if (a > b)
+ return a;
+ return b;
+}
+
+copyframe(f: ref Frame): ref Frame
+{
+
+ zr := Draw->Rect(p0, p0);
+ newf := ref Frame(
+ -1, # id
+ nil, # doc
+ nil, # src
+ " PRINT FRAME ", # name
+ f.marginw, # marginw
+ f.marginh, # marginh
+ 0, # framebd
+ Build->FRnoscroll, # flags
+ nil, # layout - filled in below, needs this frame ref
+ nil, # sublays - filled in by geometry code
+ 0, # sublayid
+ nil, # controls - filled in below, needs this frame ref
+ 0, # controlid - filled in below
+ nil, # cim
+ zr, # r
+ zr, # cr
+ zr, # totalr
+ zr, # viewr
+ nil, # vscr
+ nil, # hscr
+ nil, # parent
+ nil, # kids
+ 0, # animpid
+ nil # prctxt
+ );
+
+ newf.doc = copydoc(f, newf, f.doc);
+ controls := array [len f.controls] of ref Control;
+ for (i := 0; i < len controls; i++)
+ controls[i] = copycontrol(f, newf, f.controls[i]);
+ newf.layout = copylay(f, newf, f.layout);
+ newf.controls = controls;
+ newf.controlid = len controls;
+
+ return newf;
+}
+
+copysublay(oldf, f: ref Frame, oldid:int): int
+{
+ if (oldid < 0)
+ return -1;
+ if (f.sublayid >= len f.sublays)
+ f.sublays = (array [len f.sublays + 30] of ref Lay)[:] = f.sublays;
+ id := f.sublayid++;
+ lay := copylay(oldf, f, oldf.sublays[oldid]);
+ f.sublays[id] = lay;
+ return id;
+}
+
+copydoc(oldf, f : ref Frame, doc: ref Build->Docinfo): ref Docinfo
+{
+ background := copybackground(oldf, f, doc.background);
+ newdoc := ref Build->Docinfo(
+ nil, #src
+ nil, #base
+ nil, #referrer
+ nil, #doctitle
+ background,
+ nil, #backgrounditem
+ doc.text, doc.link, doc.vlink, doc.alink,
+ nil, #target
+ nil, #refresh
+ nil, #chset
+ nil, #lastModified
+ 0, #scripttype
+ 0, #hasscripts
+ nil, #events
+ 0, #evmask
+ nil, #kidinfo
+ 0, #frameid
+ nil, #anchors
+ nil, #dests
+ nil, #forms
+ nil, #tables
+ nil, #maps
+ nil #images
+ );
+ return newdoc;
+}
+
+copylay(oldf, f: ref Frame, l: ref Lay): ref Lay
+{
+ start := copyline(oldf, f, nil, l.start);
+ end := start;
+ for (line := l.start.next; line != nil; line = line.next)
+ end = copyline(oldf, f, end, line);
+
+ newl := ref Lay(
+ start,
+ end,
+ l.targetwidth, # targetwidth
+ l.width, # width
+ l.height, # height
+ l.margin, # margin
+ nil, # floats - filled in by geometry code
+ copybackground(oldf, f, l.background),
+ l.just,
+ Layout->Lchanged
+ );
+ start.flags = end.flags = byte 0;
+ return newl;
+}
+
+copycontrol(oldf, f: ref Frame, ctl: ref Control): ref Control
+{
+ if (ctl == nil)
+ return nil;
+
+ pick c := ctl {
+ Cbutton =>
+ return ref Control.Cbutton(f, nil, c.r, c.flags, nil, c.pic, c.picmask, c.dpic, c.dpicmask, c.label, c.dorelief);
+ Centry =>
+ scr := copycontrol(oldf, f, c.scr);
+ return ref Control.Centry(f, nil, c.r, c.flags, nil, scr, c.s, c.sel, c.left, c.linewrap, 0);
+ Ccheckbox=>
+ return ref Control.Ccheckbox(f, nil, c.r, c.flags, nil, c.isradio);
+ Cselect =>
+ scr := copycontrol(oldf, f, c.scr);
+ options := (array [len c.options] of Build->Option)[:] = c.options;
+ return ref Control.Cselect(f, nil, c.r, c.flags, nil, nil, scr, c.nvis, c.first, options);
+ Clistbox =>
+ hscr := copycontrol(oldf, f, c.hscr);
+ vscr := copycontrol(oldf, f, c.vscr);
+ options := (array [len c.options] of Build->Option)[:] = c.options;
+ return ref Control.Clistbox(f, nil, c.r, c.flags, nil, hscr, vscr, c.nvis, c.first, c.start, c.maxcol, options, nil);
+ Cscrollbar =>
+ # do not copy ctl as this is set by those associated controls
+ return ref Control.Cscrollbar(f, nil, c.r, c.flags, nil, c.top, c.bot, c.mindelta, c.deltaval, nil, c.holdstate);
+ Canimimage =>
+ bg := copybackground(oldf, f, c.bg);
+ return ref Control.Canimimage(f, nil, c.r, c.flags, nil, c.cim, 0, 0, big 0, bg);
+ Clabel =>
+ return ref Control.Clabel(f, nil, c.r, c.flags, nil, c.s);
+ * =>
+ return nil;
+ }
+}
+
+copyline(oldf, f: ref Frame, prev, l: ref Line): ref Line
+{
+ if (l == nil)
+ return nil;
+ cp := ref *l;
+ items := copyitems(oldf, f, l.items);
+ newl := ref Line (items, nil, prev, l.pos, l.width, l.height, l.ascent, Layout->Lchanged);
+ if (prev != nil)
+ prev.next = newl;
+ return newl;
+}
+
+copyitems(oldf, f: ref Frame, items: ref Item): ref Item
+{
+ if (items == nil)
+ return nil;
+ item := copyitem(oldf, f, items);
+ end := item;
+ for (items = items.next; items != nil; items = items.next) {
+ end.next = copyitem(oldf, f, items);
+ end = end.next;
+ }
+ return item;
+}
+
+copyitem(oldf, f : ref Frame, item: ref Item): ref Item
+{
+ if (item == nil)
+ return nil;
+ pick it := item {
+ Itext =>
+ return ref Item.Itext(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ it.s, it.fnt, it.fg, it.voff, it.ul);
+ Irule =>
+ return ref Item.Irule(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ it.align, it.noshade, it.size, it.wspec);
+ Iimage =>
+ # need to copy the image to prevent
+ # ongoing image fetches from messing up our layout
+ ci := copycimage(it.ci);
+ return ref Item.Iimage(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ it.imageid, ci, it.imwidth, it.imheight, it.altrep,
+ nil, it.name, -1, it.align, it.hspace, it.vspace, it.border);
+ Iformfield =>
+ return ref Item.Iformfield(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ copyformfield(oldf, f, it.formfield)
+ );
+ Itable =>
+ return ref Item.Itable(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ copytable(oldf, f, it.table));
+ Ifloat =>
+ items := copyitem(oldf, f, it.item);
+ return ref Item.Ifloat(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ items, it.x, it.y, it.side, byte 0);
+ Ispacer =>
+ return ref Item.Ispacer(
+ nil, it.width, it.height, it.ascent, 0, it.state, nil,
+ it.spkind, it.fnt);
+ * =>
+ return nil;
+ }
+}
+
+copycimage(ci: ref CharonUtils->CImage): ref CharonUtils->CImage
+{
+ if (ci == nil)
+ return nil;
+ mims : array of ref MaskedImage;
+ if (len ci.mims > 0)
+ # if len> 1 then animated, but we only want first frame
+ mims = array [1] of {0 => ci.mims[0]};
+ return ref CharonUtils->CImage(nil, nil, nil, 0, ci.width, ci.height, nil, mims, 0);
+}
+
+copyformfield(oldf, f: ref Frame, ff: ref Build->Formfield): ref Build->Formfield
+{
+ image := copyitem(oldf, f, ff.image);
+ # should be safe to reference Option list
+ newff := ref Build->Formfield(
+ ff.ftype, 0, nil, ff.name, ff.value, ff.size, ff.maxlength, ff.rows,
+ ff.cols, ff.flags, ff.options, image, ff.ctlid, nil, 0
+ );
+ return newff;
+}
+
+copytable(oldf, f: ref Frame, tbl: ref Build->Table): ref Build->Table
+{
+ nrow := tbl.nrow;
+ ncol := tbl.ncol;
+ caption_lay := copysublay(oldf, f, tbl.caption_lay);
+ cols := (array [ncol] of Build->Tablecol)[:] = tbl.cols;
+ rows := array [nrow] of ref Build->Tablerow;
+ for (i := 0; i < nrow; i++) {
+ r := tbl.rows[i];
+ rows[i] = ref Build->Tablerow(nil, r.height, r.ascent, r.align, r.background, r.pos, r.flags);
+ }
+
+ cells : list of ref Build->Tablecell;
+ grid := array [nrow] of {* => array [ncol] of ref Build->Tablecell};
+ for (rix := 0; rix < nrow; rix++) {
+ rowcells: list of ref Build->Tablecell = nil;
+ for (colix := 0; colix < ncol; colix++) {
+ cell := copytablecell(oldf, f, tbl.grid[rix][colix]);
+ if (cell == nil)
+ continue;
+ grid[rix][colix] = cell;
+ cells = cell :: cells;
+ rowcells = cell :: rowcells;
+ }
+ # reverse the row cells;
+ rcells : list of ref Build->Tablecell = nil;
+ for (; rowcells != nil; rowcells = tl rowcells)
+ rcells = hd rowcells :: rcells;
+ rows[rix].cells = rcells;
+ }
+
+ # reverse the cells
+ sllec: list of ref Build->Tablecell;
+ for (; cells != nil; cells = tl cells)
+ sllec = hd cells :: sllec;
+ cells = sllec;
+
+ return ref Build->Table(
+ tbl.tableid, # tableid
+ nrow, # nrow
+ ncol, # ncol
+ len cells, # ncell
+ tbl.align, # align
+ tbl.width, # width
+ tbl.border, # border
+ tbl.cellspacing, # cellspacing
+ tbl.cellpadding, # cellpadding
+ tbl.background, # background
+ nil, # caption
+ tbl.caption_place, # caption_place
+ caption_lay, # caption_lay
+ nil, # currows
+ cols, # cols
+ rows, # rows
+ cells, # cells
+ tbl.totw, # totw
+ tbl.toth, # toth
+ tbl.caph, # caph
+ tbl.availw, # availw
+ grid, # grid
+ nil, # tabletok
+ Layout->Lchanged # flags
+ );
+}
+
+copytablecell(oldf, f: ref Frame, cell: ref Build->Tablecell): ref Build->Tablecell
+{
+ if (cell == nil)
+ return nil;
+
+ layid := copysublay(oldf, f, cell.layid);
+ background := copybackground(oldf, f, cell.background);
+ newcell := ref Build->Tablecell(
+ cell.cellid,
+ nil, # content
+ layid,
+ cell.rowspan, cell.colspan, cell.align,
+ cell.flags, cell.wspec, cell.hspec,
+ background, cell.minw, cell.maxw,
+ cell.ascent, cell.row, cell.col, cell.pos);
+ return newcell;
+}
+
+copybackground(oldf, f: ref Frame, bg: Build->Background): Build->Background
+{
+ img := copyitem(oldf, f, bg.image);
+ if (img != nil) {
+ pick i := img {
+ Iimage =>
+ bg.image = i;
+ }
+ }
+ return bg;
+}