xref: /plan9/sys/src/libcontrol/scribble.c (revision da79363fb9fd5a76e4ca65f2f996542f71fcdfef)
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 #include <scribble.h>
980ee5cbfSDavid du Colombier 
1080ee5cbfSDavid du Colombier typedef struct Scrib Scrib;
1180ee5cbfSDavid du Colombier 
1280ee5cbfSDavid du Colombier struct Scrib
1380ee5cbfSDavid du Colombier {
1480ee5cbfSDavid du Colombier 	Control;
1580ee5cbfSDavid du Colombier 	int		border;
1680ee5cbfSDavid du Colombier 	CImage	*image;
1780ee5cbfSDavid du Colombier 	CImage	*color;
1880ee5cbfSDavid du Colombier 	CImage	*bordercolor;
1980ee5cbfSDavid du Colombier 	CFont	*font;
2080ee5cbfSDavid du Colombier 	int		align;
2180ee5cbfSDavid du Colombier 	int		lastbut;
2280ee5cbfSDavid du Colombier 	char		lastchar[8];
2380ee5cbfSDavid du Colombier 	Scribble	*scrib;
2480ee5cbfSDavid du Colombier };
2580ee5cbfSDavid du Colombier 
2680ee5cbfSDavid du Colombier enum{
2780ee5cbfSDavid du Colombier 	EAlign,
2880ee5cbfSDavid du Colombier 	EBorder,
2980ee5cbfSDavid du Colombier 	EBordercolor,
3080ee5cbfSDavid du Colombier 	EFocus,
3180ee5cbfSDavid du Colombier 	EFont,
329a747e4fSDavid du Colombier 	EHide,
3380ee5cbfSDavid du Colombier 	EImage,
3480ee5cbfSDavid du Colombier 	ELinecolor,
3580ee5cbfSDavid du Colombier 	ERect,
369a747e4fSDavid du Colombier 	EReveal,
3780ee5cbfSDavid du Colombier 	EShow,
389a747e4fSDavid du Colombier 	ESize,
3980ee5cbfSDavid du Colombier };
4080ee5cbfSDavid du Colombier 
4180ee5cbfSDavid du Colombier static char *cmds[] = {
4280ee5cbfSDavid du Colombier 	[EAlign] =		"align",
4380ee5cbfSDavid du Colombier 	[EBorder] =	"border",
4480ee5cbfSDavid du Colombier 	[EBordercolor] ="bordercolor",
4580ee5cbfSDavid du Colombier 	[EFocus] = 	"focus",
4680ee5cbfSDavid du Colombier 	[EFont] =		"font",
479a747e4fSDavid du Colombier 	[EHide] =		"hide",
4880ee5cbfSDavid du Colombier 	[EImage] =	"image",
4980ee5cbfSDavid du Colombier 	[ELinecolor] =	"linecolor",
5080ee5cbfSDavid du Colombier 	[ERect] =		"rect",
519a747e4fSDavid du Colombier 	[EReveal] =	"reveal",
5280ee5cbfSDavid du Colombier 	[EShow] =		"show",
539a747e4fSDavid du Colombier 	[ESize] =		"size",
5480ee5cbfSDavid du Colombier 	nil
5580ee5cbfSDavid du Colombier };
5680ee5cbfSDavid du Colombier 
5780ee5cbfSDavid du Colombier static void	scribshow(Scrib*);
5880ee5cbfSDavid du Colombier static void scribchar(Scrib*, Rune);
5980ee5cbfSDavid du Colombier 
6080ee5cbfSDavid du Colombier static void	resetstroke(Scrib *w);
6180ee5cbfSDavid du Colombier static void	displaystroke(Scrib *w);
6280ee5cbfSDavid du Colombier static void	displaylast(Scrib *w);
6380ee5cbfSDavid du Colombier static void	addpoint(Scrib *w, Point p);
6480ee5cbfSDavid du Colombier 
6580ee5cbfSDavid du Colombier static void
scribmouse(Control * c,Mouse * m)669a747e4fSDavid du Colombier scribmouse(Control *c, Mouse *m)
6780ee5cbfSDavid du Colombier {
6880ee5cbfSDavid du Colombier 	Scrib *b;
6980ee5cbfSDavid du Colombier 	Rune r;
7080ee5cbfSDavid du Colombier 
719a747e4fSDavid du Colombier 	b = (Scrib*)c;
729a747e4fSDavid du Colombier 	if (m->buttons & 0x1) {
7380ee5cbfSDavid du Colombier 		if ((b->lastbut & 0x1) == 0) {
7480ee5cbfSDavid du Colombier 			/* mouse went down */
7580ee5cbfSDavid du Colombier 			resetstroke(b);
7680ee5cbfSDavid du Colombier 		}
7780ee5cbfSDavid du Colombier 		/* mouse is down */
78*da79363fSDavid du Colombier 		if (ptinrect(m->xy,b->rect))
799a747e4fSDavid du Colombier 			addpoint(b, m->xy);
8080ee5cbfSDavid du Colombier 	} else if (b->lastbut & 0x1) {
8180ee5cbfSDavid du Colombier 		/* mouse went up */
82*da79363fSDavid du Colombier 		if (ptinrect(m->xy,b->rect)) {
8380ee5cbfSDavid du Colombier 			r = recognize(b->scrib);
8480ee5cbfSDavid du Colombier 			scribchar(b, r);
8580ee5cbfSDavid du Colombier 			scribshow(b);
869a747e4fSDavid du Colombier 			if (r) chanprint(b->event, b->format, b->name, r);
8780ee5cbfSDavid du Colombier 		}
88*da79363fSDavid du Colombier 	}
899a747e4fSDavid du Colombier 	b->lastbut = m->buttons;
9080ee5cbfSDavid du Colombier }
9180ee5cbfSDavid du Colombier 
9280ee5cbfSDavid du Colombier static void
scribfree(Control * c)939a747e4fSDavid du Colombier scribfree(Control *c)
9480ee5cbfSDavid du Colombier {
959a747e4fSDavid du Colombier 	Scrib *b;
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier 	b = (Scrib*)c;
9880ee5cbfSDavid du Colombier 	_putctlimage(b->image);
9980ee5cbfSDavid du Colombier 	_putctlimage(b->color);
10080ee5cbfSDavid du Colombier 	_putctlimage(b->bordercolor);
10180ee5cbfSDavid du Colombier 	_putctlfont(b->font);
10280ee5cbfSDavid du Colombier //	scribblefree(b->scrib);
10380ee5cbfSDavid du Colombier }
10480ee5cbfSDavid du Colombier 
10580ee5cbfSDavid du Colombier static void
scribchar(Scrib * b,Rune r)10680ee5cbfSDavid du Colombier scribchar(Scrib *b, Rune r)
10780ee5cbfSDavid du Colombier {
10880ee5cbfSDavid du Colombier 	if(r == 0)
10980ee5cbfSDavid du Colombier 		b->lastchar[0] = '\0';
11080ee5cbfSDavid du Colombier 	else if(r == ' ')
11180ee5cbfSDavid du Colombier 		strcpy(b->lastchar, "' '");
11280ee5cbfSDavid du Colombier 	else if(r < ' ')
11380ee5cbfSDavid du Colombier 		sprint(b->lastchar, "ctl-%c", r+'@');
11480ee5cbfSDavid du Colombier 	else
11580ee5cbfSDavid du Colombier 		sprint(b->lastchar, "%C", r);
11680ee5cbfSDavid du Colombier }
11780ee5cbfSDavid du Colombier 
11880ee5cbfSDavid du Colombier 
11980ee5cbfSDavid du Colombier static void
scribshow(Scrib * b)12080ee5cbfSDavid du Colombier scribshow(Scrib *b)
12180ee5cbfSDavid du Colombier {
12280ee5cbfSDavid du Colombier 	Image *i;
12380ee5cbfSDavid du Colombier 	Rectangle r;
12480ee5cbfSDavid du Colombier 	char *mode;
12580ee5cbfSDavid du Colombier 	Scribble *s = b->scrib;
12680ee5cbfSDavid du Colombier 	char buf[32];
12780ee5cbfSDavid du Colombier 
1289a747e4fSDavid du Colombier 	if (b->hidden)
1299a747e4fSDavid du Colombier 		return;
13080ee5cbfSDavid du Colombier 	if(b->border > 0){
13180ee5cbfSDavid du Colombier 		r = insetrect(b->rect, b->border);
13280ee5cbfSDavid du Colombier 		border(b->screen, b->rect, b->border, b->bordercolor->image, ZP);
13380ee5cbfSDavid du Colombier 	}else
13480ee5cbfSDavid du Colombier 		r = b->rect;
13580ee5cbfSDavid du Colombier 
13680ee5cbfSDavid du Colombier 	i = b->image->image;
13780ee5cbfSDavid du Colombier 	draw(b->screen, r, i, nil, i->r.min);
13880ee5cbfSDavid du Colombier 
13980ee5cbfSDavid du Colombier 	if (s->ctrlShift)
14080ee5cbfSDavid du Colombier 		mode = " ^C";
14180ee5cbfSDavid du Colombier 	else if (s->puncShift)
14280ee5cbfSDavid du Colombier 		mode = " #&^";
14380ee5cbfSDavid du Colombier 	else if (s->curCharSet == CS_DIGITS)
14480ee5cbfSDavid du Colombier 		mode = " 123";
14580ee5cbfSDavid du Colombier 	else if (s->capsLock)
14680ee5cbfSDavid du Colombier 		mode = " ABC";
14780ee5cbfSDavid du Colombier 	else if (s->tmpShift)
14880ee5cbfSDavid du Colombier 		mode = " Abc";
14980ee5cbfSDavid du Colombier 	else
15080ee5cbfSDavid du Colombier 		mode = " abc";
15180ee5cbfSDavid du Colombier 
15280ee5cbfSDavid du Colombier 	snprint(buf, sizeof buf, "%s %s", mode, b->lastchar);
15380ee5cbfSDavid du Colombier 
15480ee5cbfSDavid du Colombier 	string(b->screen, r.min, b->color->image, ZP, b->font->font, buf);
15580ee5cbfSDavid du Colombier 	flushimage(display, 1);
15680ee5cbfSDavid du Colombier }
15780ee5cbfSDavid du Colombier 
15880ee5cbfSDavid du Colombier static void
scribctl(Control * c,CParse * cp)1599a747e4fSDavid du Colombier scribctl(Control *c, CParse *cp)
16080ee5cbfSDavid du Colombier {
16180ee5cbfSDavid du Colombier 	int cmd;
16280ee5cbfSDavid du Colombier 	Rectangle r;
16380ee5cbfSDavid du Colombier 	Scrib *b;
16480ee5cbfSDavid du Colombier 
16580ee5cbfSDavid du Colombier 	b = (Scrib*)c;
1669a747e4fSDavid du Colombier 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
16780ee5cbfSDavid du Colombier 	switch(cmd){
16880ee5cbfSDavid du Colombier 	default:
1699a747e4fSDavid du Colombier 		abort();
1709a747e4fSDavid du Colombier 		ctlerror("%q: unrecognized message '%s'", b->name, cp->str);
17180ee5cbfSDavid du Colombier 		break;
17280ee5cbfSDavid du Colombier 	case EAlign:
1739a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
1749a747e4fSDavid du Colombier 		b->align = _ctlalignment(cp->args[1]);
17580ee5cbfSDavid du Colombier 		break;
17680ee5cbfSDavid du Colombier 	case EBorder:
1779a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
1789a747e4fSDavid du Colombier 		if(cp->iargs[1] < 0)
1799a747e4fSDavid du Colombier 			ctlerror("%q: bad border: %c", b->name, cp->str);
1809a747e4fSDavid du Colombier 		b->border = cp->iargs[1];
18180ee5cbfSDavid du Colombier 		break;
18280ee5cbfSDavid du Colombier 	case EBordercolor:
1839a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
1849a747e4fSDavid du Colombier 		_setctlimage(b, &b->bordercolor, cp->args[1]);
18580ee5cbfSDavid du Colombier 		break;
18680ee5cbfSDavid du Colombier 	case EFocus:
18780ee5cbfSDavid du Colombier 		break;
18880ee5cbfSDavid du Colombier 	case EImage:
1899a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
1909a747e4fSDavid du Colombier 		_setctlimage(b, &b->image, cp->args[1]);
19180ee5cbfSDavid du Colombier 		break;
19280ee5cbfSDavid du Colombier 	case ELinecolor:
1939a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
1949a747e4fSDavid du Colombier 		_setctlimage(b, &b->bordercolor, cp->args[1]);
19580ee5cbfSDavid du Colombier 		break;
19680ee5cbfSDavid du Colombier 	case ERect:
1979a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 5);
1989a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
1999a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
2009a747e4fSDavid du Colombier 		r.max.x = cp->iargs[3];
2019a747e4fSDavid du Colombier 		r.max.y = cp->iargs[4];
20280ee5cbfSDavid du Colombier 		if(Dx(r)<0 || Dy(r)<0)
2039a747e4fSDavid du Colombier 			ctlerror("%q: bad rectangle: %s", b->name, cp->str);
20480ee5cbfSDavid du Colombier 		b->rect = r;
20580ee5cbfSDavid du Colombier 		break;
2069a747e4fSDavid du Colombier 	case EReveal:
2079a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 1);
2089a747e4fSDavid du Colombier 		b->hidden = 0;
2099a747e4fSDavid du Colombier 		scribshow(b);
2109a747e4fSDavid du Colombier 		break;
21180ee5cbfSDavid du Colombier 	case EShow:
2129a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 1);
21380ee5cbfSDavid du Colombier 		scribshow(b);
21480ee5cbfSDavid du Colombier 		break;
21580ee5cbfSDavid du Colombier 	case EFont:
2169a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 2);
2179a747e4fSDavid du Colombier 		_setctlfont(b, &b->font, cp->args[1]);
2189a747e4fSDavid du Colombier 		break;
2199a747e4fSDavid du Colombier 	case EHide:
2209a747e4fSDavid du Colombier 		_ctlargcount(b, cp, 1);
2219a747e4fSDavid du Colombier 		b->hidden = 1;
2229a747e4fSDavid du Colombier 		break;
2239a747e4fSDavid du Colombier 	case ESize:
2249a747e4fSDavid du Colombier 		if (cp->nargs == 3)
2259a747e4fSDavid du Colombier 			r.max = Pt(0x7fffffff, 0x7fffffff);
2269a747e4fSDavid du Colombier 		else{
2279a747e4fSDavid du Colombier 			_ctlargcount(b, cp, 5);
2289a747e4fSDavid du Colombier 			r.max.x = cp->iargs[3];
2299a747e4fSDavid du Colombier 			r.max.y = cp->iargs[4];
2309a747e4fSDavid du Colombier 		}
2319a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
2329a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
2339a747e4fSDavid 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)
2349a747e4fSDavid du Colombier 			ctlerror("%q: bad sizes: %s", b->name, cp->str);
2359a747e4fSDavid du Colombier 		b->size.min = r.min;
2369a747e4fSDavid du Colombier 		b->size.max = r.max;
23780ee5cbfSDavid du Colombier 		break;
23880ee5cbfSDavid du Colombier 	}
23980ee5cbfSDavid du Colombier }
24080ee5cbfSDavid du Colombier 
24180ee5cbfSDavid du Colombier static void
resetstroke(Scrib * w)24280ee5cbfSDavid du Colombier resetstroke(Scrib *w)
24380ee5cbfSDavid du Colombier {
24480ee5cbfSDavid du Colombier 	Scribble *s = w->scrib;
24580ee5cbfSDavid du Colombier 
24680ee5cbfSDavid du Colombier 	s->ps.npts = 0;
24780ee5cbfSDavid du Colombier 	scribshow(w);
24880ee5cbfSDavid du Colombier }
24980ee5cbfSDavid du Colombier 
25080ee5cbfSDavid du Colombier static void
displaystroke(Scrib * b)25180ee5cbfSDavid du Colombier displaystroke(Scrib *b)
25280ee5cbfSDavid du Colombier {
25380ee5cbfSDavid du Colombier 	Scribble *s = b->scrib;
25480ee5cbfSDavid du Colombier 
25580ee5cbfSDavid du Colombier 	poly(b->screen, s->pt, s->ps.npts, Endsquare, Endsquare, 0, b->color->image, ZP);
25680ee5cbfSDavid du Colombier 	flushimage(display, 1);
25780ee5cbfSDavid du Colombier }
25880ee5cbfSDavid du Colombier 
25980ee5cbfSDavid du Colombier static void
displaylast(Scrib * w)26080ee5cbfSDavid du Colombier displaylast(Scrib *w)
26180ee5cbfSDavid du Colombier {
26280ee5cbfSDavid du Colombier 	int	    npt;
26380ee5cbfSDavid du Colombier 	Scribble *s = w->scrib;
26480ee5cbfSDavid du Colombier 
26580ee5cbfSDavid du Colombier 	npt = s->ps.npts;
26680ee5cbfSDavid du Colombier 	if (npt > 2)
26780ee5cbfSDavid du Colombier 		npt = 2;
26880ee5cbfSDavid du Colombier 	poly(w->screen, s->pt + (s->ps.npts - npt), npt, Endsquare, Endsquare,
26980ee5cbfSDavid du Colombier 		0, w->color->image, ZP);
27080ee5cbfSDavid du Colombier 	flushimage(display, 1);
27180ee5cbfSDavid du Colombier }
27280ee5cbfSDavid du Colombier 
27380ee5cbfSDavid du Colombier static void
addpoint(Scrib * w,Point p)27480ee5cbfSDavid du Colombier addpoint(Scrib *w, Point p)
27580ee5cbfSDavid du Colombier {
27680ee5cbfSDavid du Colombier 	pen_point	*ppa;
27780ee5cbfSDavid du Colombier 	Point	*pt;
27880ee5cbfSDavid du Colombier 	int		ppasize;
27980ee5cbfSDavid du Colombier 	Scribble	*s = w->scrib;
28080ee5cbfSDavid du Colombier 
28180ee5cbfSDavid du Colombier 	if (s->ps.npts == s->ppasize) {
28280ee5cbfSDavid du Colombier 		ppasize = s->ppasize + 100;
28380ee5cbfSDavid du Colombier 		ppa = malloc ((sizeof (pen_point) + sizeof (Point)) * ppasize);
28480ee5cbfSDavid du Colombier 		if (!ppa)
28580ee5cbfSDavid du Colombier 			return;
28680ee5cbfSDavid du Colombier 		pt = (Point *) (ppa + ppasize);
28780ee5cbfSDavid du Colombier 		memmove(ppa, s->ps.pts, s->ppasize * sizeof (pen_point));
28880ee5cbfSDavid du Colombier 		memmove(pt, s->pt, s->ppasize * sizeof (Point));
28980ee5cbfSDavid du Colombier 		free (s->ps.pts);
29080ee5cbfSDavid du Colombier 		s->ps.pts = ppa;
29180ee5cbfSDavid du Colombier 		s->pt = pt;
29280ee5cbfSDavid du Colombier 		s->ppasize = ppasize;
29380ee5cbfSDavid du Colombier 	}
29480ee5cbfSDavid du Colombier 	ppa = &s->ps.pts[s->ps.npts];
29580ee5cbfSDavid du Colombier 	ppa->Point = p;
29680ee5cbfSDavid du Colombier 
29780ee5cbfSDavid du Colombier 	pt = &s->pt[s->ps.npts];
29880ee5cbfSDavid du Colombier 	*pt = p;
29980ee5cbfSDavid du Colombier 
30080ee5cbfSDavid du Colombier 	s->ps.npts++;
30180ee5cbfSDavid du Colombier 
30280ee5cbfSDavid du Colombier 	displaylast(w);
30380ee5cbfSDavid du Colombier }
3049a747e4fSDavid du Colombier 
3059a747e4fSDavid du Colombier Control*
createscribble(Controlset * cs,char * name)3069a747e4fSDavid du Colombier createscribble(Controlset *cs, char *name)
3079a747e4fSDavid du Colombier {
3089a747e4fSDavid du Colombier 	Scrib *b;
3099a747e4fSDavid du Colombier 
3109a747e4fSDavid du Colombier 	b = (Scrib*)_createctl(cs, "scribble", sizeof(Scrib), name);
3119a747e4fSDavid du Colombier 	b->image = _getctlimage("white");
3129a747e4fSDavid du Colombier 	b->color = _getctlimage("black");
3139a747e4fSDavid du Colombier 	b->bordercolor = _getctlimage("black");
3149a747e4fSDavid du Colombier 	b->align = Aupperleft;
3159a747e4fSDavid du Colombier 	b->format = ctlstrdup("%q: value 0x%x");
3169a747e4fSDavid du Colombier 	b->font = _getctlfont("font");
3179a747e4fSDavid du Colombier 	b->scrib = scribblealloc();
3189a747e4fSDavid du Colombier 	b->lastbut = 0;
3199a747e4fSDavid du Colombier 	b->bordercolor = _getctlimage("black");
3209a747e4fSDavid du Colombier 	b->border = 0;
3219a747e4fSDavid du Colombier 	b->ctl = scribctl;
3229a747e4fSDavid du Colombier 	b->mouse = scribmouse;
3239a747e4fSDavid du Colombier 	b->exit = scribfree;
3249a747e4fSDavid du Colombier 	return (Control*)b;
3259a747e4fSDavid du Colombier }
326