1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <cursor.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 	m = menuhit(3, mousectl, &menu3, nil);
132 	switch(m){
133 	case -1:
134 		break;
135 
136 	case New:
137 		if(!hostlock)
138 			sweeptext(1, 0);
139 		break;
140 
141 	case Zerox:
142 	case Resize:
143 		if(!hostlock){
144 			setcursor(mousectl, &bullseye);
145 			buttons(Down);
146 			if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && getr(&r))
147 				duplicate(l, r, l->f.font, m==Resize);
148 			else
149 				setcursor(mousectl, cursor);
150 			buttons(Up);
151 		}
152 		break;
153 
154 	case Close:
155 		if(!hostlock){
156 			setcursor(mousectl, &bullseye);
157 			buttons(Down);
158 			if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && !hostlock){
159 				t=(Text *)l->user1;
160 				if (t->nwin>1)
161 					closeup(l);
162 				else if(t!=&cmd) {
163 					outTs(Tclose, t->tag);
164 					setlock();
165 				}
166 			}
167 			setcursor(mousectl, cursor);
168 			buttons(Up);
169 		}
170 		break;
171 
172 	case Write:
173 		if(!hostlock){
174 			setcursor(mousectl, &bullseye);
175 			buttons(Down);
176 			if((mousep->buttons&4) && (l = flwhich(mousep->xy))){
177 				outTs(Twrite, ((Text *)l->user1)->tag);
178 				setlock();
179 			}else
180 				setcursor(mousectl, cursor);
181 			buttons(Up);
182 		}
183 		break;
184 
185 	default:
186 		if(t = text[m-NMENU3]){
187 			i = t->front;
188 			if(t->nwin==0 || t->l[i].textfn==0)
189 				return;	/* not ready yet; try again later */
190 			if(t->nwin>1 && which==&t->l[i])
191 				do
192 					if(++i==NL)
193 						i = 0;
194 				while(i!=t->front && t->l[i].textfn==0);
195 			current(&t->l[i]);
196 		}else if(!hostlock)
197 			sweeptext(0, tag[m-NMENU3]);
198 		break;
199 	}
200 }
201 
202 
203 Text *
sweeptext(int new,int tag)204 sweeptext(int new, int tag)
205 {
206 	Rectangle r;
207 	Text *t;
208 
209 	if(getr(&r) && (t = malloc(sizeof(Text)))){
210 		memset((void*)t, 0, sizeof(Text));
211 		current((Flayer *)0);
212 		flnew(&t->l[0], gettext, 0, (char *)t);
213 		flinit(&t->l[0], r, font, maincols);	/*bnl*/
214 		t->nwin = 1;
215 		rinit(&t->rasp);
216 		if(new)
217 			startnewfile(Tstartnewfile, t);
218 		else{
219 			rinit(&t->rasp);
220 			t->tag = tag;
221 			startfile(t);
222 		}
223 		return t;
224 	}
225 	return 0;
226 }
227 
228 int
whichmenu(int tg)229 whichmenu(int tg)
230 {
231 	int i;
232 
233 	for(i=0; i<nname; i++)
234 		if(tag[i] == tg)
235 			return i;
236 	return -1;
237 }
238 
239 void
menuins(int n,uchar * s,Text * t,int m,int tg)240 menuins(int n, uchar *s, Text *t, int m, int tg)
241 {
242 	int i;
243 
244 	if(nname == mname){
245 		if(mname == 0)
246 			mname = 32;
247 		else
248 			mname *= 2;
249 		name = realloc(name, sizeof(name[0])*mname);
250 		text = realloc(text, sizeof(text[0])*mname);
251 		tag = realloc(tag, sizeof(tag[0])*mname);
252 		if(name==nil || text==nil || tag==nil)
253 			panic("realloc");
254 	}
255 	for(i=nname; i>n; --i)
256 		name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1];
257 	text[n] = t;
258 	tag[n] = tg;
259 	name[n] = alloc(strlen((char*)s)+2);
260 	name[n][0] = m;
261 	strcpy((char*)name[n]+1, (char*)s);
262 	nname++;
263 	menu3.lasthit = n+NMENU3;
264 }
265 
266 void
menudel(int n)267 menudel(int n)
268 {
269 	int i;
270 
271 	if(nname==0 || n>=nname || text[n])
272 		panic("menudel");
273 	free(name[n]);
274 	--nname;
275 	for(i = n; i<nname; i++)
276 		name[i]=name[i+1], text[i]=text[i+1], tag[i]=tag[i+1];
277 }
278 
279 void
setpat(char * s)280 setpat(char *s)
281 {
282 	static char pat[17];
283 
284 	pat[0] = '/';
285 	strncpy(pat+1, s, 15);
286 	menu2str[Search] = pat;
287 }
288 
289 #define	NBUF	64
290 static uchar buf[NBUF*UTFmax]={' ', ' ', ' ', ' '};
291 
292 char *
paren(char * s)293 paren(char *s)
294 {
295 	uchar *t = buf;
296 
297 	*t++ = '(';
298 	do; while(*t++ = *s++);
299 	t[-1] = ')';
300 	*t = 0;
301 	return (char *)buf;
302 }
303 char*
genmenu2(int n)304 genmenu2(int n)
305 {
306 	Text *t=(Text *)which->user1;
307 	char *p;
308 	if(n>=NMENU2+(menu2str[Search]!=0))
309 		return 0;
310 	p = menu2str[n];
311 	if(!hostlock && !t->lock || n==Search || n==Look)
312 		return p;
313 	return paren(p);
314 }
315 char*
genmenu2c(int n)316 genmenu2c(int n)
317 {
318 	Text *t=(Text *)which->user1;
319 	char *p;
320 	if(n >= NMENU2C)
321 		return 0;
322 	if(n == Send)
323 		p="send";
324 	else
325 		p = menu2str[n];
326 	if(!hostlock && !t->lock)
327 		return p;
328 	return paren(p);
329 }
330 char *
genmenu3(int n)331 genmenu3(int n)
332 {
333 	Text *t;
334 	int c, i, k, l, w;
335 	Rune r;
336 	char *p;
337 
338 	if(n >= NMENU3+nname)
339 		return 0;
340 	if(n < NMENU3){
341 		p = menu3str[n];
342 		if(hostlock)
343 			p = paren(p);
344 		return p;
345 	}
346 	n -= NMENU3;
347 	if(n == 0)	/* unless we've been fooled, this is cmd */
348 		return (char *)&name[n][1];
349 	if(mw == -1){
350 		mw = 7;	/* strlen("~~sam~~"); */
351 		for(i=1; i<nname; i++){
352 			w = utflen((char*)name[i]+1)+4;	/* include "'+. " */
353 			if(w > mw)
354 				mw = w;
355 		}
356 	}
357 	if(mw > NBUF)
358 		mw = NBUF;
359 	t = text[n];
360 	buf[0] = name[n][0];
361 	buf[1] = '-';
362 	buf[2] = ' ';
363 	buf[3] = ' ';
364 	if(t){
365 		if(t->nwin == 1)
366 			buf[1] = '+';
367 		else if(t->nwin > 1)
368 			buf[1] = '*';
369 		if(work && t==(Text *)work->user1) {
370 			buf[2]= '.';
371 			if(modified)
372 				buf[0] = '\'';
373 		}
374 	}
375 	l = utflen((char*)name[n]+1);
376 	if(l > NBUF-4-2){
377 		i = 4;
378 		k = 1;
379 		while(i < NBUF/2){
380 			k += chartorune(&r, (char*)name[n]+k);
381 			i++;
382 		}
383 		c = name[n][k];
384 		name[n][k] = 0;
385 		strcpy((char*)buf+4, (char*)name[n]+1);
386 		name[n][k] = c;
387 		strcat((char*)buf, "...");
388 		while((l-i) >= NBUF/2-4){
389 			k += chartorune(&r, (char*)name[n]+k);
390 			i++;
391 		}
392 		strcat((char*)buf, (char*)name[n]+k);
393 	}else
394 		strcpy((char*)buf+4, (char*)name[n]+1);
395 	i = utflen((char*)buf);
396 	k = strlen((char*)buf);
397 	while(i<mw && k<sizeof buf-1){
398 		buf[k++] = ' ';
399 		i++;
400 	}
401 	buf[k] = 0;
402 	return (char *)buf;
403 }
404