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