1*80ee5cbfSDavid du Colombier #include <u.h> 2*80ee5cbfSDavid du Colombier #include <libc.h> 3*80ee5cbfSDavid du Colombier #include <draw.h> 4*80ee5cbfSDavid du Colombier #include <thread.h> 5*80ee5cbfSDavid du Colombier #include <mouse.h> 6*80ee5cbfSDavid du Colombier #include <keyboard.h> 7*80ee5cbfSDavid du Colombier #include <control.h> 8*80ee5cbfSDavid du Colombier 9*80ee5cbfSDavid du Colombier typedef struct Entry Entry; 10*80ee5cbfSDavid du Colombier 11*80ee5cbfSDavid du Colombier struct Entry 12*80ee5cbfSDavid du Colombier { 13*80ee5cbfSDavid du Colombier Control; 14*80ee5cbfSDavid du Colombier int border; 15*80ee5cbfSDavid du Colombier CFont *font; 16*80ee5cbfSDavid du Colombier CImage *image; 17*80ee5cbfSDavid du Colombier CImage *textcolor; 18*80ee5cbfSDavid du Colombier CImage *bordercolor; 19*80ee5cbfSDavid du Colombier Rune *text; 20*80ee5cbfSDavid du Colombier int ntext; 21*80ee5cbfSDavid du Colombier int cursor; 22*80ee5cbfSDavid du Colombier int align; 23*80ee5cbfSDavid du Colombier int hasfocus; 24*80ee5cbfSDavid du Colombier int lastbut; 25*80ee5cbfSDavid du Colombier }; 26*80ee5cbfSDavid du Colombier 27*80ee5cbfSDavid du Colombier enum{ 28*80ee5cbfSDavid du Colombier EAlign, 29*80ee5cbfSDavid du Colombier EBorder, 30*80ee5cbfSDavid du Colombier EBordercolor, 31*80ee5cbfSDavid du Colombier EData, 32*80ee5cbfSDavid du Colombier EFocus, 33*80ee5cbfSDavid du Colombier EFont, 34*80ee5cbfSDavid du Colombier EFormat, 35*80ee5cbfSDavid du Colombier EImage, 36*80ee5cbfSDavid du Colombier ERect, 37*80ee5cbfSDavid du Colombier EShow, 38*80ee5cbfSDavid du Colombier ETextcolor, 39*80ee5cbfSDavid du Colombier EValue, 40*80ee5cbfSDavid du Colombier }; 41*80ee5cbfSDavid du Colombier 42*80ee5cbfSDavid du Colombier static char *cmds[] = { 43*80ee5cbfSDavid du Colombier [EAlign] = "align", 44*80ee5cbfSDavid du Colombier [EBorder] = "border", 45*80ee5cbfSDavid du Colombier [EBordercolor] = "bordercolor", 46*80ee5cbfSDavid du Colombier [EData] = "data", 47*80ee5cbfSDavid du Colombier [EFocus] = "focus", 48*80ee5cbfSDavid du Colombier [EFont] = "font", 49*80ee5cbfSDavid du Colombier [EFormat] = "format", 50*80ee5cbfSDavid du Colombier [EImage] = "image", 51*80ee5cbfSDavid du Colombier [ERect] = "rect", 52*80ee5cbfSDavid du Colombier [EShow] = "show", 53*80ee5cbfSDavid du Colombier [ETextcolor] = "textcolor", 54*80ee5cbfSDavid du Colombier [EValue] = "value", 55*80ee5cbfSDavid du Colombier nil 56*80ee5cbfSDavid du Colombier }; 57*80ee5cbfSDavid du Colombier 58*80ee5cbfSDavid du Colombier static void entryctl(Control*, char*); 59*80ee5cbfSDavid du Colombier static void entryshow(Entry*); 60*80ee5cbfSDavid du Colombier static void entrykey(Entry*, Rune); 61*80ee5cbfSDavid du Colombier static void entryfree(Entry*); 62*80ee5cbfSDavid du Colombier static Point entrypoint(Entry*, int); 63*80ee5cbfSDavid du Colombier static void entrysetpoint(Entry*, Point); 64*80ee5cbfSDavid du Colombier 65*80ee5cbfSDavid du Colombier static void 66*80ee5cbfSDavid du Colombier entrythread(void *v) 67*80ee5cbfSDavid du Colombier { 68*80ee5cbfSDavid du Colombier char buf[32]; 69*80ee5cbfSDavid du Colombier Entry *e; 70*80ee5cbfSDavid du Colombier int i; 71*80ee5cbfSDavid du Colombier 72*80ee5cbfSDavid du Colombier e = v; 73*80ee5cbfSDavid du Colombier 74*80ee5cbfSDavid du Colombier snprint(buf, sizeof buf, "entry-%s-0x%p", e->name, e); 75*80ee5cbfSDavid du Colombier threadsetname(buf); 76*80ee5cbfSDavid du Colombier 77*80ee5cbfSDavid du Colombier e->text = ctlmalloc(sizeof(Rune)); 78*80ee5cbfSDavid du Colombier e->ntext = 0; 79*80ee5cbfSDavid du Colombier e->image = _getctlimage("white"); 80*80ee5cbfSDavid du Colombier e->textcolor = _getctlimage("black"); 81*80ee5cbfSDavid du Colombier e->bordercolor = _getctlimage("black"); 82*80ee5cbfSDavid du Colombier e->font = _getctlfont("font"); 83*80ee5cbfSDavid du Colombier e->format = ctlstrdup("%q: value %q"); 84*80ee5cbfSDavid du Colombier e->border = 0; 85*80ee5cbfSDavid du Colombier 86*80ee5cbfSDavid du Colombier for(;;){ 87*80ee5cbfSDavid du Colombier switch(alt(e->alts)){ 88*80ee5cbfSDavid du Colombier default: 89*80ee5cbfSDavid du Colombier ctlerror("%q: unknown message", e->name); 90*80ee5cbfSDavid du Colombier case AKey: 91*80ee5cbfSDavid du Colombier for(i=0; e->kbdr[i]!=L'\0'; i++) 92*80ee5cbfSDavid du Colombier entrykey(e, e->kbdr[i]); 93*80ee5cbfSDavid du Colombier entryshow(e); 94*80ee5cbfSDavid du Colombier break; 95*80ee5cbfSDavid du Colombier case AMouse: 96*80ee5cbfSDavid du Colombier if(e->m.buttons==1 && e->lastbut==0) 97*80ee5cbfSDavid du Colombier entrysetpoint(e, e->m.xy); 98*80ee5cbfSDavid du Colombier e->lastbut = e->m.buttons; 99*80ee5cbfSDavid du Colombier break; 100*80ee5cbfSDavid du Colombier case ACtl: 101*80ee5cbfSDavid du Colombier _ctlcontrol(e, e->str, entryctl); 102*80ee5cbfSDavid du Colombier free(e->str); 103*80ee5cbfSDavid du Colombier break; 104*80ee5cbfSDavid du Colombier case AWire: 105*80ee5cbfSDavid du Colombier _ctlrewire(e); 106*80ee5cbfSDavid du Colombier break; 107*80ee5cbfSDavid du Colombier case AExit: 108*80ee5cbfSDavid du Colombier entryfree(e); 109*80ee5cbfSDavid du Colombier sendul(e->exit, 0); 110*80ee5cbfSDavid du Colombier return; 111*80ee5cbfSDavid du Colombier } 112*80ee5cbfSDavid du Colombier } 113*80ee5cbfSDavid du Colombier } 114*80ee5cbfSDavid du Colombier 115*80ee5cbfSDavid du Colombier Control* 116*80ee5cbfSDavid du Colombier createentry(Controlset *cs, char *name) 117*80ee5cbfSDavid du Colombier { 118*80ee5cbfSDavid du Colombier return _createctl(cs, "entry", sizeof(Entry), name, entrythread, 0); 119*80ee5cbfSDavid du Colombier } 120*80ee5cbfSDavid du Colombier 121*80ee5cbfSDavid du Colombier static void 122*80ee5cbfSDavid du Colombier entryfree(Entry *e) 123*80ee5cbfSDavid du Colombier { 124*80ee5cbfSDavid du Colombier _putctlfont(e->font); 125*80ee5cbfSDavid du Colombier _putctlimage(e->image); 126*80ee5cbfSDavid du Colombier _putctlimage(e->textcolor); 127*80ee5cbfSDavid du Colombier _putctlimage(e->bordercolor); 128*80ee5cbfSDavid du Colombier free(e->text); 129*80ee5cbfSDavid du Colombier } 130*80ee5cbfSDavid du Colombier 131*80ee5cbfSDavid du Colombier static Point 132*80ee5cbfSDavid du Colombier entrypoint(Entry *e, int c) 133*80ee5cbfSDavid du Colombier { 134*80ee5cbfSDavid du Colombier Point p; 135*80ee5cbfSDavid du Colombier Rectangle r; 136*80ee5cbfSDavid du Colombier 137*80ee5cbfSDavid du Colombier r = e->rect; 138*80ee5cbfSDavid du Colombier if(e->border > 0) 139*80ee5cbfSDavid du Colombier r = insetrect(r, e->border); 140*80ee5cbfSDavid du Colombier p = _ctlalignpoint(r, 141*80ee5cbfSDavid du Colombier runestringnwidth(e->font->font, e->text, e->ntext), 142*80ee5cbfSDavid du Colombier e->font->font->height, e->align); 143*80ee5cbfSDavid du Colombier if(c > e->ntext) 144*80ee5cbfSDavid du Colombier c = e->ntext; 145*80ee5cbfSDavid du Colombier p.x += runestringnwidth(e->font->font, e->text, c); 146*80ee5cbfSDavid du Colombier return p; 147*80ee5cbfSDavid du Colombier } 148*80ee5cbfSDavid du Colombier 149*80ee5cbfSDavid du Colombier static void 150*80ee5cbfSDavid du Colombier entrysetpoint(Entry *e, Point cp) 151*80ee5cbfSDavid du Colombier { 152*80ee5cbfSDavid du Colombier Point p; 153*80ee5cbfSDavid du Colombier int i; 154*80ee5cbfSDavid du Colombier 155*80ee5cbfSDavid du Colombier if(!ptinrect(cp, insetrect(e->rect, e->border))) 156*80ee5cbfSDavid du Colombier return; 157*80ee5cbfSDavid du Colombier p = entrypoint(e, 0); 158*80ee5cbfSDavid du Colombier for(i=0; i<e->ntext; i++){ 159*80ee5cbfSDavid du Colombier p.x += runestringnwidth(e->font->font, e->text+i, 1); 160*80ee5cbfSDavid du Colombier if(p.x > cp.x) 161*80ee5cbfSDavid du Colombier break; 162*80ee5cbfSDavid du Colombier } 163*80ee5cbfSDavid du Colombier e->cursor = i; 164*80ee5cbfSDavid du Colombier entryshow(e); 165*80ee5cbfSDavid du Colombier } 166*80ee5cbfSDavid du Colombier 167*80ee5cbfSDavid du Colombier static void 168*80ee5cbfSDavid du Colombier entryshow(Entry *e) 169*80ee5cbfSDavid du Colombier { 170*80ee5cbfSDavid du Colombier Rectangle r, dr; 171*80ee5cbfSDavid du Colombier Point p; 172*80ee5cbfSDavid du Colombier 173*80ee5cbfSDavid du Colombier r = e->rect; 174*80ee5cbfSDavid du Colombier draw(e->screen, r, e->image->image, nil, e->image->image->r.min); 175*80ee5cbfSDavid du Colombier if(e->border > 0){ 176*80ee5cbfSDavid du Colombier border(e->screen, r, e->border, e->bordercolor->image, e->bordercolor->image->r.min); 177*80ee5cbfSDavid du Colombier dr = insetrect(r, e->border); 178*80ee5cbfSDavid du Colombier }else 179*80ee5cbfSDavid du Colombier dr = r; 180*80ee5cbfSDavid du Colombier p = entrypoint(e, 0); 181*80ee5cbfSDavid du Colombier _string(e->screen, p, e->textcolor->image, 182*80ee5cbfSDavid du Colombier ZP, e->font->font, nil, e->text, e->ntext, 183*80ee5cbfSDavid du Colombier dr, nil, ZP); 184*80ee5cbfSDavid du Colombier if(e->hasfocus){ 185*80ee5cbfSDavid du Colombier p = entrypoint(e, e->cursor); 186*80ee5cbfSDavid du Colombier r.min = p; 187*80ee5cbfSDavid du Colombier r.max.x = p.x+1; 188*80ee5cbfSDavid du Colombier r.max.y = p.y+e->font->font->height; 189*80ee5cbfSDavid du Colombier if(rectclip(&r, dr)) 190*80ee5cbfSDavid du Colombier draw(e->screen, r, e->textcolor->image, nil, ZP); 191*80ee5cbfSDavid du Colombier } 192*80ee5cbfSDavid du Colombier flushimage(display, 1); 193*80ee5cbfSDavid du Colombier } 194*80ee5cbfSDavid du Colombier 195*80ee5cbfSDavid du Colombier static void 196*80ee5cbfSDavid du Colombier entryctl(Control *c, char *str) 197*80ee5cbfSDavid du Colombier { 198*80ee5cbfSDavid du Colombier int cmd; 199*80ee5cbfSDavid du Colombier CParse cp; 200*80ee5cbfSDavid du Colombier Rectangle r; 201*80ee5cbfSDavid du Colombier Entry *e; 202*80ee5cbfSDavid du Colombier Rune *rp; 203*80ee5cbfSDavid du Colombier 204*80ee5cbfSDavid du Colombier e = (Entry*)c; 205*80ee5cbfSDavid du Colombier cmd = _ctlparse(&cp, str, cmds); 206*80ee5cbfSDavid du Colombier switch(cmd){ 207*80ee5cbfSDavid du Colombier default: 208*80ee5cbfSDavid du Colombier ctlerror("%q: unrecognized message '%s'", e->name, cp.str); 209*80ee5cbfSDavid du Colombier break; 210*80ee5cbfSDavid du Colombier case EAlign: 211*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 212*80ee5cbfSDavid du Colombier e->align = _ctlalignment(cp.args[1]); 213*80ee5cbfSDavid du Colombier break; 214*80ee5cbfSDavid du Colombier case EBorder: 215*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 216*80ee5cbfSDavid du Colombier if(cp.iargs[1] < 0) 217*80ee5cbfSDavid du Colombier ctlerror("%q: bad border: %c", e->name, cp.str); 218*80ee5cbfSDavid du Colombier e->border = cp.iargs[1]; 219*80ee5cbfSDavid du Colombier break; 220*80ee5cbfSDavid du Colombier case EBordercolor: 221*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 222*80ee5cbfSDavid du Colombier _setctlimage(e, &e->bordercolor, cp.args[1]); 223*80ee5cbfSDavid du Colombier break; 224*80ee5cbfSDavid du Colombier case EData: 225*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 1); 226*80ee5cbfSDavid du Colombier printctl(e->data, "%S", e->text); 227*80ee5cbfSDavid du Colombier break; 228*80ee5cbfSDavid du Colombier case EFocus: 229*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 230*80ee5cbfSDavid du Colombier e->hasfocus = cp.iargs[1]; 231*80ee5cbfSDavid du Colombier e->lastbut = 0; 232*80ee5cbfSDavid du Colombier entryshow(e); 233*80ee5cbfSDavid du Colombier break; 234*80ee5cbfSDavid du Colombier case EFont: 235*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 236*80ee5cbfSDavid du Colombier _setctlfont(e, &e->font, cp.args[1]); 237*80ee5cbfSDavid du Colombier break; 238*80ee5cbfSDavid du Colombier case EFormat: 239*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 240*80ee5cbfSDavid du Colombier e->format = ctlstrdup(cp.args[1]); 241*80ee5cbfSDavid du Colombier break; 242*80ee5cbfSDavid du Colombier case EImage: 243*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 244*80ee5cbfSDavid du Colombier _setctlimage(e, &e->image, cp.args[1]); 245*80ee5cbfSDavid du Colombier break; 246*80ee5cbfSDavid du Colombier case ERect: 247*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 5); 248*80ee5cbfSDavid du Colombier r.min.x = cp.iargs[1]; 249*80ee5cbfSDavid du Colombier r.min.y = cp.iargs[2]; 250*80ee5cbfSDavid du Colombier r.max.x = cp.iargs[3]; 251*80ee5cbfSDavid du Colombier r.max.y = cp.iargs[4]; 252*80ee5cbfSDavid du Colombier if(Dx(r)<=0 || Dy(r)<=0) 253*80ee5cbfSDavid du Colombier ctlerror("%q: bad rectangle: %s", e->name, cp.str); 254*80ee5cbfSDavid du Colombier e->rect = r; 255*80ee5cbfSDavid du Colombier break; 256*80ee5cbfSDavid du Colombier case EShow: 257*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 1); 258*80ee5cbfSDavid du Colombier entryshow(e); 259*80ee5cbfSDavid du Colombier break; 260*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 261*80ee5cbfSDavid du Colombier _setctlimage(e, &e->textcolor, cp.args[1]); 262*80ee5cbfSDavid du Colombier break; 263*80ee5cbfSDavid du Colombier case ETextcolor: 264*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 265*80ee5cbfSDavid du Colombier _setctlimage(e, &e->textcolor, cp.args[1]); 266*80ee5cbfSDavid du Colombier break; 267*80ee5cbfSDavid du Colombier case EValue: 268*80ee5cbfSDavid du Colombier _ctlargcount(e, &cp, 2); 269*80ee5cbfSDavid du Colombier rp = _ctlrunestr(cp.args[1]); 270*80ee5cbfSDavid du Colombier if(runestrcmp(rp, e->text) != 0){ 271*80ee5cbfSDavid du Colombier free(e->text); 272*80ee5cbfSDavid du Colombier e->text = rp; 273*80ee5cbfSDavid du Colombier e->ntext = runestrlen(e->text); 274*80ee5cbfSDavid du Colombier entryshow(e); 275*80ee5cbfSDavid du Colombier }else 276*80ee5cbfSDavid du Colombier free(rp); 277*80ee5cbfSDavid du Colombier break; 278*80ee5cbfSDavid du Colombier } 279*80ee5cbfSDavid du Colombier } 280*80ee5cbfSDavid du Colombier 281*80ee5cbfSDavid du Colombier static void 282*80ee5cbfSDavid du Colombier entrykey(Entry *e, Rune r) 283*80ee5cbfSDavid du Colombier { 284*80ee5cbfSDavid du Colombier Rune *s; 285*80ee5cbfSDavid du Colombier int n; 286*80ee5cbfSDavid du Colombier char *p; 287*80ee5cbfSDavid du Colombier 288*80ee5cbfSDavid du Colombier switch(r){ 289*80ee5cbfSDavid du Colombier default: 290*80ee5cbfSDavid du Colombier e->text = ctlrealloc(e->text, (e->ntext+1+1)*sizeof(Rune)); 291*80ee5cbfSDavid du Colombier memmove(e->text+e->cursor+1, e->text+e->cursor, 292*80ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 293*80ee5cbfSDavid du Colombier e->text[e->cursor++] = r; 294*80ee5cbfSDavid du Colombier e->ntext++; 295*80ee5cbfSDavid du Colombier break; 296*80ee5cbfSDavid du Colombier case L'\n': /* newline: return value */ 297*80ee5cbfSDavid du Colombier p = _ctlstrrune(e->text); 298*80ee5cbfSDavid du Colombier printctl(e->event, e->format, e->name, p); 299*80ee5cbfSDavid du Colombier free(p); 300*80ee5cbfSDavid du Colombier return; 301*80ee5cbfSDavid du Colombier case L'\b': 302*80ee5cbfSDavid du Colombier if(e->cursor > 0){ 303*80ee5cbfSDavid du Colombier memmove(e->text+e->cursor-1, e->text+e->cursor, 304*80ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 305*80ee5cbfSDavid du Colombier e->cursor--; 306*80ee5cbfSDavid du Colombier e->ntext--; 307*80ee5cbfSDavid du Colombier } 308*80ee5cbfSDavid du Colombier break; 309*80ee5cbfSDavid du Colombier case 0x15: /* control U: kill line */ 310*80ee5cbfSDavid du Colombier e->cursor = 0; 311*80ee5cbfSDavid du Colombier e->ntext = 0; 312*80ee5cbfSDavid du Colombier break; 313*80ee5cbfSDavid du Colombier case 0x16: /* control V: paste (append snarf buffer) */ 314*80ee5cbfSDavid du Colombier s = _ctlgetsnarf(); 315*80ee5cbfSDavid du Colombier if(s != nil){ 316*80ee5cbfSDavid du Colombier n = runestrlen(s); 317*80ee5cbfSDavid du Colombier e->text = ctlrealloc(e->text, (e->ntext+n+1)*sizeof(Rune)); 318*80ee5cbfSDavid du Colombier memmove(e->text+e->cursor+n, e->text+e->cursor, 319*80ee5cbfSDavid du Colombier (e->ntext+1-e->cursor)*sizeof(Rune)); 320*80ee5cbfSDavid du Colombier memmove(e->text+e->cursor, s, n*sizeof(Rune)); 321*80ee5cbfSDavid du Colombier e->cursor += n; 322*80ee5cbfSDavid du Colombier e->ntext += n; 323*80ee5cbfSDavid du Colombier } 324*80ee5cbfSDavid du Colombier break; 325*80ee5cbfSDavid du Colombier } 326*80ee5cbfSDavid du Colombier e->text[e->ntext] = L'\0'; 327*80ee5cbfSDavid du Colombier } 328