diff options
Diffstat (limited to 'appl/ebook/table.b')
| -rw-r--r-- | appl/ebook/table.b | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/appl/ebook/table.b b/appl/ebook/table.b new file mode 100644 index 00000000..b79b81b5 --- /dev/null +++ b/appl/ebook/table.b @@ -0,0 +1,176 @@ +implement Table; +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + Point, Rect: import draw; +include "tk.m"; + tk: Tk; +include "table.m"; + +init() +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + tk = load Tk Tk->PATH; +} + +newcell(w: string, span: Draw->Point): ref Cell +{ + return ref Cell(w, span, (0, 0)); +} + +layout(cells: array of array of ref Cell, win: ref Tk->Toplevel, w: string) +{ + if (len cells == 0) + return; + dim := Point(len cells, len cells[0]); + for (y := 0; y < dim.y; y++) { + for (x := 0; x < dim.x; x++) { + cell := cells[x][y]; + # XXX should take into account cell padding + if (cell != nil) { + cell.sizereq = getsize(win, cell.w); +# sys->print("cell %d %d size %s span %s\n", x, y, p2s(cell.sizereq), p2s(cell.span)); + } +# else +# sys->print("cell %d %d blank\n", x, y); + } + } + + colwidths := array[dim.x] of {* => 0}; + # calculate column widths (ignoring multi-column cells) + for (x := 0; x < dim.x; x++) { + for (y = 0; y < dim.y; y++) { + cell := cells[x][y]; + if (cell != nil && cell.span.x == 1 && cell.sizereq.x > colwidths[x]) + colwidths[x] = cell.sizereq.x; + } + } + + # now check that multi-column cells fit in their columns + colexpand := array[dim.x] of {* => 1}; + for (x = 0; x < dim.x; x++) { + for (y = 0; y < dim.y; y++) { + cell := cells[x][y]; + if (cell != nil && cell.span.x > 1) + expandwidths(x, cell.sizereq.x, cell.span.x, colwidths, colexpand); + } + } + colexpand = nil; + + rowheights := array[dim.y] of {* => 0}; + # calculate row heights (ignoring multi-row cells) + for (y = 0; y < dim.y; y++) { + for (x = 0; x < dim.x; x++) { + cell := cells[x][y]; + if (cell != nil && cell.span.y == 1 && cell.sizereq.y > rowheights[y]) + rowheights[y] = cell.sizereq.y; + } + } + +# for (i := 0; i < len colwidths; i++) +# sys->print("colwidth %d -> %d\n", i, colwidths[i]); +# for (i = 0; i < len rowheights; i++) +# sys->print("rowheight %d -> %d\n", i, rowheights[i]); + + rowexpand := array[dim.y] of {* => 1}; + # now check that multi-row cells fit in their columns + for (y = 0; y < dim.y; y++) { + for (x = 0; x < dim.x; x++) { + cell := cells[x][y]; + if (cell != nil && cell.span.y > 1) + expandwidths(y, cell.sizereq.y, cell.span.y, rowheights, rowexpand); + } + } + +# if (rowequalise) +# equalise(rowheights, dim.y); + +# if (colequalise) +# equalise(colwidths, dim.x); + + # calculate total width and height (including cell padding) + totsize := Point(0, 0); + for (x = 0; x < dim.x; x++) + totsize.x += colwidths[x]; + for (y = 0; y < dim.y; y++) + totsize.y += rowheights[y]; + + cmd(win, "canvas " + w + " -width " + string totsize.x + " -bg white -height " + string totsize.y); + p := Point(0, 0); + for (y = 0; y < dim.y; y++) { + p.x = 0; + for (x = 0; x < dim.x; x++) { + cell := cells[x][y]; + if (cell != nil) { + cellsize := Point(0, 0); + span := cell.span; + for (xx := 0; xx < span.x; xx++) + cellsize.x += colwidths[x + xx]; + for (yy := 0; yy < span.y; yy++) + cellsize.y += rowheights[y + yy]; +# sys->print("cell [%d %d] %d %d +[%d %d]\n", x, y, p.x, p.y, cellsize.x, cellsize.y); + cmd(win, w + " create window " + p2s(p) + + " -anchor nw -window " + cell.w + + " -width " + string cellsize.x + + " -height " + string cellsize.y); + } + p.x += colwidths[x]; + } + p.y += rowheights[y]; + } +} + +expandwidths(x: int, cellwidth, xcells: int, widths: array of int, expand: array of int) +{ + # find out total space available for cell + share := 0; + tot := 0; + endx := x + xcells; + for (xx := x; xx < endx; xx++) { + tot += widths[xx]; + if (expand[xx]) + share++; + } + slack := cellwidth - tot; + + # if enough space, then nothing to do. + if (slack <= 0) + return; + + # allocate extra space amongst all cols that + # want to expand. (if any do, otherwise share it + # out between all of them) + if (share == 0) + share = xcells; + for (xx = x; xx < endx; xx++) { + m := slack / share; + widths[xx] += m; + slack -= m; + share--; + } +} + +getsize(win: ref Tk->Toplevel, w: string): Point +{ + bd := 2 * int cmd(win, w + " cget -bd"); + return Point(int cmd(win, w + " cget -width") + bd, + int cmd(win, w + " cget -height") + bd); +} + +p2s(p: Point): string +{ + return string p.x + " " + string p.y; +} + +cmd(win: ref Tk->Toplevel, s: string): string +{ +# sys->print("%ux %s\n", win, s); + r := tk->cmd(win, s); + if (len r > 0 && r[0] == '!') { + sys->fprint(sys->fildes(2), "error executing '%s': %s\n", s, r); + raise "tk error"; + } + return r; +} |
