180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier
980ee5cbfSDavid du Colombier typedef struct Textbutton Textbutton;
1080ee5cbfSDavid du Colombier
1180ee5cbfSDavid du Colombier struct Textbutton
1280ee5cbfSDavid du Colombier {
1380ee5cbfSDavid du Colombier Control;
1480ee5cbfSDavid du Colombier CFont *font;
1580ee5cbfSDavid du Colombier CImage *image;
1680ee5cbfSDavid du Colombier CImage *mask;
1780ee5cbfSDavid du Colombier CImage *light;
1880ee5cbfSDavid du Colombier CImage *bordercolor;
1980ee5cbfSDavid du Colombier CImage *textcolor;
2080ee5cbfSDavid du Colombier CImage *pressedtextcolor;
21*6f314b92SDavid du Colombier CImage *paletextcolor;
2280ee5cbfSDavid du Colombier int pressed;
2380ee5cbfSDavid du Colombier int lastbut;
2480ee5cbfSDavid du Colombier int lastshow;
2580ee5cbfSDavid du Colombier char **line;
2680ee5cbfSDavid du Colombier int nline;
2780ee5cbfSDavid du Colombier int align;
2880ee5cbfSDavid du Colombier int border;
29*6f314b92SDavid du Colombier int off;
30*6f314b92SDavid du Colombier int showoff;
31*6f314b92SDavid du Colombier int prepress;
3280ee5cbfSDavid du Colombier };
3380ee5cbfSDavid du Colombier
3480ee5cbfSDavid du Colombier enum{
3580ee5cbfSDavid du Colombier EAlign,
3680ee5cbfSDavid du Colombier EBorder,
3780ee5cbfSDavid du Colombier EBordercolor,
3880ee5cbfSDavid du Colombier EFocus,
3980ee5cbfSDavid du Colombier EFont,
4080ee5cbfSDavid du Colombier EFormat,
419a747e4fSDavid du Colombier EHide,
4280ee5cbfSDavid du Colombier EImage,
4380ee5cbfSDavid du Colombier ELight,
4480ee5cbfSDavid du Colombier EMask,
45*6f314b92SDavid du Colombier EPaletextcolor,
4680ee5cbfSDavid du Colombier EPressedtextcolor,
4780ee5cbfSDavid du Colombier ERect,
489a747e4fSDavid du Colombier EReveal,
4980ee5cbfSDavid du Colombier EShow,
509a747e4fSDavid du Colombier ESize,
5180ee5cbfSDavid du Colombier EText,
5280ee5cbfSDavid du Colombier ETextcolor,
5380ee5cbfSDavid du Colombier EValue,
5480ee5cbfSDavid du Colombier };
5580ee5cbfSDavid du Colombier
5680ee5cbfSDavid du Colombier static char *cmds[] = {
5780ee5cbfSDavid du Colombier [EAlign] = "align",
5880ee5cbfSDavid du Colombier [EBorder] = "border",
5980ee5cbfSDavid du Colombier [EBordercolor] = "bordercolor",
6080ee5cbfSDavid du Colombier [EFocus] = "focus",
6180ee5cbfSDavid du Colombier [EFont] = "font",
6280ee5cbfSDavid du Colombier [EFormat] = "format",
639a747e4fSDavid du Colombier [EHide] = "hide",
6480ee5cbfSDavid du Colombier [EImage] = "image",
6580ee5cbfSDavid du Colombier [ELight] = "light",
6680ee5cbfSDavid du Colombier [EMask] = "mask",
67*6f314b92SDavid du Colombier [EPaletextcolor] ="paletextcolor",
6880ee5cbfSDavid du Colombier [EPressedtextcolor] ="pressedtextcolor",
6980ee5cbfSDavid du Colombier [ERect] = "rect",
709a747e4fSDavid du Colombier [EReveal] = "reveal",
7180ee5cbfSDavid du Colombier [EShow] = "show",
729a747e4fSDavid du Colombier [ESize] = "size",
7380ee5cbfSDavid du Colombier [EText] = "text",
7480ee5cbfSDavid du Colombier [ETextcolor] = "textcolor",
7580ee5cbfSDavid du Colombier [EValue] = "value",
7680ee5cbfSDavid du Colombier nil
7780ee5cbfSDavid du Colombier };
7880ee5cbfSDavid du Colombier
7980ee5cbfSDavid du Colombier static void textbuttonshow(Textbutton*);
8080ee5cbfSDavid du Colombier
8180ee5cbfSDavid du Colombier static void
textbuttonmouse(Control * c,Mouse * m)829a747e4fSDavid du Colombier textbuttonmouse(Control *c, Mouse *m)
8380ee5cbfSDavid du Colombier {
8480ee5cbfSDavid du Colombier Textbutton *t;
8580ee5cbfSDavid du Colombier
869a747e4fSDavid du Colombier t = (Textbutton *)c;
87*6f314b92SDavid du Colombier if(m->buttons&7) {
88*6f314b92SDavid du Colombier if (ptinrect(m->xy,t->rect)) {
89*6f314b92SDavid du Colombier if (t->off) {
90*6f314b92SDavid du Colombier t->off = 0;
91*6f314b92SDavid du Colombier textbuttonshow(t);
92*6f314b92SDavid du Colombier }
93*6f314b92SDavid du Colombier } else {
94*6f314b92SDavid du Colombier if (!t->off) {
95*6f314b92SDavid du Colombier t->off = 1;
96*6f314b92SDavid du Colombier textbuttonshow(t);
97*6f314b92SDavid du Colombier }
98*6f314b92SDavid du Colombier }
99*6f314b92SDavid du Colombier }
1009a747e4fSDavid du Colombier if((m->buttons&7) != t->lastbut){
1019a747e4fSDavid du Colombier if(m->buttons & 7){
102*6f314b92SDavid du Colombier t->prepress = t->pressed;
1039a747e4fSDavid du Colombier if (t->pressed)
1049a747e4fSDavid du Colombier t->pressed = 0;
1059a747e4fSDavid du Colombier else
1069a747e4fSDavid du Colombier t->pressed = 1;
10780ee5cbfSDavid du Colombier textbuttonshow(t);
1089a747e4fSDavid du Colombier }else{ /* generate event on button up */
109*6f314b92SDavid du Colombier if (ptinrect(m->xy,t->rect))
1109a747e4fSDavid du Colombier chanprint(t->event, t->format, t->name, t->pressed);
111*6f314b92SDavid du Colombier else {
112*6f314b92SDavid du Colombier t->off = 0;
113*6f314b92SDavid du Colombier t->pressed = t->prepress;
114*6f314b92SDavid du Colombier textbuttonshow(t);
115*6f314b92SDavid du Colombier }
11680ee5cbfSDavid du Colombier }
11780ee5cbfSDavid du Colombier }
1189a747e4fSDavid du Colombier t->lastbut = m->buttons & 7;
11980ee5cbfSDavid du Colombier }
12080ee5cbfSDavid du Colombier
12180ee5cbfSDavid du Colombier static void
textbuttonfree(Control * c)1229a747e4fSDavid du Colombier textbuttonfree(Control *c)
12380ee5cbfSDavid du Colombier {
12480ee5cbfSDavid du Colombier int i;
1259a747e4fSDavid du Colombier Textbutton *t;
12680ee5cbfSDavid du Colombier
1279a747e4fSDavid du Colombier t = (Textbutton*)c;
12880ee5cbfSDavid du Colombier _putctlfont(t->font);
12980ee5cbfSDavid du Colombier _putctlimage(t->image);
13080ee5cbfSDavid du Colombier _putctlimage(t->light);
13180ee5cbfSDavid du Colombier _putctlimage(t->mask);
13280ee5cbfSDavid du Colombier _putctlimage(t->textcolor);
13380ee5cbfSDavid du Colombier _putctlimage(t->bordercolor);
134*6f314b92SDavid du Colombier _putctlimage(t->paletextcolor);
13580ee5cbfSDavid du Colombier _putctlimage(t->pressedtextcolor);
13680ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++)
13780ee5cbfSDavid du Colombier free(t->line[i]);
13880ee5cbfSDavid du Colombier free(t->line);
13980ee5cbfSDavid du Colombier }
14080ee5cbfSDavid du Colombier
14180ee5cbfSDavid du Colombier static void
textbuttonshow(Textbutton * t)14280ee5cbfSDavid du Colombier textbuttonshow(Textbutton *t)
14380ee5cbfSDavid du Colombier {
14480ee5cbfSDavid du Colombier Rectangle r, clipr;
14580ee5cbfSDavid du Colombier int i, dx, dy, w;
14680ee5cbfSDavid du Colombier Font *f;
14780ee5cbfSDavid du Colombier Point p, q;
14880ee5cbfSDavid du Colombier Image *im;
14980ee5cbfSDavid du Colombier
150*6f314b92SDavid du Colombier if(t->hidden || (t->lastshow == t->pressed && t->showoff == t->off))
15180ee5cbfSDavid du Colombier return;
15280ee5cbfSDavid du Colombier f = t->font->font;
15380ee5cbfSDavid du Colombier draw(t->screen, t->rect, t->image->image, nil, t->image->image->r.min);
15480ee5cbfSDavid du Colombier if(t->border > 0)
15580ee5cbfSDavid du Colombier border(t->screen, t->rect, t->border, t->bordercolor->image, ZP);
15680ee5cbfSDavid du Colombier /* text goes here */
15780ee5cbfSDavid du Colombier dx = 0;
15880ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++){
15980ee5cbfSDavid du Colombier w = stringwidth(f, t->line[i]);
16080ee5cbfSDavid du Colombier if(dx < w)
16180ee5cbfSDavid du Colombier dx = w;
16280ee5cbfSDavid du Colombier }
16380ee5cbfSDavid du Colombier dy = t->nline*f->height;
16480ee5cbfSDavid du Colombier clipr = insetrect(t->rect, t->border);
16580ee5cbfSDavid du Colombier p = _ctlalignpoint(clipr, dx, dy, t->align);
16680ee5cbfSDavid du Colombier im = t->textcolor->image;
167*6f314b92SDavid du Colombier if(t->off)
168*6f314b92SDavid du Colombier im = t->paletextcolor->image;
169*6f314b92SDavid du Colombier else if(t->pressed)
17080ee5cbfSDavid du Colombier im = t->pressedtextcolor->image;
17180ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++){
17280ee5cbfSDavid du Colombier r.min = p;
17380ee5cbfSDavid du Colombier r.max.x = p.x+dx;
17480ee5cbfSDavid du Colombier r.max.y = p.y+f->height;
17580ee5cbfSDavid du Colombier q = _ctlalignpoint(r, stringwidth(f, t->line[i]), f->height, t->align%3);
17680ee5cbfSDavid du Colombier _string(t->screen, q, im,
17780ee5cbfSDavid du Colombier ZP, f, t->line[i], nil, strlen(t->line[i]),
178ac57dd0bSDavid du Colombier clipr, nil, ZP, SoverD);
17980ee5cbfSDavid du Colombier p.y += f->height;
18080ee5cbfSDavid du Colombier }
181*6f314b92SDavid du Colombier if(t->off || t->pressed)
18280ee5cbfSDavid du Colombier draw(t->screen, t->rect, t->light->image, t->mask->image, t->mask->image->r.min);
18380ee5cbfSDavid du Colombier t->lastshow = t->pressed;
184*6f314b92SDavid du Colombier t->showoff = t->off;
18580ee5cbfSDavid du Colombier flushimage(display, 1);
18680ee5cbfSDavid du Colombier }
18780ee5cbfSDavid du Colombier
18880ee5cbfSDavid du Colombier static void
textbuttonctl(Control * c,CParse * cp)1899a747e4fSDavid du Colombier textbuttonctl(Control *c, CParse *cp)
19080ee5cbfSDavid du Colombier {
19180ee5cbfSDavid du Colombier int cmd, i;
19280ee5cbfSDavid du Colombier Rectangle r;
19380ee5cbfSDavid du Colombier Textbutton *t;
19480ee5cbfSDavid du Colombier
19580ee5cbfSDavid du Colombier t = (Textbutton*)c;
1969a747e4fSDavid du Colombier cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
19780ee5cbfSDavid du Colombier switch(cmd){
19880ee5cbfSDavid du Colombier default:
1999a747e4fSDavid du Colombier ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
20080ee5cbfSDavid du Colombier break;
20180ee5cbfSDavid du Colombier case EAlign:
2029a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2039a747e4fSDavid du Colombier t->align = _ctlalignment(cp->args[1]);
20480ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
20580ee5cbfSDavid du Colombier break;
20680ee5cbfSDavid du Colombier case EBorder:
2079a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2089a747e4fSDavid du Colombier t->border = cp->iargs[1];
20980ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
21080ee5cbfSDavid du Colombier break;
21180ee5cbfSDavid du Colombier case EBordercolor:
2129a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2139a747e4fSDavid du Colombier _setctlimage(t, &t->bordercolor, cp->args[1]);
21480ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
21580ee5cbfSDavid du Colombier break;
21680ee5cbfSDavid du Colombier case EFocus:
21780ee5cbfSDavid du Colombier break;
21880ee5cbfSDavid du Colombier case EFont:
2199a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2209a747e4fSDavid du Colombier _setctlfont(t, &t->font, cp->args[1]);
22180ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
22280ee5cbfSDavid du Colombier break;
22380ee5cbfSDavid du Colombier case EFormat:
2249a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2259a747e4fSDavid du Colombier t->format = ctlstrdup(cp->args[1]);
2269a747e4fSDavid du Colombier break;
2279a747e4fSDavid du Colombier case EHide:
2289a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
2299a747e4fSDavid du Colombier t->hidden = 1;
23080ee5cbfSDavid du Colombier break;
23180ee5cbfSDavid du Colombier case EImage:
2329a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2339a747e4fSDavid du Colombier _setctlimage(t, &t->image, cp->args[1]);
23480ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
23580ee5cbfSDavid du Colombier break;
23680ee5cbfSDavid du Colombier case ELight:
2379a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2389a747e4fSDavid du Colombier _setctlimage(t, &t->light, cp->args[1]);
23980ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
24080ee5cbfSDavid du Colombier break;
24180ee5cbfSDavid du Colombier case EMask:
2429a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2439a747e4fSDavid du Colombier _setctlimage(t, &t->mask, cp->args[1]);
24480ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
24580ee5cbfSDavid du Colombier break;
246*6f314b92SDavid du Colombier case EPaletextcolor:
247*6f314b92SDavid du Colombier _ctlargcount(t, cp, 2);
248*6f314b92SDavid du Colombier _setctlimage(t, &t->paletextcolor, cp->args[1]);
249*6f314b92SDavid du Colombier t->lastshow = -1; /* force redraw */
250*6f314b92SDavid du Colombier break;
25180ee5cbfSDavid du Colombier case EPressedtextcolor:
2529a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2539a747e4fSDavid du Colombier _setctlimage(t, &t->pressedtextcolor, cp->args[1]);
25480ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
25580ee5cbfSDavid du Colombier break;
25680ee5cbfSDavid du Colombier case ERect:
2579a747e4fSDavid du Colombier _ctlargcount(t, cp, 5);
2589a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
2599a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
2609a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
2619a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
26280ee5cbfSDavid du Colombier if(Dx(r)<=0 || Dy(r)<=0)
2639a747e4fSDavid du Colombier ctlerror("%q: bad rectangle: %s", t->name, cp->str);
26480ee5cbfSDavid du Colombier t->rect = r;
26580ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
26680ee5cbfSDavid du Colombier break;
2679a747e4fSDavid du Colombier case EReveal:
2689a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
2699a747e4fSDavid du Colombier t->hidden = 0;
27080ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
27180ee5cbfSDavid du Colombier textbuttonshow(t);
27280ee5cbfSDavid du Colombier break;
2739a747e4fSDavid du Colombier case EShow:
2749a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
2759a747e4fSDavid du Colombier t->lastshow = -1; /* force redraw */
2769a747e4fSDavid du Colombier textbuttonshow(t);
2779a747e4fSDavid du Colombier break;
2789a747e4fSDavid du Colombier case ESize:
2799a747e4fSDavid du Colombier if (cp->nargs == 3)
2809a747e4fSDavid du Colombier r.max = Pt(0x7fffffff, 0x7fffffff);
2819a747e4fSDavid du Colombier else{
2829a747e4fSDavid du Colombier _ctlargcount(t, cp, 5);
2839a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
2849a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
2879a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
2889a747e4fSDavid du Colombier 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)
2899a747e4fSDavid du Colombier ctlerror("%q: bad sizes: %s", t->name, cp->str);
2909a747e4fSDavid du Colombier t->size.min = r.min;
2919a747e4fSDavid du Colombier t->size.max = r.max;
2929a747e4fSDavid du Colombier break;
29380ee5cbfSDavid du Colombier case EText:
29480ee5cbfSDavid du Colombier /* free existing text */
29580ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++)
29680ee5cbfSDavid du Colombier free(t->line[i]);
2979a747e4fSDavid du Colombier t->nline = cp->nargs-1;
29880ee5cbfSDavid du Colombier t->line = ctlrealloc(t->line, t->nline*sizeof(char*));
29980ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++)
3009a747e4fSDavid du Colombier t->line[i] = ctlstrdup(cp->args[i+1]);
30180ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
30280ee5cbfSDavid du Colombier textbuttonshow(t);
30380ee5cbfSDavid du Colombier break;
30480ee5cbfSDavid du Colombier case ETextcolor:
3059a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3069a747e4fSDavid du Colombier _setctlimage(t, &t->textcolor, cp->args[1]);
30780ee5cbfSDavid du Colombier t->lastshow = -1; /* force redraw */
30880ee5cbfSDavid du Colombier break;
30980ee5cbfSDavid du Colombier case EValue:
3109a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3119a747e4fSDavid du Colombier if((cp->iargs[1]!=0) != t->pressed){
31280ee5cbfSDavid du Colombier t->pressed ^= 1;
31380ee5cbfSDavid du Colombier textbuttonshow(t);
31480ee5cbfSDavid du Colombier }
31580ee5cbfSDavid du Colombier break;
31680ee5cbfSDavid du Colombier }
31780ee5cbfSDavid du Colombier }
3189a747e4fSDavid du Colombier
3199a747e4fSDavid du Colombier Control*
createtextbutton(Controlset * cs,char * name)3209a747e4fSDavid du Colombier createtextbutton(Controlset *cs, char *name)
3219a747e4fSDavid du Colombier {
3229a747e4fSDavid du Colombier Textbutton *t;
3239a747e4fSDavid du Colombier
3249a747e4fSDavid du Colombier t = (Textbutton *)_createctl(cs, "textbutton", sizeof(Textbutton), name);
3259a747e4fSDavid du Colombier t->line = ctlmalloc(sizeof(char*));
3269a747e4fSDavid du Colombier t->nline = 0;
3279a747e4fSDavid du Colombier t->image = _getctlimage("white");
3289a747e4fSDavid du Colombier t->light = _getctlimage("yellow");
3299a747e4fSDavid du Colombier t->mask = _getctlimage("opaque");
3309a747e4fSDavid du Colombier t->bordercolor = _getctlimage("black");
3319a747e4fSDavid du Colombier t->textcolor = _getctlimage("black");
3329a747e4fSDavid du Colombier t->pressedtextcolor = _getctlimage("black");
333*6f314b92SDavid du Colombier t->paletextcolor = _getctlimage("paleyellow");
3349a747e4fSDavid du Colombier t->font = _getctlfont("font");
3359a747e4fSDavid du Colombier t->format = ctlstrdup("%q: value %d");
3369a747e4fSDavid du Colombier t->lastshow = -1;
3379a747e4fSDavid du Colombier t->mouse = textbuttonmouse;
3389a747e4fSDavid du Colombier t->ctl = textbuttonctl;
3399a747e4fSDavid du Colombier t->exit = textbuttonfree;
340*6f314b92SDavid du Colombier t->prepress = 0;
341*6f314b92SDavid du Colombier t->off = 0;
342*6f314b92SDavid du Colombier t->showoff = -1;
3439a747e4fSDavid du Colombier return (Control *)t;
3449a747e4fSDavid du Colombier }
345