xref: /plan9/sys/src/cmd/samterm/menu.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
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