#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h>#include <control.h>#include <scribble.h> typedef struct Scrib Scrib; struct Scrib{ Control; int border; CImage *image; CImage *color; CImage *bordercolor; CFont *font; int align; int lastbut; char lastchar[8]; Scribble *scrib;}; enum{ EAlign, EBorder, EBordercolor, EFocus, EFont, EImage, ELinecolor, ERect, EShow,}; static char *cmds[] = { [EAlign] = "align", [EBorder] = "border", [EBordercolor] ="bordercolor", [EFocus] = "focus", [EFont] = "font", [EImage] = "image", [ELinecolor] = "linecolor", [ERect] = "rect", [EShow] = "show", nil}; static void scribctl(Control*, char*);static void scribshow(Scrib*);static void scribfree(Scrib*);static void scribchar(Scrib*, Rune); static void resetstroke(Scrib *w);static void displaystroke(Scrib *w);static void displaylast(Scrib *w);static void addpoint(Scrib *w, Point p); static voidscribthread(void *v){ char buf[32]; Scrib *b; Rune r; b = v; snprint(buf, sizeof buf, "scrib-%s-0x%p", b->name, b); threadsetname(buf); b->image = _getctlimage("white"); b->color = _getctlimage("black"); b->bordercolor = _getctlimage("black"); b->align = Aupperleft; b->format = ctlstrdup("%q: value 0x%x"); b->font = _getctlfont("font"); b->scrib = scribblealloc(); b->lastbut = 0; b->bordercolor = _getctlimage("black"); b->border = 0; for(;;){ switch(alt(b->alts)){ default: ctlerror("%q: unknown message", b->name); case AKey: /* ignore keystrokes */ break; case AMouse: if (b->m.buttons & 0x1) { if ((b->lastbut & 0x1) == 0) { /* mouse went down */ resetstroke(b); } /* mouse is down */ addpoint(b, b->m.xy); } else if (b->lastbut & 0x1) { /* mouse went up */ r = recognize(b->scrib); scribchar(b, r); scribshow(b); if (r) printctl(b->event, b->format, b->name, r); } b->lastbut = b->m.buttons; break; case ACtl: _ctlcontrol(b, b->str, scribctl); free(b->str); break; case AWire: _ctlrewire(b); break; case AExit: scribfree(b); sendul(b->exit, 0); return; } }} Control*createscribble(Controlset *cs, char *name){ return _createctl(cs, "scrib", sizeof(Scrib), name, scribthread, 64*1024);} static voidscribfree(Scrib *b){ _putctlimage(b->image); _putctlimage(b->color); _putctlimage(b->bordercolor); _putctlfont(b->font);// scribblefree(b->scrib);} static voidscribchar(Scrib *b, Rune r){ if(r == 0) b->lastchar[0] = '\0'; else if(r == ' ') strcpy(b->lastchar, "' '"); else if(r < ' ') sprint(b->lastchar, "ctl-%c", r+'@'); else sprint(b->lastchar, "%C", r);} static voidscribshow(Scrib *b){ Image *i; Rectangle r; char *mode; Scribble *s = b->scrib; char buf[32]; if(b->border > 0){ r = insetrect(b->rect, b->border); border(b->screen, b->rect, b->border, b->bordercolor->image, ZP); }else r = b->rect; i = b->image->image; draw(b->screen, r, i, nil, i->r.min); if (s->ctrlShift) mode = " ^C"; else if (s->puncShift) mode = " #&^"; else if (s->curCharSet == CS_DIGITS) mode = " 123"; else if (s->capsLock) mode = " ABC"; else if (s->tmpShift) mode = " Abc"; else mode = " abc"; snprint(buf, sizeof buf, "%s %s", mode, b->lastchar); string(b->screen, r.min, b->color->image, ZP, b->font->font, buf); flushimage(display, 1);} static voidscribctl(Control *c, char *str){ int cmd; CParse cp; Rectangle r; Scrib *b; b = (Scrib*)c; cmd = _ctlparse(&cp, str, cmds); switch(cmd){ default: ctlerror("%q: unrecognized message '%s'", b->name, cp.str); break; case EAlign: _ctlargcount(b, &cp, 2); b->align = _ctlalignment(cp.args[1]); break; case EBorder: _ctlargcount(b, &cp, 2); if(cp.iargs[1] < 0) ctlerror("%q: bad border: %c", b->name, cp.str); b->border = cp.iargs[1]; break; case EBordercolor: _ctlargcount(b, &cp, 2); _setctlimage(b, &b->bordercolor, cp.args[1]); break; case EFocus: break; case EImage: _ctlargcount(b, &cp, 2); _setctlimage(b, &b->image, cp.args[1]); break; case ELinecolor: _ctlargcount(b, &cp, 2); _setctlimage(b, &b->bordercolor, cp.args[1]); break; case ERect: _ctlargcount(b, &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", b->name, cp.str); b->rect = r; break; case EShow: _ctlargcount(b, &cp, 1); scribshow(b); break; case EFont: _ctlargcount(b, &cp, 2); _setctlfont(b, &b->font, cp.args[1]); break; }} static voidresetstroke(Scrib *w){ Scribble *s = w->scrib; s->ps.npts = 0; scribshow(w);} static voiddisplaystroke(Scrib *b){ Scribble *s = b->scrib; poly(b->screen, s->pt, s->ps.npts, Endsquare, Endsquare, 0, b->color->image, ZP); flushimage(display, 1);} static voiddisplaylast(Scrib *w){ int npt; Scribble *s = w->scrib; npt = s->ps.npts; if (npt > 2) npt = 2; poly(w->screen, s->pt + (s->ps.npts - npt), npt, Endsquare, Endsquare, 0, w->color->image, ZP); flushimage(display, 1);} static voidaddpoint(Scrib *w, Point p){ pen_point *ppa; Point *pt; int ppasize; Scribble *s = w->scrib; if (s->ps.npts == s->ppasize) { ppasize = s->ppasize + 100; ppa = malloc ((sizeof (pen_point) + sizeof (Point)) * ppasize); if (!ppa) return; pt = (Point *) (ppa + ppasize); memmove(ppa, s->ps.pts, s->ppasize * sizeof (pen_point)); memmove(pt, s->pt, s->ppasize * sizeof (Point)); free (s->ps.pts); s->ps.pts = ppa; s->pt = pt; s->ppasize = ppasize; } ppa = &s->ps.pts[s->ps.npts]; ppa->Point = p; pt = &s->pt[s->ps.npts]; *pt = p; s->ps.npts++; displaylast(w);}
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <control.h>
#include <scribble.h>
typedef struct Scrib Scrib;
struct Scrib
{
Control;
int border;
CImage *image;
CImage *color;
CImage *bordercolor;
CFont *font;
int align;
int lastbut;
char lastchar[8];
Scribble *scrib;
};
enum{
EAlign,
EBorder,
EBordercolor,
EFocus,
EFont,
EImage,
ELinecolor,
ERect,
EShow,
};
static char *cmds[] = {
[EAlign] = "align",
[EBorder] = "border",
[EBordercolor] ="bordercolor",
[EFocus] = "focus",
[EFont] = "font",
[EImage] = "image",
[ELinecolor] = "linecolor",
[ERect] = "rect",
[EShow] = "show",
nil
};
static void scribctl(Control*, char*);
static void scribshow(Scrib*);
static void scribfree(Scrib*);
static void scribchar(Scrib*, Rune);
static void resetstroke(Scrib *w);
static void displaystroke(Scrib *w);
static void displaylast(Scrib *w);
static void addpoint(Scrib *w, Point p);
static void
scribthread(void *v)
{
char buf[32];
Scrib *b;
Rune r;
b = v;
snprint(buf, sizeof buf, "scrib-%s-0x%p", b->name, b);
threadsetname(buf);
b->image = _getctlimage("white");
b->color = _getctlimage("black");
b->bordercolor = _getctlimage("black");
b->align = Aupperleft;
b->format = ctlstrdup("%q: value 0x%x");
b->font = _getctlfont("font");
b->scrib = scribblealloc();
b->lastbut = 0;
b->bordercolor = _getctlimage("black");
b->border = 0;
for(;;){
switch(alt(b->alts)){
default:
ctlerror("%q: unknown message", b->name);
case AKey:
/* ignore keystrokes */
break;
case AMouse:
if (b->m.buttons & 0x1) {
if ((b->lastbut & 0x1) == 0) {
/* mouse went down */
resetstroke(b);
}
/* mouse is down */
addpoint(b, b->m.xy);
} else if (b->lastbut & 0x1) {
/* mouse went up */
r = recognize(b->scrib);
scribchar(b, r);
scribshow(b);
if (r) printctl(b->event, b->format, b->name, r);
}
b->lastbut = b->m.buttons;
break;
case ACtl:
_ctlcontrol(b, b->str, scribctl);
free(b->str);
break;
case AWire:
_ctlrewire(b);
break;
case AExit:
scribfree(b);
sendul(b->exit, 0);
return;
}
}
}
Control*
createscribble(Controlset *cs, char *name)
{
return _createctl(cs, "scrib", sizeof(Scrib), name, scribthread, 64*1024);
}
static void
scribfree(Scrib *b)
{
_putctlimage(b->image);
_putctlimage(b->color);
_putctlimage(b->bordercolor);
_putctlfont(b->font);
// scribblefree(b->scrib);
}
static void
scribchar(Scrib *b, Rune r)
{
if(r == 0)
b->lastchar[0] = '\0';
else if(r == ' ')
strcpy(b->lastchar, "' '");
else if(r < ' ')
sprint(b->lastchar, "ctl-%c", r+'@');
else
sprint(b->lastchar, "%C", r);
}
static void
scribshow(Scrib *b)
{
Image *i;
Rectangle r;
char *mode;
Scribble *s = b->scrib;
char buf[32];
if(b->border > 0){
r = insetrect(b->rect, b->border);
border(b->screen, b->rect, b->border, b->bordercolor->image, ZP);
}else
r = b->rect;
i = b->image->image;
draw(b->screen, r, i, nil, i->r.min);
if (s->ctrlShift)
mode = " ^C";
else if (s->puncShift)
mode = " #&^";
else if (s->curCharSet == CS_DIGITS)
mode = " 123";
else if (s->capsLock)
mode = " ABC";
else if (s->tmpShift)
mode = " Abc";
else
mode = " abc";
snprint(buf, sizeof buf, "%s %s", mode, b->lastchar);
string(b->screen, r.min, b->color->image, ZP, b->font->font, buf);
flushimage(display, 1);
}
static void
scribctl(Control *c, char *str)
{
int cmd;
CParse cp;
Rectangle r;
Scrib *b;
b = (Scrib*)c;
cmd = _ctlparse(&cp, str, cmds);
switch(cmd){
default:
ctlerror("%q: unrecognized message '%s'", b->name, cp.str);
break;
case EAlign:
_ctlargcount(b, &cp, 2);
b->align = _ctlalignment(cp.args[1]);
break;
case EBorder:
_ctlargcount(b, &cp, 2);
if(cp.iargs[1] < 0)
ctlerror("%q: bad border: %c", b->name, cp.str);
b->border = cp.iargs[1];
break;
case EBordercolor:
_ctlargcount(b, &cp, 2);
_setctlimage(b, &b->bordercolor, cp.args[1]);
break;
case EFocus:
break;
case EImage:
_ctlargcount(b, &cp, 2);
_setctlimage(b, &b->image, cp.args[1]);
break;
case ELinecolor:
_ctlargcount(b, &cp, 2);
_setctlimage(b, &b->bordercolor, cp.args[1]);
break;
case ERect:
_ctlargcount(b, &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", b->name, cp.str);
b->rect = r;
break;
case EShow:
_ctlargcount(b, &cp, 1);
scribshow(b);
break;
case EFont:
_ctlargcount(b, &cp, 2);
_setctlfont(b, &b->font, cp.args[1]);
break;
}
}
static void
resetstroke(Scrib *w)
{
Scribble *s = w->scrib;
s->ps.npts = 0;
scribshow(w);
}
static void
displaystroke(Scrib *b)
{
Scribble *s = b->scrib;
poly(b->screen, s->pt, s->ps.npts, Endsquare, Endsquare, 0, b->color->image, ZP);
flushimage(display, 1);
}
static void
displaylast(Scrib *w)
{
int npt;
Scribble *s = w->scrib;
npt = s->ps.npts;
if (npt > 2)
npt = 2;
poly(w->screen, s->pt + (s->ps.npts - npt), npt, Endsquare, Endsquare,
0, w->color->image, ZP);
flushimage(display, 1);
}
static void
addpoint(Scrib *w, Point p)
{
pen_point *ppa;
Point *pt;
int ppasize;
Scribble *s = w->scrib;
if (s->ps.npts == s->ppasize) {
ppasize = s->ppasize + 100;
ppa = malloc ((sizeof (pen_point) + sizeof (Point)) * ppasize);
if (!ppa)
return;
pt = (Point *) (ppa + ppasize);
memmove(ppa, s->ps.pts, s->ppasize * sizeof (pen_point));
memmove(pt, s->pt, s->ppasize * sizeof (Point));
free (s->ps.pts);
s->ps.pts = ppa;
s->pt = pt;
s->ppasize = ppasize;
}
ppa = &s->ps.pts[s->ps.npts];
ppa->Point = p;
pt = &s->pt[s->ps.npts];
*pt = p;
s->ps.npts++;
displaylast(w);
}