#include #include #include #include #include #include #include #include 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); }