1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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;
}
|