ref: c7d9da8f5a41b833946027c802e0e8d7dd014b22
dir: /sys/src/cmd/samterm/menu.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <cursor.h> #include <mouse.h> #include <keyboard.h> #include <frame.h> #include "flayer.h" #include "samterm.h" uchar **name; /* first byte is ' ' or '\'': modified state */ Text **text; /* pointer to Text associated with file */ ushort *tag; /* text[i].tag, even if text[i] not defined */ int nname; int mname; int mw; char *genmenu3(int); char *genmenu2(int); char *genmenu2c(int); enum Menu2 { Cut, Paste, Snarf, Plumb, Look, Exch, Search, NMENU2 = Search, Send = Search, NMENU2C }; enum Menu3 { New, Zerox, Resize, Close, Write, NMENU3 }; char *menu2str[] = { "cut", "paste", "snarf", "plumb", "look", "<rio>", 0, /* storage for last pattern */ }; char *menu3str[] = { "new", "zerox", "resize", "close", "write", }; Menu menu2 = {0, genmenu2}; Menu menu2c ={0, genmenu2c}; Menu menu3 = {0, genmenu3}; void menu2hit(void) { Text *t=(Text *)which->user1; int w = which-t->l; int m; if(hversion==0 || plumbfd<0) menu2str[Plumb] = "(plumb)"; m = menuhit(2, mousectl, t==&cmd? &menu2c : &menu2, nil); if(hostlock || t->lock) return; switch(m){ case Cut: cut(t, w, 1, 1); break; case Paste: paste(t, w); break; case Snarf: snarf(t, w); break; case Plumb: if(hversion > 0) outTsll(Tplumb, t->tag, which->p0, which->p1); break; case Exch: snarf(t, w); outT0(Tstartsnarf); setlock(); break; case Look: outTsll(Tlook, t->tag, which->p0, which->p1); setlock(); break; case Search: outcmd(); if(t==&cmd) outTsll(Tsend, 0 /*ignored*/, which->p0, which->p1); else outT0(Tsearch); setlock(); break; } } void menu3hit(void) { Rectangle r; Flayer *l; int m, i; Text *t; mw = -1; switch(m = menuhit(3, mousectl, &menu3, nil)){ case -1: break; case New: if(!hostlock) sweeptext(1, 0); break; case Zerox: case Resize: if(!hostlock){ setcursor(mousectl, &bullseye); buttons(Down); if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && getr(&r)) duplicate(l, r, l->f.font, m==Resize); else setcursor(mousectl, cursor); buttons(Up); } break; case Close: if(!hostlock){ setcursor(mousectl, &bullseye); buttons(Down); if((mousep->buttons&4) && (l = flwhich(mousep->xy)) && !hostlock){ t=(Text *)l->user1; if (t->nwin>1) closeup(l); else if(t!=&cmd) { outTs(Tclose, t->tag); setlock(); } } setcursor(mousectl, cursor); buttons(Up); } break; case Write: if(!hostlock){ setcursor(mousectl, &bullseye); buttons(Down); if((mousep->buttons&4) && (l = flwhich(mousep->xy))){ outTs(Twrite, ((Text *)l->user1)->tag); setlock(); }else setcursor(mousectl, cursor); buttons(Up); } break; default: if(t = text[m-NMENU3]){ i = t->front; if(t->nwin==0 || t->l[i].textfn==0) return; /* not ready yet; try again later */ if(t->nwin>1 && which==&t->l[i]) do if(++i==NL) i = 0; while(i!=t->front && t->l[i].textfn==0); current(&t->l[i]); }else if(!hostlock) sweeptext(0, tag[m-NMENU3]); break; } } Text * sweeptext(int new, int tag) { Rectangle r; Text *t; if(getr(&r) && (t = malloc(sizeof(Text)))){ memset((void*)t, 0, sizeof(Text)); current((Flayer *)0); flnew(&t->l[0], gettext, 0, (char *)t); flinit(&t->l[0], r, font, maincols); /*bnl*/ t->nwin = 1; rinit(&t->rasp); if(new) startnewfile(Tstartnewfile, t); else{ rinit(&t->rasp); t->tag = tag; startfile(t); } return t; } return 0; } int whichmenu(int tg) { int i; for(i=0; i<nname; i++) if(tag[i] == tg) return i; return -1; } void menuins(int n, uchar *s, Text *t, int m, int tg) { int i; if(nname == mname){ if(mname == 0) mname = 32; else mname *= 2; name = realloc(name, sizeof(name[0])*mname); text = realloc(text, sizeof(text[0])*mname); tag = realloc(tag, sizeof(tag[0])*mname); if(name==nil || text==nil || tag==nil) panic("realloc"); } for(i=nname; i>n; --i) name[i]=name[i-1], text[i]=text[i-1], tag[i]=tag[i-1]; text[n] = t; tag[n] = tg; name[n] = alloc(strlen((char*)s)+2); name[n][0] = m; strcpy((char*)name[n]+1, (char*)s); nname++; menu3.lasthit = n+NMENU3; } void menudel(int n) { int i; if(nname==0 || n>=nname || text[n]) panic("menudel"); free(name[n]); --nname; for(i = n; i<nname; i++) name[i]=name[i+1], text[i]=text[i+1], tag[i]=tag[i+1]; } void setpat(char *s) { static char pat[17]; pat[0] = '/'; strncpy(pat+1, s, 15); menu2str[Search] = pat; } #define NBUF 64 static uchar buf[NBUF*UTFmax]={' ', ' ', ' ', ' '}; char * paren(char *s) { uchar *t = buf; *t++ = '('; do; while(*t++ = *s++); t[-1] = ')'; *t = 0; return (char *)buf; } char* genmenu2(int n) { Text *t=(Text *)which->user1; char *p; if(n>=NMENU2+(menu2str[Search]!=0)) return 0; p = menu2str[n]; if(!hostlock && !t->lock || n==Search || n==Look) return p; return paren(p); } char* genmenu2c(int n) { Text *t=(Text *)which->user1; char *p; if(n >= NMENU2C) return 0; if(n == Send) p="send"; else p = menu2str[n]; if(!hostlock && !t->lock) return p; return paren(p); } char * genmenu3(int n) { Text *t; int c, i, k, l, w; Rune r; char *p; if(n >= NMENU3+nname) return 0; if(n < NMENU3){ p = menu3str[n]; if(hostlock) p = paren(p); return p; } n -= NMENU3; if(n == 0) /* unless we've been fooled, this is cmd */ return (char *)&name[n][1]; if(mw == -1){ mw = 7; /* strlen("~~sam~~"); */ for(i=1; i<nname; i++){ w = utflen((char*)name[i]+1)+4; /* include "'+. " */ if(w > mw) mw = w; } } if(mw > NBUF) mw = NBUF; t = text[n]; buf[0] = name[n][0]; buf[1] = '-'; buf[2] = ' '; buf[3] = ' '; if(t){ if(t->nwin == 1) buf[1] = '+'; else if(t->nwin > 1) buf[1] = '*'; if(work && t==(Text *)work->user1) { buf[2]= '.'; if(modified) buf[0] = '\''; } } l = utflen((char*)name[n]+1); if(l > NBUF-4-2){ i = 4; k = 1; while(i < NBUF/2){ k += chartorune(&r, (char*)name[n]+k); i++; } c = name[n][k]; name[n][k] = 0; strcpy((char*)buf+4, (char*)name[n]+1); name[n][k] = c; strcat((char*)buf, "..."); while((l-i) >= NBUF/2-4){ k += chartorune(&r, (char*)name[n]+k); i++; } strcat((char*)buf, (char*)name[n]+k); }else strcpy((char*)buf+4, (char*)name[n]+1); i = utflen((char*)buf); k = strlen((char*)buf); while(i<mw && k<sizeof buf-1){ buf[k++] = ' '; i++; } buf[k] = 0; return (char *)buf; }