group.c 19 KB

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