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 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 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 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* 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 for(i--; i >= olddim.y; i--) 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* 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 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 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 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* 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* 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 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 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 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 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 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 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 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 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* 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 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* 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 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 /* 725 * optimised way to find a given slave, but somewhat more fragile 726 * as it assumes the slave has already been placed on the grid. 727 * not tested. 728 */ 729 static int 730 findslave(TkGrid *grid, Tk *tk, Point *pt) 731 { 732 Point loc, dim, p; 733 TkGridcell **cells; 734 dim = grid->dim; 735 cells = grid->cells; 736 loc.x = gridfindloc(grid->cols, grid->dim.x, tk->act.x); 737 if(loc.x == -1) 738 loc.x = 0; 739 loc.y = gridfindloc(grid->rows, grid->dim.y, tk->act.y); 740 if(loc.y == -1) 741 loc.y = 0; 742 for(p.y = loc.y; p.y < dim.y; p.y++) 743 for(p.x = loc.x; p.x < dim.x; p.x++) 744 if(cells[p.y][p.x].tk == tk){ 745 *pt = p; 746 return 1; 747 } 748 return 0; 749 } 750 static char* 751 tkgridcellinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 752 { 753 /* grid cellinfo master x y */ 754 Tk *master; 755 char *e; 756 Point p; 757 TkGrid *grid; 758 TkGridcell **cells; 759 760 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 761 if(e != nil || master->grid == nil) 762 return e; 763 grid = master->grid; 764 765 e = tkfracword(t, &arg, &p.x, nil); 766 if(e != nil) 767 return e; 768 e = tkfracword(t, &arg, &p.y, nil); 769 if(e != nil) 770 return e; 771 772 p.x = TKF2I(p.x); 773 p.y = TKF2I(p.y); 774 if(p.x < 0 || p.x >= grid->dim.x || p.y < 0 || p.y >= grid->dim.y) 775 return nil; 776 777 if(!findspan(grid, p, &p)) 778 return nil; 779 780 cells = grid->cells; 781 return tkvalue(val, "%s -in %s -column %d -row %d -columnspan %d -rowspan %d", 782 cells[p.y][p.x].tk->name->name, 783 cells[p.y][p.x].tk->master->name->name, p.x, p.y, 784 cells[p.y][p.x].span.x, cells[p.y][p.x].span.y); 785 } 786 787 static char* 788 tkgridlocation(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 789 { 790 /* grid location master x y */ 791 Tk *master; 792 char *e; 793 Point p; 794 int col, row; 795 TkGrid *grid; 796 797 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 798 if(e != nil || master->grid == nil) 799 return e; 800 grid = master->grid; 801 802 e = tkfracword(t, &arg, &p.x, nil); 803 if(e != nil) 804 return e; 805 e = tkfracword(t, &arg, &p.y, nil); 806 if(e != nil) 807 return e; 808 809 p.x = TKF2I(p.x); 810 p.y = TKF2I(p.y); 811 812 p = subpt(p, grid->origin); 813 col = gridfindloc(grid->cols, grid->dim.x, p.x); 814 row = gridfindloc(grid->rows, grid->dim.y, p.y); 815 if(col < 0 || row < 0) 816 return nil; 817 return tkvalue(val, "%d %d", col, row); 818 } 819 820 static char* 821 tkgridinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 822 { 823 Tk *tk; 824 TkGrid *grid; 825 int x, y; 826 Point dim; 827 TkGridcell *row; 828 829 tkword(t, arg, buf, ebuf, nil); 830 tk = tklook(t, buf, 0); 831 if(tk == nil) 832 return TkBadwp; 833 if(tk->master == nil || tk->master->grid == nil) 834 return TkNotgrid; 835 grid = tk->master->grid; 836 dim = grid->dim; 837 for(y = 0; y < dim.y; y++){ 838 row = grid->cells[y]; 839 for(x = 0; x < dim.x; x++) 840 if(row[x].tk == tk) 841 goto Found; 842 } 843 return TkNotgrid; /* should not happen */ 844 Found: 845 return tkvalue(val, "-in %s -column %d -row %d -columnspan %d -rowspan %d", 846 tk->master->name->name, x, y, grid->cells[y][x].span.x, grid->cells[y][x].span.y); 847 } 848 849 static char* 850 tkgridforget(TkTop *t, char *arg, char *buf, char *ebuf) 851 { 852 Tk *tk; 853 for(;;){ 854 arg = tkword(t, arg, buf, ebuf, nil); 855 if(arg == nil || buf[0] == '\0') 856 break; 857 tk = tklook(t, buf, 0); 858 if(tk == nil){ 859 tkrunpack(t); 860 tkerr(t, buf); 861 return TkBadwp; 862 } 863 tkpackqit(tk->master); 864 tkdelpack(tk); 865 } 866 tkrunpack(t); 867 return nil; 868 } 869 870 static char* 871 tkgridslaves(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 872 { 873 Tk *master, *tk; 874 char *fmt; 875 int i, isrow, index; 876 TkGrid *grid; 877 TkGridcell *cell; 878 char *e; 879 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 880 if(e != nil || master->grid == nil) 881 return e; 882 grid = master->grid; 883 arg = tkword(t, arg, buf, ebuf, nil); 884 fmt = "%s"; 885 if(buf[0] == '\0'){ 886 for(tk = master->slave; tk != nil; tk = tk->next){ 887 if(tk->name != nil){ 888 e = tkvalue(val, fmt, tk->name->name); 889 if(e != nil) 890 return e; 891 fmt = " %s"; 892 } 893 } 894 return nil; 895 } 896 if(strcmp(buf, "-row") == 0) 897 isrow = 1; 898 else if(strcmp(buf, "-column") == 0) 899 isrow = 0; 900 else 901 return TkBadop; 902 tkword(t, arg, buf, ebuf, nil); 903 if(isrow) 904 index = parsegridindex(grid->rows, grid->dim.y, buf); 905 else 906 index = parsegridindex(grid->cols, grid->dim.x, buf); 907 if(index < 0) 908 return TkBadix; 909 if(isrow){ 910 if(index >= grid->dim.y) 911 return nil; 912 for(i = 0; i < grid->dim.x; i++){ 913 cell = &grid->cells[index][i]; 914 if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){ 915 e = tkvalue(val, fmt, cell->tk->name->name); 916 if(e != nil) 917 return e; 918 fmt = " %s"; 919 } 920 } 921 } else{ 922 if(index >= grid->dim.x) 923 return nil; 924 for(i = 0; i < grid->dim.y; i++){ 925 cell = &grid->cells[i][index]; 926 if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){ 927 e = tkvalue(val, fmt, cell->tk->name->name); 928 if(e != nil) 929 return e; 930 fmt = " %s"; 931 } 932 } 933 } 934 935 return nil; 936 } 937 938 static char* 939 tkgriddelete(TkTop *t, char *arg, char *buf, char *ebuf, int delrow) 940 { 941 Tk *master, **l, *f; 942 TkGrid *grid; 943 TkGridbeam *beam; 944 int blen, i0, i1, x, y; 945 Point dim; 946 TkGridcell **cells; 947 char *e; 948 949 /* 950 * grid (columndelete|rowdelete) master index0 ?index1? 951 */ 952 953 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 954 if(e != nil || master->grid == nil) 955 return e; 956 grid = master->grid; 957 958 if(delrow){ 959 beam = grid->rows; 960 blen = grid->dim.y; 961 } else{ 962 beam = grid->cols; 963 blen = grid->dim.x; 964 } 965 966 arg = tkword(t, arg, buf, ebuf, nil); 967 i0 = parsegridindex(beam, blen, buf); 968 if(i0 < 0) 969 return TkBadix; 970 971 tkword(t, arg, buf, ebuf, nil); 972 if(buf[0] == '\0') 973 i1 = i0 + 1; 974 else 975 i1 = parsegridindex(beam, blen, buf); 976 if(i1 < 0 || i0 > i1) 977 return TkBadix; 978 if(i0 > blen || i0 == i1) 979 return nil; 980 if(i1 > blen) 981 i1 = blen; 982 cells = grid->cells; 983 dim = grid->dim; 984 if(delrow){ 985 if(gridrowhasspan(grid, i0) || gridrowhasspan(grid, i1)) 986 return TkBadgridcell; 987 for(y = i0; y < i1; y++) 988 for(x = 0; x < dim.x; x++) 989 if(cells[y][x].tk != nil) 990 cells[y][x].tk->flag |= Tkgridremove; 991 delrows(grid, i0, i1); 992 grid->rows = delbeams(beam, blen, i0, i1); 993 } else{ 994 if(gridcolhasspan(grid, i0) || gridcolhasspan(grid, i1)) 995 return TkBadgridcell; 996 for(y = 0; y < dim.y; y++) 997 for(x = i0; x < i1; x++) 998 if(cells[y][x].tk != nil) 999 cells[y][x].tk->flag |= Tkgridremove; 1000 delcols(grid, i0, i1); 1001 grid->cols = delbeams(beam, blen, i0, i1); 1002 } 1003 l = &master->slave; 1004 for(f = *l; f; f = f->next){ 1005 if(f->flag & Tkgridremove){ 1006 *l = f->next; 1007 f->master = nil; 1008 f->flag &= ~Tkgridremove; 1009 } else 1010 l = &f->next; 1011 } 1012 tkpackqit(master); 1013 tkrunpack(t); 1014 return nil; 1015 } 1016 1017 1018 static char* 1019 tkgridinsert(TkTop *t, char *arg, char *buf, char *ebuf, int insertrow) 1020 { 1021 int index, count; 1022 Point dim; 1023 Tk *master; 1024 TkGrid *grid; 1025 int gotarg; 1026 char *e; 1027 1028 /* 1029 * grid (rowinsert|columninsert) master index ?count? 1030 * it's an error ifthe insert splits any spanning cells. 1031 */ 1032 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 1033 if(e != nil || master->grid == nil) 1034 return e; 1035 grid = master->grid; 1036 dim = grid->dim; 1037 1038 arg = tkword(t, arg, buf, ebuf, nil); 1039 if(insertrow) 1040 index = parsegridindex(grid->rows, dim.y, buf); 1041 else 1042 index = parsegridindex(grid->cols, dim.x, buf); 1043 if(index < 0 || index > (insertrow ? dim.y : dim.x)) 1044 return TkBadix; 1045 1046 tkword(t, arg, buf, ebuf, &gotarg); 1047 if(gotarg){ 1048 count = strtol(buf, &buf, 10); 1049 if(buf[0] != '\0' || count < 0) 1050 return TkBadvl; 1051 } else 1052 count = 1; 1053 1054 /* 1055 * check that we're not splitting any spanning cells 1056 */ 1057 if(insertrow){ 1058 if(gridrowhasspan(grid, index)) 1059 return TkBadgridcell; 1060 e = insrows(grid, index, count); 1061 } else{ 1062 if(gridcolhasspan(grid, index)) 1063 return TkBadgridcell; 1064 e = inscols(grid, index, count); 1065 } 1066 tkpackqit(master); 1067 tkrunpack(t); 1068 return e; 1069 } 1070 1071 /* 1072 * (rowconfigure|columnconfigure) master index ?-option value ...? 1073 */ 1074 static char* 1075 tkbeamconfigure(TkTop *t, char *arg, int isrow) 1076 { 1077 TkBeamparam p; 1078 TkOptab tko[2]; 1079 TkName *names; 1080 Tk *master; 1081 int index; 1082 TkGrid *grid; 1083 TkGridbeam *beam; 1084 Point dim; 1085 char *e; 1086 1087 p.equalise = BoolX; 1088 p.name = nil; 1089 p.weight = -1; 1090 p.minsize = -1; 1091 p.maxsize = -1; 1092 p.pad = -1; 1093 1094 tko[0].ptr = &p; 1095 tko[0].optab = beamopts; 1096 tko[1].ptr = nil; 1097 1098 names = nil; 1099 e = tkparse(t, arg, tko, &names); 1100 if(e != nil) 1101 return e; 1102 1103 if(names == nil || names->link == nil) 1104 return TkBadvl; 1105 1106 master = tklook(t, names->name, 0); 1107 if(master == nil) 1108 return TkBadwp; 1109 1110 grid = master->grid; 1111 if(grid == nil){ 1112 if(master->slave != nil) 1113 return TkNotgrid; 1114 grid = master->grid = malloc(sizeof(TkGrid)); 1115 if(grid == nil){ 1116 tkfreename(names); 1117 return TkNomem; 1118 } 1119 } 1120 1121 if(isrow){ 1122 index = parsegridindex(grid->rows, grid->dim.y, names->link->name); 1123 } else 1124 index = parsegridindex(grid->cols, grid->dim.x, names->link->name); 1125 if(index < 0){ 1126 e = TkBadix; 1127 goto Error; 1128 } 1129 if(isrow) 1130 dim = Pt(grid->dim.x, index + 1); 1131 else 1132 dim = Pt(index + 1, grid->dim.y); 1133 e = ensuregridsize(grid, dim); 1134 if(e != nil) 1135 goto Error; 1136 1137 if(isrow) 1138 beam = &grid->rows[index]; 1139 else 1140 beam = &grid->cols[index]; 1141 1142 if(p.minsize >= 0) 1143 beam->minsize = p.minsize; 1144 if(p.maxsize >= 0) 1145 beam->maxsize = p.maxsize; 1146 if(p.weight >= 0) 1147 beam->weight = p.weight; 1148 if(p.pad >= 0) 1149 beam->pad = p.pad; 1150 if(p.name != nil){ 1151 free(beam->name); 1152 beam->name = p.name; 1153 } 1154 if(p.equalise != BoolX) 1155 beam->equalise = p.equalise == BoolT; 1156 1157 tkpackqit(master); 1158 tkrunpack(t); 1159 1160 Error: 1161 tkfreename(names); 1162 return e; 1163 } 1164 1165 char* 1166 tkgridsize(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 1167 { 1168 Tk *master; 1169 TkGrid *grid; 1170 char *e; 1171 1172 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 1173 if(e != nil) 1174 return e; 1175 grid = master->grid; 1176 if(grid == nil) 1177 return tkvalue(val, "0 0"); 1178 else 1179 return tkvalue(val, "%d %d", grid->dim.x, grid->dim.y); 1180 } 1181 1182 char* 1183 tkgridbbox(TkTop *t, char *arg, char **val, char *buf, char *ebuf) 1184 { 1185 Point p0, p1; 1186 Tk *master; 1187 TkGrid *grid; 1188 char *e; 1189 int gotarg; 1190 Point dim; 1191 Rectangle r; 1192 1193 e = tkgetgridmaster(t, &arg, buf, ebuf, &master); 1194 if(e != nil || master->grid == nil) 1195 return e; 1196 1197 grid = master->grid; 1198 dim = grid->dim; 1199 arg = tkword(t, arg, buf, ebuf, &gotarg); 1200 if(!gotarg){ 1201 p0 = ZP; 1202 p1 = dim; 1203 } else{ 1204 p0.x = parsegridindex(grid->cols, dim.x, buf); 1205 arg = tkword(t, arg, buf, ebuf, &gotarg); 1206 if(!gotarg) 1207 return TkFewpt; 1208 p0.y = parsegridindex(grid->rows, dim.y, buf); 1209 arg = tkword(t, arg, buf, ebuf, &gotarg); 1210 if(!gotarg){ 1211 p1 = p0; 1212 } else{ 1213 p1.x = parsegridindex(grid->cols, dim.x, buf); 1214 arg = tkword(t, arg, buf, ebuf, &gotarg); 1215 if(!gotarg) 1216 return TkFewpt; 1217 p1.y = parsegridindex(grid->rows, dim.y, buf); 1218 } 1219 } 1220 if(p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0) 1221 return TkBadix; 1222 1223 r = cellbbox(grid, p0); 1224 if(!eqpt(p0, p1)) 1225 combinerect(&r, cellbbox(grid, p1)); 1226 return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y); 1227 } 1228 1229 char* 1230 tkgridindex(TkTop *t, char *arg, char **val, char *buf, char *ebuf, int isrow) 1231 { 1232 Tk *master; 1233 TkGrid *grid; 1234 TkGridbeam *beam; 1235 int blen, i; 1236 1237 arg = tkword(t, arg, buf, ebuf, nil); 1238 master = tklook(t, buf, 0); 1239 if(master == nil) 1240 return TkBadwp; 1241 tkword(t, arg, buf, ebuf, nil); 1242 grid = master->grid; 1243 if(grid == nil){ 1244 beam = nil; 1245 blen = 0; 1246 } else if(isrow){ 1247 beam = grid->rows; 1248 blen = grid->dim.y; 1249 } else{ 1250 beam = grid->cols; 1251 blen = grid->dim.x; 1252 } 1253 i = parsegridindex(beam, blen, buf); 1254 if(i < 0) 1255 return TkBadix; 1256 return tkvalue(val, "%d", i); 1257 } 1258 1259 void 1260 tkfreegrid(TkGrid *grid) 1261 { 1262 Point dim; 1263 int i; 1264 dim = grid->dim; 1265 for(i = 0; i < dim.x; i++) 1266 free(grid->cols[i].name); 1267 for(i = 0; i < dim.y; i++) 1268 free(grid->rows[i].name); 1269 for(i = 0; i < dim.y; i++) 1270 free(grid->cells[i]); 1271 free(grid->cells); 1272 free(grid->rows); 1273 free(grid->cols); 1274 free(grid); 1275 } 1276 1277 char* 1278 tkgrid(TkTop *t, char *arg, char **val) 1279 { 1280 TkGridparam *p; 1281 TkOptab tko[2]; 1282 TkName *names; 1283 char *e, *w, *buf; 1284 1285 buf = mallocz(Tkmaxitem, 0); 1286 if(buf == nil) 1287 return TkNomem; 1288 1289 w = tkword(t, arg, buf, buf+Tkmaxitem, nil); 1290 if('a' <= buf[0] && buf[0] <= 'z'){ 1291 if(strcmp(buf, "debug") == 0){ 1292 Tk *tk; 1293 e = tkgetgridmaster(t, &w, buf, buf+Tkmaxitem, &tk); 1294 if(e == nil) 1295 printgrid(tk->grid); 1296 } else 1297 if(strcmp(buf, "forget") == 0) 1298 e = tkgridforget(t, w, buf, buf+Tkmaxitem); 1299 else if(strcmp(buf, "propagate") == 0) 1300 e = tkpropagate(t, w); 1301 else if(strcmp(buf, "slaves") == 0) 1302 e = tkgridslaves(t, w, val, buf, buf+Tkmaxitem); 1303 else if(strcmp(buf, "rowconfigure") == 0) 1304 e = tkbeamconfigure(t, w, 1); 1305 else if(strcmp(buf, "columnconfigure") == 0) 1306 e = tkbeamconfigure(t, w, 0); 1307 else if(strcmp(buf, "rowinsert") == 0) 1308 e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 1); 1309 else if(strcmp(buf, "columninsert") == 0) 1310 e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 0); 1311 else if(strcmp(buf, "size") == 0) 1312 e = tkgridsize(t, w, val, buf, buf+Tkmaxitem); 1313 else if(strcmp(buf, "rowdelete") == 0) 1314 e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 1); 1315 else if(strcmp(buf, "columndelete") == 0) 1316 e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 0); 1317 else if(strcmp(buf, "rowindex") == 0) 1318 e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 1); 1319 else if(strcmp(buf, "columnindex") == 0) 1320 e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 0); 1321 else if(strcmp(buf, "bbox") == 0) 1322 e = tkgridbbox(t, w, val, buf, buf+Tkmaxitem); 1323 else if(strcmp(buf, "location") == 0) 1324 e = tkgridlocation(t, w, val, buf, buf+Tkmaxitem); 1325 else if(strcmp(buf, "cellinfo") == 0) 1326 e = tkgridcellinfo(t, w, val, buf, buf+Tkmaxitem); 1327 else if(strcmp(buf, "info") == 0) 1328 e = tkgridinfo(t, w, val, buf, buf+Tkmaxitem); 1329 else{ 1330 tkerr(t, buf); 1331 e = TkBadcm; 1332 } 1333 } else{ 1334 p = malloc(sizeof(TkGridparam)); 1335 if(p == nil) 1336 return TkNomem; 1337 tko[0].ptr = p; 1338 tko[0].optab = opts; 1339 tko[1].ptr = nil; 1340 1341 p->span.x = 1; 1342 p->span.y = 1; 1343 p->pad.x = p->pad.y = p->ipad.x = p->ipad.y = -1; 1344 p->sticky = -1; 1345 1346 names = nil; 1347 e = tkparse(t, arg, tko, &names); 1348 if(e != nil){ 1349 free(p); 1350 return e; 1351 } 1352 1353 e = tkgridconfigure(t, p, names); 1354 free(p->row); 1355 free(p->col); 1356 free(p); 1357 tkfreename(names); 1358 } 1359 free(buf); 1360 return e; 1361 } 1362 1363 /* 1364 * expand widths of rows/columns according to weight. 1365 * return amount of space still left over. 1366 */ 1367 static int 1368 expandwidths(int x0, int x1, int totwidth, TkGridbeam *cols, int expandzero) 1369 { 1370 int share, x, slack, m, w, equal; 1371 1372 if(x0 >= x1) 1373 return 0; 1374 1375 share = 0; 1376 for(x = x0; x < x1; x++) 1377 share += cols[x].weight; 1378 1379 slack = totwidth - beamsize(cols, x0, x1); 1380 if(slack <= 0) 1381 return 0; 1382 1383 if(share == 0 && expandzero){ 1384 share = x1 - x0; 1385 equal = 1; 1386 } else 1387 equal = 0; 1388 1389 for(x = x0; x < x1 && share > 0 ; x++){ 1390 w = equal ? 1 : cols[x].weight; 1391 m = slack * w / share; 1392 cols[x].act += m; 1393 slack -= m; 1394 share -= w; 1395 } 1396 return slack; 1397 } 1398 1399 static void 1400 gridequalise(TkGridbeam *beam, int blen) 1401 { 1402 int i, max; 1403 1404 max = 0; 1405 for(i = 0; i < blen; i++) 1406 if(beam[i].equalise == BoolT && beam[i].act > max) 1407 max = beam[i].act; 1408 1409 if(max > 0) 1410 for(i = 0; i < blen; i++) 1411 if(beam[i].equalise == BoolT) 1412 beam[i].act = max; 1413 } 1414 1415 /* 1416 * take into account min/max beam sizes. 1417 * max takes precedence 1418 */ 1419 static void 1420 beamminmax(TkGridbeam *beam, int n) 1421 { 1422 TkGridbeam *e; 1423 e = &beam[n]; 1424 for(; beam < e; beam++){ 1425 if(beam->act < beam->minsize) 1426 beam->act = beam->minsize; 1427 if(beam->act > beam->maxsize) 1428 beam->act = beam->maxsize; 1429 } 1430 } 1431 1432 int 1433 tkgridder(Tk *master) 1434 { 1435 TkGrid *grid; 1436 TkGridcell **cells, *cell; 1437 TkGridbeam *rows, *cols; 1438 TkGeom pos; 1439 Point org; 1440 Tk *slave; 1441 int dx, dy, x, y, w, bw2, fpadx, fpady; 1442 Point req; 1443 1444 grid = master->grid; 1445 dx = grid->dim.x; 1446 dy = grid->dim.y; 1447 cells = grid->cells; 1448 rows = grid->rows; 1449 cols = grid->cols; 1450 1451 for(x = 0; x < dx; x++) 1452 cols[x].act = 0; 1453 1454 /* calculate column widths and row heights (ignoring multi-column cells) */ 1455 for(y = 0; y < dy; y++){ 1456 rows[y].act = 0; 1457 for(x = 0; x < dx; x++){ 1458 cell = &cells[y][x]; 1459 if((slave = cell->tk) != nil){ 1460 bw2 = slave->borderwidth * 2; 1461 w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x; 1462 if(cell->span.x == 1 && w > cols[x].act) 1463 cols[x].act = w; 1464 w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y; 1465 if(cell->span.y == 1 && w > rows[y].act) 1466 rows[y].act = w; 1467 } 1468 } 1469 } 1470 1471 beamminmax(rows, dy); 1472 beamminmax(cols, dx); 1473 1474 /* now check that spanning cells fit in their rows/columns */ 1475 for(y = 0; y < dy; y++) 1476 for(x = 0; x < dx; x++){ 1477 cell = &cells[y][x]; 1478 if((slave = cell->tk) != nil){ 1479 bw2 = slave->borderwidth * 2; 1480 if(cell->span.x > 1){ 1481 w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x; 1482 expandwidths(x, x+cell->span.x, w, cols, 1); 1483 } 1484 if(cell->span.y > 1){ 1485 w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y; 1486 expandwidths(y, y+cell->span.y, w, rows, 1); 1487 } 1488 } 1489 } 1490 1491 gridequalise(rows, dy); 1492 gridequalise(cols, dx); 1493 1494 if(dx == 0) 1495 req.x = 0; 1496 else 1497 req.x = beamsize(cols, 0, dx) + cols[0].pad + cols[dx-1].pad; 1498 1499 if(dy == 0) 1500 req.y = 0; 1501 else 1502 req.y = beamsize(rows, 0, dy) + rows[0].pad + rows[dy-1].pad; 1503 1504 if(req.x != master->req.width || req.y != master->req.height) 1505 if((master->flag & Tknoprop) == 0){ 1506 if(master->geom != nil){ 1507 master->geom(master, master->act.x, master->act.y, 1508 req.x, req.y); 1509 } else{ 1510 master->req.width = req.x; 1511 master->req.height = req.y; 1512 tkpackqit(master->master); 1513 } 1514 return 0; 1515 } 1516 org = ZP; 1517 if(dx > 0 && master->act.width > req.x) 1518 org.x = expandwidths(0, dx, 1519 master->act.width - (cols[0].pad + cols[dx-1].pad), 1520 cols, 0) / 2; 1521 if(dy > 0 && master->act.height > req.y) 1522 org.y = expandwidths(0, dy, 1523 master->act.height - (rows[0].pad + rows[dy-1].pad), 1524 rows, 0) / 2; 1525 1526 grid->origin = org; 1527 pos.y = org.y; 1528 fpady = 0; 1529 for(y = 0; y < dy; y++){ 1530 pos.y += maximum(fpady, rows[y].pad); 1531 fpady = rows[y].pad; 1532 1533 pos.x = org.x; 1534 fpadx = 0; 1535 for(x = 0; x < dx; x++){ 1536 cell = &cells[y][x]; 1537 pos.x += maximum(fpadx, cols[x].pad); 1538 fpadx = cols[x].pad; 1539 if((slave = cell->tk) != nil && cell->span.x > 0){ 1540 pos.width = beamsize(cols, x, x + cell->span.x); 1541 pos.height = beamsize(rows, y, y + cell->span.y); 1542 tksetslavereq(slave, pos); 1543 } 1544 pos.x += cols[x].act; 1545 } 1546 pos.y += rows[y].act; 1547 } 1548 1549 master->dirty = tkrect(master, 1); 1550 tkdirty(master); 1551 return 1; 1552 } 1553