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 Entry Entry; 1080ee5cbfSDavid du Colombier 1180ee5cbfSDavid du Colombier struct Entry 1280ee5cbfSDavid du Colombier { 1380ee5cbfSDavid du Colombier Control; 1480ee5cbfSDavid du Colombier int border; 1580ee5cbfSDavid du Colombier CFont *font; 1680ee5cbfSDavid du Colombier CImage *image; 1780ee5cbfSDavid du Colombier CImage *textcolor; 1880ee5cbfSDavid du Colombier CImage *bordercolor; 1980ee5cbfSDavid du Colombier Rune *text; 2080ee5cbfSDavid du Colombier int ntext; 2180ee5cbfSDavid du Colombier int cursor; 2280ee5cbfSDavid du Colombier int align; 2380ee5cbfSDavid du Colombier int hasfocus; 2480ee5cbfSDavid du Colombier int lastbut; 2580ee5cbfSDavid du Colombier }; 2680ee5cbfSDavid du Colombier 2780ee5cbfSDavid du Colombier enum{ 2880ee5cbfSDavid du Colombier EAlign, 2980ee5cbfSDavid du Colombier EBorder, 3080ee5cbfSDavid du Colombier EBordercolor, 3180ee5cbfSDavid du Colombier EData, 3280ee5cbfSDavid du Colombier EFocus, 3380ee5cbfSDavid du Colombier EFont, 3480ee5cbfSDavid du Colombier EFormat, 359a747e4fSDavid du Colombier EHide, 3680ee5cbfSDavid du Colombier EImage, 3780ee5cbfSDavid du Colombier ERect, 389a747e4fSDavid du Colombier EReveal, 3980ee5cbfSDavid du Colombier EShow, 409a747e4fSDavid du Colombier ESize, 4180ee5cbfSDavid du Colombier ETextcolor, 4280ee5cbfSDavid du Colombier EValue, 4380ee5cbfSDavid du Colombier }; 4480ee5cbfSDavid du Colombier 4580ee5cbfSDavid du Colombier static char *cmds[] = { 4680ee5cbfSDavid du Colombier [EAlign] = "align", 4780ee5cbfSDavid du Colombier [EBorder] = "border", 4880ee5cbfSDavid du Colombier [EBordercolor] = "bordercolor", 4980ee5cbfSDavid du Colombier [EData] = "data", 5080ee5cbfSDavid du Colombier [EFocus] = "focus", 5180ee5cbfSDavid du Colombier [EFont] = "font", 5280ee5cbfSDavid du Colombier [EFormat] = "format", 539a747e4fSDavid du Colombier [EHide] = "hide", 5480ee5cbfSDavid du Colombier [EImage] = "image", 5580ee5cbfSDavid du Colombier [ERect] = "rect", 569a747e4fSDavid du Colombier [EReveal] = "reveal", 5780ee5cbfSDavid du Colombier [EShow] = "show", 589a747e4fSDavid du Colombier [ESize] = "size", 5980ee5cbfSDavid du Colombier [ETextcolor] = "textcolor", 6080ee5cbfSDavid du Colombier [EValue] = "value", 6180ee5cbfSDavid du Colombier nil 6280ee5cbfSDavid du Colombier }; 6380ee5cbfSDavid du Colombier 6480ee5cbfSDavid du Colombier static void 659a747e4fSDavid du Colombier entryfree(Control *c) 6680ee5cbfSDavid du Colombier { 6780ee5cbfSDavid du Colombier Entry *e; 6880ee5cbfSDavid du Colombier 699a747e4fSDavid du Colombier e = (Entry *)c; 7080ee5cbfSDavid du Colombier _putctlfont(e->font); 7180ee5cbfSDavid du Colombier _putctlimage(e->image); 7280ee5cbfSDavid du Colombier _putctlimage(e->textcolor); 7380ee5cbfSDavid du Colombier _putctlimage(e->bordercolor); 7480ee5cbfSDavid du Colombier free(e->text); 7580ee5cbfSDavid du Colombier } 7680ee5cbfSDavid du Colombier 7780ee5cbfSDavid du Colombier static Point 7880ee5cbfSDavid du Colombier entrypoint(Entry *e, int c) 7980ee5cbfSDavid du Colombier { 8080ee5cbfSDavid du Colombier Point p; 8180ee5cbfSDavid du Colombier Rectangle r; 8280ee5cbfSDavid du Colombier 8380ee5cbfSDavid du Colombier r = e->rect; 8480ee5cbfSDavid du Colombier if(e->border > 0) 8580ee5cbfSDavid du Colombier r = insetrect(r, e->border); 8680ee5cbfSDavid du Colombier p = _ctlalignpoint(r, 8780ee5cbfSDavid du Colombier runestringnwidth(e->font->font, e->text, e->ntext), 8880ee5cbfSDavid du Colombier e->font->font->height, e->align); 8980ee5cbfSDavid du Colombier if(c > e->ntext) 9080ee5cbfSDavid du Colombier c = e->ntext; 9180ee5cbfSDavid du Colombier p.x += runestringnwidth(e->font->font, e->text, c); 9280ee5cbfSDavid du Colombier return p; 9380ee5cbfSDavid du Colombier } 9480ee5cbfSDavid du Colombier 9580ee5cbfSDavid du Colombier static void 9680ee5cbfSDavid du Colombier entryshow(Entry *e) 9780ee5cbfSDavid du Colombier { 9880ee5cbfSDavid du Colombier Rectangle r, dr; 9980ee5cbfSDavid du Colombier Point p; 10080ee5cbfSDavid du Colombier 1019a747e4fSDavid du Colombier if (e->hidden) 1029a747e4fSDavid du Colombier return; 10380ee5cbfSDavid du Colombier r = e->rect; 10480ee5cbfSDavid du Colombier draw(e->screen, r, e->image->image, nil, e->image->image->r.min); 10580ee5cbfSDavid du Colombier if(e->border > 0){ 10680ee5cbfSDavid du Colombier border(e->screen, r, e->border, e->bordercolor->image, e->bordercolor->image->r.min); 10780ee5cbfSDavid du Colombier dr = insetrect(r, e->border); 10880ee5cbfSDavid du Colombier }else 10980ee5cbfSDavid du Colombier dr = r; 11080ee5cbfSDavid du Colombier p = entrypoint(e, 0); 11180ee5cbfSDavid du Colombier _string(e->screen, p, e->textcolor->image, 11280ee5cbfSDavid du Colombier ZP, e->font->font, nil, e->text, e->ntext, 113*ac57dd0bSDavid du Colombier dr, nil, ZP, SoverD); 11480ee5cbfSDavid du Colombier if(e->hasfocus){ 11580ee5cbfSDavid du Colombier p = entrypoint(e, e->cursor); 11680ee5cbfSDavid du Colombier r.min = p; 11780ee5cbfSDavid du Colombier r.max.x = p.x+1; 11880ee5cbfSDavid du Colombier r.max.y = p.y+e->font->font->height; 11980ee5cbfSDavid du Colombier if(rectclip(&r, dr)) 12080ee5cbfSDavid du Colombier draw(e->screen, r, e->textcolor->image, nil, ZP); 12180ee5cbfSDavid du Colombier } 12280ee5cbfSDavid du Colombier flushimage(display, 1); 12380ee5cbfSDavid du Colombier } 12480ee5cbfSDavid du Colombier 12580ee5cbfSDavid du Colombier static void 1269a747e4fSDavid du Colombier entrysetpoint(Entry *e, Point cp) 1279a747e4fSDavid du Colombier { 1289a747e4fSDavid du Colombier Point p; 1299a747e4fSDavid du Colombier int i; 1309a747e4fSDavid du Colombier 1319a747e4fSDavid du Colombier if(!ptinrect(cp, insetrect(e->rect, e->border))) 1329a747e4fSDavid du Colombier return; 1339a747e4fSDavid du Colombier p = entrypoint(e, 0); 1349a747e4fSDavid du Colombier for(i=0; i<e->ntext; i++){ 1359a747e4fSDavid du Colombier p.x += runestringnwidth(e->font->font, e->text+i, 1); 1369a747e4fSDavid du Colombier if(p.x > cp.x) 1379a747e4fSDavid du Colombier break; 1389a747e4fSDavid du Colombier } 1399a747e4fSDavid du Colombier e->cursor = i; 1409a747e4fSDavid du Colombier entryshow(e); 1419a747e4fSDavid du Colombier } 1429a747e4fSDavid du Colombier 1439a747e4fSDavid du Colombier static void 1449a747e4fSDavid du Colombier entrymouse(Control *c, Mouse *m) 1459a747e4fSDavid du Colombier { 1469a747e4fSDavid du Colombier Entry *e; 1479a747e4fSDavid du Colombier 1489a747e4fSDavid du Colombier e = (Entry*)c; 1499a747e4fSDavid du Colombier if(m->buttons==1 && e->lastbut==0) 1509a747e4fSDavid du Colombier entrysetpoint(e, m->xy); 1519a747e4fSDavid du Colombier e->lastbut = m->buttons; 1529a747e4fSDavid du Colombier } 1539a747e4fSDavid du Colombier 1549a747e4fSDavid du Colombier static void 1559a747e4fSDavid du Colombier entryctl(Control *c, CParse *cp) 15680ee5cbfSDavid du Colombier { 15780ee5cbfSDavid du Colombier int cmd; 15880ee5cbfSDavid du Colombier Rectangle r; 15980ee5cbfSDavid du Colombier Entry *e; 16080ee5cbfSDavid du Colombier Rune *rp; 16180ee5cbfSDavid du Colombier 16280ee5cbfSDavid du Colombier e = (Entry*)c; 1639a747e4fSDavid du Colombier cmd = _ctllookup(cp->args[0], cmds, nelem(cmds)); 16480ee5cbfSDavid du Colombier switch(cmd){ 16580ee5cbfSDavid du Colombier default: 1669a747e4fSDavid du Colombier ctlerror("%q: unrecognized message '%s'", e->name, cp->str); 16780ee5cbfSDavid du Colombier break; 16880ee5cbfSDavid du Colombier case EAlign: 1699a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1709a747e4fSDavid du Colombier e->align = _ctlalignment(cp->args[1]); 17180ee5cbfSDavid du Colombier break; 17280ee5cbfSDavid du Colombier case EBorder: 1739a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1749a747e4fSDavid du Colombier if(cp->iargs[1] < 0) 1759a747e4fSDavid du Colombier ctlerror("%q: bad border: %c", e->name, cp->str); 1769a747e4fSDavid du Colombier e->border = cp->iargs[1]; 17780ee5cbfSDavid du Colombier break; 17880ee5cbfSDavid du Colombier case EBordercolor: 1799a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1809a747e4fSDavid du Colombier _setctlimage(e, &e->bordercolor, cp->args[1]); 18180ee5cbfSDavid du Colombier break; 18280ee5cbfSDavid du Colombier case EData: 1839a747e4fSDavid du Colombier _ctlargcount(e, cp, 1); 1849a747e4fSDavid du Colombier chanprint(e->data, "%S", e->text); 18580ee5cbfSDavid du Colombier break; 18680ee5cbfSDavid du Colombier case EFocus: 1879a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1889a747e4fSDavid du Colombier e->hasfocus = cp->iargs[1]; 18980ee5cbfSDavid du Colombier e->lastbut = 0; 19080ee5cbfSDavid du Colombier entryshow(e); 19180ee5cbfSDavid du Colombier break; 19280ee5cbfSDavid du Colombier case EFont: 1939a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1949a747e4fSDavid du Colombier _setctlfont(e, &e->font, cp->args[1]); 19580ee5cbfSDavid du Colombier break; 19680ee5cbfSDavid du Colombier case EFormat: 1979a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 1989a747e4fSDavid du Colombier e->format = ctlstrdup(cp->args[1]); 1999a747e4fSDavid du Colombier break; 2009a747e4fSDavid du Colombier case EHide: 2019a747e4fSDavid du Colombier _ctlargcount(e, cp, 1); 2029a747e4fSDavid du Colombier e->hidden = 1; 20380ee5cbfSDavid du Colombier break; 20480ee5cbfSDavid du Colombier case EImage: 2059a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 2069a747e4fSDavid du Colombier _setctlimage(e, &e->image, cp->args[1]); 20780ee5cbfSDavid du Colombier break; 20880ee5cbfSDavid du Colombier case ERect: 2099a747e4fSDavid du Colombier _ctlargcount(e, cp, 5); 2109a747e4fSDavid du Colombier r.min.x = cp->iargs[1]; 2119a747e4fSDavid du Colombier r.min.y = cp->iargs[2]; 2129a747e4fSDavid du Colombier r.max.x = cp->iargs[3]; 2139a747e4fSDavid du Colombier r.max.y = cp->iargs[4]; 21480ee5cbfSDavid du Colombier if(Dx(r)<=0 || Dy(r)<=0) 2159a747e4fSDavid du Colombier ctlerror("%q: bad rectangle: %s", e->name, cp->str); 21680ee5cbfSDavid du Colombier e->rect = r; 21780ee5cbfSDavid du Colombier break; 2189a747e4fSDavid du Colombier case EReveal: 2199a747e4fSDavid du Colombier _ctlargcount(e, cp, 1); 2209a747e4fSDavid du Colombier e->hidden = 0; 22180ee5cbfSDavid du Colombier entryshow(e); 22280ee5cbfSDavid du Colombier break; 2239a747e4fSDavid du Colombier case EShow: 2249a747e4fSDavid du Colombier _ctlargcount(e, cp, 1); 2259a747e4fSDavid du Colombier entryshow(e); 2269a747e4fSDavid du Colombier break; 2279a747e4fSDavid du Colombier case ESize: 2289a747e4fSDavid du Colombier if (cp->nargs == 3) 2299a747e4fSDavid du Colombier r.max = Pt(0x7fffffff, 0x7fffffff); 2309a747e4fSDavid du Colombier else{ 2319a747e4fSDavid du Colombier _ctlargcount(e, cp, 5); 2329a747e4fSDavid du Colombier r.max.x = cp->iargs[3]; 2339a747e4fSDavid du Colombier r.max.y = cp->iargs[4]; 2349a747e4fSDavid du Colombier } 2359a747e4fSDavid du Colombier r.min.x = cp->iargs[1]; 2369a747e4fSDavid du Colombier r.min.y = cp->iargs[2]; 2379a747e4fSDavid 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) 2389a747e4fSDavid du Colombier ctlerror("%q: bad sizes: %s", e->name, cp->str); 2399a747e4fSDavid du Colombier e->size.min = r.min; 2409a747e4fSDavid du Colombier e->size.max = r.max; 24180ee5cbfSDavid du Colombier break; 24280ee5cbfSDavid du Colombier case ETextcolor: 2439a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 2449a747e4fSDavid du Colombier _setctlimage(e, &e->textcolor, cp->args[1]); 24580ee5cbfSDavid du Colombier break; 24680ee5cbfSDavid du Colombier case EValue: 2479a747e4fSDavid du Colombier _ctlargcount(e, cp, 2); 2489a747e4fSDavid du Colombier rp = _ctlrunestr(cp->args[1]); 24980ee5cbfSDavid du Colombier if(runestrcmp(rp, e->text) != 0){ 25080ee5cbfSDavid du Colombier free(e->text); 25180ee5cbfSDavid du Colombier e->text = rp; 25280ee5cbfSDavid du Colombier e->ntext = runestrlen(e->text); 2539a747e4fSDavid du Colombier e->cursor = e->ntext; 25480ee5cbfSDavid du Colombier entryshow(e); 25580ee5cbfSDavid du Colombier }else 25680ee5cbfSDavid du Colombier free(rp); 25780ee5cbfSDavid du Colombier break; 25880ee5cbfSDavid du Colombier } 25980ee5cbfSDavid du Colombier } 26080ee5cbfSDavid du Colombier 26180ee5cbfSDavid du Colombier static void 26280ee5cbfSDavid du Colombier entrykey(Entry *e, Rune r) 26380ee5cbfSDavid du Colombier { 26480ee5cbfSDavid du Colombier Rune *s; 26580ee5cbfSDavid du Colombier int n; 26680ee5cbfSDavid du Colombier char *p; 26780ee5cbfSDavid du Colombier 26880ee5cbfSDavid du Colombier switch(r){ 26980ee5cbfSDavid du Colombier default: 27080ee5cbfSDavid du Colombier e->text = ctlrealloc(e->text, (e->ntext+1+1)*sizeof(Rune)); 27180ee5cbfSDavid du Colombier memmove(e->text+e->cursor+1, e->text+e->cursor, 27280ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 27380ee5cbfSDavid du Colombier e->text[e->cursor++] = r; 27480ee5cbfSDavid du Colombier e->ntext++; 27580ee5cbfSDavid du Colombier break; 27680ee5cbfSDavid du Colombier case L'\n': /* newline: return value */ 27780ee5cbfSDavid du Colombier p = _ctlstrrune(e->text); 2789a747e4fSDavid du Colombier chanprint(e->event, e->format, e->name, p); 27980ee5cbfSDavid du Colombier free(p); 28080ee5cbfSDavid du Colombier return; 28180ee5cbfSDavid du Colombier case L'\b': 28280ee5cbfSDavid du Colombier if(e->cursor > 0){ 28380ee5cbfSDavid du Colombier memmove(e->text+e->cursor-1, e->text+e->cursor, 28480ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 28580ee5cbfSDavid du Colombier e->cursor--; 28680ee5cbfSDavid du Colombier e->ntext--; 28780ee5cbfSDavid du Colombier } 28880ee5cbfSDavid du Colombier break; 28980ee5cbfSDavid du Colombier case 0x15: /* control U: kill line */ 29080ee5cbfSDavid du Colombier e->cursor = 0; 29180ee5cbfSDavid du Colombier e->ntext = 0; 29280ee5cbfSDavid du Colombier break; 29380ee5cbfSDavid du Colombier case 0x16: /* control V: paste (append snarf buffer) */ 29480ee5cbfSDavid du Colombier s = _ctlgetsnarf(); 29580ee5cbfSDavid du Colombier if(s != nil){ 29680ee5cbfSDavid du Colombier n = runestrlen(s); 29780ee5cbfSDavid du Colombier e->text = ctlrealloc(e->text, (e->ntext+n+1)*sizeof(Rune)); 29880ee5cbfSDavid du Colombier memmove(e->text+e->cursor+n, e->text+e->cursor, 29980ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 30080ee5cbfSDavid du Colombier memmove(e->text+e->cursor, s, n*sizeof(Rune)); 30180ee5cbfSDavid du Colombier e->cursor += n; 30280ee5cbfSDavid du Colombier e->ntext += n; 30380ee5cbfSDavid du Colombier } 30480ee5cbfSDavid du Colombier break; 30580ee5cbfSDavid du Colombier } 30680ee5cbfSDavid du Colombier e->text[e->ntext] = L'\0'; 30780ee5cbfSDavid du Colombier } 3089a747e4fSDavid du Colombier 3099a747e4fSDavid du Colombier static void 3109a747e4fSDavid du Colombier entrykeys(Control *c, Rune *rp) 3119a747e4fSDavid du Colombier { 3129a747e4fSDavid du Colombier Entry *e; 3139a747e4fSDavid du Colombier int i; 3149a747e4fSDavid du Colombier 3159a747e4fSDavid du Colombier e = (Entry *)c; 3169a747e4fSDavid du Colombier for(i=0; rp[i]!=L'\0'; i++) 3179a747e4fSDavid du Colombier entrykey(e, rp[i]); 3189a747e4fSDavid du Colombier entryshow(e); 3199a747e4fSDavid du Colombier } 3209a747e4fSDavid du Colombier 3219a747e4fSDavid du Colombier Control* 3229a747e4fSDavid du Colombier createentry(Controlset *cs, char *name) 3239a747e4fSDavid du Colombier { 3249a747e4fSDavid du Colombier Entry *e; 3259a747e4fSDavid du Colombier 3269a747e4fSDavid du Colombier e = (Entry*) _createctl(cs, "entry", sizeof(Entry), name); 3279a747e4fSDavid du Colombier e->text = ctlmalloc(sizeof(Rune)); 3289a747e4fSDavid du Colombier e->ntext = 0; 3299a747e4fSDavid du Colombier e->image = _getctlimage("white"); 3309a747e4fSDavid du Colombier e->textcolor = _getctlimage("black"); 3319a747e4fSDavid du Colombier e->bordercolor = _getctlimage("black"); 3329a747e4fSDavid du Colombier e->font = _getctlfont("font"); 3339a747e4fSDavid du Colombier e->format = ctlstrdup("%q: value %q"); 3349a747e4fSDavid du Colombier e->border = 0; 3359a747e4fSDavid du Colombier e->ctl = entryctl; 3369a747e4fSDavid du Colombier e->mouse = entrymouse; 3379a747e4fSDavid du Colombier e->key = entrykeys; 3389a747e4fSDavid du Colombier e->exit = entryfree; 3399a747e4fSDavid du Colombier return (Control *)e; 3409a747e4fSDavid du Colombier } 341