1 #include "lib9.h"
2 #include "draw.h"
3 #include "tk.h"
4
5 /*
6 * XXX TODO
7 * - grid rowcget|columncget
8 * - grid columnconfigure/rowconfigure accepts a list of indexes?
9 */
10
11 #define O(t, e) ((long)(&((t*)0)->e))
12
13 typedef struct TkGridparam TkGridparam;
14 typedef struct TkBeamparam TkBeamparam;
15
16 struct TkGridparam{
17 Point span;
18 Tk* in;
19 Point pad;
20 Point ipad;
21 char *row;
22 char *col;
23 int sticky;
24 };
25
26 struct TkBeamparam{
27 int minsize;
28 int maxsize;
29 int weight;
30 int pad;
31 char *name;
32 int equalise;
33 };
34
35 static
36 TkOption opts[] =
37 {
38 "padx", OPTnndist, O(TkGridparam, pad.x), nil,
39 "pady", OPTnndist, O(TkGridparam, pad.y), nil,
40 "ipadx", OPTnndist, O(TkGridparam, ipad.x), nil,
41 "ipady", OPTnndist, O(TkGridparam, ipad.y), nil,
42 "in", OPTwinp, O(TkGridparam, in), nil,
43 "row", OPTtext, O(TkGridparam, row), nil,
44 "column", OPTtext, O(TkGridparam, col), nil,
45 "rowspan", OPTnndist, O(TkGridparam, span.y), nil,
46 "columnspan", OPTnndist, O(TkGridparam, span.x), nil,
47 "sticky", OPTsticky, O(TkGridparam, sticky), nil,
48 nil
49 };
50
51 static
52 TkOption beamopts[] =
53 {
54 "minsize", OPTnndist, O(TkBeamparam, minsize), nil,
55 "maxsize", OPTnndist, O(TkBeamparam, maxsize), nil,
56 "weight", OPTnndist, O(TkBeamparam, weight), nil,
57 "pad", OPTnndist, O(TkBeamparam, pad), nil,
58 "name", OPTtext, O(TkBeamparam, name), nil,
59 "equalise", OPTstab, O(TkBeamparam, equalise), tkbool,
60 nil
61 };
62
63 void
printgrid(TkGrid * grid)64 printgrid(TkGrid *grid)
65 {
66 int x, y;
67 Point dim;
68
69 dim = grid->dim;
70 print("grid %P\n", grid->dim);
71 print(" row heights: ");
72 for(y = 0; y < dim.y; y++)
73 print("%d[%d,%d,w%d,p%d]%s ",
74 grid->rows[y].act,
75 grid->rows[y].minsize,
76 grid->rows[y].maxsize < 0x7fffffff ? grid->rows[y].maxsize : -1,
77 grid->rows[y].weight,
78 grid->rows[y].pad,
79 grid->rows[y].name ? grid->rows[y].name : "");
80 print("\n");
81 print(" col widths: ");
82 for(x = 0; x < dim.x; x++)
83 print("%d[%d,%d,w%d,p%d]%s ",
84 grid->cols[x].act,
85 grid->cols[x].minsize,
86 grid->cols[x].maxsize < 0x7fffffff ? grid->cols[x].maxsize : -1,
87 grid->cols[x].weight,
88 grid->cols[x].pad,
89 grid->cols[x].name ? grid->cols[x].name : "");
90 print("\n");
91 for(y = 0; y < dim.y; y++){
92 print(" row %d: ", y);
93 for(x = 0; x < dim.x; x++){
94 print("%p;", grid->cells[y][x].tk);
95 print("%s%P\t", grid->cells[y][x].tk?grid->cells[y][x].tk->name->name:"(nil)",
96 grid->cells[y][x].span);
97 }
98 print("\n");
99 }
100 }
101
102 static void
tkgridsetopt(TkGridparam * p,Tk * tk)103 tkgridsetopt(TkGridparam *p, Tk *tk)
104 {
105 if(p->pad.x != -1)
106 tk->pad.x = p->pad.x*2;
107 if(p->pad.y != -1)
108 tk->pad.y = p->pad.y*2;
109 if(p->ipad.x != -1)
110 tk->ipad.x = p->ipad.x*2;
111 if(p->ipad.y != -1)
112 tk->ipad.y = p->ipad.y*2;
113 if(p->sticky != -1)
114 tk->flag = (tk->flag & ~(Tkanchor|Tkfill)) | (p->sticky & (Tkanchor|Tkfill));
115 }
116
117 static void
initbeam(TkGridbeam * beam,int n)118 initbeam(TkGridbeam *beam, int n)
119 {
120 int i;
121 memset(beam, 0, n * sizeof(TkGridbeam));
122 for(i = 0; i < n; i++)
123 beam[i].maxsize = 0x7fffffff;
124 }
125
126 static char*
ensuregridsize(TkGrid * grid,Point dim)127 ensuregridsize(TkGrid *grid, Point dim)
128 {
129 TkGridcell **cells, *cellrow;
130 TkGridbeam *cols, *rows;
131 Point olddim;
132 int i;
133 olddim = grid->dim;
134 if(dim.x < olddim.x)
135 dim.x = olddim.x;
136 if(dim.y < olddim.y)
137 dim.y = olddim.y;
138 if(dim.y > olddim.y){
139 cells = realloc(grid->cells, sizeof(TkGridcell*)*dim.y);
140 if(cells == nil)
141 return TkNomem;
142 grid->cells = cells;
143 for(i = olddim.y; i < dim.y; i++){
144 cells[i] = malloc(sizeof(TkGridcell)*dim.x);
145 if(cells[i] == nil){
146 while(--i >= olddim.y)
147 free(cells[i]);
148 return TkNomem;
149 }
150 }
151 rows = realloc(grid->rows, sizeof(TkGridbeam)*dim.y);
152 if(rows == nil)
153 return TkNomem;
154 grid->rows = rows;
155 initbeam(rows + olddim.y, dim.y - olddim.y);
156 grid->dim.y = dim.y;
157 }
158
159 if(dim.x > olddim.x){
160 /*
161 * any newly allocated rows will have the correct number of
162 * columns, so we don't need to reallocate them
163 */
164 cells = grid->cells;
165 for(i = 0; i < olddim.y; i++){
166 cellrow = realloc(cells[i], sizeof(TkGridcell) * dim.x);
167 if(cellrow == nil)
168 return TkNomem; /* leak some earlier rows, but not permanently */
169 memset(cellrow + olddim.x, 0, (dim.x-olddim.x)*sizeof(TkGridcell));
170 cells[i] = cellrow;
171 }
172 cols = realloc(grid->cols, sizeof(TkGridbeam)*dim.x);
173 if(cols == nil)
174 return TkNomem;
175 initbeam(cols + olddim.x, dim.x - olddim.x);
176 grid->cols = cols;
177 grid->dim.x = dim.x;
178 }
179 return nil;
180 }
181
182 static TkGridbeam*
delbeams(TkGridbeam * beam,int nb,int x0,int x1)183 delbeams(TkGridbeam *beam, int nb, int x0, int x1)
184 {
185 int i;
186 TkGridbeam *b;
187 for(i = x0; i < x1; i++)
188 free(beam[i].name);
189 memmove(&beam[x0], &beam[x1], sizeof(TkGridbeam) * (nb-x1));
190 b = realloc(beam, sizeof(TkGridbeam) * (nb-(x1-x0)));
191 return b ? b : beam;
192 }
193
194 static void
delrows(TkGrid * grid,int y0,int y1)195 delrows(TkGrid *grid, int y0, int y1)
196 {
197 TkGridcell **cells;
198 memmove(grid->cells+y0, grid->cells+y1, sizeof(TkGridcell*) * (grid->dim.y-y1));
199 grid->dim.y -= (y1 - y0);
200 cells = realloc(grid->cells, sizeof(TkGridcell*) * grid->dim.y);
201 if(cells != nil || grid->dim.y == 0)
202 grid->cells = cells; /* can realloc to a smaller size ever fail? */
203 }
204
205 static void
delcols(TkGrid * grid,int x0,int x1)206 delcols(TkGrid *grid, int x0, int x1)
207 {
208 TkGridcell **cells, *row;
209 int y, ndx;
210 Point dim;
211 dim = grid->dim;
212 ndx = dim.x - (x1 - x0);
213 cells = grid->cells;
214 for(y = 0; y < dim.y; y++){
215 row = cells[y];
216 memmove(row+x0, row+x1, sizeof(TkGridcell) * (dim.x - x1));
217 row = realloc(row, sizeof(TkGridcell) * ndx);
218 if(row != nil || ndx == 0)
219 cells[y] = row;
220 }
221 grid->dim.x = ndx;
222 }
223
224 /*
225 * insert items into rows/cols; the beam has already been expanded appropriately.
226 */
227 void
insbeams(TkGridbeam * beam,int nb,int x,int n)228 insbeams(TkGridbeam *beam, int nb, int x, int n)
229 {
230 memmove(&beam[x+n], &beam[x], sizeof(TkGridbeam)*(nb-x-n));
231 initbeam(beam+x, n);
232 }
233
234 static char*
insrows(TkGrid * grid,int y0,int n)235 insrows(TkGrid *grid, int y0, int n)
236 {
237 Point olddim;
238 char *e;
239 TkGridcell **cells, *tmp;
240 int y;
241
242 olddim = grid->dim;
243 if(y0 > olddim.y){
244 n = y0 + n - olddim.y;
245 y0 = olddim.y;
246 }
247
248 e = ensuregridsize(grid, Pt(olddim.x, olddim.y + n));
249 if(e != nil)
250 return e;
251 /*
252 * we know the extra rows will have been filled
253 * with blank, properly allocated rows, so just swap 'em with the
254 * ones that need moving.
255 */
256 cells = grid->cells;
257 for(y = olddim.y - 1; y >= y0; y--){
258 tmp = cells[y + n];
259 cells[y + n] = cells[y];
260 cells[y] = tmp;
261 }
262 insbeams(grid->rows, grid->dim.y, y0, n);
263 return nil;
264 }
265
266 static char*
inscols(TkGrid * grid,int x0,int n)267 inscols(TkGrid *grid, int x0, int n)
268 {
269 TkGridcell **cells;
270 Point olddim;
271 int y;
272 char *e;
273
274 olddim = grid->dim;
275 if(x0 > olddim.x){
276 n = x0 + n - olddim.x;
277 x0 = olddim.x;
278 }
279
280 e = ensuregridsize(grid, Pt(olddim.x + n, olddim.y));
281 if(e != nil)
282 return e;
283
284 cells = grid->cells;
285 for(y = 0; y < olddim.y; y++){
286 memmove(cells[y] + x0 + n, cells[y] + x0, sizeof(TkGridcell) * (olddim.x - x0));
287 memset(cells[y] + x0, 0, sizeof(TkGridcell) * n);
288 }
289 insbeams(grid->cols, grid->dim.x, x0, n);
290 return nil;
291 }
292
293 static int
maximum(int a,int b)294 maximum(int a, int b)
295 {
296 if(a > b)
297 return a;
298 return b;
299 }
300
301 /*
302 * return the width of cols/rows between x0 and x1 in the beam,
303 * excluding the padding at either end, but including padding in the middle.
304 */
305 static int
beamsize(TkGridbeam * cols,int x0,int x1)306 beamsize(TkGridbeam *cols, int x0, int x1)
307 {
308 int tot, fpad, x;
309
310 if(x0 >= x1)
311 return 0;
312
313 tot = cols[x0].act;
314 fpad = cols[x0].pad;
315 for(x = x0 + 1; x < x1; x++){
316 tot += cols[x].act + maximum(cols[x].pad, fpad);
317 fpad = cols[x].pad;
318 }
319 return tot;
320 }
321
322 /*
323 * return starting position of cell index on beam, relative
324 * to top-left of grid
325 */
326 static int
beamcellpos(TkGridbeam * beam,int blen,int index)327 beamcellpos(TkGridbeam *beam, int blen, int index)
328 {
329 int x;
330 if(blen == 0 || index >= blen || index < 0)
331 return 0;
332 x = beam[0].pad + beamsize(beam, 0, index);
333 if(index > 0)
334 x += maximum(beam[index-1].pad, beam[index].pad);
335 return x;
336 }
337
338 static Rectangle
cellbbox(TkGrid * grid,Point pos)339 cellbbox(TkGrid *grid, Point pos)
340 {
341 Point dim;
342 Rectangle r;
343
344 dim = grid->dim;
345 if(pos.x > dim.x)
346 pos.x = dim.x;
347 if(pos.y > dim.y)
348 pos.y = dim.y;
349
350 r.min.x = beamcellpos(grid->cols, dim.x, pos.x);
351 r.min.y = beamcellpos(grid->rows, dim.y, pos.y);
352 if(pos.x == dim.x)
353 r.max.x = r.min.x;
354 else
355 r.max.x = r.min.x + grid->cols[pos.x].act;
356 if(pos.y == dim.y)
357 r.max.y = r.min.y;
358 else
359 r.max.y = r.min.y + grid->rows[pos.y].act;
360 return rectaddpt(r, grid->origin);
361 }
362
363 /*
364 * return true ifthere are any spanning cells covering row _index_
365 */
366 static int
gridrowhasspan(TkGrid * grid,int index)367 gridrowhasspan(TkGrid *grid, int index)
368 {
369 int i, d;
370 Point dim;
371 TkGridcell *cell;
372
373 dim = grid->dim;
374 if(index > 0 && index < dim.y){
375 for(i = 0; i < dim.x; i++){
376 cell = &grid->cells[index][i];
377 if(cell->tk != nil){
378 d = cell->span.x;
379 if(d == 0)
380 return 1;
381 i += d - 1;
382 }
383 }
384 }
385 return 0;
386 }
387
388 /*
389 * return true ifthere are any spanning cells covering column _index_
390 */
391 static int
gridcolhasspan(TkGrid * grid,int index)392 gridcolhasspan(TkGrid *grid, int index)
393 {
394 int i, d;
395 Point dim;
396 TkGridcell *cell;
397
398 dim = grid->dim;
399 if(index > 0 && index < dim.x){
400 for(i = 0; i < dim.y; i++){
401 cell = &grid->cells[i][index];
402 if(cell->tk != nil){
403 d = cell->span.y;
404 if(d == 0)
405 return 1;
406 i += d - 1;
407 }
408 }
409 }
410 return 0;
411 }
412
413 /*
414 * find cell that's spanning the grid position p
415 */
416 static int
findspan(TkGrid * grid,Point p,Point * cp)417 findspan(TkGrid *grid, Point p, Point *cp)
418 {
419 Point dim;
420 TkGridcell **cells;
421 Tk *tk;
422
423 dim = grid->dim;
424 cells = grid->cells;
425
426 if(p.x < 0 || p.y < 0 || p.x >= dim.x || p.y >= dim.y)
427 return 0;
428
429 if(cells[p.y][p.x].tk == nil)
430 return 0;
431
432 if(cells[p.y][p.x].span.x == 0){
433 tk = cells[p.y][p.x].tk;
434 for(; p.y >= 0; p.y--)
435 if(cells[p.y][p.x].tk != tk)
436 break;
437 p.y++;
438 for(; p.x >= 0; p.x--)
439 if(cells[p.y][p.x].tk != tk)
440 break;
441 p.x++;
442 }
443 *cp = p;
444 return 1;
445 }
446
447 static int
parsegridindex(TkGridbeam * beam,int blen,char * s)448 parsegridindex(TkGridbeam *beam, int blen, char *s)
449 {
450 int n, i;
451 char *e;
452
453 if(s[0] == '\0')
454 return -1;
455
456 n = strtol(s, &e, 10);
457 if(*e == '\0')
458 return n;
459
460 if(strcmp(s, "end") == 0)
461 return blen;
462
463 for(i = 0; i < blen; i++)
464 if(beam[i].name != nil && strcmp(beam[i].name, s) == 0)
465 return i;
466 return -1;
467 }
468
469 static char*
tkgridconfigure(TkTop * t,TkGridparam * p,TkName * names)470 tkgridconfigure(TkTop *t, TkGridparam *p, TkName *names)
471 {
472 TkGrid *grid;
473 TkGridcell **cells;
474 TkName *n;
475 Tk *tkf, *tkp;
476 Point dim, pos, q, span, startpos;
477 int maxcol, c, i, j, x;
478 char *e;
479
480 if(names == nil)
481 return nil;
482
483 if(p->span.x < 1 || p->span.y < 1)
484 return TkBadvl;
485
486 tkf = nil;
487
488 maxcol = 0;
489 for(n = names; n; n = n->link){
490 c = n->name[0];
491 if((c=='-' || c=='^' || c=='x') && n->name[1] == '\0'){
492 maxcol++;
493 continue;
494 }
495 tkp = tklook(t, n->name, 0);
496 if(tkp == nil){
497 tkerr(t, n->name);
498 return TkBadwp;
499 }
500 if(tkp->flag & Tkwindow)
501 return TkIstop;
502 if(tkp->parent != nil)
503 return TkWpack;
504
505 /*
506 * unpacking now does give an non-reversible side effect
507 * ifthere's an error encountered later, but also means
508 * that a widget repacked in the same grid will
509 * have its original cell still available
510 */
511 if(tkp->master != nil){
512 tkpackqit(tkp->master);
513 tkdelpack(tkp);
514 }
515 if(tkf == nil)
516 tkf = tkp;
517 n->obj = tkp;
518 tkp->flag &= ~Tkgridpack;
519 maxcol += p->span.x;
520 }
521
522 if(p->in == nil && tkf != nil)
523 p->in = tklook(t, tkf->name->name, 1);
524
525 if(p->in == nil)
526 return TkNomaster;
527
528 grid = p->in->grid;
529 if(grid == nil && p->in->slave != nil)
530 return TkNotgrid;
531
532 if(grid == nil){
533 grid = malloc(sizeof(TkGrid));
534 if(grid == nil)
535 return TkNomem;
536 p->in->grid = grid;
537 }
538
539 dim = grid->dim;
540 pos = ZP;
541 if(p->row != nil){
542 pos.y = parsegridindex(grid->rows, dim.y, p->row);
543 if(pos.y < 0)
544 return TkBadix;
545 }
546 if(p->col != nil){
547 pos.x = parsegridindex(grid->cols, dim.x, p->col);
548 if(pos.x < 0)
549 return TkBadix;
550 }
551 /*
552 * ifrow is not specified, find first unoccupied row
553 */
554 if(p->row == nil){
555 for(pos.y = 0; pos.y < dim.y; pos.y++){
556 for(x = 0; x < dim.x; x++)
557 if(grid->cells[pos.y][x].tk != nil)
558 break;
559 if(x == dim.x)
560 break;
561 }
562 }
563 e = ensuregridsize(grid, Pt(pos.x + maxcol, pos.y + p->span.y));
564 if(e != nil)
565 return e;
566 cells = grid->cells;
567
568 startpos = pos;
569 /*
570 * check that all our grid cells are empty, and that row/col spans
571 * are well formed
572 */
573 n = names;
574 while(n != nil){
575 c = n->name[0];
576 switch (c){
577 case 'x':
578 n = n->link;
579 pos.x++;
580 break;
581 case '^':
582 if(findspan(grid, Pt(pos.x, pos.y - 1), &q) == 0)
583 return TkBadspan;
584 span = cells[q.y][q.x].span;
585 for(i = 0; i < span.x; i++){
586 if(n == nil || strcmp(n->name, "^"))
587 return TkBadspan;
588 if(cells[pos.y][pos.x + i].tk != nil)
589 return TkBadgridcell;
590 n = n->link;
591 }
592 pos.x += span.x;
593 break;
594 case '-':
595 return TkBadspan;
596 case '.':
597 tkp = n->obj;
598 if(tkisslave(p->in, tkp))
599 return TkRecur;
600 n = n->link;
601 if(tkp->flag & Tkgridpack)
602 return TkWpack;
603 tkp->flag |= Tkgridpack;
604 span = p->span;
605 for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
606 span.x++;
607 for(i = pos.x; i < pos.x + span.x; i++)
608 for(j = pos.y; j < pos.y + span.y; j++)
609 if(cells[j][i].tk != nil)
610 return TkBadgridcell;
611 pos.x = i;
612 break;
613 }
614 }
615
616 /*
617 * actually insert the items into the grid
618 */
619 n = names;
620 pos = startpos;
621 while(n != nil){
622 c = n->name[0];
623 switch (c){
624 case 'x':
625 n = n->link;
626 pos.x++;
627 break;
628 case '^':
629 findspan(grid, Pt(pos.x, pos.y - 1), &q);
630 span = cells[q.y][q.x].span;
631 tkf = cells[q.y][q.x].tk;
632 if(q.y + span.y == pos.y)
633 cells[q.y][q.x].span.y++;
634
635 for(i = 0; i < span.x; i++){
636 cells[pos.y][pos.x++].tk = tkf;
637 n = n->link;
638 }
639 break;
640 case '.':
641 tkf = n->obj;
642 n = n->link;
643 span = p->span;
644 for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
645 span.x++;
646 for(i = pos.x; i < pos.x + span.x; i++)
647 for(j = pos.y; j < pos.y + span.y; j++)
648 cells[j][i].tk = tkf;
649 cells[pos.y][pos.x].span = span;
650 tkf->master = p->in;
651 tkf->next = p->in->slave;
652 p->in->slave = tkf;
653 if(p->in->flag & Tksubsub)
654 tksetbits(tkf, Tksubsub);
655 tkgridsetopt(p, tkf);
656 pos.x = i;
657 break;
658 }
659 }
660 tkpackqit(p->in);
661 tkrunpack(t);
662 return nil;
663 }
664
665 void
tkgriddelslave(Tk * tk)666 tkgriddelslave(Tk *tk)
667 {
668 int y, x, yy;
669 TkGrid *grid;
670 TkGridcell **cells, *cell;
671 Point dim, span;
672
673 if(tk == nil || tk->master == nil || tk->master->grid == nil)
674 return;
675 grid = tk->master->grid;
676 cells = grid->cells;
677 dim = grid->dim;
678 for(y = 0; y < dim.y; y++){
679 for(x = 0; x < dim.x; x++){
680 cell = &cells[y][x];
681 if(cell->tk == tk){
682 span = cell->span;
683 for(yy = y; yy < y + span.y; yy++)
684 memset(cells[yy] + x, 0, span.x * sizeof(TkGridcell));
685 return;
686 }
687 }
688 }
689 }
690
691 char*
tkgetgridmaster(TkTop * t,char ** arg,char * buf,char * ebuf,Tk ** master)692 tkgetgridmaster(TkTop *t, char **arg, char *buf, char *ebuf, Tk **master)
693 {
694 TkGrid *grid;
695
696 *arg = tkword(t, *arg, buf, ebuf, nil);
697 *master = tklook(t, buf, 0);
698 if(*master == nil)
699 return TkBadwp;
700 grid = (*master)->grid;
701 if(grid == nil && (*master)->slave != nil)
702 return TkNotgrid;
703 return nil;
704 }
705
706 static int
gridfindloc(TkGridbeam * beam,int blen,int f)707 gridfindloc(TkGridbeam *beam, int blen, int f)
708 {
709 int x, i, fpad;
710 if(blen == 0 || f < 0)
711 return -1;
712
713 fpad = 0;
714 x = 0;
715 for(i = 0; i < blen; i++){
716 x += maximum(fpad, beam[i].pad);
717 if(x <= f && f < x + beam[i].act)
718 return i;
719 x += beam[i].act;
720 }
721 return -1;
722 }
723
724 static char*
tkgridcellinfo(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)725 tkgridcellinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
726 {
727 /* grid cellinfo master x y */
728 Tk *master;
729 char *e;
730 Point p;
731 TkGrid *grid;
732 TkGridcell **cells;
733
734 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
735 if(e != nil || master->grid == nil)
736 return e;
737 grid = master->grid;
738
739 e = tkfracword(t, &arg, &p.x, nil);
740 if(e != nil)
741 return e;
742 e = tkfracword(t, &arg, &p.y, nil);
743 if(e != nil)
744 return e;
745
746 p.x = TKF2I(p.x);
747 p.y = TKF2I(p.y);
748 if(p.x < 0 || p.x >= grid->dim.x || p.y < 0 || p.y >= grid->dim.y)
749 return nil;
750
751 if(!findspan(grid, p, &p))
752 return nil;
753
754 cells = grid->cells;
755 return tkvalue(val, "%s -in %s -column %d -row %d -columnspan %d -rowspan %d",
756 cells[p.y][p.x].tk->name->name,
757 cells[p.y][p.x].tk->master->name->name, p.x, p.y,
758 cells[p.y][p.x].span.x, cells[p.y][p.x].span.y);
759 }
760
761 static char*
tkgridlocation(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)762 tkgridlocation(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
763 {
764 /* grid location master x y */
765 Tk *master;
766 char *e;
767 Point p;
768 int col, row;
769 TkGrid *grid;
770
771 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
772 if(e != nil || master->grid == nil)
773 return e;
774 grid = master->grid;
775
776 e = tkfracword(t, &arg, &p.x, nil);
777 if(e != nil)
778 return e;
779 e = tkfracword(t, &arg, &p.y, nil);
780 if(e != nil)
781 return e;
782
783 p.x = TKF2I(p.x);
784 p.y = TKF2I(p.y);
785
786 p = subpt(p, grid->origin);
787 col = gridfindloc(grid->cols, grid->dim.x, p.x);
788 row = gridfindloc(grid->rows, grid->dim.y, p.y);
789 if(col < 0 || row < 0)
790 return nil;
791 return tkvalue(val, "%d %d", col, row);
792 }
793
794 static char*
tkgridinfo(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)795 tkgridinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
796 {
797 Tk *tk;
798 TkGrid *grid;
799 int x, y;
800 Point dim;
801 TkGridcell *row;
802
803 tkword(t, arg, buf, ebuf, nil);
804 tk = tklook(t, buf, 0);
805 if(tk == nil)
806 return TkBadwp;
807 if(tk->master == nil || tk->master->grid == nil)
808 return TkNotgrid;
809 grid = tk->master->grid;
810 dim = grid->dim;
811 for(y = 0; y < dim.y; y++){
812 row = grid->cells[y];
813 for(x = 0; x < dim.x; x++)
814 if(row[x].tk == tk)
815 goto Found;
816 }
817 return TkNotgrid; /* should not happen */
818 Found:
819 return tkvalue(val, "-in %s -column %d -row %d -columnspan %d -rowspan %d",
820 tk->master->name->name, x, y, grid->cells[y][x].span.x, grid->cells[y][x].span.y);
821 }
822
823 static char*
tkgridforget(TkTop * t,char * arg,char * buf,char * ebuf)824 tkgridforget(TkTop *t, char *arg, char *buf, char *ebuf)
825 {
826 Tk *tk;
827 for(;;){
828 arg = tkword(t, arg, buf, ebuf, nil);
829 if(arg == nil || buf[0] == '\0')
830 break;
831 tk = tklook(t, buf, 0);
832 if(tk == nil){
833 tkrunpack(t);
834 tkerr(t, buf);
835 return TkBadwp;
836 }
837 tkpackqit(tk->master);
838 tkdelpack(tk);
839 }
840 tkrunpack(t);
841 return nil;
842 }
843
844 static char*
tkgridslaves(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)845 tkgridslaves(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
846 {
847 Tk *master, *tk;
848 char *fmt;
849 int i, isrow, index;
850 TkGrid *grid;
851 TkGridcell *cell;
852 char *e;
853 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
854 if(e != nil || master->grid == nil)
855 return e;
856 grid = master->grid;
857 arg = tkword(t, arg, buf, ebuf, nil);
858 fmt = "%s";
859 if(buf[0] == '\0'){
860 for(tk = master->slave; tk != nil; tk = tk->next){
861 if(tk->name != nil){
862 e = tkvalue(val, fmt, tk->name->name);
863 if(e != nil)
864 return e;
865 fmt = " %s";
866 }
867 }
868 return nil;
869 }
870 if(strcmp(buf, "-row") == 0)
871 isrow = 1;
872 else if(strcmp(buf, "-column") == 0)
873 isrow = 0;
874 else
875 return TkBadop;
876 tkword(t, arg, buf, ebuf, nil);
877 if(isrow)
878 index = parsegridindex(grid->rows, grid->dim.y, buf);
879 else
880 index = parsegridindex(grid->cols, grid->dim.x, buf);
881 if(index < 0)
882 return TkBadix;
883 if(isrow){
884 if(index >= grid->dim.y)
885 return nil;
886 for(i = 0; i < grid->dim.x; i++){
887 cell = &grid->cells[index][i];
888 if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
889 e = tkvalue(val, fmt, cell->tk->name->name);
890 if(e != nil)
891 return e;
892 fmt = " %s";
893 }
894 }
895 } else{
896 if(index >= grid->dim.x)
897 return nil;
898 for(i = 0; i < grid->dim.y; i++){
899 cell = &grid->cells[i][index];
900 if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
901 e = tkvalue(val, fmt, cell->tk->name->name);
902 if(e != nil)
903 return e;
904 fmt = " %s";
905 }
906 }
907 }
908
909 return nil;
910 }
911
912 static char*
tkgriddelete(TkTop * t,char * arg,char * buf,char * ebuf,int delrow)913 tkgriddelete(TkTop *t, char *arg, char *buf, char *ebuf, int delrow)
914 {
915 Tk *master, **l, *f;
916 TkGrid *grid;
917 TkGridbeam *beam;
918 int blen, i0, i1, x, y;
919 Point dim;
920 TkGridcell **cells;
921 char *e;
922
923 /*
924 * grid (columndelete|rowdelete) master index0 ?index1?
925 */
926
927 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
928 if(e != nil || master->grid == nil)
929 return e;
930 grid = master->grid;
931
932 if(delrow){
933 beam = grid->rows;
934 blen = grid->dim.y;
935 } else{
936 beam = grid->cols;
937 blen = grid->dim.x;
938 }
939
940 arg = tkword(t, arg, buf, ebuf, nil);
941 i0 = parsegridindex(beam, blen, buf);
942 if(i0 < 0)
943 return TkBadix;
944
945 tkword(t, arg, buf, ebuf, nil);
946 if(buf[0] == '\0')
947 i1 = i0 + 1;
948 else
949 i1 = parsegridindex(beam, blen, buf);
950 if(i1 < 0 || i0 > i1)
951 return TkBadix;
952 if(i0 > blen || i0 == i1)
953 return nil;
954 if(i1 > blen)
955 i1 = blen;
956 cells = grid->cells;
957 dim = grid->dim;
958 if(delrow){
959 if(gridrowhasspan(grid, i0) || gridrowhasspan(grid, i1))
960 return TkBadgridcell;
961 for(y = i0; y < i1; y++)
962 for(x = 0; x < dim.x; x++)
963 if(cells[y][x].tk != nil)
964 cells[y][x].tk->flag |= Tkgridremove;
965 delrows(grid, i0, i1);
966 grid->rows = delbeams(beam, blen, i0, i1);
967 } else{
968 if(gridcolhasspan(grid, i0) || gridcolhasspan(grid, i1))
969 return TkBadgridcell;
970 for(y = 0; y < dim.y; y++)
971 for(x = i0; x < i1; x++)
972 if(cells[y][x].tk != nil)
973 cells[y][x].tk->flag |= Tkgridremove;
974 delcols(grid, i0, i1);
975 grid->cols = delbeams(beam, blen, i0, i1);
976 }
977 l = &master->slave;
978 for(f = *l; f; f = f->next){
979 if(f->flag & Tkgridremove){
980 *l = f->next;
981 f->master = nil;
982 f->flag &= ~Tkgridremove;
983 } else
984 l = &f->next;
985 }
986 tkpackqit(master);
987 tkrunpack(t);
988 return nil;
989 }
990
991
992 static char*
tkgridinsert(TkTop * t,char * arg,char * buf,char * ebuf,int insertrow)993 tkgridinsert(TkTop *t, char *arg, char *buf, char *ebuf, int insertrow)
994 {
995 int index, count;
996 Point dim;
997 Tk *master;
998 TkGrid *grid;
999 int gotarg;
1000 char *e;
1001
1002 /*
1003 * grid (rowinsert|columninsert) master index ?count?
1004 * it's an error ifthe insert splits any spanning cells.
1005 */
1006 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
1007 if(e != nil || master->grid == nil)
1008 return e;
1009 grid = master->grid;
1010 dim = grid->dim;
1011
1012 arg = tkword(t, arg, buf, ebuf, nil);
1013 if(insertrow)
1014 index = parsegridindex(grid->rows, dim.y, buf);
1015 else
1016 index = parsegridindex(grid->cols, dim.x, buf);
1017 if(index < 0 || index > (insertrow ? dim.y : dim.x))
1018 return TkBadix;
1019
1020 tkword(t, arg, buf, ebuf, &gotarg);
1021 if(gotarg){
1022 count = strtol(buf, &buf, 10);
1023 if(buf[0] != '\0' || count < 0)
1024 return TkBadvl;
1025 } else
1026 count = 1;
1027
1028 /*
1029 * check that we're not splitting any spanning cells
1030 */
1031 if(insertrow){
1032 if(gridrowhasspan(grid, index))
1033 return TkBadgridcell;
1034 e = insrows(grid, index, count);
1035 } else{
1036 if(gridcolhasspan(grid, index))
1037 return TkBadgridcell;
1038 e = inscols(grid, index, count);
1039 }
1040 tkpackqit(master);
1041 tkrunpack(t);
1042 return e;
1043 }
1044
1045 /*
1046 * (rowconfigure|columnconfigure) master index ?-option value ...?
1047 */
1048 static char*
tkbeamconfigure(TkTop * t,char * arg,int isrow)1049 tkbeamconfigure(TkTop *t, char *arg, int isrow)
1050 {
1051 TkBeamparam p;
1052 TkOptab tko[2];
1053 TkName *names;
1054 Tk *master;
1055 int index;
1056 TkGrid *grid;
1057 TkGridbeam *beam;
1058 Point dim;
1059 char *e;
1060
1061 p.equalise = BoolX;
1062 p.name = nil;
1063 p.weight = -1;
1064 p.minsize = -1;
1065 p.maxsize = -1;
1066 p.pad = -1;
1067
1068 tko[0].ptr = &p;
1069 tko[0].optab = beamopts;
1070 tko[1].ptr = nil;
1071
1072 names = nil;
1073 e = tkparse(t, arg, tko, &names);
1074 if(e != nil)
1075 return e;
1076
1077 if(names == nil || names->link == nil)
1078 return TkBadvl;
1079
1080 master = tklook(t, names->name, 0);
1081 if(master == nil)
1082 return TkBadwp;
1083
1084 grid = master->grid;
1085 if(grid == nil){
1086 if(master->slave != nil)
1087 return TkNotgrid;
1088 grid = master->grid = malloc(sizeof(TkGrid));
1089 if(grid == nil){
1090 tkfreename(names);
1091 return TkNomem;
1092 }
1093 }
1094
1095 if(isrow){
1096 index = parsegridindex(grid->rows, grid->dim.y, names->link->name);
1097 } else
1098 index = parsegridindex(grid->cols, grid->dim.x, names->link->name);
1099 if(index < 0){
1100 e = TkBadix;
1101 goto Error;
1102 }
1103 if(isrow)
1104 dim = Pt(grid->dim.x, index + 1);
1105 else
1106 dim = Pt(index + 1, grid->dim.y);
1107 e = ensuregridsize(grid, dim);
1108 if(e != nil)
1109 goto Error;
1110
1111 if(isrow)
1112 beam = &grid->rows[index];
1113 else
1114 beam = &grid->cols[index];
1115
1116 if(p.minsize >= 0)
1117 beam->minsize = p.minsize;
1118 if(p.maxsize >= 0)
1119 beam->maxsize = p.maxsize;
1120 if(p.weight >= 0)
1121 beam->weight = p.weight;
1122 if(p.pad >= 0)
1123 beam->pad = p.pad;
1124 if(p.name != nil){
1125 free(beam->name);
1126 beam->name = p.name;
1127 }
1128 if(p.equalise != BoolX)
1129 beam->equalise = p.equalise == BoolT;
1130
1131 tkpackqit(master);
1132 tkrunpack(t);
1133
1134 Error:
1135 tkfreename(names);
1136 return e;
1137 }
1138
1139 char*
tkgridsize(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)1140 tkgridsize(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
1141 {
1142 Tk *master;
1143 TkGrid *grid;
1144 char *e;
1145
1146 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
1147 if(e != nil)
1148 return e;
1149 grid = master->grid;
1150 if(grid == nil)
1151 return tkvalue(val, "0 0");
1152 else
1153 return tkvalue(val, "%d %d", grid->dim.x, grid->dim.y);
1154 }
1155
1156 char*
tkgridbbox(TkTop * t,char * arg,char ** val,char * buf,char * ebuf)1157 tkgridbbox(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
1158 {
1159 Point p0, p1;
1160 Tk *master;
1161 TkGrid *grid;
1162 char *e;
1163 int gotarg;
1164 Point dim;
1165 Rectangle r;
1166
1167 e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
1168 if(e != nil || master->grid == nil)
1169 return e;
1170
1171 grid = master->grid;
1172 dim = grid->dim;
1173 arg = tkword(t, arg, buf, ebuf, &gotarg);
1174 if(!gotarg){
1175 p0 = ZP;
1176 p1 = dim;
1177 } else{
1178 p0.x = parsegridindex(grid->cols, dim.x, buf);
1179 arg = tkword(t, arg, buf, ebuf, &gotarg);
1180 if(!gotarg)
1181 return TkFewpt;
1182 p0.y = parsegridindex(grid->rows, dim.y, buf);
1183 arg = tkword(t, arg, buf, ebuf, &gotarg);
1184 if(!gotarg){
1185 p1 = p0;
1186 } else{
1187 p1.x = parsegridindex(grid->cols, dim.x, buf);
1188 arg = tkword(t, arg, buf, ebuf, &gotarg);
1189 if(!gotarg)
1190 return TkFewpt;
1191 p1.y = parsegridindex(grid->rows, dim.y, buf);
1192 }
1193 }
1194 if(p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0)
1195 return TkBadix;
1196
1197 r = cellbbox(grid, p0);
1198 if(!eqpt(p0, p1))
1199 combinerect(&r, cellbbox(grid, p1));
1200 return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y);
1201 }
1202
1203 char*
tkgridindex(TkTop * t,char * arg,char ** val,char * buf,char * ebuf,int isrow)1204 tkgridindex(TkTop *t, char *arg, char **val, char *buf, char *ebuf, int isrow)
1205 {
1206 Tk *master;
1207 TkGrid *grid;
1208 TkGridbeam *beam;
1209 int blen, i;
1210
1211 arg = tkword(t, arg, buf, ebuf, nil);
1212 master = tklook(t, buf, 0);
1213 if(master == nil)
1214 return TkBadwp;
1215 tkword(t, arg, buf, ebuf, nil);
1216 grid = master->grid;
1217 if(grid == nil){
1218 beam = nil;
1219 blen = 0;
1220 } else if(isrow){
1221 beam = grid->rows;
1222 blen = grid->dim.y;
1223 } else{
1224 beam = grid->cols;
1225 blen = grid->dim.x;
1226 }
1227 i = parsegridindex(beam, blen, buf);
1228 if(i < 0)
1229 return TkBadix;
1230 return tkvalue(val, "%d", i);
1231 }
1232
1233 void
tkfreegrid(TkGrid * grid)1234 tkfreegrid(TkGrid *grid)
1235 {
1236 Point dim;
1237 int i;
1238 dim = grid->dim;
1239 for(i = 0; i < dim.x; i++)
1240 free(grid->cols[i].name);
1241 for(i = 0; i < dim.y; i++)
1242 free(grid->rows[i].name);
1243 for(i = 0; i < dim.y; i++)
1244 free(grid->cells[i]);
1245 free(grid->cells);
1246 free(grid->rows);
1247 free(grid->cols);
1248 free(grid);
1249 }
1250
1251 char*
tkgrid(TkTop * t,char * arg,char ** val)1252 tkgrid(TkTop *t, char *arg, char **val)
1253 {
1254 TkGridparam *p;
1255 TkOptab tko[2];
1256 TkName *names;
1257 char *e, *w, *buf;
1258
1259 buf = mallocz(Tkmaxitem, 0);
1260 if(buf == nil)
1261 return TkNomem;
1262
1263 w = tkword(t, arg, buf, buf+Tkmaxitem, nil);
1264 if('a' <= buf[0] && buf[0] <= 'z'){
1265 if(strcmp(buf, "debug") == 0){
1266 Tk *tk;
1267 e = tkgetgridmaster(t, &w, buf, buf+Tkmaxitem, &tk);
1268 if(e == nil)
1269 printgrid(tk->grid);
1270 } else
1271 if(strcmp(buf, "forget") == 0)
1272 e = tkgridforget(t, w, buf, buf+Tkmaxitem);
1273 else if(strcmp(buf, "propagate") == 0)
1274 e = tkpropagate(t, w);
1275 else if(strcmp(buf, "slaves") == 0)
1276 e = tkgridslaves(t, w, val, buf, buf+Tkmaxitem);
1277 else if(strcmp(buf, "rowconfigure") == 0)
1278 e = tkbeamconfigure(t, w, 1);
1279 else if(strcmp(buf, "columnconfigure") == 0)
1280 e = tkbeamconfigure(t, w, 0);
1281 else if(strcmp(buf, "rowinsert") == 0)
1282 e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 1);
1283 else if(strcmp(buf, "columninsert") == 0)
1284 e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 0);
1285 else if(strcmp(buf, "size") == 0)
1286 e = tkgridsize(t, w, val, buf, buf+Tkmaxitem);
1287 else if(strcmp(buf, "rowdelete") == 0)
1288 e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 1);
1289 else if(strcmp(buf, "columndelete") == 0)
1290 e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 0);
1291 else if(strcmp(buf, "rowindex") == 0)
1292 e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 1);
1293 else if(strcmp(buf, "columnindex") == 0)
1294 e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 0);
1295 else if(strcmp(buf, "bbox") == 0)
1296 e = tkgridbbox(t, w, val, buf, buf+Tkmaxitem);
1297 else if(strcmp(buf, "location") == 0)
1298 e = tkgridlocation(t, w, val, buf, buf+Tkmaxitem);
1299 else if(strcmp(buf, "cellinfo") == 0)
1300 e = tkgridcellinfo(t, w, val, buf, buf+Tkmaxitem);
1301 else if(strcmp(buf, "info") == 0)
1302 e = tkgridinfo(t, w, val, buf, buf+Tkmaxitem);
1303 else{
1304 tkerr(t, buf);
1305 e = TkBadcm;
1306 }
1307 } else{
1308 p = malloc(sizeof(TkGridparam));
1309 if(p == nil)
1310 return TkNomem;
1311 tko[0].ptr = p;
1312 tko[0].optab = opts;
1313 tko[1].ptr = nil;
1314
1315 p->span.x = 1;
1316 p->span.y = 1;
1317 p->pad.x = p->pad.y = p->ipad.x = p->ipad.y = -1;
1318 p->sticky = -1;
1319
1320 names = nil;
1321 e = tkparse(t, arg, tko, &names);
1322 if(e != nil){
1323 free(p);
1324 return e;
1325 }
1326
1327 e = tkgridconfigure(t, p, names);
1328 free(p->row);
1329 free(p->col);
1330 free(p);
1331 tkfreename(names);
1332 }
1333 free(buf);
1334 return e;
1335 }
1336
1337 /*
1338 * expand widths of rows/columns according to weight.
1339 * return amount of space still left over.
1340 */
1341 static int
expandwidths(int x0,int x1,int totwidth,TkGridbeam * cols,int expandzero)1342 expandwidths(int x0, int x1, int totwidth, TkGridbeam *cols, int expandzero)
1343 {
1344 int share, x, slack, m, w, equal;
1345
1346 if(x0 >= x1)
1347 return 0;
1348
1349 share = 0;
1350 for(x = x0; x < x1; x++)
1351 share += cols[x].weight;
1352
1353 slack = totwidth - beamsize(cols, x0, x1);
1354 if(slack <= 0)
1355 return 0;
1356
1357 if(share == 0 && expandzero){
1358 share = x1 - x0;
1359 equal = 1;
1360 } else
1361 equal = 0;
1362
1363 for(x = x0; x < x1 && share > 0 ; x++){
1364 w = equal ? 1 : cols[x].weight;
1365 m = slack * w / share;
1366 cols[x].act += m;
1367 slack -= m;
1368 share -= w;
1369 }
1370 return slack;
1371 }
1372
1373 static void
gridequalise(TkGridbeam * beam,int blen)1374 gridequalise(TkGridbeam *beam, int blen)
1375 {
1376 int i, max;
1377
1378 max = 0;
1379 for(i = 0; i < blen; i++)
1380 if(beam[i].equalise == BoolT && beam[i].act > max)
1381 max = beam[i].act;
1382
1383 if(max > 0)
1384 for(i = 0; i < blen; i++)
1385 if(beam[i].equalise == BoolT)
1386 beam[i].act = max;
1387 }
1388
1389 /*
1390 * take into account min/max beam sizes.
1391 * max takes precedence
1392 */
1393 static void
beamminmax(TkGridbeam * beam,int n)1394 beamminmax(TkGridbeam *beam, int n)
1395 {
1396 TkGridbeam *e;
1397 e = &beam[n];
1398 for(; beam < e; beam++){
1399 if(beam->act < beam->minsize)
1400 beam->act = beam->minsize;
1401 if(beam->act > beam->maxsize)
1402 beam->act = beam->maxsize;
1403 }
1404 }
1405
1406 int
tkgridder(Tk * master)1407 tkgridder(Tk *master)
1408 {
1409 TkGrid *grid;
1410 TkGridcell **cells, *cell;
1411 TkGridbeam *rows, *cols;
1412 TkGeom pos;
1413 Point org;
1414 Tk *slave;
1415 int dx, dy, x, y, w, bw2, fpadx, fpady;
1416 Point req;
1417
1418 grid = master->grid;
1419 dx = grid->dim.x;
1420 dy = grid->dim.y;
1421 cells = grid->cells;
1422 rows = grid->rows;
1423 cols = grid->cols;
1424
1425 for(x = 0; x < dx; x++)
1426 cols[x].act = 0;
1427
1428 /* calculate column widths and row heights (ignoring multi-column cells) */
1429 for(y = 0; y < dy; y++){
1430 rows[y].act = 0;
1431 for(x = 0; x < dx; x++){
1432 cell = &cells[y][x];
1433 if((slave = cell->tk) != nil){
1434 bw2 = slave->borderwidth * 2;
1435 w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
1436 if(cell->span.x == 1 && w > cols[x].act)
1437 cols[x].act = w;
1438 w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
1439 if(cell->span.y == 1 && w > rows[y].act)
1440 rows[y].act = w;
1441 }
1442 }
1443 }
1444
1445 beamminmax(rows, dy);
1446 beamminmax(cols, dx);
1447
1448 /* now check that spanning cells fit in their rows/columns */
1449 for(y = 0; y < dy; y++)
1450 for(x = 0; x < dx; x++){
1451 cell = &cells[y][x];
1452 if((slave = cell->tk) != nil){
1453 bw2 = slave->borderwidth * 2;
1454 if(cell->span.x > 1){
1455 w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
1456 expandwidths(x, x+cell->span.x, w, cols, 1);
1457 }
1458 if(cell->span.y > 1){
1459 w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
1460 expandwidths(y, y+cell->span.y, w, rows, 1);
1461 }
1462 }
1463 }
1464
1465 gridequalise(rows, dy);
1466 gridequalise(cols, dx);
1467
1468 if(dx == 0)
1469 req.x = 0;
1470 else
1471 req.x = beamsize(cols, 0, dx) + cols[0].pad + cols[dx-1].pad;
1472
1473 if(dy == 0)
1474 req.y = 0;
1475 else
1476 req.y = beamsize(rows, 0, dy) + rows[0].pad + rows[dy-1].pad;
1477
1478 if(req.x != master->req.width || req.y != master->req.height)
1479 if((master->flag & Tknoprop) == 0){
1480 if(master->geom != nil){
1481 master->geom(master, master->act.x, master->act.y,
1482 req.x, req.y);
1483 } else{
1484 master->req.width = req.x;
1485 master->req.height = req.y;
1486 tkpackqit(master->master);
1487 }
1488 return 0;
1489 }
1490 org = ZP;
1491 if(dx > 0 && master->act.width > req.x)
1492 org.x = expandwidths(0, dx,
1493 master->act.width - (cols[0].pad + cols[dx-1].pad),
1494 cols, 0) / 2;
1495 if(dy > 0 && master->act.height > req.y)
1496 org.y = expandwidths(0, dy,
1497 master->act.height - (rows[0].pad + rows[dy-1].pad),
1498 rows, 0) / 2;
1499
1500 grid->origin = org;
1501 pos.y = org.y;
1502 fpady = 0;
1503 for(y = 0; y < dy; y++){
1504 pos.y += maximum(fpady, rows[y].pad);
1505 fpady = rows[y].pad;
1506
1507 pos.x = org.x;
1508 fpadx = 0;
1509 for(x = 0; x < dx; x++){
1510 cell = &cells[y][x];
1511 pos.x += maximum(fpadx, cols[x].pad);
1512 fpadx = cols[x].pad;
1513 if((slave = cell->tk) != nil && cell->span.x > 0){
1514 pos.width = beamsize(cols, x, x + cell->span.x);
1515 pos.height = beamsize(rows, y, y + cell->span.y);
1516 tksetslavereq(slave, pos);
1517 }
1518 pos.x += cols[x].act;
1519 }
1520 pos.y += rows[y].act;
1521 }
1522
1523 master->dirty = tkrect(master, 1);
1524 tkdirty(master);
1525 return 1;
1526 }
1527