1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include "flayer.h"
10 #include "samterm.h"
11
12 uchar **name; /* first byte is ' ' or '\'': modified state */
13 Text **text; /* pointer to Text associated with file */
14 ushort *tag; /* text[i].tag, even if text[i] not defined */
15 int nname;
16 int mname;
17 int mw;
18
19 char *genmenu3(int);
20 char *genmenu2(int);
21 char *genmenu2c(int);
22
23 enum Menu2
24 {
25 Cut,
26 Paste,
27 Snarf,
28 Plumb,
29 Look,
30 Exch,
31 Search,
32 NMENU2 = Search,
33 Send = Search,
34 NMENU2C
35 };
36
37 enum Menu3
38 {
39 New,
40 Zerox,
41 Resize,
42 Close,
43 Write,
44 NMENU3
45 };
46
47 char *menu2str[] = {
48 "cut",
49 "paste",
50 "snarf",
51 "plumb",
52 "look",
53 "<rio>",
54 0, /* storage for last pattern */
55 };
56
57 char *menu3str[] = {
58 "new",
59 "zerox",
60 "resize",
61 "close",
62 "write",
63 };
64
65 Menu menu2 = {0, genmenu2};
66 Menu menu2c ={0, genmenu2c};
67 Menu menu3 = {0, genmenu3};
68
69 void
menu2hit(void)70 menu2hit(void)
71 {
72 Text *t=(Text *)which->user1;
73 int w = which-t->l;
74 int m;
75
76 if(hversion==0 || plumbfd<0)
77 menu2str[Plumb] = "(plumb)";
78 m = menuhit(2, mousectl, t==&cmd? &menu2c : &menu2, nil);
79 if(hostlock || t->lock)
80 return;
81
82 switch(m){
83 case Cut:
84 cut(t, w, 1, 1);
85 break;
86
87 case Paste:
88 paste(t, w);
89 break;
90
91 case Snarf:
92 snarf(t, w);
93 break;
94
95 case Plumb:
96 if(hversion > 0)
97 outTsll(Tplumb, t->tag, which->p0, which->p1);
98 break;
99
100 case Exch:
101 snarf(t, w);
102 outT0(Tstartsnarf);
103 setlock();
104 break;
105
106 case Look:
107 outTsll(Tlook, t->tag, which->p0, which->p1);
108 setlock();
109 break;
110
111 case Search:
112 outcmd();
113 if(t==&cmd)
114 outTsll(Tsend, 0 /*ignored*/, which->p0, which->p1);
115 else
116 outT0(Tsearch);
117 setlock();
118 break;
119 }
120 }
121
122 void
menu3hit(void)123 menu3hit(void)
124 {
125 Rectangle r;
126 Flayer *l;
127 int m, i;
128 Text *t;
129
130 mw = -1;
131 switch(m = menuhit(3, mousectl, &menu3, nil)){
132 case -1:
133 break;
134
135 case New:
136 if(!hostlock)
137 sweeptext(1, 0);
138 break;
139
140 case Zerox:
141 case Resize:
142 if(!hostlock){
143 setcursor(mousectl, &bullseye);
144 buttons(Down);
145 if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && getr(&r))
146 duplicate(l, r, l->f.font, m==Resize);
147 else
148 setcursor(mousectl, cursor);
149 buttons(Up);
150 }
151 break;
152
153 case Close:
154 if(!hostlock){
155 setcursor(mousectl, &bullseye);
156 buttons(Down);
157 if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && !hostlock){
158 t=(Text *)l->user1;
159 if (t->nwin>1)
160 closeup(l);
161 else if(t!=&cmd) {
162 outTs(Tclose, t->tag);
163 setlock();
164 }
165 }
166 setcursor(mousectl, cursor);
167 buttons(Up);
168 }
169 break;
170
171 case Write:
172 if(!hostlock){
173 setcursor(mousectl, &bullseye);
174 buttons(Down);
175 if((mousep->buttons&4) && (l = flwhich(mousep->xy))){
176 outTs(Twrite, ((Text *)l->user1)->tag);
177 setlock();
178 }else
179 setcursor(mousectl, cursor);
180 buttons(Up);
181 }
182 break;
183
184 default:
185 if(t = text[m-NMENU3]){
186 i = t->front;
187 if(t->nwin==0 || t->l[i].textfn==0)
188 return; /* not ready yet; try again later */
189 if(t->nwin>1 && which==&t->l[i])
190 do
191 if(++i==NL)
192 i = 0;
193 while(i!=t->front && t->l[i].textfn==0);
194 current(&t->l[i]);
195 }else if(!hostlock)
196 sweeptext(0, tag[m-NMENU3]);
197 break;
198 }
199 }
200
201
202 Text *
sweeptext(int new,int tag)203 sweeptext(int new, int tag)
204 {
205 Rectangle r;
206 Text *t;
207
208 if(getr(&r) && (t = malloc(sizeof(Text)))){
209 memset((void*)t, 0, sizeof(Text));
210 current((Flayer *)0);
211 flnew(&t->l[0], gettext, 0, (char *)t);
212 flinit(&t->l[0], r, font, maincols); /*bnl*/
213 t->nwin = 1;
214 rinit(&t->rasp);
215 if(new)
216 startnewfile(Tstartnewfile, t);
217 else{
218 rinit(&t->rasp);
219 t->tag = tag;
220 startfile(t);
221 }
222 return t;
223 }
224 return 0;
225 }
226
227 int
whichmenu(int tg)228 whichmenu(int tg)
229 {
230 int i;
231
232 for(i=0; i<nname; i++)
233 if(tag[i] == tg)
234 return i;
235 return -1;
236 }
237
238 void
menuins(int n,uchar * s,Text * t,int m,int tg)239 menuins(int n, uchar *s, Text *t, int m, int tg)
240 {
241 int i;
242
243 if(nname == mname){
244 if(mname == 0)
245 mname = 32;
246 else
247 mname *= 2;
248 name = realloc(name, sizeof(name[0])*mname);
249 text = realloc(text, sizeof(text[0])*mname);
250 tag = realloc(tag, sizeof(tag[0])*mname);
251 if(name==nil || text==nil || tag==nil)
252 panic("realloc");
253 }
254 for(i=nname; i>n; --i)
255 name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1];
256 text[n] = t;
257 tag[n] = tg;
258 name[n] = alloc(strlen((char*)s)+2);
259 name[n][0] = m;
260 strcpy((char*)name[n]+1, (char*)s);
261 nname++;
262 menu3.lasthit = n+NMENU3;
263 }
264
265 void
menudel(int n)266 menudel(int n)
267 {
268 int i;
269
270 if(nname==0 || n>=nname || text[n])
271 panic("menudel");
272 free(name[n]);
273 --nname;
274 for(i = n; i<nname; i++)
275 name[i]=name[i+1], text[i]=text[i+1], tag[i]=tag[i+1];
276 }
277
278 void
setpat(char * s)279 setpat(char *s)
280 {
281 static char pat[17];
282
283 pat[0] = '/';
284 strncpy(pat+1, s, 15);
285 menu2str[Search] = pat;
286 }
287
288 #define NBUF 64
289 static uchar buf[NBUF*UTFmax]={' ', ' ', ' ', ' '};
290
291 char *
paren(char * s)292 paren(char *s)
293 {
294 uchar *t = buf;
295
296 *t++ = '(';
297 do; while(*t++ = *s++);
298 t[-1] = ')';
299 *t = 0;
300 return (char *)buf;
301 }
302 char*
genmenu2(int n)303 genmenu2(int n)
304 {
305 Text *t=(Text *)which->user1;
306 char *p;
307 if(n>=NMENU2+(menu2str[Search]!=0))
308 return 0;
309 p = menu2str[n];
310 if(!hostlock && !t->lock || n==Search || n==Look)
311 return p;
312 return paren(p);
313 }
314 char*
genmenu2c(int n)315 genmenu2c(int n)
316 {
317 Text *t=(Text *)which->user1;
318 char *p;
319 if(n >= NMENU2C)
320 return 0;
321 if(n == Send)
322 p="send";
323 else
324 p = menu2str[n];
325 if(!hostlock && !t->lock)
326 return p;
327 return paren(p);
328 }
329 char *
genmenu3(int n)330 genmenu3(int n)
331 {
332 Text *t;
333 int c, i, k, l, w;
334 Rune r;
335 char *p;
336
337 if(n >= NMENU3+nname)
338 return 0;
339 if(n < NMENU3){
340 p = menu3str[n];
341 if(hostlock)
342 p = paren(p);
343 return p;
344 }
345 n -= NMENU3;
346 if(n == 0) /* unless we've been fooled, this is cmd */
347 return (char *)&name[n][1];
348 if(mw == -1){
349 mw = 7; /* strlen("~~sam~~"); */
350 for(i=1; i<nname; i++){
351 w = utflen((char*)name[i]+1)+4; /* include "'+. " */
352 if(w > mw)
353 mw = w;
354 }
355 }
356 if(mw > NBUF)
357 mw = NBUF;
358 t = text[n];
359 buf[0] = name[n][0];
360 buf[1] = '-';
361 buf[2] = ' ';
362 buf[3] = ' ';
363 if(t){
364 if(t->nwin == 1)
365 buf[1] = '+';
366 else if(t->nwin > 1)
367 buf[1] = '*';
368 if(work && t==(Text *)work->user1) {
369 buf[2]= '.';
370 if(modified)
371 buf[0] = '\'';
372 }
373 }
374 l = utflen((char*)name[n]+1);
375 if(l > NBUF-4-2){
376 i = 4;
377 k = 1;
378 while(i < NBUF/2){
379 k += chartorune(&r, (char*)name[n]+k);
380 i++;
381 }
382 c = name[n][k];
383 name[n][k] = 0;
384 strcpy((char*)buf+4, (char*)name[n]+1);
385 name[n][k] = c;
386 strcat((char*)buf, "...");
387 while((l-i) >= NBUF/2-4){
388 k += chartorune(&r, (char*)name[n]+k);
389 i++;
390 }
391 strcat((char*)buf, (char*)name[n]+k);
392 }else
393 strcpy((char*)buf+4, (char*)name[n]+1);
394 i = utflen((char*)buf);
395 k = strlen((char*)buf);
396 while(i<mw && k<sizeof buf-1){
397 buf[k++] = ' ';
398 i++;
399 }
400 buf[k] = 0;
401 return (char *)buf;
402 }
403