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