group.c 17 KB

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