1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <thread.h>
4*9a747e4fSDavid du Colombier #include <draw.h>
5*9a747e4fSDavid du Colombier #include <mouse.h>
6*9a747e4fSDavid du Colombier #include <keyboard.h>
7*9a747e4fSDavid du Colombier #include <control.h>
8*9a747e4fSDavid du Colombier #include "group.h"
9*9a747e4fSDavid du Colombier
10*9a747e4fSDavid du Colombier typedef struct Tab Tab;
11*9a747e4fSDavid du Colombier
12*9a747e4fSDavid du Colombier struct Tab {
13*9a747e4fSDavid du Colombier Control;
14*9a747e4fSDavid du Colombier int border;
15*9a747e4fSDavid du Colombier int selected;
16*9a747e4fSDavid du Colombier int separation;
17*9a747e4fSDavid du Colombier char *format;
18*9a747e4fSDavid du Colombier CImage *bordercolor;
19*9a747e4fSDavid du Colombier CImage *image;
20*9a747e4fSDavid du Colombier Control *tabrow;
21*9a747e4fSDavid du Colombier Control *tabstack;
22*9a747e4fSDavid du Colombier Control *tabcolumn;
23*9a747e4fSDavid du Colombier int ntabs;
24*9a747e4fSDavid du Colombier int nbuttons;
25*9a747e4fSDavid du Colombier Control **buttons;
26*9a747e4fSDavid du Colombier };
27*9a747e4fSDavid du Colombier
28*9a747e4fSDavid du Colombier enum{
29*9a747e4fSDavid du Colombier EAdd,
30*9a747e4fSDavid du Colombier EBorder,
31*9a747e4fSDavid du Colombier EBordercolor,
32*9a747e4fSDavid du Colombier EButton,
33*9a747e4fSDavid du Colombier EFocus,
34*9a747e4fSDavid du Colombier EFormat,
35*9a747e4fSDavid du Colombier EHide,
36*9a747e4fSDavid du Colombier EImage,
37*9a747e4fSDavid du Colombier ERect,
38*9a747e4fSDavid du Colombier EReveal,
39*9a747e4fSDavid du Colombier ESeparation,
40*9a747e4fSDavid du Colombier ESeparatorcolor,
41*9a747e4fSDavid du Colombier EShow,
42*9a747e4fSDavid du Colombier ESize,
43*9a747e4fSDavid du Colombier EValue,
44*9a747e4fSDavid du Colombier };
45*9a747e4fSDavid du Colombier
46*9a747e4fSDavid du Colombier static char *cmds[] = {
47*9a747e4fSDavid du Colombier [EAdd] = "add",
48*9a747e4fSDavid du Colombier [EBorder] = "border",
49*9a747e4fSDavid du Colombier [EBordercolor] = "bordercolor",
50*9a747e4fSDavid du Colombier [EButton] = "button",
51*9a747e4fSDavid du Colombier [EFocus] = "focus",
52*9a747e4fSDavid du Colombier [EFormat] = "format",
53*9a747e4fSDavid du Colombier [EHide] = "hide",
54*9a747e4fSDavid du Colombier [EImage] = "image",
55*9a747e4fSDavid du Colombier [ERect] = "rect",
56*9a747e4fSDavid du Colombier [EReveal] = "reveal",
57*9a747e4fSDavid du Colombier [ESeparation] = "separation",
58*9a747e4fSDavid du Colombier [ESeparatorcolor] = "separatorcolor",
59*9a747e4fSDavid du Colombier [EShow] = "show",
60*9a747e4fSDavid du Colombier [ESize] = "size",
61*9a747e4fSDavid du Colombier [EValue] = "value",
62*9a747e4fSDavid du Colombier };
63*9a747e4fSDavid du Colombier
64*9a747e4fSDavid du Colombier static void
tabshow(Tab * t)65*9a747e4fSDavid du Colombier tabshow(Tab *t)
66*9a747e4fSDavid du Colombier {
67*9a747e4fSDavid du Colombier int i;
68*9a747e4fSDavid du Colombier Rectangle r;
69*9a747e4fSDavid du Colombier Group *g;
70*9a747e4fSDavid du Colombier
71*9a747e4fSDavid du Colombier if (t->hidden)
72*9a747e4fSDavid du Colombier return;
73*9a747e4fSDavid du Colombier for(i=0; i<t->nbuttons; i++){
74*9a747e4fSDavid du Colombier _ctlprint(t->buttons[i], "value %d", (t->selected==i));
75*9a747e4fSDavid du Colombier }
76*9a747e4fSDavid du Colombier _ctlprint(t->tabstack, "reveal %d", t->selected);
77*9a747e4fSDavid du Colombier _ctlprint(t->tabcolumn, "show");
78*9a747e4fSDavid du Colombier if (t->selected < 0)
79*9a747e4fSDavid du Colombier return;
80*9a747e4fSDavid du Colombier g = (Group*)t->tabcolumn;
81*9a747e4fSDavid du Colombier if (g->nseparators == 0){
82*9a747e4fSDavid du Colombier return;
83*9a747e4fSDavid du Colombier }
84*9a747e4fSDavid du Colombier r = g->separators[0];
85*9a747e4fSDavid du Colombier r.min.x = t->buttons[t->selected]->rect.min.x;
86*9a747e4fSDavid du Colombier r.max.x = t->buttons[t->selected]->rect.max.x;
87*9a747e4fSDavid du Colombier draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
88*9a747e4fSDavid du Colombier flushimage(display, 1);
89*9a747e4fSDavid du Colombier }
90*9a747e4fSDavid du Colombier
91*9a747e4fSDavid du Colombier static void
tabsize(Control * c)92*9a747e4fSDavid du Colombier tabsize(Control *c)
93*9a747e4fSDavid du Colombier {
94*9a747e4fSDavid du Colombier Tab *t = (Tab*)c;
95*9a747e4fSDavid du Colombier if (t->tabcolumn && t->tabcolumn->setsize)
96*9a747e4fSDavid du Colombier t->tabcolumn->setsize((Control*)t->tabcolumn);
97*9a747e4fSDavid du Colombier }
98*9a747e4fSDavid du Colombier
99*9a747e4fSDavid du Colombier static void
tabctl(Control * c,CParse * cp)100*9a747e4fSDavid du Colombier tabctl(Control *c, CParse *cp)
101*9a747e4fSDavid du Colombier {
102*9a747e4fSDavid du Colombier int cmd, i;
103*9a747e4fSDavid du Colombier Control *cbut, *cwin;
104*9a747e4fSDavid du Colombier Tab *t;
105*9a747e4fSDavid du Colombier Rectangle r;
106*9a747e4fSDavid du Colombier
107*9a747e4fSDavid du Colombier t = (Tab*)c;
108*9a747e4fSDavid du Colombier cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
109*9a747e4fSDavid du Colombier switch(cmd){
110*9a747e4fSDavid du Colombier case EAdd:
111*9a747e4fSDavid du Colombier if ((cp->nargs & 1) == 0)
112*9a747e4fSDavid du Colombier ctlerror("%q: arg count: %s", t->name, cp->args[1]);
113*9a747e4fSDavid du Colombier for (i = 1; i < cp->nargs; i += 2){
114*9a747e4fSDavid du Colombier cbut = controlcalled(cp->args[i]);
115*9a747e4fSDavid du Colombier if (cbut == nil)
116*9a747e4fSDavid du Colombier ctlerror("%q: no such control: %s", t->name, cp->args[i]);
117*9a747e4fSDavid du Colombier cwin = controlcalled(cp->args[i+1]);
118*9a747e4fSDavid du Colombier if (cwin == nil)
119*9a747e4fSDavid du Colombier ctlerror("%q: no such control: %s", t->name, cp->args[i+1]);
120*9a747e4fSDavid du Colombier _ctladdgroup(t->tabrow, cbut);
121*9a747e4fSDavid du Colombier _ctlprint(t->tabstack, "add %q", cp->args[i+1]);
122*9a747e4fSDavid du Colombier _ctlprint(cbut, "format '%%s: %q button %%d'", t->name);
123*9a747e4fSDavid du Colombier controlwire(cbut, "event", t->controlset->ctl);
124*9a747e4fSDavid du Colombier t->buttons = ctlrealloc(t->buttons, (t->nbuttons+1)*sizeof(Control*));
125*9a747e4fSDavid du Colombier t->buttons[t->nbuttons] = cbut;
126*9a747e4fSDavid du Colombier t->nbuttons++;
127*9a747e4fSDavid du Colombier t->selected = -1;
128*9a747e4fSDavid du Colombier }
129*9a747e4fSDavid du Colombier _ctlprint(t->tabcolumn, "size");
130*9a747e4fSDavid du Colombier t->size = t->tabcolumn->size;
131*9a747e4fSDavid du Colombier break;
132*9a747e4fSDavid du Colombier case EBorder:
133*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
134*9a747e4fSDavid du Colombier if(cp->iargs[1] < 0)
135*9a747e4fSDavid du Colombier ctlerror("%q: bad border: %c", t->name, cp->str);
136*9a747e4fSDavid du Colombier t->border = cp->iargs[1];
137*9a747e4fSDavid du Colombier break;
138*9a747e4fSDavid du Colombier case EBordercolor:
139*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
140*9a747e4fSDavid du Colombier _setctlimage(t, &t->bordercolor, cp->args[1]);
141*9a747e4fSDavid du Colombier break;
142*9a747e4fSDavid du Colombier case EButton:
143*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
144*9a747e4fSDavid du Colombier if (cp->sender == nil)
145*9a747e4fSDavid du Colombier ctlerror("%q: senderless buttonevent: %q", t->name, cp->str);
146*9a747e4fSDavid du Colombier cbut = controlcalled(cp->sender);
147*9a747e4fSDavid du Colombier for(i=0; i<t->nbuttons; i++)
148*9a747e4fSDavid du Colombier if (cbut == t->buttons[i])
149*9a747e4fSDavid du Colombier break;
150*9a747e4fSDavid du Colombier if (i == t->nbuttons)
151*9a747e4fSDavid du Colombier ctlerror("%q: not my event: %q", t->name, cp->str);
152*9a747e4fSDavid du Colombier if(cp->iargs[1] == 0){
153*9a747e4fSDavid du Colombier /* button was turned off; turn it back on */
154*9a747e4fSDavid du Colombier _ctlprint(cbut, "value 1");
155*9a747e4fSDavid du Colombier }else{
156*9a747e4fSDavid du Colombier t->selected = i;
157*9a747e4fSDavid du Colombier if (t->format)
158*9a747e4fSDavid du Colombier chanprint(t->event, t->format, t->name, i);
159*9a747e4fSDavid du Colombier tabshow(t);
160*9a747e4fSDavid du Colombier }
161*9a747e4fSDavid du Colombier break;
162*9a747e4fSDavid du Colombier case EFocus:
163*9a747e4fSDavid du Colombier /* ignore focus change */
164*9a747e4fSDavid du Colombier break;
165*9a747e4fSDavid du Colombier case EFormat:
166*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
167*9a747e4fSDavid du Colombier t->format = ctlstrdup(cp->args[1]);
168*9a747e4fSDavid du Colombier break;
169*9a747e4fSDavid du Colombier case EImage:
170*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
171*9a747e4fSDavid du Colombier _setctlimage(t, &t->image, cp->args[1]);
172*9a747e4fSDavid du Colombier break;
173*9a747e4fSDavid du Colombier case ESeparation:
174*9a747e4fSDavid du Colombier t->tabrow->ctl(t->tabrow, cp);
175*9a747e4fSDavid du Colombier t->tabcolumn->ctl(t->tabcolumn, cp);
176*9a747e4fSDavid du Colombier break;
177*9a747e4fSDavid du Colombier case ERect:
178*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 5);
179*9a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
180*9a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
181*9a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
182*9a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
183*9a747e4fSDavid du Colombier if(Dx(r)<=0 || Dy(r)<=0)
184*9a747e4fSDavid du Colombier ctlerror("%q: bad rectangle: %s", t->name, cp->str);
185*9a747e4fSDavid du Colombier t->rect = r;
186*9a747e4fSDavid du Colombier r = insetrect(r, t->border);
187*9a747e4fSDavid du Colombier _ctlprint(t->tabcolumn, "rect %R", r);
188*9a747e4fSDavid du Colombier break;
189*9a747e4fSDavid du Colombier case EReveal:
190*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
191*9a747e4fSDavid du Colombier case EHide:
192*9a747e4fSDavid du Colombier case ESize:
193*9a747e4fSDavid du Colombier t->tabcolumn->ctl(t->tabcolumn, cp);
194*9a747e4fSDavid du Colombier break;
195*9a747e4fSDavid du Colombier case EShow:
196*9a747e4fSDavid du Colombier tabshow(t);
197*9a747e4fSDavid du Colombier break;
198*9a747e4fSDavid du Colombier case EValue:
199*9a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
200*9a747e4fSDavid du Colombier if (cp->iargs[1] < 0 || cp->iargs[1] >= t->nbuttons)
201*9a747e4fSDavid du Colombier ctlerror("%q: illegal value '%s'", t->name, cp->str);
202*9a747e4fSDavid du Colombier t->selected = cp->iargs[1];
203*9a747e4fSDavid du Colombier tabshow(t);
204*9a747e4fSDavid du Colombier break;
205*9a747e4fSDavid du Colombier default:
206*9a747e4fSDavid du Colombier ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
207*9a747e4fSDavid du Colombier break;
208*9a747e4fSDavid du Colombier }
209*9a747e4fSDavid du Colombier }
210*9a747e4fSDavid du Colombier
211*9a747e4fSDavid du Colombier static void
tabfree(Control * c)212*9a747e4fSDavid du Colombier tabfree(Control*c)
213*9a747e4fSDavid du Colombier {
214*9a747e4fSDavid du Colombier Tab *t = (Tab*)c;
215*9a747e4fSDavid du Colombier t->nbuttons = 0;
216*9a747e4fSDavid du Colombier free(t->buttons);
217*9a747e4fSDavid du Colombier t->buttons = 0;
218*9a747e4fSDavid du Colombier }
219*9a747e4fSDavid du Colombier
220*9a747e4fSDavid du Colombier static void
activatetab(Control * c,int act)221*9a747e4fSDavid du Colombier activatetab(Control *c, int act)
222*9a747e4fSDavid du Colombier {
223*9a747e4fSDavid du Colombier Tab *t;
224*9a747e4fSDavid du Colombier
225*9a747e4fSDavid du Colombier t = (Tab*)c;
226*9a747e4fSDavid du Colombier if (act)
227*9a747e4fSDavid du Colombier activate(t->tabcolumn);
228*9a747e4fSDavid du Colombier else
229*9a747e4fSDavid du Colombier deactivate(t->tabcolumn);
230*9a747e4fSDavid du Colombier }
231*9a747e4fSDavid du Colombier
232*9a747e4fSDavid du Colombier Control *
createtab(Controlset * cs,char * name)233*9a747e4fSDavid du Colombier createtab(Controlset *cs, char *name)
234*9a747e4fSDavid du Colombier {
235*9a747e4fSDavid du Colombier char s[128];
236*9a747e4fSDavid du Colombier
237*9a747e4fSDavid du Colombier Tab *t;
238*9a747e4fSDavid du Colombier t = (Tab*)_createctl(cs, "tab", sizeof(Tab), name);
239*9a747e4fSDavid du Colombier t->selected = -1;
240*9a747e4fSDavid du Colombier t->nbuttons = 0;
241*9a747e4fSDavid du Colombier t->ctl = tabctl;
242*9a747e4fSDavid du Colombier t->mouse = nil;
243*9a747e4fSDavid du Colombier t->exit = tabfree;
244*9a747e4fSDavid du Colombier snprint(s, sizeof s, "_%s-row", name);
245*9a747e4fSDavid du Colombier t->tabrow = createrow(cs, s);
246*9a747e4fSDavid du Colombier snprint(s, sizeof s, "_%s-stack", name);
247*9a747e4fSDavid du Colombier t->tabstack = createstack(cs, s);
248*9a747e4fSDavid du Colombier snprint(s, sizeof s, "_%s-column", name);
249*9a747e4fSDavid du Colombier t->tabcolumn = createcolumn(cs, s);
250*9a747e4fSDavid du Colombier ctlprint(t->tabcolumn, "add %q %q", t->tabrow->name, t->tabstack->name);
251*9a747e4fSDavid du Colombier t->bordercolor = _getctlimage("black");
252*9a747e4fSDavid du Colombier t->image = _getctlimage("white");
253*9a747e4fSDavid du Colombier t->setsize = tabsize;
254*9a747e4fSDavid du Colombier t->activate = activatetab;
255*9a747e4fSDavid du Colombier return (Control*)t;
256*9a747e4fSDavid du Colombier }
257