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