]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bitsy/prompter.c
bitsy/keyboard: do not rely on atoi() being able to parse hex
[plan9front.git] / sys / src / cmd / bitsy / prompter.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <control.h>
8
9 int     Nline;
10
11 enum{
12         Back,
13         Shade,
14         Light,
15         Mask,
16         Ncol
17 };
18
19 enum {
20         Keyback         = 0xeeee9eff,
21         Keyshade                = 0xaaaa55ff,
22         Keylight                = DWhite,
23         Keymask         = 0x0C0C0C0C,
24 };
25
26 Image   *cols[Ncol];
27
28 int nline;
29
30 char *lines[24];        /* plus one so last line gets terminated by getfields */
31 Control *entry[24];
32 Control *kbd;
33 Control *scrib;
34 Controlset *keyboard;
35 Controlset *text;
36 int kbdy;
37
38 int resizeready;
39
40 int ctldeletequits = 1;
41
42 Channel *eventchan;
43
44 void
45 resizecontrolset(Controlset *cs)
46 {
47         int i;
48         Rectangle r, r1;
49
50         if(cs != keyboard)
51                 return;
52         if (!resizeready)
53                 return;
54         if(getwindow(display, Refnone) < 0)
55                 ctlerror("resize failed: %r");
56         draw(screen, screen->r, cols[Back], nil, ZP);
57         r = insetrect(screen->r, 4);
58         for(i=0; i<Nline; i++){
59                 r.max.y = r.min.y + font->height;
60                 ctlprint(entry[i], "rect %R", r);
61                 ctlprint(entry[i], "show");
62                 r.min.y = r.max.y;
63         }
64         kbdy = r.min.y;
65
66         r = screen->r;
67         r.min.y = kbdy;
68         r.max.y = screen->r.max.y;
69         r.min.y = r.max.y - 2*2 - 5*13;
70         if(r.min.y >= r.max.y)
71                 r.min.y = r.max.y;
72         r1 = r;
73         if(scrib)
74                 r.max.x = (3*r.max.x + r.min.x)/4;
75         ctlprint(kbd, "rect %R", r);
76         ctlprint(kbd, "show");
77         if(scrib){
78                 r1.min.x = (3*r1.max.x + r1.min.x)/4;
79                 ctlprint(scrib, "rect %R", r1);
80                 ctlprint(scrib, "show");
81         }
82 }
83
84 void
85 readall(char *s)
86 {
87         char *buf;
88         int fd;
89         Dir *d;
90
91         fd = open(s, OREAD);
92         if(fd < 0){
93                 fprint(2, "prompter: can't open %s: %r\n", s);
94                 exits("open");
95         }
96         d = dirfstat(fd);
97         if(d == nil){
98                 fprint(2, "prompter: can't stat %s: %r\n", s);
99                 exits("stat");
100         }
101         buf = ctlmalloc(d->length+1);   /* +1 for NUL on end */
102         if(read(fd, buf, d->length) != d->length){
103                 fprint(2, "prompter: can't read %s: %r\n", s);
104                 exits("stat");
105         }
106         nline = getfields(buf, lines, nelem(lines), 0, "\n");
107         free(d);
108         close(fd);
109 }
110
111 void
112 mousemux(void *v)
113 {
114         Mouse m;
115         Channel *c;
116
117         c = v;
118
119         for(;;){
120                 if(recv(c, &m) < 0)
121                         break;
122                 if(m.buttons & 0x20) {
123                         sendp(eventchan, "mouse: exit");
124                         break;
125                 }
126                 if(m.xy.y >= kbdy)
127                         send(keyboard->mousec, &m);
128                 else
129                         send(text->mousec, &m);
130         }
131 }
132
133 void
134 resizemux(void *v)
135 {
136         Channel *c;
137
138         c = v;
139
140         for(;;){
141                 if(recv(c, nil) < 0)
142                         break;
143                 send(keyboard->resizec, nil);
144                 send(text->resizec, nil);
145         }
146 }
147
148 void
149 writeall(char *s)
150 {
151         int fd;
152         int i, n;
153
154         fd = create(s, OWRITE, 0666);
155         if(fd < 0){
156                 fprint(2, "prompter: can't create %s: %r\n", s);
157                 exits("open");
158         }
159
160         for(n=Nline; --n>=0; )
161                 if(lines[n][0] != '\0')
162                         break;
163
164         for(i=0; i<=n; i++)
165                 fprint(fd, "%s\n", lines[i]);
166         close(fd);
167 }
168
169 void
170 usage(void)
171 {
172         fprint(2, "usage: prompter file\n");
173         threadexitsall("usage");
174 }
175
176 void
177 threadmain(int argc, char *argv[])
178 {
179         char *s;
180         Font *f;
181         int i, n;
182         char buf[32], *args[3];
183         Keyboardctl *kbdctl;
184         Mousectl *mousectl;
185         Rune r;
186         Channel *mtok, *mtot, *ktok, *rtok, *rtot;
187         int noscrib;
188
189         noscrib = 0;
190         ARGBEGIN{
191         case 'n':
192                 noscrib++;
193                 break;
194         default:
195                 usage();
196         }ARGEND
197
198         if(argc != 1)
199                 usage();
200
201         readall(argv[0]);
202
203         initdraw(0, 0, "prompter");
204         mousectl = initmouse(nil, screen);
205         kbdctl = initkeyboard(nil);
206
207         mtok = chancreate(sizeof(Mouse), 0);
208         mtot = chancreate(sizeof(Mouse), 0);
209         ktok = chancreate(sizeof(Rune), 20);
210         rtok = chancreate(sizeof(int), 2);
211         rtot = chancreate(sizeof(int), 2);
212
213         initcontrols();
214
215         keyboard = newcontrolset(screen, ktok, mtok, rtok);
216         text = newcontrolset(screen, kbdctl->c, mtot, rtot);
217         text->clicktotype = 1;
218
219         threadcreate(mousemux, mousectl->c, 4096);
220         threadcreate(resizemux, mousectl->resizec, 4096);
221
222         eventchan = chancreate(sizeof(char*), 0);
223
224         cols[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback);
225         namectlimage(cols[Back], "keyback");
226         cols[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight);
227         namectlimage(cols[Light], "keylight");
228         cols[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade);
229         namectlimage(cols[Shade], "keyshade");
230         cols[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask);
231         namectlimage(cols[Shade], "keymask");
232         f = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font");
233         namectlfont(f, "bold");
234         f = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font");
235         namectlfont(f, "roman");
236         font = f;
237
238         Nline = (screen->r.max.y - 2*2 - 5*13 - 8)/font->height;
239         if (Nline > nelem(entry)) Nline = nelem(entry);
240
241         for(i=0; i<Nline; i++){
242                 snprint(buf, sizeof buf, "line.%.2d", i);
243                 entry[i] = createentry(text, buf);
244                 ctlprint(entry[i], "font roman");
245                 ctlprint(entry[i], "image keyback");
246                 if(i < nline)
247                         ctlprint(entry[i], "value %q", lines[i]);
248                 controlwire(entry[i], "event", eventchan);
249                 activate(entry[i]);
250         }
251
252         kbd = createkeyboard(keyboard, "keyboard");
253         ctlprint(kbd, "font bold roman");
254         ctlprint(kbd, "image keyback");
255         ctlprint(kbd, "light keylight");
256         ctlprint(kbd, "mask keymask");
257         ctlprint(kbd, "border 1");
258         controlwire(kbd, "event", eventchan);
259
260         scrib = nil;
261         if(!noscrib){
262                 scrib = createscribble(keyboard, "scribble");
263                 ctlprint(scrib, "font bold");
264                 ctlprint(scrib, "image keyback");
265                 ctlprint(scrib, "border 1");
266                 controlwire(scrib, "event", eventchan);
267                 activate(scrib);
268         }
269
270         activate(kbd);
271         resizeready = 1;
272         resizecontrolset(keyboard);
273
274         for(;;){
275                 s = recvp(eventchan);
276                 n = tokenize(s, args, nelem(args));
277                 if(n == 2 && strcmp(args[0], "mouse:")==0 && strcmp(args[1], "exit")==0)
278                         break;
279                 if(n == 3)
280                 if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0)
281                 if(strcmp(args[1], "value") == 0){
282                         n = strtol(args[2], 0, 0);
283                         if(n == '\033') /* Escape exits */
284                                 break;
285                         if(n <= Runemax){
286                                 r = n;
287                                 send(kbdctl->c, &r);
288                         }
289                 }
290         }
291
292         for(i=0; i<Nline; i++){
293                 ctlprint(entry[i], "data");
294                 lines[i] = ctlstrdup(recvp(entry[i]->data));
295         }
296
297         writeall(argv[0]);
298
299         draw(screen, screen->r, display->white, nil, ZP);
300         flushimage(display, 1);
301
302         threadexitsall(nil);
303 }