ref: 5c1feb0ef0b795e5de71e956f9ccddcd5c4b7f21
dir: /sys/src/cmd/bitsy/prompter.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include <control.h> int Nline; enum{ Back, Shade, Light, Mask, Ncol }; enum { Keyback = 0xeeee9eff, Keyshade = 0xaaaa55ff, Keylight = DWhite, Keymask = 0x0C0C0C0C, }; Image *cols[Ncol]; int nline; char *lines[24]; /* plus one so last line gets terminated by getfields */ Control *entry[24]; Control *kbd; Control *scrib; Controlset *keyboard; Controlset *text; int kbdy; int resizeready; int ctldeletequits = 1; Channel *eventchan; void resizecontrolset(Controlset *cs) { int i; Rectangle r, r1; if(cs != keyboard) return; if (!resizeready) return; if(getwindow(display, Refnone) < 0) ctlerror("resize failed: %r"); draw(screen, screen->r, cols[Back], nil, ZP); r = insetrect(screen->r, 4); for(i=0; i<Nline; i++){ r.max.y = r.min.y + font->height; ctlprint(entry[i], "rect %R", r); ctlprint(entry[i], "show"); r.min.y = r.max.y; } kbdy = r.min.y; r = screen->r; r.min.y = kbdy; r.max.y = screen->r.max.y; r.min.y = r.max.y - 2*2 - 5*13; if(r.min.y >= r.max.y) r.min.y = r.max.y; r1 = r; if(scrib) r.max.x = (3*r.max.x + r.min.x)/4; ctlprint(kbd, "rect %R", r); ctlprint(kbd, "show"); if(scrib){ r1.min.x = (3*r1.max.x + r1.min.x)/4; ctlprint(scrib, "rect %R", r1); ctlprint(scrib, "show"); } } void readall(char *s) { char *buf; int fd; Dir *d; fd = open(s, OREAD); if(fd < 0){ fprint(2, "prompter: can't open %s: %r\n", s); exits("open"); } d = dirfstat(fd); if(d == nil){ fprint(2, "prompter: can't stat %s: %r\n", s); exits("stat"); } buf = ctlmalloc(d->length+1); /* +1 for NUL on end */ if(read(fd, buf, d->length) != d->length){ fprint(2, "prompter: can't read %s: %r\n", s); exits("stat"); } nline = getfields(buf, lines, nelem(lines), 0, "\n"); free(d); close(fd); } void mousemux(void *v) { Mouse m; Channel *c; c = v; for(;;){ if(recv(c, &m) < 0) break; if(m.buttons & 0x20) { sendp(eventchan, "mouse: exit"); break; } if(m.xy.y >= kbdy) send(keyboard->mousec, &m); else send(text->mousec, &m); } } void resizemux(void *v) { Channel *c; c = v; for(;;){ if(recv(c, nil) < 0) break; send(keyboard->resizec, nil); send(text->resizec, nil); } } void writeall(char *s) { int fd; int i, n; fd = create(s, OWRITE, 0666); if(fd < 0){ fprint(2, "prompter: can't create %s: %r\n", s); exits("open"); } for(n=Nline; --n>=0; ) if(lines[n][0] != '\0') break; for(i=0; i<=n; i++) fprint(fd, "%s\n", lines[i]); close(fd); } void usage(void) { fprint(2, "usage: prompter file\n"); threadexitsall("usage"); } void threadmain(int argc, char *argv[]) { char *s; Font *f; int i, n; char buf[32], *args[3]; Keyboardctl *kbdctl; Mousectl *mousectl; Rune r; Channel *mtok, *mtot, *ktok, *rtok, *rtot; int noscrib; noscrib = 0; ARGBEGIN{ case 'n': noscrib++; break; default: usage(); }ARGEND if(argc != 1) usage(); readall(argv[0]); initdraw(0, 0, "prompter"); mousectl = initmouse(nil, screen); kbdctl = initkeyboard(nil); mtok = chancreate(sizeof(Mouse), 0); mtot = chancreate(sizeof(Mouse), 0); ktok = chancreate(sizeof(Rune), 20); rtok = chancreate(sizeof(int), 2); rtot = chancreate(sizeof(int), 2); initcontrols(); keyboard = newcontrolset(screen, ktok, mtok, rtok); text = newcontrolset(screen, kbdctl->c, mtot, rtot); text->clicktotype = 1; threadcreate(mousemux, mousectl->c, 4096); threadcreate(resizemux, mousectl->resizec, 4096); eventchan = chancreate(sizeof(char*), 0); cols[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback); namectlimage(cols[Back], "keyback"); cols[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight); namectlimage(cols[Light], "keylight"); cols[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade); namectlimage(cols[Shade], "keyshade"); cols[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask); namectlimage(cols[Shade], "keymask"); f = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font"); namectlfont(f, "bold"); f = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font"); namectlfont(f, "roman"); font = f; Nline = (screen->r.max.y - 2*2 - 5*13 - 8)/font->height; if (Nline > nelem(entry)) Nline = nelem(entry); for(i=0; i<Nline; i++){ snprint(buf, sizeof buf, "line.%.2d", i); entry[i] = createentry(text, buf); ctlprint(entry[i], "font roman"); ctlprint(entry[i], "image keyback"); if(i < nline) ctlprint(entry[i], "value %q", lines[i]); controlwire(entry[i], "event", eventchan); activate(entry[i]); } kbd = createkeyboard(keyboard, "keyboard"); ctlprint(kbd, "font bold roman"); ctlprint(kbd, "image keyback"); ctlprint(kbd, "light keylight"); ctlprint(kbd, "mask keymask"); ctlprint(kbd, "border 1"); controlwire(kbd, "event", eventchan); scrib = nil; if(!noscrib){ scrib = createscribble(keyboard, "scribble"); ctlprint(scrib, "font bold"); ctlprint(scrib, "image keyback"); ctlprint(scrib, "border 1"); controlwire(scrib, "event", eventchan); activate(scrib); } activate(kbd); resizeready = 1; resizecontrolset(keyboard); for(;;){ s = recvp(eventchan); n = tokenize(s, args, nelem(args)); if(n == 2 && strcmp(args[0], "mouse:")==0 && strcmp(args[1], "exit")==0) break; if(n == 3) if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0) if(strcmp(args[1], "value") == 0){ n = strtol(args[2], 0, 0); if(n == '\033') /* Escape exits */ break; if(n <= Runemax){ r = n; send(kbdctl->c, &r); } } } for(i=0; i<Nline; i++){ ctlprint(entry[i], "data"); lines[i] = ctlstrdup(recvp(entry[i]->data)); } writeall(argv[0]); draw(screen, screen->r, display->white, nil, ZP); flushimage(display, 1); threadexitsall(nil); }