1 /* $Id: menu.c,v 1.46 2007/05/23 12:34:20 inu Exp $ */
2 /*
3  * w3m menu.c
4  */
5 #include <stdio.h>
6 
7 #include "fm.h"
8 #include "menu.h"
9 #include "func.h"
10 #include "myctype.h"
11 #include "regex.h"
12 
13 #ifdef USE_MOUSE
14 #ifdef USE_GPM
15 #include <gpm.h>
16 static int gpm_process_menu_mouse(Gpm_Event * event, void *data);
17 extern int gpm_process_mouse(Gpm_Event *, void *);
18 #endif				/* USE_GPM */
19 #ifdef USE_SYSMOUSE
20 extern int (*sysm_handler) (int x, int y, int nbs, int obs);
21 static int sysm_process_menu_mouse(int, int, int, int);
22 extern int sysm_process_mouse(int, int, int, int);
23 #endif				/* USE_SYSMOUSE */
24 #if defined(USE_GPM) || defined(USE_SYSMOUSE)
25 #define X_MOUSE_SELECTED (char)0xff
26 static int X_Mouse_Selection;
27 extern int do_getch();
28 #define getch()	do_getch()
29 #endif				/* defined(USE_GPM) || defined(USE_SYSMOUSE) */
30 #endif				/* USE_MOUSE */
31 
32 #ifdef USE_MENU
33 
34 static char **FRAME;
35 static int FRAME_WIDTH;
36 static int graph_mode = FALSE;
37 #define G_start  {if (graph_mode) graphstart();}
38 #define G_end    {if (graph_mode) graphend();}
39 
40 static int mEsc(char c);
41 static int mEscB(char c);
42 static int mEscD(char c);
43 static int mNull(char c);
44 static int mSelect(char c);
45 static int mDown(char c);
46 static int mUp(char c);
47 static int mLast(char c);
48 static int mTop(char c);
49 static int mNext(char c);
50 static int mPrev(char c);
51 static int mFore(char c);
52 static int mBack(char c);
53 static int mLineU(char c);
54 static int mLineD(char c);
55 static int mOk(char c);
56 static int mCancel(char c);
57 static int mClose(char c);
58 static int mSusp(char c);
59 static int mMouse(char c);
60 static int mSgrMouse(char c);
61 static int mSrchF(char c);
62 static int mSrchB(char c);
63 static int mSrchN(char c);
64 static int mSrchP(char c);
65 #ifdef __EMX__
66 static int mPc(char c);
67 #endif
68 
69 /* *INDENT-OFF* */
70 static int (*MenuKeymap[128]) (char c) = {
71 /*  C-@     C-a     C-b     C-c     C-d     C-e     C-f     C-g      */
72 #ifdef __EMX__
73     mPc,    mTop,   mPrev,  mClose, mNull,  mLast,  mNext,  mNull,
74 #else
75     mNull,  mTop,   mPrev,  mClose, mNull,  mLast,  mNext,  mNull,
76 #endif
77 /*  C-h     C-i     C-j     C-k     C-l     C-m     C-n     C-o      */
78     mCancel,mNull,  mOk,    mNull,  mNull,  mOk,    mDown,  mNull,
79 /*  C-p     C-q     C-r     C-s     C-t     C-u     C-v     C-w      */
80     mUp,    mNull,  mSrchB, mSrchF, mNull,  mNull,  mNext,  mNull,
81 /*  C-x     C-y     C-z     C-[     C-\     C-]     C-^     C-_      */
82     mNull,  mNull,  mSusp,  mEsc,   mNull,  mNull,  mNull,  mNull,
83 /*  SPC     !       "       #       $       %       &       '        */
84     mOk,    mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
85 /*  (       )       *       +       ,       -       .       /        */
86     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mSrchF,
87 /*  0       1       2       3       4       5       6       7        */
88     mNull,  mNull,  mNull,  mNull,  mNull,  mNull , mNull,  mNull,
89 /*  8       9       :       ;       <       =       >       ?        */
90     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mSrchB,
91 /*  @       A       B       C       D       E       F       G        */
92     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
93 /*  H       I       J       K       L       M       N       O        */
94     mNull,  mNull,  mLineU, mLineD, mNull,  mNull,  mSrchP, mNull,
95 /*  P       Q       R       S       T       U       V       W        */
96     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
97 /*  X       Y       Z       [       \       ]       ^       _        */
98     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
99 /*  `       a       b       c       d       e       f       g        */
100     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
101 /*  h       i       j       k       l       m       n       o        */
102     mCancel,mNull,  mDown,  mUp,    mOk,    mNull,  mSrchN, mNull,
103 /*  p       q       r       s       t       u       v       w        */
104     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
105 /*  x       y       z       {       |       }       ~       DEL      */
106     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mCancel,
107 };
108 static int (*MenuEscKeymap[128]) (char c) = {
109     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
110     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
111     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
112     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
113 
114     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
115     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
116     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
117     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
118 
119     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
120 /*                                                          O     */
121     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mEscB,
122     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
123 /*                          [                                     */
124     mNull,  mNull,  mNull,  mEscB,  mNull,  mNull,  mNull,  mNull,
125 
126     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
127     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
128 /*                                                  v             */
129     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mPrev,  mNull,
130     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
131 };
132 static int (*MenuEscBKeymap[128]) (char c) = {
133     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
134     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
135     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
136     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
137 
138     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
139     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
140     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
141 /*  8       9       :       ;       <       =       >       ?     */
142     mNull,  mNull,  mNull,  mNull,  mSgrMouse,mNull,mNull,  mNull,
143 /*          A       B       C       D       E                     */
144     mNull,  mUp,    mDown,  mOk,    mCancel,mClose, mNull, mNull,
145 /*                                  L       M                     */
146     mNull,  mNull,  mNull,  mNull,  mClose, mMouse, mNull,  mNull,
147     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
148     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
149 
150     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
151     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
152     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
153     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
154 };
155 static int (*MenuEscDKeymap[128]) (char c) = {
156 /*  0       1       INS     3       4       PgUp,   PgDn    7     */
157     mNull,  mNull,  mClose, mNull,  mNull,  mBack,  mFore,  mNull,
158 /*  8       9       10      F1      F2      F3      F4      F5       */
159     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
160 /*  16      F6      F7      F8      F9      F10     22      23       */
161     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
162 /*  24      25      26      27      HELP    29      30      31       */
163     mNull,  mNull,  mNull,  mNull,  mClose, mNull,  mNull,  mNull,
164 
165     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
166     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
167     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
168     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
169 
170     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
171     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
172     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
173     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
174 
175     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
176     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
177     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
178     mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
179 };
180 
181 #ifdef __EMX__
182 static int (*MenuPcKeymap[256])(char c)={
183 //			  Null
184   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
185 //							  S-Tab
186   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
187 // A-q	  A-w	  A-E	  A-r	  A-t	  A-y	  A-u	  A-i
188   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
189 // A-o	  A-p	  A-[	  A-]			  A-a	  A-s
190   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
191 // A-d	  A-f	  A-g	  A-h	  A-j	  A-k	  A-l	  A-;
192   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
193 // A-'    A-'		  A-\		  A-x	  A-c	  A-v
194   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mPrev,
195 // A-b	  A-n	  A-m	  A-,	  A-.	  A-/		  A-+
196   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
197 //			  F1	  F2	  F3	  F4	  F5
198   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
199 // F6	  F7	  F8	  F9	  F10			  Home
200   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mTop,
201 // Up	  PgUp	  A-/	  Left	  5	  Right	  C-*	  End
202   mUp,	  mUp,	  mNull,  mCancel,mNull,  mOk,	  mNull,  mLast,
203 // Down	  PgDn	  Ins	  Del	  S-F1	  S-F2	  S-F3	  S-F4
204   mDown,  mDown,  mClose, mCancel,mNull,  mNull,  mNull,  mNull,
205 // S-F5	  S-F6	  S-F7	  S-F8	  S-F9	  S-F10	  C-F1	  C-F2
206   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
207 // C-F3	  C-F4	  C-F5	  C-F6	  C-F7	  C-F8	  C-F9	  C-F10
208   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
209 // A-F1	  A-F2	  A-F3	  A-F4	  A-F5	  A-F6	  A-F7	  A-F8
210   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
211 // A-F9	  A-F10	  PrtSc	  C-Left  C-Right C-End	  C-PgDn  C-Home
212   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
213 // A-1	  A-2	  A-3	  A-4	  A-5	  A-6	  A-7/8	  A-9
214   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
215 // A-0	  A -	  A-=		  C-PgUp  F11	  F12	  S-F11
216   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
217 // S-F12  C-F11	  C-F12	  A-F11	  A-F12	  C-Up	  C-/	  C-5
218   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
219 // S-*	  C-Down  C-Ins	  C-Del	  C-Tab	  C -	  C-+
220   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
221   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
222 //				  A -	  A-Tab	  A-Enter
223   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 160
224   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 168
225   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 176
226   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 184
227   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 192
228   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 200
229   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 208
230   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 216
231   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 224
232   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 232
233   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 240
234   mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull	   // 248
235 };
236 #endif
237 /* *INDENT-ON* */
238 /* --- SelectMenu --- */
239 
240 static Menu SelectMenu;
241 static int SelectV = 0;
242 static void initSelectMenu(void);
243 static void smChBuf(void);
244 static int smDelBuf(char c);
245 
246 /* --- SelectMenu (END) --- */
247 
248 /* --- SelTabMenu --- */
249 
250 static Menu SelTabMenu;
251 static int SelTabV = 0;
252 static void initSelTabMenu(void);
253 static void smChTab(void);
254 static int smDelTab(char c);
255 
256 /* --- SelTabMenu (END) --- */
257 
258 /* --- MainMenu --- */
259 
260 static Menu MainMenu;
261 #ifdef USE_M17N
262 /* FIXME: gettextize here */
263 static wc_ces MainMenuCharset = WC_CES_US_ASCII;	/* FIXME: charset of source code */
264 static int MainMenuEncode = FALSE;
265 #endif
266 
267 static MenuItem MainMenuItem[] = {
268     /* type        label           variable value func     popup keys data  */
269     {MENU_FUNC, N_(" Back         (b) "), NULL, 0, backBf, NULL, "b", NULL},
270     {MENU_POPUP, N_(" Select Buffer(s) "), NULL, 0, NULL, &SelectMenu, "s",
271      NULL},
272     {MENU_POPUP, N_(" Select Tab   (t) "), NULL, 0, NULL, &SelTabMenu, "tT",
273      NULL},
274     {MENU_FUNC, N_(" View Source  (v) "), NULL, 0, vwSrc, NULL, "vV", NULL},
275     {MENU_FUNC, N_(" Edit Source  (e) "), NULL, 0, editBf, NULL, "eE", NULL},
276     {MENU_FUNC, N_(" Save Source  (S) "), NULL, 0, svSrc, NULL, "S", NULL},
277     {MENU_FUNC, N_(" Reload       (r) "), NULL, 0, reload, NULL, "rR", NULL},
278     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
279     {MENU_FUNC, N_(" Go Link      (a) "), NULL, 0, followA, NULL, "a", NULL},
280     {MENU_FUNC, N_("   on New Tab (n) "), NULL, 0, tabA, NULL, "nN", NULL},
281     {MENU_FUNC, N_(" Save Link    (A) "), NULL, 0, svA, NULL, "A", NULL},
282     {MENU_FUNC, N_(" View Image   (i) "), NULL, 0, followI, NULL, "i", NULL},
283     {MENU_FUNC, N_(" Save Image   (I) "), NULL, 0, svI, NULL, "I", NULL},
284     {MENU_FUNC, N_(" View Frame   (f) "), NULL, 0, rFrame, NULL, "fF", NULL},
285     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
286     {MENU_FUNC, N_(" Bookmark     (B) "), NULL, 0, ldBmark, NULL, "B", NULL},
287     {MENU_FUNC, N_(" Help         (h) "), NULL, 0, ldhelp, NULL, "hH", NULL},
288     {MENU_FUNC, N_(" Option       (o) "), NULL, 0, ldOpt, NULL, "oO", NULL},
289     {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
290     {MENU_FUNC, N_(" Quit         (q) "), NULL, 0, qquitfm, NULL, "qQ", NULL},
291     {MENU_END, "", NULL, 0, nulcmd, NULL, "", NULL},
292 };
293 
294 /* --- MainMenu (END) --- */
295 
296 static MenuList *w3mMenuList;
297 
298 static Menu *CurrentMenu = NULL;
299 
300 #define mvaddch(y, x, c)        (move(y, x), addch(c))
301 #define mvaddstr(y, x, str)     (move(y, x), addstr(str))
302 #define mvaddnstr(y, x, str, n) (move(y, x), addnstr_sup(str, n))
303 
304 void
new_menu(Menu * menu,MenuItem * item)305 new_menu(Menu *menu, MenuItem *item)
306 {
307     int i, l;
308     char *p;
309 
310     menu->cursorX = 0;
311     menu->cursorY = 0;
312     menu->x = 0;
313     menu->y = 0;
314     menu->nitem = 0;
315     menu->item = item;
316     menu->initial = 0;
317     menu->select = 0;
318     menu->offset = 0;
319     menu->active = 0;
320 
321     if (item == NULL)
322 	return;
323 
324     for (i = 0; item[i].type != MENU_END; i++) ;
325     menu->nitem = i;
326     menu->height = menu->nitem;
327     for (i = 0; i < 128; i++)
328 	menu->keymap[i] = MenuKeymap[i];
329     menu->width = 0;
330     for (i = 0; i < menu->nitem; i++) {
331 	if ((p = item[i].keys) != NULL) {
332 	    while (*p) {
333 		if (IS_ASCII(*p)) {
334 		    menu->keymap[(int)*p] = mSelect;
335 		    menu->keyselect[(int)*p] = i;
336 		}
337 		p++;
338 	    }
339 	}
340 	l = get_strwidth(item[i].label);
341 	if (l > menu->width)
342 	    menu->width = l;
343     }
344 }
345 
346 void
geom_menu(Menu * menu,int x,int y,int mselect)347 geom_menu(Menu *menu, int x, int y, int mselect)
348 {
349     int win_x, win_y, win_w, win_h;
350 
351     menu->select = mselect;
352 
353     if (menu->width % FRAME_WIDTH)
354 	menu->width = (menu->width / FRAME_WIDTH + 1) * FRAME_WIDTH;
355     win_x = menu->x - FRAME_WIDTH;
356     win_w = menu->width + 2 * FRAME_WIDTH;
357     if (win_x + win_w > COLS)
358 	win_x = COLS - win_w;
359     if (win_x < 0) {
360 	win_x = 0;
361 	if (win_w > COLS) {
362 	    menu->width = COLS - 2 * FRAME_WIDTH;
363 	    menu->width -= menu->width % FRAME_WIDTH;
364 	}
365     }
366     menu->x = win_x + FRAME_WIDTH;
367 
368     win_y = menu->y - mselect - 1;
369     win_h = menu->height + 2;
370     if (win_y + win_h > LASTLINE)
371 	win_y = LASTLINE - win_h;
372     if (win_y < 0) {
373 	win_y = 0;
374 	if (win_y + win_h > LASTLINE) {
375 	    win_h = LASTLINE - win_y;
376 	    menu->height = win_h - 2;
377 	    if (menu->height <= mselect)
378 		menu->offset = mselect - menu->height + 1;
379 	}
380     }
381     menu->y = win_y + 1;
382 }
383 
384 void
draw_all_menu(Menu * menu)385 draw_all_menu(Menu *menu)
386 {
387     if (menu->parent != NULL)
388 	draw_all_menu(menu->parent);
389     draw_menu(menu);
390 }
391 
392 void
draw_menu(Menu * menu)393 draw_menu(Menu *menu)
394 {
395     int x, y, w;
396     int i, j;
397 
398     x = menu->x - FRAME_WIDTH;
399     w = menu->width + 2 * FRAME_WIDTH;
400     y = menu->y - 1;
401 
402     if (menu->offset == 0) {
403 	G_start;
404 	mvaddstr(y, x, FRAME[3]);
405 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
406 	    mvaddstr(y, x + i, FRAME[10]);
407 	mvaddstr(y, x + i, FRAME[6]);
408 	G_end;
409     }
410     else {
411 	G_start;
412 	mvaddstr(y, x, FRAME[5]);
413 	G_end;
414 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
415 	    mvaddstr(y, x + i, " ");
416 	G_start;
417 	mvaddstr(y, x + i, FRAME[5]);
418 	G_end;
419 	i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
420 	mvaddstr(y, x + i, ":");
421     }
422 
423     for (j = 0; j < menu->height; j++) {
424 	y++;
425 	G_start;
426 	mvaddstr(y, x, FRAME[5]);
427 	G_end;
428 	draw_menu_item(menu, menu->offset + j);
429 	G_start;
430 	mvaddstr(y, x + w - FRAME_WIDTH, FRAME[5]);
431 	G_end;
432     }
433     y++;
434     if (menu->offset + menu->height == menu->nitem) {
435 	G_start;
436 	mvaddstr(y, x, FRAME[9]);
437 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
438 	    mvaddstr(y, x + i, FRAME[10]);
439 	mvaddstr(y, x + i, FRAME[12]);
440 	G_end;
441     }
442     else {
443 	G_start;
444 	mvaddstr(y, x, FRAME[5]);
445 	G_end;
446 	for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
447 	    mvaddstr(y, x + i, " ");
448 	G_start;
449 	mvaddstr(y, x + i, FRAME[5]);
450 	G_end;
451 	i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
452 	mvaddstr(y, x + i, ":");
453     }
454 }
455 
456 void
draw_menu_item(Menu * menu,int mselect)457 draw_menu_item(Menu *menu, int mselect)
458 {
459     mvaddnstr(menu->y + mselect - menu->offset, menu->x,
460 	      menu->item[mselect].label, menu->width);
461 }
462 
463 int
select_menu(Menu * menu,int mselect)464 select_menu(Menu *menu, int mselect)
465 {
466     if (mselect < 0 || mselect >= menu->nitem)
467 	return (MENU_NOTHING);
468     if (mselect < menu->offset)
469 	up_menu(menu, menu->offset - mselect);
470     else if (mselect >= menu->offset + menu->height)
471 	down_menu(menu, mselect - menu->offset - menu->height + 1);
472 
473     if (menu->select >= menu->offset &&
474 	menu->select < menu->offset + menu->height)
475 	draw_menu_item(menu, menu->select);
476     menu->select = mselect;
477     standout();
478     draw_menu_item(menu, menu->select);
479     standend();
480     /*
481      * move(menu->cursorY, menu->cursorX); */
482     move(menu->y + mselect - menu->offset, menu->x);
483     toggle_stand();
484     refresh();
485 
486     return (menu->select);
487 }
488 
489 void
goto_menu(Menu * menu,int mselect,int down)490 goto_menu(Menu *menu, int mselect, int down)
491 {
492     int select_in;
493     if (mselect >= menu->nitem)
494 	mselect = menu->nitem - 1;
495     else if (mselect < 0)
496 	mselect = 0;
497     select_in = mselect;
498     while (menu->item[mselect].type == MENU_NOP) {
499 	if (down > 0) {
500 	    if (++mselect >= menu->nitem) {
501 		down_menu(menu, select_in - menu->select);
502 		mselect = menu->select;
503 		break;
504 	    }
505 	}
506 	else if (down < 0) {
507 	    if (--mselect < 0) {
508 		up_menu(menu, menu->select - select_in);
509 		mselect = menu->select;
510 		break;
511 	    }
512 	}
513 	else {
514 	    return;
515 	}
516     }
517     select_menu(menu, mselect);
518 }
519 
520 void
up_menu(Menu * menu,int n)521 up_menu(Menu *menu, int n)
522 {
523     if (n < 0 || menu->offset == 0)
524 	return;
525     menu->offset -= n;
526     if (menu->offset < 0)
527 	menu->offset = 0;
528 
529     draw_menu(menu);
530 }
531 
532 void
down_menu(Menu * menu,int n)533 down_menu(Menu *menu, int n)
534 {
535     if (n < 0 || menu->offset + menu->height == menu->nitem)
536 	return;
537     menu->offset += n;
538     if (menu->offset + menu->height > menu->nitem)
539 	menu->offset = menu->nitem - menu->height;
540 
541     draw_menu(menu);
542 }
543 
544 int
action_menu(Menu * menu)545 action_menu(Menu *menu)
546 {
547     char c;
548     int mselect;
549     MenuItem item;
550 
551     if (menu->active == 0) {
552 	if (menu->parent != NULL)
553 	    menu->parent->active = 0;
554 	return (0);
555     }
556     draw_all_menu(menu);
557     select_menu(menu, menu->select);
558 
559     while (1) {
560 #ifdef USE_MOUSE
561 	if (use_mouse)
562 	    mouse_active();
563 #endif				/* USE_MOUSE */
564 	c = getch();
565 #ifdef USE_MOUSE
566 	if (use_mouse)
567 	    mouse_inactive();
568 #if defined(USE_GPM) || defined(USE_SYSMOUSE)
569 	if (c == X_MOUSE_SELECTED) {
570 	    mselect = X_Mouse_Selection;
571 	    if (mselect != MENU_NOTHING)
572 		break;
573 	}
574 #endif				/* defined(USE_GPM) || defined(USE_SYSMOUSE) */
575 #endif				/* USE_MOUSE */
576 	if (IS_ASCII(c)) {	/* Ascii */
577 	    mselect = (*menu->keymap[(int)c]) (c);
578 	    if (mselect != MENU_NOTHING)
579 		break;
580 	}
581     }
582     if (mselect >= 0 && mselect < menu->nitem) {
583 	item = menu->item[mselect];
584 	if (item.type & MENU_POPUP) {
585 	    popup_menu(menu, item.popup);
586 	    return (1);
587 	}
588 	if (menu->parent != NULL)
589 	    menu->parent->active = 0;
590 	if (item.type & MENU_VALUE)
591 	    *item.variable = item.value;
592 	if (item.type & MENU_FUNC) {
593 	    CurrentKey = -1;
594 	    CurrentKeyData = NULL;
595 	    CurrentCmdData = item.data;
596 	    (*item.func) ();
597 	    CurrentCmdData = NULL;
598 	}
599     }
600     else if (mselect == MENU_CLOSE) {
601 	if (menu->parent != NULL)
602 	    menu->parent->active = 0;
603     }
604     return (0);
605 }
606 
607 void
popup_menu(Menu * parent,Menu * menu)608 popup_menu(Menu *parent, Menu *menu)
609 {
610     int active = 1;
611 
612     if (menu->item == NULL || menu->nitem == 0)
613 	return;
614     if (menu->active)
615 	return;
616 
617 #ifdef USE_MOUSE
618 #ifdef USE_GPM
619     gpm_handler = gpm_process_menu_mouse;
620 #endif				/* USE_GPM */
621 #ifdef USE_SYSMOUSE
622     sysm_handler = sysm_process_menu_mouse;
623 #endif				/* USE_SYSMOUSE */
624 #endif				/* USE_MOUSE */
625     menu->parent = parent;
626     menu->select = menu->initial;
627     menu->offset = 0;
628     menu->active = 1;
629     if (parent != NULL) {
630 	menu->cursorX = parent->cursorX;
631 	menu->cursorY = parent->cursorY;
632 	guess_menu_xy(parent, menu->width, &menu->x, &menu->y);
633     }
634     geom_menu(menu, menu->x, menu->y, menu->select);
635 
636     CurrentMenu = menu;
637     while (active) {
638 	active = action_menu(CurrentMenu);
639 	displayBuffer(Currentbuf, B_FORCE_REDRAW);
640     }
641     menu->active = 0;
642     CurrentMenu = parent;
643 #ifdef USE_MOUSE
644 #ifdef USE_GPM
645     if (CurrentMenu == NULL)
646 	gpm_handler = gpm_process_mouse;
647 #endif				/* USE_GPM */
648 #ifdef USE_SYSMOUSE
649     if (CurrentMenu == NULL)
650 	sysm_handler = sysm_process_mouse;
651 #endif				/* USE_SYSMOUSE */
652 #endif				/* USE_MOUSE */
653 }
654 
655 void
guess_menu_xy(Menu * parent,int width,int * x,int * y)656 guess_menu_xy(Menu *parent, int width, int *x, int *y)
657 {
658     *x = parent->x + parent->width + FRAME_WIDTH - 1;
659     if (*x + width + FRAME_WIDTH > COLS) {
660 	*x = COLS - width - FRAME_WIDTH;
661 	if ((parent->x + parent->width / 2 > *x) &&
662 	    (parent->x + parent->width / 2 > COLS / 2))
663 	    *x = parent->x - width - FRAME_WIDTH + 1;
664     }
665     *y = parent->y + parent->select - parent->offset;
666 }
667 
668 void
new_option_menu(Menu * menu,char ** label,int * variable,void (* func)())669 new_option_menu(Menu *menu, char **label, int *variable, void (*func) ())
670 {
671     int i, nitem;
672     char **p;
673     MenuItem *item;
674 
675     if (label == NULL || *label == NULL)
676 	return;
677 
678     for (i = 0, p = label; *p != NULL; i++, p++) ;
679     nitem = i;
680 
681     item = New_N(MenuItem, nitem + 1);
682 
683     for (i = 0, p = label; i < nitem; i++, p++) {
684 	if (func != NULL)
685 	    item[i].type = MENU_VALUE | MENU_FUNC;
686 	else
687 	    item[i].type = MENU_VALUE;
688 	item[i].label = *p;
689 	item[i].variable = variable;
690 	item[i].value = i;
691 	item[i].func = func;
692 	item[i].popup = NULL;
693 	item[i].keys = "";
694     }
695     item[nitem].type = MENU_END;
696 
697     new_menu(menu, item);
698 }
699 
700 static void
set_menu_frame(void)701 set_menu_frame(void)
702 {
703     if (graph_ok()) {
704 	graph_mode = TRUE;
705 	FRAME_WIDTH = 1;
706 	FRAME = graph_symbol;
707     }
708     else {
709 	graph_mode = FALSE;
710 #ifdef USE_M17N
711 	FRAME_WIDTH = 0;
712 	FRAME = get_symbol(DisplayCharset, &FRAME_WIDTH);
713 	if (!WcOption.use_wide)
714 	    FRAME_WIDTH = 1;
715 #else
716 	FRAME_WIDTH = 1;
717 	FRAME = get_symbol();
718 #endif
719     }
720 }
721 
722 /* --- MenuFunctions --- */
723 
724 #ifdef __EMX__
725 static int
mPc(char c)726 mPc(char c)
727 {
728     c = getch();
729     return (MenuPcKeymap[(int)c] (c));
730 }
731 #endif
732 
733 static int
mEsc(char c)734 mEsc(char c)
735 {
736     c = getch();
737     return (MenuEscKeymap[(int)c] (c));
738 }
739 
740 static int
mEscB(char c)741 mEscB(char c)
742 {
743     c = getch();
744     if (IS_DIGIT(c))
745 	return (mEscD(c));
746     else
747 	return (MenuEscBKeymap[(int)c] (c));
748 }
749 
750 static int
mEscD(char c)751 mEscD(char c)
752 {
753     int d;
754 
755     d = (int)c - (int)'0';
756     c = getch();
757     if (IS_DIGIT(c)) {
758 	d = d * 10 + (int)c - (int)'0';
759 	c = getch();
760     }
761     if (c == '~')
762 	return (MenuEscDKeymap[d] (c));
763     else
764 	return (MENU_NOTHING);
765 }
766 
767 static int
mNull(char c)768 mNull(char c)
769 {
770     return (MENU_NOTHING);
771 }
772 
773 static int
mSelect(char c)774 mSelect(char c)
775 {
776     if (IS_ASCII(c))
777 	return (select_menu(CurrentMenu, CurrentMenu->keyselect[(int)c]));
778     else
779 	return (MENU_NOTHING);
780 }
781 
782 static int
mDown(char c)783 mDown(char c)
784 {
785     if (CurrentMenu->select >= CurrentMenu->nitem - 1)
786 	return (MENU_NOTHING);
787     goto_menu(CurrentMenu, CurrentMenu->select + 1, 1);
788     return (MENU_NOTHING);
789 }
790 
791 static int
mUp(char c)792 mUp(char c)
793 {
794     if (CurrentMenu->select <= 0)
795 	return (MENU_NOTHING);
796     goto_menu(CurrentMenu, CurrentMenu->select - 1, -1);
797     return (MENU_NOTHING);
798 }
799 
800 static int
mLast(char c)801 mLast(char c)
802 {
803     goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
804     return (MENU_NOTHING);
805 }
806 
807 static int
mTop(char c)808 mTop(char c)
809 {
810     goto_menu(CurrentMenu, 0, 1);
811     return (MENU_NOTHING);
812 }
813 
814 static int
mNext(char c)815 mNext(char c)
816 {
817     int mselect = CurrentMenu->select + CurrentMenu->height;
818 
819     if (mselect >= CurrentMenu->nitem)
820 	return mLast(c);
821     down_menu(CurrentMenu, CurrentMenu->height);
822     goto_menu(CurrentMenu, mselect, -1);
823     return (MENU_NOTHING);
824 }
825 
826 static int
mPrev(char c)827 mPrev(char c)
828 {
829     int mselect = CurrentMenu->select - CurrentMenu->height;
830 
831     if (mselect < 0)
832 	return mTop(c);
833     up_menu(CurrentMenu, CurrentMenu->height);
834     goto_menu(CurrentMenu, mselect, 1);
835     return (MENU_NOTHING);
836 }
837 
838 static int
mFore(char c)839 mFore(char c)
840 {
841     if (CurrentMenu->select >= CurrentMenu->nitem - 1)
842 	return (MENU_NOTHING);
843     goto_menu(CurrentMenu, (CurrentMenu->select + CurrentMenu->height - 1),
844 	      (CurrentMenu->height + 1));
845     return (MENU_NOTHING);
846 }
847 
848 static int
mBack(char c)849 mBack(char c)
850 {
851     if (CurrentMenu->select <= 0)
852 	return (MENU_NOTHING);
853     goto_menu(CurrentMenu, (CurrentMenu->select - CurrentMenu->height + 1),
854 	      (-1 - CurrentMenu->height));
855     return (MENU_NOTHING);
856 }
857 
858 static int
mLineU(char c)859 mLineU(char c)
860 {
861     int mselect = CurrentMenu->select;
862 
863     if (mselect >= CurrentMenu->nitem)
864 	return mLast(c);
865     if (CurrentMenu->offset + CurrentMenu->height >= CurrentMenu->nitem)
866 	mselect++;
867     else {
868 	down_menu(CurrentMenu, 1);
869 	if (mselect < CurrentMenu->offset)
870 	    mselect++;
871     }
872     goto_menu(CurrentMenu, mselect, 1);
873     return (MENU_NOTHING);
874 }
875 
876 static int
mLineD(char c)877 mLineD(char c)
878 {
879     int mselect = CurrentMenu->select;
880 
881     if (mselect <= 0)
882 	return mTop(c);
883     if (CurrentMenu->offset <= 0)
884 	mselect--;
885     else {
886 	up_menu(CurrentMenu, 1);
887 	if (mselect >= CurrentMenu->offset + CurrentMenu->height)
888 	    mselect--;
889     }
890     goto_menu(CurrentMenu, mselect, -1);
891     return (MENU_NOTHING);
892 }
893 
894 static int
mOk(char c)895 mOk(char c)
896 {
897     int mselect = CurrentMenu->select;
898 
899     if (CurrentMenu->item[mselect].type == MENU_NOP)
900 	return (MENU_NOTHING);
901     return (mselect);
902 }
903 
904 static int
mCancel(char c)905 mCancel(char c)
906 {
907     return (MENU_CANCEL);
908 }
909 
910 static int
mClose(char c)911 mClose(char c)
912 {
913     return (MENU_CLOSE);
914 }
915 
916 static int
mSusp(char c)917 mSusp(char c)
918 {
919     susp();
920     draw_all_menu(CurrentMenu);
921     select_menu(CurrentMenu, CurrentMenu->select);
922     return (MENU_NOTHING);
923 }
924 
925 static char *SearchString = NULL;
926 
927 int (*menuSearchRoutine) (Menu *, char *, int);
928 
929 static int
menuForwardSearch(Menu * menu,char * str,int from)930 menuForwardSearch(Menu *menu, char *str, int from)
931 {
932     int i;
933     char *p;
934     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
935 	message(p, 0, 0);
936 	return -1;
937     }
938     if (from < 0)
939 	from = 0;
940     for (i = from; i < menu->nitem; i++)
941 	if (menu->item[i].type != MENU_NOP &&
942 	    regexMatch(menu->item[i].label, -1, 1) == 1)
943 	    return i;
944     return -1;
945 }
946 
947 static int
menu_search_forward(Menu * menu,int from)948 menu_search_forward(Menu *menu, int from)
949 {
950     char *str;
951     int found;
952     str = inputStrHist("Forward: ", NULL, TextHist);
953     if (str != NULL && *str == '\0')
954 	str = SearchString;
955     if (str == NULL || *str == '\0')
956 	return -1;
957     SearchString = str;
958     str = conv_search_string(str, DisplayCharset);
959     menuSearchRoutine = menuForwardSearch;
960     found = menuForwardSearch(menu, str, from + 1);
961     if (WrapSearch && found == -1)
962 	found = menuForwardSearch(menu, str, 0);
963     if (found >= 0)
964 	return found;
965     disp_message("Not found", TRUE);
966     return -1;
967 }
968 
969 static int
mSrchF(char c)970 mSrchF(char c)
971 {
972     int mselect;
973     mselect = menu_search_forward(CurrentMenu, CurrentMenu->select);
974     if (mselect >= 0)
975 	goto_menu(CurrentMenu, mselect, 1);
976     return (MENU_NOTHING);
977 }
978 
979 static int
menuBackwardSearch(Menu * menu,char * str,int from)980 menuBackwardSearch(Menu *menu, char *str, int from)
981 {
982     int i;
983     char *p;
984     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
985 	message(p, 0, 0);
986 	return -1;
987     }
988     if (from >= menu->nitem)
989 	from = menu->nitem - 1;
990     for (i = from; i >= 0; i--)
991 	if (menu->item[i].type != MENU_NOP &&
992 	    regexMatch(menu->item[i].label, -1, 1) == 1)
993 	    return i;
994     return -1;
995 }
996 
997 static int
menu_search_backward(Menu * menu,int from)998 menu_search_backward(Menu *menu, int from)
999 {
1000     char *str;
1001     int found;
1002     str = inputStrHist("Backward: ", NULL, TextHist);
1003     if (str != NULL && *str == '\0')
1004 	str = SearchString;
1005     if (str == NULL || *str == '\0')
1006 	return -1;
1007     SearchString = str;
1008     str = conv_search_string(str, DisplayCharset);
1009     menuSearchRoutine = menuBackwardSearch;
1010     found = menuBackwardSearch(menu, str, from - 1);
1011     if (WrapSearch && found == -1)
1012 	found = menuBackwardSearch(menu, str, menu->nitem);
1013     if (found >= 0)
1014 	return found;
1015     disp_message("Not found", TRUE);
1016     return -1;
1017 }
1018 
1019 static int
mSrchB(char c)1020 mSrchB(char c)
1021 {
1022     int mselect;
1023     mselect = menu_search_backward(CurrentMenu, CurrentMenu->select);
1024     if (mselect >= 0)
1025 	goto_menu(CurrentMenu, mselect, -1);
1026     return (MENU_NOTHING);
1027 }
1028 
1029 static int
menu_search_next_previous(Menu * menu,int from,int reverse)1030 menu_search_next_previous(Menu *menu, int from, int reverse)
1031 {
1032     int found;
1033     static int (*routine[2]) (Menu *, char *, int) = {
1034     menuForwardSearch, menuBackwardSearch};
1035     char *str;
1036 
1037     if (menuSearchRoutine == NULL) {
1038 	disp_message("No previous regular expression", TRUE);
1039 	return -1;
1040     }
1041     str = conv_search_string(SearchString, DisplayCharset);
1042     if (reverse != 0)
1043 	reverse = 1;
1044     if (menuSearchRoutine == menuBackwardSearch)
1045 	reverse ^= 1;
1046     from += reverse ? -1 : 1;
1047     found = (*routine[reverse]) (menu, str, from);
1048     if (WrapSearch && found == -1)
1049 	found = (*routine[reverse]) (menu, str, reverse * menu->nitem);
1050     if (found >= 0)
1051 	return found;
1052     disp_message("Not found", TRUE);
1053     return -1;
1054 }
1055 
1056 static int
mSrchN(char c)1057 mSrchN(char c)
1058 {
1059     int mselect;
1060     mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 0);
1061     if (mselect >= 0)
1062 	goto_menu(CurrentMenu, mselect, 1);
1063     return (MENU_NOTHING);
1064 }
1065 
1066 static int
mSrchP(char c)1067 mSrchP(char c)
1068 {
1069     int mselect;
1070     mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 1);
1071     if (mselect >= 0)
1072 	goto_menu(CurrentMenu, mselect, -1);
1073     return (MENU_NOTHING);
1074 }
1075 
1076 #ifdef USE_MOUSE
1077 #define MOUSE_BTN1_DOWN 0
1078 #define MOUSE_BTN2_DOWN 1
1079 #define MOUSE_BTN3_DOWN 2
1080 #define MOUSE_BTN4_DOWN_RXVT 3
1081 #define MOUSE_BTN5_DOWN_RXVT 4
1082 #define MOUSE_BTN4_DOWN_XTERM 64
1083 #define MOUSE_BTN5_DOWN_XTERM 65
1084 #define MOUSE_BTN_UP 3
1085 #define MOUSE_BTN_RESET -1
1086 
1087 static int
mMouse_scroll_line(void)1088 mMouse_scroll_line(void)
1089 {
1090     int i = 0;
1091     if (relative_wheel_scroll)
1092 	i = (relative_wheel_scroll_ratio * CurrentMenu->height + 99) / 100;
1093     else
1094 	i = fixed_wheel_scroll_count;
1095     return i ? i : 1;
1096 }
1097 
1098 static int
process_mMouse(int btn,int x,int y)1099 process_mMouse(int btn, int x, int y)
1100 {
1101     Menu *menu;
1102     int mselect, i;
1103     static int press_btn = MOUSE_BTN_RESET, press_x, press_y;
1104     char c = ' ';
1105 
1106     menu = CurrentMenu;
1107 
1108     if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
1109 	return (MENU_NOTHING);
1110 
1111     if (btn == MOUSE_BTN_UP) {
1112 	switch (press_btn) {
1113 	case MOUSE_BTN1_DOWN:
1114 	case MOUSE_BTN3_DOWN:
1115 	    if (x < menu->x - FRAME_WIDTH ||
1116 		x >= menu->x + menu->width + FRAME_WIDTH ||
1117 		y < menu->y - 1 || y >= menu->y + menu->height + 1) {
1118 		return (MENU_CANCEL);
1119 	    }
1120 	    else if ((x >= menu->x - FRAME_WIDTH &&
1121 		      x < menu->x) ||
1122 		     (x >= menu->x + menu->width &&
1123 		      x < menu->x + menu->width + FRAME_WIDTH)) {
1124 		return (MENU_NOTHING);
1125 	    }
1126 	    else if (press_y > y) {
1127 		for (i = 0; i < press_y - y; i++)
1128 		    mLineU(c);
1129 		return (MENU_NOTHING);
1130 	    }
1131 	    else if (press_y < y) {
1132 		for (i = 0; i < y - press_y; i++)
1133 		    mLineD(c);
1134 		return (MENU_NOTHING);
1135 	    }
1136 	    else if (y == menu->y - 1) {
1137 		mPrev(c);
1138 		return (MENU_NOTHING);
1139 	    }
1140 	    else if (y == menu->y + menu->height) {
1141 		mNext(c);
1142 		return (MENU_NOTHING);
1143 	    }
1144 	    else {
1145 		mselect = y - menu->y + menu->offset;
1146 		if (menu->item[mselect].type == MENU_NOP)
1147 		    return (MENU_NOTHING);
1148 		return (select_menu(menu, mselect));
1149 	    }
1150 	    break;
1151 	case MOUSE_BTN4_DOWN_RXVT:
1152 	    for (i = 0; i < mMouse_scroll_line(); i++)
1153 		mLineD(c);
1154 	    break;
1155 	case MOUSE_BTN5_DOWN_RXVT:
1156 	    for (i = 0; i < mMouse_scroll_line(); i++)
1157 		mLineU(c);
1158 	    break;
1159 	}
1160     }
1161     else if (btn == MOUSE_BTN4_DOWN_XTERM) {
1162 	for (i = 0; i < mMouse_scroll_line(); i++)
1163 	    mLineD(c);
1164     }
1165     else if (btn == MOUSE_BTN5_DOWN_XTERM) {
1166 	for (i = 0; i < mMouse_scroll_line(); i++)
1167 	    mLineU(c);
1168     }
1169 
1170     if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) {
1171 	press_btn = btn;
1172 	press_x = x;
1173 	press_y = y;
1174     }
1175     else {
1176 	press_btn = MOUSE_BTN_RESET;
1177     }
1178     return (MENU_NOTHING);
1179 }
1180 
1181 static int
mMouse(char c)1182 mMouse(char c)
1183 {
1184     int btn, x, y;
1185 
1186     btn = (unsigned char)getch() - 32;
1187 #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
1188     if (cygwin_mouse_btn_swapped) {
1189 	if (btn == MOUSE_BTN2_DOWN)
1190 	    btn = MOUSE_BTN3_DOWN;
1191 	else if (btn == MOUSE_BTN3_DOWN)
1192 	    btn = MOUSE_BTN2_DOWN;
1193     }
1194 #endif
1195     x = (unsigned char)getch() - 33;
1196     if (x < 0)
1197 	x += 0x100;
1198     y = (unsigned char)getch() - 33;
1199     if (y < 0)
1200 	y += 0x100;
1201 
1202     /*
1203      * if (x < 0 || x >= COLS || y < 0 || y > LASTLINE) return; */
1204     return process_mMouse(btn, x, y);
1205 }
1206 
1207 static int
mSgrMouse(char c)1208 mSgrMouse(char c)
1209 {
1210     int btn = 0, x = 0, y = 0;
1211     unsigned char ch;
1212 
1213     for (ch = getch(); IS_DIGIT(ch); ch = getch())
1214 	btn = btn * 10 + ch - '0';
1215     if (ch != ';')
1216 	return MENU_NOTHING;
1217 
1218 #if defined (__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
1219     if (cygwin_mouse_btn_swapped) {
1220 	if (btn == MOUSE_BTN2_DOWN)
1221 	    btn = MOUSE_BTN3_DOWN;
1222 	else if (btn == MOUSE_BTN3_DOWN)
1223 	    btn = MOUSE_BTN2_DOWN;
1224     }
1225 #endif
1226 
1227     for (ch = getch(); IS_DIGIT(ch); ch = getch())
1228 	x = x * 10 + ch - '0';
1229     if (ch != ';')
1230 	return MENU_NOTHING;
1231     if (x > 0)
1232 	x--;
1233 
1234     for (ch = getch(); IS_DIGIT(ch); ch = getch())
1235 	y = y * 10 + ch - '0';
1236     if (ch == 'm')
1237 	btn |= 3;
1238     else if (ch != 'M' && ch != ';')
1239 	return MENU_NOTHING;
1240     if (y > 0)
1241 	y--;
1242 
1243     if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
1244 	return MENU_NOTHING;
1245 
1246     return process_mMouse(btn, x, y);
1247 }
1248 
1249 #ifdef USE_GPM
1250 static int
gpm_process_menu_mouse(Gpm_Event * event,void * data)1251 gpm_process_menu_mouse(Gpm_Event * event, void *data)
1252 {
1253     int btn = MOUSE_BTN_RESET, x, y;
1254     if (event->type & GPM_UP)
1255 	btn = MOUSE_BTN_UP;
1256     else if (event->type & GPM_DOWN) {
1257 	switch (event->buttons) {
1258 	case GPM_B_LEFT:
1259 	    btn = MOUSE_BTN1_DOWN;
1260 	    break;
1261 	case GPM_B_MIDDLE:
1262 	    btn = MOUSE_BTN2_DOWN;
1263 	    break;
1264 	case GPM_B_RIGHT:
1265 	    btn = MOUSE_BTN3_DOWN;
1266 	    break;
1267 	}
1268     }
1269     else {
1270 	GPM_DRAWPOINTER(event);
1271 	return 0;
1272     }
1273     x = event->x;
1274     y = event->y;
1275     X_Mouse_Selection = process_mMouse(btn, x - 1, y - 1);
1276     return X_MOUSE_SELECTED;
1277 }
1278 #endif				/* USE_GPM */
1279 
1280 #ifdef USE_SYSMOUSE
1281 static int
sysm_process_menu_mouse(int x,int y,int nbs,int obs)1282 sysm_process_menu_mouse(int x, int y, int nbs, int obs)
1283 {
1284     int btn;
1285     int bits;
1286 
1287     if (obs & ~nbs)
1288 	btn = MOUSE_BTN_UP;
1289     else if (nbs & ~obs) {
1290 	bits = nbs & ~obs;
1291 	btn = bits & 0x1 ? MOUSE_BTN1_DOWN :
1292 	    (bits & 0x2 ? MOUSE_BTN2_DOWN :
1293 	     (bits & 0x4 ? MOUSE_BTN3_DOWN : 0));
1294     }
1295     else			/* nbs == obs */
1296 	return 0;
1297     X_Mouse_Selection = process_mMouse(btn, x, y);
1298     return X_MOUSE_SELECTED;
1299 }
1300 #endif				/* USE_SYSMOUSE */
1301 #else				/* not USE_MOUSE */
1302 static int
mMouse(char c)1303 mMouse(char c)
1304 {
1305     return (MENU_NOTHING);
1306 }
1307 
1308 static int
mSgrMouse(char c)1309 mSgrMouse(char c)
1310 {
1311     return (MENU_NOTHING);
1312 }
1313 #endif				/* not USE_MOUSE */
1314 
1315 /* --- MenuFunctions (END) --- */
1316 
1317 /* --- MainMenu --- */
1318 
1319 void
popupMenu(int x,int y,Menu * menu)1320 popupMenu(int x, int y, Menu *menu)
1321 {
1322     set_menu_frame();
1323 
1324     initSelectMenu();
1325     initSelTabMenu();
1326 
1327     menu->cursorX = Currentbuf->cursorX + Currentbuf->rootX;
1328     menu->cursorY = Currentbuf->cursorY + Currentbuf->rootY;
1329     menu->x = x + FRAME_WIDTH + 1;
1330     menu->y = y + 2;
1331 
1332     popup_menu(NULL, menu);
1333 }
1334 
1335 void
mainMenu(int x,int y)1336 mainMenu(int x, int y)
1337 {
1338     popupMenu(x, y, &MainMenu);
1339 }
1340 
1341 DEFUN(mainMn, MAIN_MENU MENU, "Pop up menu")
1342 {
1343     Menu *menu = &MainMenu;
1344     char *data;
1345     int n;
1346     int x = Currentbuf->cursorX + Currentbuf->rootX,
1347 	y = Currentbuf->cursorY + Currentbuf->rootY;
1348 
1349     data = searchKeyData();
1350     if (data != NULL) {
1351 	n = getMenuN(w3mMenuList, data);
1352 	if (n < 0)
1353 	    return;
1354 	menu = w3mMenuList[n].menu;
1355     }
1356 #ifdef USE_MOUSE
1357     if (mouse_action.in_action) {
1358 	x = mouse_action.cursorX;
1359 	y = mouse_action.cursorY;
1360     }
1361 #endif
1362     popupMenu(x, y, menu);
1363 }
1364 
1365 /* --- MainMenu (END) --- */
1366 
1367 /* --- SelectMenu --- */
1368 
1369 DEFUN(selMn, SELECT_MENU, "Pop up buffer-stack menu")
1370 {
1371     int x = Currentbuf->cursorX + Currentbuf->rootX,
1372 	y = Currentbuf->cursorY + Currentbuf->rootY;
1373 
1374 #ifdef USE_MOUSE
1375     if (mouse_action.in_action) {
1376 	x = mouse_action.cursorX;
1377 	y = mouse_action.cursorY;
1378     }
1379 #endif
1380     popupMenu(x, y, &SelectMenu);
1381 }
1382 
1383 static void
initSelectMenu(void)1384 initSelectMenu(void)
1385 {
1386     int i, nitem, len = 0, l;
1387     Buffer *buf;
1388     Str str;
1389     char **label;
1390     char *p;
1391     static char *comment = " SPC for select / D for delete buffer ";
1392 
1393     SelectV = -1;
1394     for (i = 0, buf = Firstbuf; buf != NULL; i++, buf = buf->nextBuffer) {
1395 	if (buf == Currentbuf)
1396 	    SelectV = i;
1397     }
1398     nitem = i;
1399 
1400     label = New_N(char *, nitem + 2);
1401     for (i = 0, buf = Firstbuf; i < nitem; i++, buf = buf->nextBuffer) {
1402 	str = Sprintf("<%s>", buf->buffername);
1403 	if (buf->filename != NULL) {
1404 	    switch (buf->currentURL.scheme) {
1405 	    case SCM_LOCAL:
1406 		if (strcmp(buf->currentURL.file, "-")) {
1407 		    Strcat_char(str, ' ');
1408 		    Strcat_charp(str,
1409 				 conv_from_system(buf->currentURL.real_file));
1410 		}
1411 		break;
1412 		/* case SCM_UNKNOWN: */
1413 	    case SCM_MISSING:
1414 		break;
1415 	    default:
1416 		Strcat_char(str, ' ');
1417 		p = url_decode2(parsedURL2Str(&buf->currentURL)->ptr, NULL);
1418 		Strcat_charp(str, p);
1419 		break;
1420 	    }
1421 	}
1422 	label[i] = str->ptr;
1423 	if (len < str->length)
1424 	    len = str->length;
1425     }
1426     l = get_strwidth(comment);
1427     if (len < l + 4)
1428 	len = l + 4;
1429     if (len > COLS - 2 * FRAME_WIDTH)
1430 	len = COLS - 2 * FRAME_WIDTH;
1431     len = (len > 1) ? ((len - l + 1) / 2) : 0;
1432     str = Strnew();
1433     for (i = 0; i < len; i++)
1434 	Strcat_char(str, '-');
1435     Strcat_charp(str, comment);
1436     for (i = 0; i < len; i++)
1437 	Strcat_char(str, '-');
1438     label[nitem] = str->ptr;
1439     label[nitem + 1] = NULL;
1440 
1441     new_option_menu(&SelectMenu, label, &SelectV, smChBuf);
1442     SelectMenu.initial = SelectV;
1443     SelectMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
1444     SelectMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
1445     SelectMenu.keymap['D'] = smDelBuf;
1446     SelectMenu.item[nitem].type = MENU_NOP;
1447 }
1448 
1449 static void
smChBuf(void)1450 smChBuf(void)
1451 {
1452     int i;
1453     Buffer *buf;
1454 
1455     if (SelectV < 0 || SelectV >= SelectMenu.nitem)
1456 	return;
1457     for (i = 0, buf = Firstbuf; i < SelectV; i++, buf = buf->nextBuffer) ;
1458     Currentbuf = buf;
1459     for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) {
1460 	if (buf == Currentbuf)
1461 	    continue;
1462 #ifdef USE_IMAGE
1463 	deleteImage(buf);
1464 #endif
1465 	if (clear_buffer)
1466 	    tmpClearBuffer(buf);
1467     }
1468 }
1469 
1470 static int
smDelBuf(char c)1471 smDelBuf(char c)
1472 {
1473     int i, x, y, mselect;
1474     Buffer *buf;
1475 
1476     if (CurrentMenu->select < 0 || CurrentMenu->select >= SelectMenu.nitem)
1477 	return (MENU_NOTHING);
1478     for (i = 0, buf = Firstbuf; i < CurrentMenu->select;
1479 	 i++, buf = buf->nextBuffer) ;
1480     if (Currentbuf == buf)
1481 	Currentbuf = buf->nextBuffer;
1482     Firstbuf = deleteBuffer(Firstbuf, buf);
1483     if (!Currentbuf)
1484 	Currentbuf = nthBuffer(Firstbuf, i - 1);;
1485     if (Firstbuf == NULL) {
1486 	Firstbuf = nullBuffer();
1487 	Currentbuf = Firstbuf;
1488     }
1489 
1490     x = CurrentMenu->x;
1491     y = CurrentMenu->y;
1492     mselect = CurrentMenu->select;
1493 
1494     initSelectMenu();
1495 
1496     CurrentMenu->x = x;
1497     CurrentMenu->y = y;
1498 
1499     geom_menu(CurrentMenu, x, y, 0);
1500 
1501     CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
1502 	: (CurrentMenu->nitem - 2);
1503 
1504     displayBuffer(Currentbuf, B_FORCE_REDRAW);
1505     draw_all_menu(CurrentMenu);
1506     select_menu(CurrentMenu, CurrentMenu->select);
1507     return (MENU_NOTHING);
1508 }
1509 
1510 /* --- SelectMenu (END) --- */
1511 
1512 /* --- SelTabMenu --- */
1513 
1514 DEFUN(tabMn, TAB_MENU, "Pop up tab selection menu")
1515 {
1516     int x = Currentbuf->cursorX + Currentbuf->rootX,
1517 	y = Currentbuf->cursorY + Currentbuf->rootY;
1518 
1519 #ifdef USE_MOUSE
1520     if (mouse_action.in_action) {
1521 	x = mouse_action.cursorX;
1522 	y = mouse_action.cursorY;
1523     }
1524 #endif
1525     popupMenu(x, y, &SelTabMenu);
1526 }
1527 
1528 static void
initSelTabMenu(void)1529 initSelTabMenu(void)
1530 {
1531     int i, nitem, len = 0, l;
1532     TabBuffer *tab;
1533     Buffer *buf;
1534     Str str;
1535     char **label;
1536     char *p;
1537     static char *comment = " SPC for select / D for delete tab ";
1538 
1539     SelTabV = -1;
1540     for (i = 0, tab = LastTab; tab != NULL; i++, tab = tab->prevTab) {
1541 	if (tab == CurrentTab)
1542 	    SelTabV = i;
1543     }
1544     nitem = i;
1545 
1546     label = New_N(char *, nitem + 2);
1547     for (i = 0, tab = LastTab; i < nitem; i++, tab = tab->prevTab) {
1548 	buf = tab->currentBuffer;
1549 	str = Sprintf("<%s>", buf->buffername);
1550 	if (buf->filename != NULL) {
1551 	    switch (buf->currentURL.scheme) {
1552 	    case SCM_LOCAL:
1553 		if (strcmp(buf->currentURL.file, "-")) {
1554 		    Strcat_char(str, ' ');
1555 		    Strcat_charp(str,
1556 				 conv_from_system(buf->currentURL.real_file));
1557 		}
1558 		break;
1559 		/* case SCM_UNKNOWN: */
1560 	    case SCM_MISSING:
1561 		break;
1562 	    default:
1563 		p = url_decode2(parsedURL2Str(&buf->currentURL)->ptr, NULL);
1564 		Strcat_charp(str, p);
1565 		break;
1566 	    }
1567 	}
1568 	label[i] = str->ptr;
1569 	if (len < str->length)
1570 	    len = str->length;
1571     }
1572     l = strlen(comment);
1573     if (len < l + 4)
1574 	len = l + 4;
1575     if (len > COLS - 2 * FRAME_WIDTH)
1576 	len = COLS - 2 * FRAME_WIDTH;
1577     len = (len > 1) ? ((len - l + 1) / 2) : 0;
1578     str = Strnew();
1579     for (i = 0; i < len; i++)
1580 	Strcat_char(str, '-');
1581     Strcat_charp(str, comment);
1582     for (i = 0; i < len; i++)
1583 	Strcat_char(str, '-');
1584     label[nitem] = str->ptr;
1585     label[nitem + 1] = NULL;
1586 
1587     new_option_menu(&SelTabMenu, label, &SelTabV, smChTab);
1588     SelTabMenu.initial = SelTabV;
1589     SelTabMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
1590     SelTabMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
1591     SelTabMenu.keymap['D'] = smDelTab;
1592     SelTabMenu.item[nitem].type = MENU_NOP;
1593 }
1594 
1595 static void
smChTab(void)1596 smChTab(void)
1597 {
1598     int i;
1599     TabBuffer *tab;
1600     Buffer *buf;
1601 
1602     if (SelTabV < 0 || SelTabV >= SelTabMenu.nitem)
1603 	return;
1604     for (i = 0, tab = LastTab; i < SelTabV && tab != NULL;
1605 	 i++, tab = tab->prevTab) ;
1606     CurrentTab = tab;
1607     for (tab = LastTab; tab != NULL; tab = tab->prevTab) {
1608 	if (tab == CurrentTab)
1609 	    continue;
1610 	buf = tab->currentBuffer;
1611 #ifdef USE_IMAGE
1612 	deleteImage(buf);
1613 #endif
1614 	if (clear_buffer)
1615 	    tmpClearBuffer(buf);
1616     }
1617 }
1618 
1619 static int
smDelTab(char c)1620 smDelTab(char c)
1621 {
1622     int i, x, y, mselect;
1623     TabBuffer *tab;
1624 
1625     if (CurrentMenu->select < 0 || CurrentMenu->select >= SelTabMenu.nitem)
1626 	return (MENU_NOTHING);
1627     for (i = 0, tab = LastTab; i < CurrentMenu->select && tab != NULL;
1628 	 i++, tab = tab->prevTab) ;
1629     deleteTab(tab);
1630 
1631     x = CurrentMenu->x;
1632     y = CurrentMenu->y;
1633     mselect = CurrentMenu->select;
1634 
1635     initSelTabMenu();
1636 
1637     CurrentMenu->x = x;
1638     CurrentMenu->y = y;
1639 
1640     geom_menu(CurrentMenu, x, y, 0);
1641 
1642     CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
1643 	: (CurrentMenu->nitem - 2);
1644 
1645     displayBuffer(Currentbuf, B_FORCE_REDRAW);
1646     draw_all_menu(CurrentMenu);
1647     select_menu(CurrentMenu, CurrentMenu->select);
1648     return (MENU_NOTHING);
1649 }
1650 
1651 /* --- SelectMenu (END) --- */
1652 
1653 /* --- OptionMenu --- */
1654 
1655 void
optionMenu(int x,int y,char ** label,int * variable,int initial,void (* func)())1656 optionMenu(int x, int y, char **label, int *variable, int initial,
1657 	   void (*func) ())
1658 {
1659     Menu menu;
1660 
1661     set_menu_frame();
1662 
1663     new_option_menu(&menu, label, variable, func);
1664     menu.cursorX = COLS - 1;
1665     menu.cursorY = LASTLINE;
1666     menu.x = x;
1667     menu.y = y;
1668     menu.initial = initial;
1669 
1670     popup_menu(NULL, &menu);
1671 }
1672 
1673 /* --- OptionMenu (END) --- */
1674 
1675 /* --- InitMenu --- */
1676 
1677 static void
interpret_menu(FILE * mf)1678 interpret_menu(FILE * mf)
1679 {
1680     Str line;
1681     char *p, *s;
1682     int in_menu = 0, nmenu = 0, nitem = 0, type;
1683     MenuItem *item = NULL;
1684 #ifdef USE_M17N
1685     wc_ces charset = SystemCharset;
1686 #endif
1687 
1688     while (!feof(mf)) {
1689 	line = Strfgets(mf);
1690 	Strchop(line);
1691 	Strremovefirstspaces(line);
1692 	if (line->length == 0)
1693 	    continue;
1694 #ifdef USE_M17N
1695 	line = wc_Str_conv(line, charset, InnerCharset);
1696 #endif
1697 	p = line->ptr;
1698 	s = getWord(&p);
1699 	if (*s == '#')		/* comment */
1700 	    continue;
1701 	if (in_menu) {
1702 	    type = setMenuItem(&item[nitem], s, p);
1703 	    if (type == -1)
1704 		continue;	/* error */
1705 	    if (type == MENU_END)
1706 		in_menu = 0;
1707 	    else {
1708 		nitem++;
1709 		item = New_Reuse(MenuItem, item, (nitem + 1));
1710 		w3mMenuList[nmenu].item = item;
1711 		item[nitem].type = MENU_END;
1712 	    }
1713 	}
1714 	else if (!strcmp(s, "menu")) {
1715 	    s = getQWord(&p);
1716 	    if (*s == '\0')	/* error */
1717 		continue;
1718 	    in_menu = 1;
1719 	    if ((nmenu = getMenuN(w3mMenuList, s)) != -1)
1720 		w3mMenuList[nmenu].item = New(MenuItem);
1721 	    else
1722 		nmenu = addMenuList(&w3mMenuList, s);
1723 	    item = w3mMenuList[nmenu].item;
1724 	    nitem = 0;
1725 	    item[nitem].type = MENU_END;
1726 	}
1727 #ifdef USE_M17N
1728 	else if (!strcmp(s, "charset") || !strcmp(s, "encoding")) {
1729 	    s = getQWord(&p);
1730 	    if (*s == '\0')	/* error */
1731 		continue;
1732 	    charset = wc_guess_charset(s, charset);
1733 	}
1734 #endif
1735     }
1736 }
1737 
1738 void
initMenu(void)1739 initMenu(void)
1740 {
1741     FILE *mf;
1742     MenuList *list;
1743 
1744     w3mMenuList = New_N(MenuList, 4);
1745     w3mMenuList[0].id = "Main";
1746     w3mMenuList[0].menu = &MainMenu;
1747     w3mMenuList[0].item = MainMenuItem;
1748     w3mMenuList[1].id = "Select";
1749     w3mMenuList[1].menu = &SelectMenu;
1750     w3mMenuList[1].item = NULL;
1751     w3mMenuList[2].id = "SelectTab";
1752     w3mMenuList[2].menu = &SelTabMenu;
1753     w3mMenuList[2].item = NULL;
1754     w3mMenuList[3].id = NULL;
1755 
1756 #ifdef USE_M17N
1757     if (!MainMenuEncode) {
1758 	MenuItem *item;
1759 #ifdef ENABLE_NLS
1760 	/* FIXME: charset that gettext(3) returns */
1761 	MainMenuCharset = SystemCharset;
1762 #endif
1763 	for (item = MainMenuItem; item->type != MENU_END; item++)
1764 	    item->label =
1765 		wc_conv(_(item->label), MainMenuCharset,
1766 			InnerCharset)->ptr;
1767 	MainMenuEncode = TRUE;
1768     }
1769 #endif
1770     if ((mf = fopen(confFile(MENU_FILE), "rt")) != NULL) {
1771 	interpret_menu(mf);
1772 	fclose(mf);
1773     }
1774     if ((mf = fopen(rcFile(MENU_FILE), "rt")) != NULL) {
1775 	interpret_menu(mf);
1776 	fclose(mf);
1777     }
1778 
1779     for (list = w3mMenuList; list->id != NULL; list++) {
1780 	if (list->item == NULL)
1781 	    continue;
1782 	new_menu(list->menu, list->item);
1783     }
1784 }
1785 
1786 int
setMenuItem(MenuItem * item,char * type,char * line)1787 setMenuItem(MenuItem *item, char *type, char *line)
1788 {
1789     char *label, *func, *popup, *keys, *data;
1790     int f;
1791     int n;
1792 
1793     if (type == NULL || *type == '\0')	/* error */
1794 	return -1;
1795     if (strcmp(type, "end") == 0) {
1796 	item->type = MENU_END;
1797 	return MENU_END;
1798     }
1799     else if (strcmp(type, "nop") == 0) {
1800 	item->type = MENU_NOP;
1801 	item->label = getQWord(&line);
1802 	return MENU_NOP;
1803     }
1804     else if (strcmp(type, "func") == 0) {
1805 	label = getQWord(&line);
1806 	func = getWord(&line);
1807 	keys = getQWord(&line);
1808 	data = getQWord(&line);
1809 	if (*func == '\0')	/* error */
1810 	    return -1;
1811 	item->type = MENU_FUNC;
1812 	item->label = label;
1813 	f = getFuncList(func);
1814 	item->func = w3mFuncList[(f >= 0) ? f : FUNCNAME_nulcmd].func;
1815 	item->keys = keys;
1816 	item->data = data;
1817 	return MENU_FUNC;
1818     }
1819     else if (strcmp(type, "popup") == 0) {
1820 	label = getQWord(&line);
1821 	popup = getQWord(&line);
1822 	keys = getQWord(&line);
1823 	if (*popup == '\0')	/* error */
1824 	    return -1;
1825 	item->type = MENU_POPUP;
1826 	item->label = label;
1827 	if ((n = getMenuN(w3mMenuList, popup)) == -1)
1828 	    n = addMenuList(&w3mMenuList, popup);
1829 	item->popup = w3mMenuList[n].menu;
1830 	item->keys = keys;
1831 	return MENU_POPUP;
1832     }
1833     return -1;			/* error */
1834 }
1835 
1836 int
addMenuList(MenuList ** mlist,char * id)1837 addMenuList(MenuList **mlist, char *id)
1838 {
1839     int n;
1840     MenuList *list = *mlist;
1841 
1842     for (n = 0; list->id != NULL; list++, n++) ;
1843     *mlist = New_Reuse(MenuList, *mlist, (n + 2));
1844     list = *mlist + n;
1845     list->id = id;
1846     list->menu = New(Menu);
1847     list->item = New(MenuItem);
1848     (list + 1)->id = NULL;
1849     return n;
1850 }
1851 
1852 int
getMenuN(MenuList * list,char * id)1853 getMenuN(MenuList *list, char *id)
1854 {
1855     int n;
1856 
1857     for (n = 0; list->id != NULL; list++, n++) {
1858 	if (strcmp(id, list->id) == 0)
1859 	    return n;
1860     }
1861     return -1;
1862 }
1863 
1864 /* --- InitMenu (END) --- */
1865 
1866 LinkList *
link_menu(Buffer * buf)1867 link_menu(Buffer *buf)
1868 {
1869     Menu menu;
1870     LinkList *l;
1871     int i, nitem, len = 0, linkV = -1;
1872     char **label;
1873     Str str;
1874     char *p;
1875 
1876     if (!buf->linklist)
1877 	return NULL;
1878 
1879     for (i = 0, l = buf->linklist; l; i++, l = l->next) ;
1880     nitem = i;
1881 
1882     label = New_N(char *, nitem + 1);
1883     for (i = 0, l = buf->linklist; l; i++, l = l->next) {
1884 	str = Strnew_charp(l->title ? l->title : "(empty)");
1885 	if (l->type == LINK_TYPE_REL)
1886 	    Strcat_charp(str, " [Rel] ");
1887 	else if (l->type == LINK_TYPE_REV)
1888 	    Strcat_charp(str, " [Rev] ");
1889 	else
1890 	    Strcat_charp(str, " ");
1891 	if (!l->url)
1892 	    p = "";
1893 	else
1894 	    p = url_decode2(l->url, buf);
1895 	Strcat_charp(str, p);
1896 	label[i] = str->ptr;
1897 	if (len < str->length)
1898 	    len = str->length;
1899     }
1900     label[nitem] = NULL;
1901 
1902     set_menu_frame();
1903     new_option_menu(&menu, label, &linkV, NULL);
1904 
1905     menu.initial = 0;
1906     menu.cursorX = buf->cursorX + buf->rootX;
1907     menu.cursorY = buf->cursorY + buf->rootY;
1908     menu.x = menu.cursorX + FRAME_WIDTH + 1;
1909     menu.y = menu.cursorY + 2;
1910 
1911     popup_menu(NULL, &menu);
1912 
1913     if (linkV < 0)
1914 	return NULL;
1915     for (i = 0, l = buf->linklist; l; i++, l = l->next) {
1916 	if (i == linkV)
1917 	    return l;
1918     }
1919     return NULL;
1920 }
1921 
1922 /* --- LinkMenu (END) --- */
1923 
1924 Anchor *
accesskey_menu(Buffer * buf)1925 accesskey_menu(Buffer *buf)
1926 {
1927     Menu menu;
1928     AnchorList *al = buf->href;
1929     Anchor *a;
1930     Anchor **ap;
1931     int i, n, nitem = 0, key = -1;
1932     char **label;
1933     char *t;
1934     unsigned char c;
1935 
1936     if (!al)
1937 	return NULL;
1938     for (i = 0; i < al->nanchor; i++) {
1939 	a = &al->anchors[i];
1940 	if (!a->slave && a->accesskey && IS_ASCII(a->accesskey))
1941 	    nitem++;
1942     }
1943     if (!nitem)
1944 	return NULL;
1945 
1946     label = New_N(char *, nitem + 1);
1947     ap = New_N(Anchor *, nitem);
1948     for (i = 0, n = 0; i < al->nanchor; i++) {
1949 	a = &al->anchors[i];
1950 	if (!a->slave && a->accesskey && IS_ASCII(a->accesskey)) {
1951 	    t = getAnchorText(buf, al, a);
1952 	    label[n] = Sprintf("%c: %s", a->accesskey, t ? t : "")->ptr;
1953 	    ap[n] = a;
1954 	    n++;
1955 	}
1956     }
1957     label[nitem] = NULL;
1958 
1959     set_menu_frame();
1960     new_option_menu(&menu, label, &key, NULL);
1961 
1962     menu.initial = 0;
1963     menu.cursorX = buf->cursorX + buf->rootX;
1964     menu.cursorY = buf->cursorY + buf->rootY;
1965     menu.x = menu.cursorX + FRAME_WIDTH + 1;
1966     menu.y = menu.cursorY + 2;
1967     for (i = 0; i < 128; i++)
1968 	menu.keyselect[i] = -1;
1969     for (i = 0; i < nitem; i++) {
1970 	c = ap[i]->accesskey;
1971 	menu.keymap[(int)c] = mSelect;
1972 	menu.keyselect[(int)c] = i;
1973     }
1974     for (i = 0; i < nitem; i++) {
1975 	c = ap[i]->accesskey;
1976 	if (!IS_ALPHA(c) || menu.keyselect[n] >= 0)
1977 	    continue;
1978 	c = TOLOWER(c);
1979 	menu.keymap[(int)c] = mSelect;
1980 	menu.keyselect[(int)c] = i;
1981 	c = TOUPPER(c);
1982 	menu.keymap[(int)c] = mSelect;
1983 	menu.keyselect[(int)c] = i;
1984     }
1985 
1986     a = retrieveCurrentAnchor(buf);
1987     if (a && a->accesskey && IS_ASCII(a->accesskey)) {
1988 	for (i = 0; i < nitem; i++) {
1989 	    if (a->hseq == ap[i]->hseq) {
1990 		menu.initial = i;
1991 		break;
1992 	    }
1993 	}
1994     }
1995 
1996     popup_menu(NULL, &menu);
1997 
1998     return (key >= 0) ? ap[key] : NULL;
1999 }
2000 
2001 static char lmKeys[] = "abcdefgimopqrstuvwxyz";
2002 static char lmKeys2[] = "1234567890ABCDEFGHILMOPQRSTUVWXYZ";
2003 #define nlmKeys (sizeof(lmKeys) - 1)
2004 #define nlmKeys2 (sizeof(lmKeys2) - 1)
2005 
2006 static int
lmGoto(char c)2007 lmGoto(char c)
2008 {
2009     if (IS_ASCII(c) && CurrentMenu->keyselect[(int)c] >= 0) {
2010 	goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
2011 	goto_menu(CurrentMenu, CurrentMenu->keyselect[(int)c] * nlmKeys, 1);
2012     }
2013     return (MENU_NOTHING);
2014 }
2015 
2016 static int
lmSelect(char c)2017 lmSelect(char c)
2018 {
2019     if (IS_ASCII(c))
2020 	return select_menu(CurrentMenu, (CurrentMenu->select / nlmKeys) *
2021 			   nlmKeys + CurrentMenu->keyselect[(int)c]);
2022     else
2023 	return (MENU_NOTHING);
2024 }
2025 
2026 Anchor *
list_menu(Buffer * buf)2027 list_menu(Buffer *buf)
2028 {
2029     Menu menu;
2030     AnchorList *al = buf->href;
2031     Anchor *a;
2032     Anchor **ap;
2033     int i, n, nitem = 0, key = -1, two = FALSE;
2034     char **label;
2035     char *t;
2036     unsigned char c;
2037 
2038     if (!al)
2039 	return NULL;
2040     for (i = 0; i < al->nanchor; i++) {
2041 	a = &al->anchors[i];
2042 	if (!a->slave)
2043 	    nitem++;
2044     }
2045     if (!nitem)
2046 	return NULL;
2047 
2048     if (nitem >= nlmKeys)
2049 	two = TRUE;
2050     label = New_N(char *, nitem + 1);
2051     ap = New_N(Anchor *, nitem);
2052     for (i = 0, n = 0; i < al->nanchor; i++) {
2053 	a = &al->anchors[i];
2054 	if (!a->slave) {
2055 	    t = getAnchorText(buf, al, a);
2056 	    if (!t)
2057 		t = "";
2058 	    if (two && n >= nlmKeys2 * nlmKeys)
2059 		label[n] = Sprintf("  : %s", t)->ptr;
2060 	    else if (two)
2061 		label[n] = Sprintf("%c%c: %s", lmKeys2[n / nlmKeys],
2062 				   lmKeys[n % nlmKeys], t)->ptr;
2063 	    else
2064 		label[n] = Sprintf("%c: %s", lmKeys[n], t)->ptr;
2065 	    ap[n] = a;
2066 	    n++;
2067 	}
2068     }
2069     label[nitem] = NULL;
2070 
2071     set_menu_frame();
2072     new_option_menu(&menu, label, &key, NULL);
2073 
2074     menu.initial = 0;
2075     menu.cursorX = buf->cursorX + buf->rootX;
2076     menu.cursorY = buf->cursorY + buf->rootY;
2077     menu.x = menu.cursorX + FRAME_WIDTH + 1;
2078     menu.y = menu.cursorY + 2;
2079     for (i = 0; i < 128; i++)
2080 	menu.keyselect[i] = -1;
2081     if (two) {
2082 	for (i = 0; i < nlmKeys2; i++) {
2083 	    c = lmKeys2[i];
2084 	    menu.keymap[(int)c] = lmGoto;
2085 	    menu.keyselect[(int)c] = i;
2086 	}
2087 	for (i = 0; i < nlmKeys; i++) {
2088 	    c = lmKeys[i];
2089 	    menu.keymap[(int)c] = lmSelect;
2090 	    menu.keyselect[(int)c] = i;
2091 	}
2092     }
2093     else {
2094 	for (i = 0; i < nitem; i++) {
2095 	    c = lmKeys[i];
2096 	    menu.keymap[(int)c] = mSelect;
2097 	    menu.keyselect[(int)c] = i;
2098 	}
2099     }
2100 
2101     a = retrieveCurrentAnchor(buf);
2102     if (a) {
2103 	for (i = 0; i < nitem; i++) {
2104 	    if (a->hseq == ap[i]->hseq) {
2105 		menu.initial = i;
2106 		break;
2107 	    }
2108 	}
2109     }
2110 
2111     popup_menu(NULL, &menu);
2112 
2113     return (key >= 0) ? ap[key] : NULL;
2114 }
2115 
2116 #endif				/* USE_MENU */
2117