Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/libcontrol/group.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}