2016-11-25 17:18:40 +01:00
|
|
|
|
/*
|
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
|
* in the LICENSE file.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
|
#include <lib9.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
|
#include <thread.h>
|
|
|
|
|
#include <draw.h>
|
|
|
|
|
#include <mouse.h>
|
|
|
|
|
#include <keyboard.h>
|
|
|
|
|
#include <control.h>
|
|
|
|
|
#include "group.h"
|
|
|
|
|
|
|
|
|
|
static int debug = 0;
|
|
|
|
|
static int debugm = 0;
|
|
|
|
|
static int debugr = 0;
|
|
|
|
|
|
|
|
|
|
enum{
|
|
|
|
|
EAdd,
|
|
|
|
|
EBorder,
|
|
|
|
|
EBordercolor,
|
|
|
|
|
EFocus,
|
|
|
|
|
EHide,
|
|
|
|
|
EImage,
|
|
|
|
|
ERect,
|
|
|
|
|
ERemove,
|
|
|
|
|
EReveal,
|
|
|
|
|
ESeparation,
|
|
|
|
|
EShow,
|
|
|
|
|
ESize,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static char *cmds[] = {
|
|
|
|
|
[EAdd] = "add",
|
|
|
|
|
[EBorder] = "border",
|
|
|
|
|
[EBordercolor] = "bordercolor",
|
|
|
|
|
[EFocus] = "focus",
|
|
|
|
|
[EHide] = "hide",
|
|
|
|
|
[EImage] = "image",
|
|
|
|
|
[ERect] = "rect",
|
|
|
|
|
[ERemove] = "remove",
|
|
|
|
|
[EReveal] = "reveal",
|
|
|
|
|
[ESeparation] = "separation",
|
|
|
|
|
[EShow] = "show",
|
|
|
|
|
[ESize] = "size",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void boxboxresize(Group*, Rectangle);
|
|
|
|
|
static void columnresize(Group*, Rectangle);
|
|
|
|
|
static void groupctl(Control *c, CParse *cp);
|
|
|
|
|
static void groupfree(Control*);
|
|
|
|
|
static void groupmouse(Control *, Mouse *);
|
|
|
|
|
static void groupsize(Control *c);
|
|
|
|
|
static void removegroup(Group*, int);
|
|
|
|
|
static void rowresize(Group*, Rectangle);
|
|
|
|
|
static void stackresize(Group*, Rectangle);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
groupinit(Group *g)
|
|
|
|
|
{
|
|
|
|
|
g->bordercolor = _getctlimage("black");
|
|
|
|
|
g->image = _getctlimage("white");
|
|
|
|
|
g->border = 0;
|
|
|
|
|
g->mansize = 0;
|
|
|
|
|
g->separation = 0;
|
|
|
|
|
g->selected = -1;
|
|
|
|
|
g->lastkid = -1;
|
|
|
|
|
g->kids = nil;
|
|
|
|
|
g->separators = nil;
|
|
|
|
|
g->nkids = 0;
|
|
|
|
|
g->nseparators = 0;
|
|
|
|
|
g->ctl = groupctl;
|
|
|
|
|
g->mouse = groupmouse;
|
|
|
|
|
g->exit = groupfree;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
groupctl(Control *c, CParse *cp)
|
|
|
|
|
{
|
|
|
|
|
int cmd, i, n;
|
|
|
|
|
|
|
|
|
|
Rectangle r;
|
|
|
|
|
Group *g;
|
|
|
|
|
|
|
|
|
|
g = (Group*)c;
|
|
|
|
|
cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
|
|
|
|
|
switch(cmd){
|
|
|
|
|
case EAdd:
|
|
|
|
|
for (i = 1; i < cp->nargs; i++){
|
|
|
|
|
c = controlcalled(cp->args[i]);
|
|
|
|
|
if (c == nil)
|
|
|
|
|
ctlerror("%q: no such control: %s", g->name, cp->args[i]);
|
|
|
|
|
_ctladdgroup(g, c);
|
|
|
|
|
}
|
|
|
|
|
if (g->setsize)
|
|
|
|
|
g->setsize((Control*)g);
|
|
|
|
|
break;
|
|
|
|
|
case EBorder:
|
|
|
|
|
_ctlargcount(g, cp, 2);
|
|
|
|
|
if(cp->iargs[1] < 0)
|
|
|
|
|
ctlerror("%q: bad border: %c", g->name, cp->str);
|
|
|
|
|
g->border = cp->iargs[1];
|
|
|
|
|
break;
|
|
|
|
|
case EBordercolor:
|
|
|
|
|
_ctlargcount(g, cp, 2);
|
|
|
|
|
_setctlimage(g, &g->bordercolor, cp->args[1]);
|
|
|
|
|
break;
|
|
|
|
|
case EFocus:
|
|
|
|
|
/* ignore focus change */
|
|
|
|
|
break;
|
|
|
|
|
case EHide:
|
|
|
|
|
_ctlargcount(g, cp, 1);
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
if (g->kids[i]->ctl)
|
|
|
|
|
_ctlprint(g->kids[i], "hide");
|
|
|
|
|
g->hidden = 1;
|
|
|
|
|
break;
|
|
|
|
|
case EImage:
|
|
|
|
|
_ctlargcount(g, cp, 2);
|
|
|
|
|
_setctlimage(g, &g->image, cp->args[1]);
|
|
|
|
|
break;
|
|
|
|
|
case ERect:
|
|
|
|
|
_ctlargcount(g, cp, 5);
|
|
|
|
|
r.min.x = cp->iargs[1];
|
|
|
|
|
r.min.y = cp->iargs[2];
|
|
|
|
|
r.max.x = cp->iargs[3];
|
|
|
|
|
r.max.y = cp->iargs[4];
|
|
|
|
|
if(Dx(r)<=0 || Dy(r)<=0)
|
|
|
|
|
ctlerror("%q: bad rectangle: %s", g->name, cp->str);
|
|
|
|
|
g->rect = r;
|
|
|
|
|
r = insetrect(r, g->border);
|
|
|
|
|
if (g->nkids == 0)
|
|
|
|
|
return;
|
|
|
|
|
switch(g->type){
|
|
|
|
|
case Ctlboxbox:
|
|
|
|
|
boxboxresize(g, r);
|
|
|
|
|
break;
|
|
|
|
|
case Ctlcolumn:
|
|
|
|
|
columnresize(g, r);
|
|
|
|
|
break;
|
|
|
|
|
case Ctlrow:
|
|
|
|
|
rowresize(g, r);
|
|
|
|
|
break;
|
|
|
|
|
case Ctlstack:
|
|
|
|
|
stackresize(g, r);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ERemove:
|
|
|
|
|
_ctlargcount(g, cp, 2);
|
|
|
|
|
for (n = 0; n < g->nkids; n++)
|
|
|
|
|
if (strcmp(cp->args[1], g->kids[n]->name) == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (n == g->nkids)
|
|
|
|
|
ctlerror("%s: remove nonexistent control: %q", g->name, cp->args[1]);
|
|
|
|
|
removegroup(g, n);
|
|
|
|
|
if (g->setsize)
|
|
|
|
|
g->setsize((Control*)g);
|
|
|
|
|
break;
|
|
|
|
|
case EReveal:
|
|
|
|
|
g->hidden = 0;
|
|
|
|
|
if (debugr) fprint(2, "reveal %s\n", g->name);
|
|
|
|
|
if (g->type == Ctlstack){
|
|
|
|
|
if (cp->nargs == 2){
|
|
|
|
|
if (cp->iargs[1] < 0 || cp->iargs[1] >= g->nkids)
|
|
|
|
|
ctlerror("%s: control out of range: %q", g->name, cp->str);
|
|
|
|
|
g->selected = cp->iargs[1];
|
|
|
|
|
}else
|
|
|
|
|
_ctlargcount(g, cp, 1);
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
if (g->kids[i]->ctl){
|
|
|
|
|
if (g->selected == i){
|
|
|
|
|
if (debugr) fprint(2, "reveal %s: reveal kid %s\n", g->name, g->kids[i]->name);
|
|
|
|
|
_ctlprint(g->kids[i], "reveal");
|
|
|
|
|
}else{
|
|
|
|
|
if (debugr) fprint(2, "reveal %s: hide kid %s\n", g->name, g->kids[i]->name);
|
|
|
|
|
_ctlprint(g->kids[i], "hide");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
_ctlargcount(g, cp, 1);
|
|
|
|
|
if (debug) fprint(2, "reveal %s: border %R/%d\n", g->name, g->rect, g->border);
|
|
|
|
|
border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min);
|
|
|
|
|
r = insetrect(g->rect, g->border);
|
|
|
|
|
if (debug) fprint(2, "reveal %s: draw %R\n", g->name, r);
|
|
|
|
|
draw(g->screen, r, g->image->image, nil, g->image->image->r.min);
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
if (g->kids[i]->ctl)
|
|
|
|
|
_ctlprint(g->kids[i], "reveal");
|
|
|
|
|
break;
|
|
|
|
|
case EShow:
|
|
|
|
|
_ctlargcount(g, cp, 1);
|
|
|
|
|
if (g->hidden)
|
|
|
|
|
break;
|
|
|
|
|
// pass it on to the kiddies
|
|
|
|
|
if (debug) fprint(2, "show %s: border %R/%d\n", g->name, g->rect, g->border);
|
|
|
|
|
border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min);
|
|
|
|
|
r = insetrect(g->rect, g->border);
|
|
|
|
|
if (debug) fprint(2, "show %s: draw %R\n", g->name, r);
|
|
|
|
|
draw(g->screen, r, g->image->image, nil, g->image->image->r.min);
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
if (g->kids[i]->ctl){
|
|
|
|
|
if (debug) fprint(2, "show %s: kid %s: %q\n", g->name, g->kids[i]->name, cp->str);
|
|
|
|
|
_ctlprint(g->kids[i], "show");
|
|
|
|
|
}
|
|
|
|
|
flushimage(display, 1);
|
|
|
|
|
break;
|
|
|
|
|
case ESize:
|
|
|
|
|
r.max = Pt(_Ctlmaxsize, _Ctlmaxsize);
|
|
|
|
|
if (g->type == Ctlboxbox)
|
|
|
|
|
_ctlargcount(g, cp, 5);
|
|
|
|
|
switch(cp->nargs){
|
|
|
|
|
default:
|
|
|
|
|
ctlerror("%s: args of %q", g->name, cp->str);
|
|
|
|
|
case 1:
|
|
|
|
|
/* recursively set size */
|
|
|
|
|
g->mansize = 0;
|
|
|
|
|
if (g->setsize)
|
|
|
|
|
g->setsize((Control*)g);
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
_ctlargcount(g, cp, 5);
|
|
|
|
|
r.max.x = cp->iargs[3];
|
|
|
|
|
r.max.y = cp->iargs[4];
|
|
|
|
|
/* fall through */
|
|
|
|
|
case 3:
|
|
|
|
|
r.min.x = cp->iargs[1];
|
|
|
|
|
r.min.y = cp->iargs[2];
|
|
|
|
|
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)
|
|
|
|
|
ctlerror("%q: bad sizes: %s", g->name, cp->str);
|
|
|
|
|
g->size = r;
|
|
|
|
|
g->mansize = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ESeparation:
|
|
|
|
|
if (g->type != Ctlstack){
|
|
|
|
|
_ctlargcount(g, cp, 2);
|
|
|
|
|
if(cp->iargs[1] < 0)
|
|
|
|
|
ctlerror("%q: illegal value: %c", g->name, cp->str);
|
|
|
|
|
g->separation = cp->iargs[1];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// fall through for Ctlstack
|
|
|
|
|
default:
|
|
|
|
|
ctlerror("%q: unrecognized message '%s'", g->name, cp->str);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
groupfree(Control *c)
|
|
|
|
|
{
|
|
|
|
|
Group *g;
|
|
|
|
|
|
|
|
|
|
g = (Group*)c;
|
|
|
|
|
_putctlimage(g->bordercolor);
|
|
|
|
|
free(g->kids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
groupmouse(Control *c, Mouse *m)
|
|
|
|
|
{
|
|
|
|
|
Group *g;
|
|
|
|
|
int i, lastkid;
|
|
|
|
|
|
|
|
|
|
g = (Group*)c;
|
|
|
|
|
if (g->type == Ctlstack){
|
|
|
|
|
i = g->selected;
|
|
|
|
|
if (i >= 0 && g->kids[i]->mouse &&
|
|
|
|
|
( ( ((m->buttons == 0) || (g->lastbut == 0)) &&
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ) ||
|
|
|
|
|
( ((m->buttons != 0) || (g->lastbut != 0)) &&
|
|
|
|
|
(g->lastkid == i) ) ) ) {
|
|
|
|
|
if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",
|
|
|
|
|
g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);
|
|
|
|
|
(g->kids[i]->mouse)(g->kids[i], m);
|
|
|
|
|
g->lastkid = i;
|
|
|
|
|
g->lastbut = m->buttons;
|
|
|
|
|
} else {
|
|
|
|
|
if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",
|
|
|
|
|
g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastkid = -1;
|
|
|
|
|
for(i=0; i<g->nkids; i++) {
|
|
|
|
|
if(g->kids[i]->mouse &&
|
|
|
|
|
( ( ((m->buttons == 0) || (g->lastbut == 0)) &&
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ) ||
|
|
|
|
|
( ((m->buttons != 0) || (g->lastbut != 0)) &&
|
|
|
|
|
(g->lastkid == i) ) ) ) {
|
|
|
|
|
if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",
|
|
|
|
|
g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);
|
|
|
|
|
(g->kids[i]->mouse)(g->kids[i], m);
|
|
|
|
|
lastkid = i;
|
|
|
|
|
} else {
|
|
|
|
|
if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",
|
|
|
|
|
g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,
|
|
|
|
|
ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g->lastkid = lastkid;
|
|
|
|
|
g->lastbut = m->buttons;
|
|
|
|
|
|
|
|
|
|
#ifdef notdef
|
|
|
|
|
if(m->buttons == 0){
|
|
|
|
|
/* buttons now up */
|
|
|
|
|
g->lastbut = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(g->lastbut == 0 && m->buttons != 0){
|
|
|
|
|
/* button went down, start tracking border */
|
|
|
|
|
switch(g->stacking){
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
case Vertical:
|
|
|
|
|
p = Pt(m->xy.x, middle_of_border.y);
|
|
|
|
|
p0 = Pt(g->r.min.x, m->xy.y);
|
|
|
|
|
p1 = Pt(g->r.max.x, m->xy.y);
|
|
|
|
|
break;
|
|
|
|
|
case Horizontal:
|
|
|
|
|
p = Pt(middle_of_border.x, m->xy.y);
|
|
|
|
|
p0 = Pt(m->xy.x, g->r.min.y);
|
|
|
|
|
p1 = Pt(m->xy.x, g->r.max.y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// setcursor();
|
|
|
|
|
oi = nil;
|
|
|
|
|
} else if (g->lastbut != 0 && s->m.buttons != 0){
|
|
|
|
|
/* button is down, keep tracking border */
|
|
|
|
|
if(!eqpt(s->m.xy, p)){
|
|
|
|
|
p = onscreen(s->m.xy);
|
|
|
|
|
r = canonrect(Rpt(p0, p));
|
|
|
|
|
if(Dx(r)>5 && Dy(r)>5){
|
|
|
|
|
i = allocwindow(wscreen, r, Refnone, 0xEEEEEEFF); /* grey */
|
|
|
|
|
freeimage(oi);
|
|
|
|
|
if(i == nil)
|
|
|
|
|
goto Rescue;
|
|
|
|
|
oi = i;
|
|
|
|
|
border(i, r, Selborder, red, ZP);
|
|
|
|
|
flushimage(display, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (g->lastbut != 0 && s->m.buttons == 0){
|
|
|
|
|
/* button went up, resize kiddies */
|
|
|
|
|
}
|
|
|
|
|
g->lastbut = s->m.buttons;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
activategroup(Control *c, int act)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
Group *g;
|
|
|
|
|
|
|
|
|
|
g = (Group*)c;
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
if (act)
|
|
|
|
|
activate(g->kids[i]);
|
|
|
|
|
else
|
|
|
|
|
deactivate(g->kids[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Control *
|
|
|
|
|
createrow(Controlset *cs, char *name)
|
|
|
|
|
{
|
|
|
|
|
Control *c;
|
|
|
|
|
c = _createctl(cs, "row", sizeof(Group), name);
|
|
|
|
|
groupinit((Group*)c);
|
|
|
|
|
c->setsize = groupsize;
|
|
|
|
|
c->activate = activategroup;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Control *
|
|
|
|
|
createcolumn(Controlset *cs, char *name)
|
|
|
|
|
{
|
|
|
|
|
Control *c;
|
|
|
|
|
c = _createctl(cs, "column", sizeof(Group), name);
|
|
|
|
|
groupinit((Group*)c);
|
|
|
|
|
c->setsize = groupsize;
|
|
|
|
|
c->activate = activategroup;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Control *
|
|
|
|
|
createboxbox(Controlset *cs, char *name)
|
|
|
|
|
{
|
|
|
|
|
Control *c;
|
|
|
|
|
c = _createctl(cs, "boxbox", sizeof(Group), name);
|
|
|
|
|
groupinit((Group*)c);
|
|
|
|
|
c->activate = activategroup;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Control *
|
|
|
|
|
createstack(Controlset *cs, char *name)
|
|
|
|
|
{
|
|
|
|
|
Control *c;
|
|
|
|
|
c = _createctl(cs, "stack", sizeof(Group), name);
|
|
|
|
|
groupinit((Group*)c);
|
|
|
|
|
c->setsize = groupsize;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_ctladdgroup(Control *c, Control *q)
|
|
|
|
|
{
|
|
|
|
|
Group *g = (Group*)c;
|
|
|
|
|
|
|
|
|
|
g->kids = ctlrealloc(g->kids, sizeof(Group*)*(g->nkids+1));
|
|
|
|
|
g->kids[g->nkids++] = q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
removegroup(Group *g, int n)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (g->selected == n)
|
|
|
|
|
g->selected = -1;
|
|
|
|
|
else if (g->selected > n)
|
|
|
|
|
g->selected--;
|
|
|
|
|
|
|
|
|
|
for (i = n+1; i < g->nkids; i++)
|
|
|
|
|
g->kids[i-1] = g->kids[i];
|
|
|
|
|
g->nkids--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
groupsize(Control *c)
|
|
|
|
|
{
|
|
|
|
|
Rectangle r;
|
|
|
|
|
int i;
|
|
|
|
|
Control *q;
|
|
|
|
|
Group *g;
|
|
|
|
|
|
|
|
|
|
g = (Group*)c;
|
|
|
|
|
assert(g->type == Ctlcolumn || g->type == Ctlrow || g->type == Ctlstack);
|
|
|
|
|
if (g->mansize) return;
|
|
|
|
|
r = Rect(1, 1, 1, 1);
|
|
|
|
|
if (debug) fprint(2, "groupsize %q\n", g->name);
|
|
|
|
|
for (i = 0; i < g->nkids; i++){
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if (q->setsize)
|
|
|
|
|
q->setsize(q);
|
|
|
|
|
if (q->size.min.x == 0 || q->size.min.y == 0 || q->size.max.x == 0 || q->size.max.y == 0)
|
|
|
|
|
ctlerror("%q: bad size %R", q->name, q->size);
|
|
|
|
|
if (debug) fprint(2, "groupsize %q: [%d %q]: %R\n", g->name, i, q->name, q->size);
|
|
|
|
|
switch(g->type){
|
|
|
|
|
case Ctlrow:
|
|
|
|
|
if (i)
|
|
|
|
|
r.min.x += q->size.min.x + g->border;
|
|
|
|
|
else
|
|
|
|
|
r.min.x = q->size.min.x;
|
|
|
|
|
if (i)
|
|
|
|
|
r.max.x += q->size.max.x + g->border;
|
|
|
|
|
else
|
|
|
|
|
r.max.x = q->size.max.x;
|
|
|
|
|
if (r.min.y < q->size.min.y) r.min.y = q->size.min.y;
|
|
|
|
|
if (r.max.y < q->size.max.y) r.max.y = q->size.max.y;
|
|
|
|
|
break;
|
|
|
|
|
case Ctlcolumn:
|
|
|
|
|
if (r.min.x < q->size.min.x) r.min.x = q->size.min.x;
|
|
|
|
|
if (r.max.x < q->size.max.x) r.max.x = q->size.max.x;
|
|
|
|
|
if (i)
|
|
|
|
|
r.min.y += q->size.min.y + g->border;
|
|
|
|
|
else
|
|
|
|
|
r.min.y = q->size.min.y;
|
|
|
|
|
if (i)
|
|
|
|
|
r.max.y += q->size.max.y + g->border;
|
|
|
|
|
else
|
|
|
|
|
r.max.y = q->size.max.y;
|
|
|
|
|
break;
|
|
|
|
|
case Ctlstack:
|
|
|
|
|
if (r.min.x < q->size.min.x) r.min.x = q->size.min.x;
|
|
|
|
|
if (r.max.x < q->size.max.x) r.max.x = q->size.max.x;
|
|
|
|
|
if (r.min.y < q->size.min.y) r.min.y = q->size.min.y;
|
|
|
|
|
if (r.max.y < q->size.max.y) r.max.y = q->size.max.y;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g->size = rectaddpt(r, Pt(g->border, g->border));
|
|
|
|
|
if (debug) fprint(2, "groupsize %q: %R\n", g->name, g->size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
boxboxresize(Group *g, Rectangle r)
|
|
|
|
|
{
|
|
|
|
|
int rows, cols, ht, wid, i, hpad, wpad;
|
|
|
|
|
Rectangle rr;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
ht = 0;
|
|
|
|
|
for(i=0; i<g->nkids; i++){
|
|
|
|
|
if (g->kids[i]->size.min.y > ht)
|
|
|
|
|
ht = g->kids[i]->size.min.y;
|
|
|
|
|
}
|
|
|
|
|
if (ht == 0)
|
|
|
|
|
ctlerror("boxboxresize: height");
|
|
|
|
|
rows = Dy(r) / (ht+g->separation);
|
|
|
|
|
hpad = (Dy(r) % (ht+g->separation)) / g->nkids;
|
|
|
|
|
cols = (g->nkids+rows-1)/rows;
|
|
|
|
|
wid = Dx(r) / cols - g->separation;
|
|
|
|
|
for(i=0; i<g->nkids; i++){
|
|
|
|
|
if (g->kids[i]->size.max.x < wid)
|
|
|
|
|
wid = g->kids[i]->size.max.x;
|
|
|
|
|
}
|
|
|
|
|
for(i=0; i<g->nkids; i++){
|
|
|
|
|
if (g->kids[i]->size.min.x > wid)
|
|
|
|
|
wid = g->kids[i]->size.min.x;
|
|
|
|
|
}
|
|
|
|
|
if (wid > Dx(r) / cols)
|
|
|
|
|
ctlerror("can't fit controls in boxbox");
|
|
|
|
|
wpad = (Dx(r) % (wid+g->separation)) / g->nkids;
|
|
|
|
|
rr = rectaddpt(Rect(0,0,wid, ht), addpt(r.min, Pt(g->separation/2, g->separation/2)));
|
|
|
|
|
if(debug) fprint(2, "boxboxresize rows %d, cols %d, wid %d, ht %d, wpad %d, hpad %d\n", rows, cols, wid, ht, wpad, hpad);
|
|
|
|
|
for(i=0; i<g->nkids; i++){
|
|
|
|
|
if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, g->kids[i]->name, rr, Dx(rr), Dy(rr));
|
|
|
|
|
_ctlprint(g->kids[i], "rect %R",
|
|
|
|
|
rectaddpt(rr, Pt((wpad+wid+g->separation)*(i/rows), (hpad+ht+g->separation)*(i%rows))));
|
|
|
|
|
}
|
|
|
|
|
g->nseparators = rows + cols - 2;
|
|
|
|
|
g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle));
|
|
|
|
|
rr = r;
|
|
|
|
|
rr.max.y = rr.min.y + g->separation+hpad;
|
|
|
|
|
for (i = 1; i < rows; i++){
|
|
|
|
|
g->separators[i-1] = rectaddpt(rr, Pt(0, (hpad+ht+g->separation)*i-g->separation-hpad));
|
|
|
|
|
if(debug) fprint(2, "row separation %d [%d]: %R\n", i, i-1, rectaddpt(rr, Pt(0, (hpad+ht+g->separation)*i-g->separation)));
|
|
|
|
|
}
|
|
|
|
|
rr = r;
|
|
|
|
|
rr.max.x = rr.min.x + g->separation+wpad;
|
|
|
|
|
for (i = 1; i < cols; i++){
|
|
|
|
|
g->separators[i+rows-2] = rectaddpt(rr, Pt((wpad+wid+g->separation)*i-g->separation-wpad, 0));
|
|
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
columnresize(Group *g, Rectangle r)
|
|
|
|
|
{
|
|
|
|
|
int x, y, *d, *p, i, j, t;
|
|
|
|
|
Rectangle rr;
|
|
|
|
|
Control *q;
|
|
|
|
|
|
|
|
|
|
x = Dx(r);
|
|
|
|
|
y = Dy(r);
|
|
|
|
|
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);
|
|
|
|
|
if (x < g->size.min.x) {
|
|
|
|
|
werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x);
|
|
|
|
|
r.max.x = r.min.x + g->size.min.x;
|
|
|
|
|
}
|
|
|
|
|
if (y < g->size.min.y) {
|
|
|
|
|
werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y);
|
|
|
|
|
r.max.y = r.min.y + g->size.min.y;
|
|
|
|
|
y = Dy(r);
|
|
|
|
|
}
|
|
|
|
|
d = ctlmalloc(g->nkids*sizeof(int));
|
|
|
|
|
p = ctlmalloc(g->nkids*sizeof(int));
|
|
|
|
|
if(debug) fprint(2, "kiddies: ");
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if(debug) fprint(2, "[%q]: %d⋯%d\t", q->name, q->size.min.y, q->size.max.y);
|
|
|
|
|
d[i] = q->size.min.y;
|
|
|
|
|
y -= d[i];
|
|
|
|
|
p[i] = q->size.max.y - q->size.min.y;
|
|
|
|
|
}
|
|
|
|
|
if(debug) fprint(2, "\n");
|
|
|
|
|
y -= (g->nkids-1) * g->separation;
|
|
|
|
|
if(y < 0){
|
|
|
|
|
if (debug) fprint(2, "columnresize: y == %d\n", y);
|
|
|
|
|
y = 0;
|
|
|
|
|
}
|
|
|
|
|
if (y >= g->size.max.y - g->size.min.y) {
|
|
|
|
|
// all rects can be maximum width
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
d[i] += p[i];
|
|
|
|
|
y -= g->size.max.y - g->size.min.y;
|
|
|
|
|
} else {
|
|
|
|
|
// rects can't be max width, divide up the rest
|
|
|
|
|
j = y;
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
t = p[i] * y/(g->size.max.y - g->size.min.y);
|
|
|
|
|
d[i] += t;
|
|
|
|
|
j -= t;
|
|
|
|
|
}
|
|
|
|
|
d[0] += j;
|
|
|
|
|
y = 0;
|
|
|
|
|
}
|
|
|
|
|
g->nseparators = g->nkids-1;
|
|
|
|
|
g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle));
|
|
|
|
|
j = 0;
|
|
|
|
|
rr = r;
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if (i < g->nkids - 1){
|
|
|
|
|
g->separators[i].min.x = r.min.x;
|
|
|
|
|
g->separators[i].max.x = r.max.x;
|
|
|
|
|
}
|
|
|
|
|
t = y / (g->nkids - i);
|
|
|
|
|
y -= t;
|
|
|
|
|
j += t/2;
|
|
|
|
|
rr.min.y = r.min.y + j;
|
|
|
|
|
if (i)
|
|
|
|
|
g->separators[i-1].max.y = rr.min.y;
|
|
|
|
|
j += d[i];
|
|
|
|
|
rr.max.y = r.min.y + j;
|
|
|
|
|
if (i < g->nkids - 1)
|
|
|
|
|
g->separators[i].min.y = rr.max.y;
|
|
|
|
|
j += g->separation + t - t/2;
|
|
|
|
|
_ctlprint(q, "rect %R", rr);
|
|
|
|
|
if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, rr, Dx(rr), Dy(rr));
|
|
|
|
|
}
|
|
|
|
|
free(d);
|
|
|
|
|
free(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rowresize(Group *g, Rectangle r)
|
|
|
|
|
{
|
|
|
|
|
int x, y, *d, *p, i, j, t;
|
|
|
|
|
Rectangle rr;
|
|
|
|
|
Control *q;
|
|
|
|
|
|
|
|
|
|
x = Dx(r);
|
|
|
|
|
y = Dy(r);
|
|
|
|
|
if(debug) fprint(2, "rowresize %q %R (%d×%d), separation %d\n", g->name, r, Dx(r), Dy(r), g->separation);
|
|
|
|
|
if (x < g->size.min.x) {
|
|
|
|
|
werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x);
|
|
|
|
|
r.max.x = r.min.x + g->size.min.x;
|
|
|
|
|
x = Dx(r);
|
|
|
|
|
}
|
|
|
|
|
if (y < g->size.min.y) {
|
|
|
|
|
werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y);
|
|
|
|
|
r.max.y = r.min.y + g->size.min.y;
|
|
|
|
|
}
|
|
|
|
|
d = ctlmalloc(g->nkids*sizeof(int));
|
|
|
|
|
p = ctlmalloc(g->nkids*sizeof(int));
|
|
|
|
|
if(debug) fprint(2, "kiddies: ");
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if(debug) fprint(2, "[%q]: %d⋯%d\t", q->name, q->size.min.x, q->size.max.x);
|
|
|
|
|
d[i] = q->size.min.x;
|
|
|
|
|
x -= d[i];
|
|
|
|
|
p[i] = q->size.max.x - q->size.min.x;
|
|
|
|
|
}
|
|
|
|
|
if(debug) fprint(2, "\n");
|
|
|
|
|
x -= (g->nkids-1) * g->separation;
|
|
|
|
|
if(x < 0){
|
|
|
|
|
if (debug) fprint(2, "rowresize: x == %d\n", x);
|
|
|
|
|
x = 0;
|
|
|
|
|
}
|
|
|
|
|
if (x >= g->size.max.x - g->size.min.x) {
|
|
|
|
|
if (debug) fprint(2, "max: %d > %d - %d", x, g->size.max.x, g->size.min.x);
|
|
|
|
|
// all rects can be maximum width
|
|
|
|
|
for (i = 0; i < g->nkids; i++)
|
|
|
|
|
d[i] += p[i];
|
|
|
|
|
x -= g->size.max.x - g->size.min.x;
|
|
|
|
|
} else {
|
|
|
|
|
if (debug) fprint(2, "divvie up: %d < %d - %d", x, g->size.max.x, g->size.min.x);
|
|
|
|
|
// rects can't be max width, divide up the rest
|
|
|
|
|
j = x;
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
t = p[i] * x/(g->size.max.x - g->size.min.x);
|
|
|
|
|
d[i] += t;
|
|
|
|
|
j -= t;
|
|
|
|
|
}
|
|
|
|
|
d[0] += j;
|
|
|
|
|
x = 0;
|
|
|
|
|
}
|
|
|
|
|
j = 0;
|
|
|
|
|
g->nseparators = g->nkids-1;
|
|
|
|
|
g->separators = realloc(g->separators, g->nseparators*sizeof(Rectangle));
|
|
|
|
|
rr = r;
|
|
|
|
|
for (i = 0; i < g->nkids; i++) {
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if (i < g->nkids - 1){
|
|
|
|
|
g->separators[i].min.y = r.min.y;
|
|
|
|
|
g->separators[i].max.y = r.max.y;
|
|
|
|
|
}
|
|
|
|
|
t = x / (g->nkids - i);
|
|
|
|
|
x -= t;
|
|
|
|
|
j += t/2;
|
|
|
|
|
rr.min.x = r.min.x + j;
|
|
|
|
|
if (i)
|
|
|
|
|
g->separators[i-1].max.x = rr.min.x;
|
|
|
|
|
j += d[i];
|
|
|
|
|
rr.max.x = r.min.x + j;
|
|
|
|
|
if (i < g->nkids - 1)
|
|
|
|
|
g->separators[i].min.x = rr.max.x;
|
|
|
|
|
j += g->separation + t - t/2;
|
|
|
|
|
_ctlprint(q, "rect %R", rr);
|
|
|
|
|
if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, rr, Dx(rr), Dy(rr));
|
|
|
|
|
}
|
|
|
|
|
free(d);
|
|
|
|
|
free(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
stackresize(Group *g, Rectangle r)
|
|
|
|
|
{
|
|
|
|
|
int x, y, i;
|
|
|
|
|
Control *q;
|
|
|
|
|
|
|
|
|
|
x = Dx(r);
|
|
|
|
|
y = Dy(r);
|
|
|
|
|
if(debug) fprint(2, "stackresize %q %R (%d×%d)\n", g->name, r, Dx(r), Dy(r));
|
|
|
|
|
if (x < g->size.min.x){
|
|
|
|
|
werrstr("resize %s: too narrow: need %d, have %d", g->name, g->size.min.x, x);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (y < g->size.min.y){
|
|
|
|
|
werrstr("resize %s: too short: need %d, have %d", g->name, g->size.min.y, y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (x > g->size.max.x) {
|
|
|
|
|
x = (x - g->size.max.x)/2;
|
|
|
|
|
r.min.x += x;
|
|
|
|
|
r.max.x -= x;
|
|
|
|
|
}
|
|
|
|
|
if (y > g->size.max.y) {
|
|
|
|
|
y = (y - g->size.max.y)/2;
|
|
|
|
|
r.min.y += y;
|
|
|
|
|
r.max.y -= y;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < g->nkids; i++){
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
if(debug) fprint(2, " %d %q: %R (%d×%d)\n", i, q->name, r, Dx(r), Dy(r));
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < g->nkids; i++){
|
|
|
|
|
q = g->kids[i];
|
|
|
|
|
_ctlprint(q, "rect %R", r);
|
|
|
|
|
}
|
|
|
|
|
}
|