group.c 20 KB

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