1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <draw.h> 5 #include <mouse.h> 6 #include <keyboard.h> 7 #include <control.h> 8 #include "group.h" 9 10 static int debug = 0; 11 static int debugm = 0; 12 static int debugr = 0; 13 14 enum{ 15 EAdd, 16 EBorder, 17 EBordercolor, 18 EFocus, 19 EHide, 20 EImage, 21 ERect, 22 ERemove, 23 EReveal, 24 ESeparation, 25 EShow, 26 ESize, 27 }; 28 29 static char *cmds[] = { 30 [EAdd] = "add", 31 [EBorder] = "border", 32 [EBordercolor] = "bordercolor", 33 [EFocus] = "focus", 34 [EHide] = "hide", 35 [EImage] = "image", 36 [ERect] = "rect", 37 [ERemove] = "remove", 38 [EReveal] = "reveal", 39 [ESeparation] = "separation", 40 [EShow] = "show", 41 [ESize] = "size", 42 }; 43 44 static void boxboxresize(Group*, Rectangle); 45 static void columnresize(Group*, Rectangle); 46 static void groupctl(Control *c, CParse *cp); 47 static void groupfree(Control*); 48 static void groupmouse(Control *, Mouse *); 49 static void groupsize(Control *c); 50 static void removegroup(Group*, int); 51 static void rowresize(Group*, Rectangle); 52 static void stackresize(Group*, Rectangle); 53 54 static void 55 groupinit(Group *g) 56 { 57 g->bordercolor = _getctlimage("black"); 58 g->image = _getctlimage("white"); 59 g->border = 0; 60 g->mansize = 0; 61 g->separation = 0; 62 g->selected = -1; 63 g->lastkid = -1; 64 g->kids = nil; 65 g->separators = nil; 66 g->nkids = 0; 67 g->nseparators = 0; 68 g->ctl = groupctl; 69 g->mouse = groupmouse; 70 g->exit = groupfree; 71 } 72 73 static void 74 groupctl(Control *c, CParse *cp) 75 { 76 int cmd, i, n; 77 78 Rectangle r; 79 Group *g; 80 81 g = (Group*)c; 82 cmd = _ctllookup(cp->args[0], cmds, nelem(cmds)); 83 switch(cmd){ 84 case EAdd: 85 for (i = 1; i < cp->nargs; i++){ 86 c = controlcalled(cp->args[i]); 87 if (c == nil) 88 ctlerror("%q: no such control: %s", g->name, cp->args[i]); 89 _ctladdgroup(g, c); 90 } 91 if (g->setsize) 92 g->setsize((Control*)g); 93 break; 94 case EBorder: 95 _ctlargcount(g, cp, 2); 96 if(cp->iargs[1] < 0) 97 ctlerror("%q: bad border: %c", g->name, cp->str); 98 g->border = cp->iargs[1]; 99 break; 100 case EBordercolor: 101 _ctlargcount(g, cp, 2); 102 _setctlimage(g, &g->bordercolor, cp->args[1]); 103 break; 104 case EFocus: 105 /* ignore focus change */ 106 break; 107 case EHide: 108 _ctlargcount(g, cp, 1); 109 for (i = 0; i < g->nkids; i++) 110 if (g->kids[i]->ctl) 111 _ctlprint(g->kids[i], "hide"); 112 g->hidden = 1; 113 break; 114 case EImage: 115 _ctlargcount(g, cp, 2); 116 _setctlimage(g, &g->image, cp->args[1]); 117 break; 118 case ERect: 119 _ctlargcount(g, cp, 5); 120 r.min.x = cp->iargs[1]; 121 r.min.y = cp->iargs[2]; 122 r.max.x = cp->iargs[3]; 123 r.max.y = cp->iargs[4]; 124 if(Dx(r)<=0 || Dy(r)<=0) 125 ctlerror("%q: bad rectangle: %s", g->name, cp->str); 126 g->rect = r; 127 r = insetrect(r, g->border); 128 if (g->nkids == 0) 129 return; 130 switch(g->type){ 131 case Ctlboxbox: 132 boxboxresize(g, r); 133 break; 134 case Ctlcolumn: 135 columnresize(g, r); 136 break; 137 case Ctlrow: 138 rowresize(g, r); 139 break; 140 case Ctlstack: 141 stackresize(g, r); 142 break; 143 } 144 break; 145 case ERemove: 146 _ctlargcount(g, cp, 2); 147 for (n = 0; n < g->nkids; n++) 148 if (strcmp(cp->args[1], g->kids[n]->name) == 0) 149 break; 150 if (n == g->nkids) 151 ctlerror("%s: remove nonexistent control: %q", g->name, cp->args[1]); 152 removegroup(g, n); 153 if (g->setsize) 154 g->setsize((Control*)g); 155 break; 156 case EReveal: 157 g->hidden = 0; 158 if (debugr) fprint(2, "reveal %s\n", g->name); 159 if (g->type == Ctlstack){ 160 if (cp->nargs == 2){ 161 if (cp->iargs[1] < 0 || cp->iargs[1] >= g->nkids) 162 ctlerror("%s: control out of range: %q", g->name, cp->str); 163 g->selected = cp->iargs[1]; 164 }else 165 _ctlargcount(g, cp, 1); 166 for (i = 0; i < g->nkids; i++) 167 if (g->kids[i]->ctl){ 168 if (g->selected == i){ 169 if (debugr) fprint(2, "reveal %s: reveal kid %s\n", g->name, g->kids[i]->name); 170 _ctlprint(g->kids[i], "reveal"); 171 }else{ 172 if (debugr) fprint(2, "reveal %s: hide kid %s\n", g->name, g->kids[i]->name); 173 _ctlprint(g->kids[i], "hide"); 174 } 175 } 176 break; 177 } 178 _ctlargcount(g, cp, 1); 179 if (debug) fprint(2, "reveal %s: border %R/%d\n", g->name, g->rect, g->border); 180 border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min); 181 r = insetrect(g->rect, g->border); 182 if (debug) fprint(2, "reveal %s: draw %R\n", g->name, r); 183 draw(g->screen, r, g->image->image, nil, g->image->image->r.min); 184 for (i = 0; i < g->nkids; i++) 185 if (g->kids[i]->ctl) 186 _ctlprint(g->kids[i], "reveal"); 187 break; 188 case EShow: 189 _ctlargcount(g, cp, 1); 190 if (g->hidden) 191 break; 192 // pass it on to the kiddies 193 if (debug) fprint(2, "show %s: border %R/%d\n", g->name, g->rect, g->border); 194 border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min); 195 r = insetrect(g->rect, g->border); 196 if (debug) fprint(2, "show %s: draw %R\n", g->name, r); 197 draw(g->screen, r, g->image->image, nil, g->image->image->r.min); 198 for (i = 0; i < g->nkids; i++) 199 if (g->kids[i]->ctl){ 200 if (debug) fprint(2, "show %s: kid %s: %q\n", g->name, g->kids[i]->name, cp->str); 201 _ctlprint(g->kids[i], "show"); 202 } 203 flushimage(display, 1); 204 break; 205 case ESize: 206 r.max = Pt(_Ctlmaxsize, _Ctlmaxsize); 207 if (g->type == Ctlboxbox) 208 _ctlargcount(g, cp, 5); 209 switch(cp->nargs){ 210 default: 211 ctlerror("%s: args of %q", g->name, cp->str); 212 case 1: 213 /* recursively set size */ 214 g->mansize = 0; 215 if (g->setsize) 216 g->setsize((Control*)g); 217 break; 218 case 5: 219 _ctlargcount(g, cp, 5); 220 r.max.x = cp->iargs[3]; 221 r.max.y = cp->iargs[4]; 222 /* fall through */ 223 case 3: 224 r.min.x = cp->iargs[1]; 225 r.min.y = cp->iargs[2]; 226 if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y) 227 ctlerror("%q: bad sizes: %s", g->name, cp->str); 228 g->size = r; 229 g->mansize = 1; 230 break; 231 } 232 break; 233 case ESeparation: 234 if (g->type != Ctlstack){ 235 _ctlargcount(g, cp, 2); 236 if(cp->iargs[1] < 0) 237 ctlerror("%q: illegal value: %c", g->name, cp->str); 238 g->separation = cp->iargs[1]; 239 break; 240 } 241 // fall through for Ctlstack 242 default: 243 ctlerror("%q: unrecognized message '%s'", g->name, cp->str); 244 break; 245 } 246 } 247 248 static void 249 groupfree(Control *c) 250 { 251 Group *g; 252 253 g = (Group*)c; 254 _putctlimage(g->bordercolor); 255 free(g->kids); 256 } 257 258 static void 259 groupmouse(Control *c, Mouse *m) 260 { 261 Group *g; 262 int i, lastkid; 263 264 g = (Group*)c; 265 if (g->type == Ctlstack){ 266 i = g->selected; 267 if (i >= 0 && g->kids[i]->mouse && 268 ( ( ((m->buttons == 0) || (g->lastbut == 0)) && 269 ptinrect(m->xy, g->kids[i]->rect) ) || 270 ( ((m->buttons != 0) || (g->lastbut != 0)) && 271 (g->lastkid == i) ) ) ) { 272 if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n", 273 g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut, 274 ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0); 275 (g->kids[i]->mouse)(g->kids[i], m); 276 g->lastkid = i; 277 g->lastbut = m->buttons; 278 } else { 279 if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n", 280 g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut, 281 ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0); 282 } 283 return; 284 } 285 286 lastkid = -1; 287 for(i=0; i<g->nkids; i++) { 288 if(g->kids[i]->mouse && 289 ( ( ((m->buttons == 0) || (g->lastbut == 0)) && 290 ptinrect(m->xy, g->kids[i]->rect) ) || 291 ( ((m->buttons != 0) || (g->lastbut != 0)) && 292 (g->lastkid == i) ) ) ) { 293 if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n", 294 g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut, 295 ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0); 296 (g->kids[i]->mouse)(g->kids[i], m); 297 lastkid = i; 298 } else { 299 if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n", 300 g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut, 301 ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0); 302 } 303 } 304 g->lastkid = lastkid; 305 g->lastbut = m->buttons; 306 307 #ifdef notdef 308 if(m->buttons == 0){ 309 /* buttons now up */ 310 g->lastbut = 0; 311 return; 312 } 313 if(g->lastbut == 0 && m->buttons != 0){ 314 /* button went down, start tracking border */ 315 switch(g->stacking){ 316 default: 317 return; 318 case Vertical: 319 p = Pt(m->xy.x, middle_of_border.y); 320 p0 = Pt(g->r.min.x, m->xy.y); 321 p1 = Pt(g->r.max.x, m->xy.y); 322 break; 323 case Horizontal: 324 p = Pt(middle_of_border.x, m->xy.y); 325 p0 = Pt(m->xy.x, g->r.min.y); 326 p1 = Pt(m->xy.x, g->r.max.y); 327 break; 328 } 329 // setcursor(); 330 oi = nil; 331 } else if (g->lastbut != 0 && s->m.buttons != 0){ 332 /* button is down, keep tracking border */ 333 if(!eqpt(s->m.xy, p)){ 334 p = onscreen(s->m.xy); 335 r = canonrect(Rpt(p0, p)); 336 if(Dx(r)>5 && Dy(r)>5){ 337 i = allocwindow(wscreen, r, Refnone, 0xEEEEEEFF); /* grey */ 338 freeimage(oi); 339 if(i == nil) 340 goto Rescue; 341 oi = i; 342 border(i, r, Selborder, red, ZP); 343 flushimage(display, 1); 344 } 345 } 346 } else if (g->lastbut != 0 && s->m.buttons == 0){ 347 /* button went up, resize kiddies */ 348 } 349 g->lastbut = s->m.buttons; 350 #endif 351 } 352 353 static void 354 activategroup(Control *c, int act) 355 { 356 int i; 357 Group *g; 358 359 g = (Group*)c; 360 for (i = 0; i < g->nkids; i++) 361 if (act) 362 activate(g->kids[i]); 363 else 364 deactivate(g->kids[i]); 365 } 366 367 Control * 368 createrow(Controlset *cs, char *name) 369 { 370 Control *c; 371 c = _createctl(cs, "row", sizeof(Group), name); 372 groupinit((Group*)c); 373 c->setsize = groupsize; 374 c->activate = activategroup; 375 return c; 376 } 377 378 Control * 379 createcolumn(Controlset *cs, char *name) 380 { 381 Control *c; 382 c = _createctl(cs, "column", sizeof(Group), name); 383 groupinit((Group*)c); 384 c->setsize = groupsize; 385 c->activate = activategroup; 386 return c; 387 } 388 389 Control * 390 createboxbox(Controlset *cs, char *name) 391 { 392 Control *c; 393 c = _createctl(cs, "boxbox", sizeof(Group), name); 394 groupinit((Group*)c); 395 c->activate = activategroup; 396 return c; 397 } 398 399 Control * 400 createstack(Controlset *cs, char *name) 401 { 402 Control *c; 403 c = _createctl(cs, "stack", sizeof(Group), name); 404 groupinit((Group*)c); 405 c->setsize = groupsize; 406 return c; 407 } 408 409 void 410 _ctladdgroup(Control *c, Control *q) 411 { 412 Group *g = (Group*)c; 413 414 g->kids = ctlrealloc(g->kids, sizeof(Group*)*(g->nkids+1)); 415 g->kids[g->nkids++] = q; 416 } 417 418 static void 419 removegroup(Group *g, int n) 420 { 421 int i; 422 423 if (g->selected == n) 424 g->selected = -1; 425 else if (g->selected > n) 426 g->selected--; 427 428 for (i = n+1; i < g->nkids; i++) 429 g->kids[i-1] = g->kids[i]; 430 g->nkids--; 431 } 432 433 static void 434 groupsize(Control *c) 435 { 436 Rectangle r; 437 int i; 438 Control *q; 439 Group *g; 440 441 g = (Group*)c; 442 assert(g->type == Ctlcolumn || g->type == Ctlrow || g->type == Ctlstack); 443 if (g->mansize) return; 444 r = Rect(1, 1, 1, 1); 445 if (debug) fprint(2, "groupsize %q\n", g->name); 446 for (i = 0; i < g->nkids; i++){ 447 q = g->kids[i]; 448 if (q->setsize) 449 q->setsize(q); 450 if (q->size.min.x == 0 || q->size.min.y == 0 || q->size.max.x == 0 || q->size.max.y == 0) 451 ctlerror("%q: bad size %R", q->name, q->size); 452 if (debug) fprint(2, "groupsize %q: [%d %q]: %R\n", g->name, i, q->name, q->size); 453 switch(g->type){ 454 case Ctlrow: 455 if (i) 456 r.min.x += q->size.min.x + g->border; 457 else 458 r.min.x = q->size.min.x; 459 if (i) 460 r.max.x += q->size.max.x + g->border; 461 else 462 r.max.x = q->size.max.x; 463 if (r.min.y < q->size.min.y) r.min.y = q->size.min.y; 464 if (r.max.y < q->size.max.y) r.max.y = q->size.max.y; 465 break; 466 case Ctlcolumn: 467 if (r.min.x < q->size.min.x) r.min.x = q->size.min.x; 468 if (r.max.x < q->size.max.x) r.max.x = q->size.max.x; 469 if (i) 470 r.min.y += q->size.min.y + g->border; 471 else 472 r.min.y = q->size.min.y; 473 if (i) 474 r.max.y += q->size.max.y + g->border; 475 else 476 r.max.y = q->size.max.y; 477 break; 478 case Ctlstack: 479 if (r.min.x < q->size.min.x) r.min.x = q->size.min.x; 480 if (r.max.x < q->size.max.x) r.max.x = q->size.max.x; 481 if (r.min.y < q->size.min.y) r.min.y = q->size.min.y; 482 if (r.max.y < q->size.max.y) r.max.y = q->size.max.y; 483 break; 484 } 485 } 486 g->size = rectaddpt(r, Pt(g->border, g->border)); 487 if (debug) fprint(2, "groupsize %q: %R\n", g->name, g->size); 488 } 489 490 static void 491 boxboxresize(Group *g, Rectangle r) 492 { 493 int rows, cols, ht, wid, i, hpad, wpad; 494 Rectangle rr; 495 496 if(debug) fprint(2, "boxboxresize %q %R (%d×%d) min/max %R separation %d\n", g->name, r, Dx(r), Dy(r), g->size, g->separation); 497 ht = 0; 498 for(i=0; i<g->nkids; i++){ 499 if (g->kids[i]->size.min.y > ht) 500 ht = g->kids[i]->size.min.y; 501 } 502 if (ht == 0) 503 ctlerror("boxboxresize: height"); 504 rows = Dy(r) / (ht+g->separation); 505 hpad = (Dy(r) % (ht+g->separation)) / g->nkids; 506 cols = (g->nkids+rows-1)/rows; 507 wid = Dx(r) / cols - g->separation; 508 for(i=0; i<g->nkids; i++){ 509 if (g->kids[i]->size.max.x < wid) 510 wid = g->kids[i]->size.max.x; 511 } 512 for(i=0; i<g->nkids; i++){ 513 if (g->kids[i]->size.min.x > wid) 514 wid = g->kids[i]->size.min.x; 515 } 516 if (wid > Dx(r) / cols) 517 ctlerror("can't fit controls in boxbox"); 518 wpad = (Dx(r) % (wid+g->separation)) / g->nkids; 519 rr = rectaddpt(Rect(0,0,wid, ht), addpt(r.min, Pt(g->separation/2, g->separation/2))); 520 if(debug) fprint(2, "boxboxresize rows %d, cols %d, wid %d, ht %d, wpad %d, hpad %d\n", rows, cols, wid, ht, wpad, hpad); 521 for(i=0; i<g->nkids; i++){ 522 if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, g->kids[i]->name, rr, Dx(rr), Dy(rr)); 523 _ctlprint(g->kids[i], "rect %R", 524 rectaddpt(rr, Pt((wpad+wid+g->separation)*(i/rows), (hpad+ht+g->separation)*(i%rows)))); 525 } 526 g->nseparators = rows + cols - 2; 527 g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle)); 528 rr = r; 529 rr.max.y = rr.min.y + g->separation+hpad; 530 for (i = 1; i < rows; i++){ 531 g->separators[i-1] = rectaddpt(rr, Pt(0, (hpad+ht+g->separation)*i-g->separation-hpad)); 532 if(debug) fprint(2, "row separation %d [%d]: %R\n", i, i-1, rectaddpt(rr, Pt(0, (hpad+ht+g->separation)*i-g->separation))); 533 } 534 rr = r; 535 rr.max.x = rr.min.x + g->separation+wpad; 536 for (i = 1; i < cols; i++){ 537 g->separators[i+rows-2] = rectaddpt(rr, Pt((wpad+wid+g->separation)*i-g->separation-wpad, 0)); 538 if(debug) fprint(2, "col separation %d [%d]: %R\n", i, i+rows-2, rectaddpt(rr, Pt((wpad+wid+g->separation)*i-g->separation, 0))); 539 } 540 } 541 542 static void 543 columnresize(Group *g, Rectangle r) 544 { 545 int x, y, *d, *p, i, j, t; 546 Rectangle rr; 547 Control *q; 548 549 x = Dx(r); 550 y = Dy(r); 551 if(debug) fprint(2, "columnresize %q %R (%d×%d) min/max %R separation %d\n", g->name, r, Dx(r), Dy(r), g->size, g->separation); 552 if (x < g->size.min.x) { 553 werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x); 554 r.max.x = r.min.x + g->size.min.x; 555 } 556 if (y < g->size.min.y) { 557 werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y); 558 r.max.y = r.min.y + g->size.min.y; 559 y = Dy(r); 560 } 561 d = ctlmalloc(g->nkids*sizeof(int)); 562 p = ctlmalloc(g->nkids*sizeof(int)); 563 if(debug) fprint(2, "kiddies: "); 564 for (i = 0; i < g->nkids; i++) { 565 q = g->kids[i]; 566 if(debug) fprint(2, "[%q]: %d⋯%d\t", q->name, q->size.min.y, q->size.max.y); 567 d[i] = q->size.min.y; 568 y -= d[i]; 569 p[i] = q->size.max.y - q->size.min.y; 570 } 571 if(debug) fprint(2, "\n"); 572 y -= (g->nkids-1) * g->separation; 573 if(y < 0){ 574 if (debug) fprint(2, "columnresize: y == %d\n", y); 575 y = 0; 576 } 577 if (y >= g->size.max.y - g->size.min.y) { 578 // all rects can be maximum width 579 for (i = 0; i < g->nkids; i++) 580 d[i] += p[i]; 581 y -= g->size.max.y - g->size.min.y; 582 } else { 583 // rects can't be max width, divide up the rest 584 j = y; 585 for (i = 0; i < g->nkids; i++) { 586 t = p[i] * y/(g->size.max.y - g->size.min.y); 587 d[i] += t; 588 j -= t; 589 } 590 d[0] += j; 591 y = 0; 592 } 593 g->nseparators = g->nkids-1; 594 g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle)); 595 j = 0; 596 rr = r; 597 for (i = 0; i < g->nkids; i++) { 598 q = g->kids[i]; 599 if (i < g->nkids - 1){ 600 g->separators[i].min.x = r.min.x; 601 g->separators[i].max.x = r.max.x; 602 } 603 t = y / (g->nkids - i); 604 y -= t; 605 j += t/2; 606 rr.min.y = r.min.y + j; 607 if (i) 608 g->separators[i-1].max.y = rr.min.y; 609 j += d[i]; 610 rr.max.y = r.min.y + j; 611 if (i < g->nkids - 1) 612 g->separators[i].min.y = rr.max.y; 613 j += g->separation + t - t/2; 614 _ctlprint(q, "rect %R", rr); 615 if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, rr, Dx(rr), Dy(rr)); 616 } 617 free(d); 618 free(p); 619 } 620 621 static void 622 rowresize(Group *g, Rectangle r) 623 { 624 int x, y, *d, *p, i, j, t; 625 Rectangle rr; 626 Control *q; 627 628 x = Dx(r); 629 y = Dy(r); 630 if(debug) fprint(2, "rowresize %q %R (%d×%d), separation %d\n", g->name, r, Dx(r), Dy(r), g->separation); 631 if (x < g->size.min.x) { 632 werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x); 633 r.max.x = r.min.x + g->size.min.x; 634 x = Dx(r); 635 } 636 if (y < g->size.min.y) { 637 werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y); 638 r.max.y = r.min.y + g->size.min.y; 639 } 640 d = ctlmalloc(g->nkids*sizeof(int)); 641 p = ctlmalloc(g->nkids*sizeof(int)); 642 if(debug) fprint(2, "kiddies: "); 643 for (i = 0; i < g->nkids; i++) { 644 q = g->kids[i]; 645 if(debug) fprint(2, "[%q]: %d⋯%d\t", q->name, q->size.min.x, q->size.max.x); 646 d[i] = q->size.min.x; 647 x -= d[i]; 648 p[i] = q->size.max.x - q->size.min.x; 649 } 650 if(debug) fprint(2, "\n"); 651 x -= (g->nkids-1) * g->separation; 652 if(x < 0){ 653 if (debug) fprint(2, "rowresize: x == %d\n", x); 654 x = 0; 655 } 656 if (x >= g->size.max.x - g->size.min.x) { 657 if (debug) fprint(2, "max: %d > %d - %d", x, g->size.max.x, g->size.min.x); 658 // all rects can be maximum width 659 for (i = 0; i < g->nkids; i++) 660 d[i] += p[i]; 661 x -= g->size.max.x - g->size.min.x; 662 } else { 663 if (debug) fprint(2, "divvie up: %d < %d - %d", x, g->size.max.x, g->size.min.x); 664 // rects can't be max width, divide up the rest 665 j = x; 666 for (i = 0; i < g->nkids; i++) { 667 t = p[i] * x/(g->size.max.x - g->size.min.x); 668 d[i] += t; 669 j -= t; 670 } 671 d[0] += j; 672 x = 0; 673 } 674 j = 0; 675 g->nseparators = g->nkids-1; 676 g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle)); 677 rr = r; 678 for (i = 0; i < g->nkids; i++) { 679 q = g->kids[i]; 680 if (i < g->nkids - 1){ 681 g->separators[i].min.y = r.min.y; 682 g->separators[i].max.y = r.max.y; 683 } 684 t = x / (g->nkids - i); 685 x -= t; 686 j += t/2; 687 rr.min.x = r.min.x + j; 688 if (i) 689 g->separators[i-1].max.x = rr.min.x; 690 j += d[i]; 691 rr.max.x = r.min.x + j; 692 if (i < g->nkids - 1) 693 g->separators[i].min.x = rr.max.x; 694 j += g->separation + t - t/2; 695 _ctlprint(q, "rect %R", rr); 696 if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, rr, Dx(rr), Dy(rr)); 697 } 698 free(d); 699 free(p); 700 } 701 702 static void 703 stackresize(Group *g, Rectangle r) 704 { 705 int x, y, i; 706 Control *q; 707 708 x = Dx(r); 709 y = Dy(r); 710 if(debug) fprint(2, "stackresize %q %R (%d×%d)\n", g->name, r, Dx(r), Dy(r)); 711 if (x < g->size.min.x){ 712 werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x); 713 return; 714 } 715 if (y < g->size.min.y){ 716 werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y); 717 return; 718 } 719 if (x > g->size.max.x) { 720 x = (x - g->size.max.x)/2; 721 r.min.x += x; 722 r.max.x -= x; 723 } 724 if (y > g->size.max.y) { 725 y = (y - g->size.max.y)/2; 726 r.min.y += y; 727 r.max.y -= y; 728 } 729 for (i = 0; i < g->nkids; i++){ 730 q = g->kids[i]; 731 if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, r, Dx(r), Dy(r)); 732 } 733 for (i = 0; i < g->nkids; i++){ 734 q = g->kids[i]; 735 _ctlprint(q, "rect %R", r); 736 } 737 } 738