aboutsummaryrefslogtreecommitdiffstats
path: root/menu.c
diff options
context:
space:
mode:
Diffstat (limited to 'menu.c')
-rw-r--r--menu.c2073
1 files changed, 2073 insertions, 0 deletions
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..a17c490
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,2073 @@
+/* $Id: menu.c,v 1.41 2004/03/23 16:44:02 ukai Exp $ */
+/*
+ * w3m menu.c
+ */
+#include <stdio.h>
+
+#include "fm.h"
+#include "menu.h"
+#include "func.h"
+#include "myctype.h"
+#include "regex.h"
+
+#ifdef USE_MOUSE
+#ifdef USE_GPM
+#include <gpm.h>
+static int gpm_process_menu_mouse(Gpm_Event * event, void *data);
+extern int gpm_process_mouse(Gpm_Event *, void *);
+#endif /* USE_GPM */
+#ifdef USE_SYSMOUSE
+extern int (*sysm_handler) (int x, int y, int nbs, int obs);
+static int sysm_process_menu_mouse(int, int, int, int);
+extern int sysm_process_mouse(int, int, int, int);
+#endif /* USE_SYSMOUSE */
+#if defined(USE_GPM) || defined(USE_SYSMOUSE)
+#define X_MOUSE_SELECTED (char)0xff
+static int X_Mouse_Selection;
+extern int do_getch();
+#define getch() do_getch()
+#endif /* defined(USE_GPM) || defined(USE_SYSMOUSE) */
+#endif /* USE_MOUSE */
+
+#ifdef USE_MENU
+
+static char **FRAME;
+static int FRAME_WIDTH;
+static int graph_mode = FALSE;
+#define G_start {if (graph_mode) graphstart();}
+#define G_end {if (graph_mode) graphend();}
+
+static int mEsc(char c);
+static int mEscB(char c);
+static int mEscD(char c);
+static int mNull(char c);
+static int mSelect(char c);
+static int mDown(char c);
+static int mUp(char c);
+static int mLast(char c);
+static int mTop(char c);
+static int mNext(char c);
+static int mPrev(char c);
+static int mFore(char c);
+static int mBack(char c);
+static int mLineU(char c);
+static int mLineD(char c);
+static int mOk(char c);
+static int mCancel(char c);
+static int mClose(char c);
+static int mSusp(char c);
+static int mMouse(char c);
+static int mSrchF(char c);
+static int mSrchB(char c);
+static int mSrchN(char c);
+static int mSrchP(char c);
+#ifdef __EMX__
+static int mPc(char c);
+#endif
+
+/* *INDENT-OFF* */
+static int (*MenuKeymap[128]) (char c) = {
+/* C-@ C-a C-b C-c C-d C-e C-f C-g */
+#ifdef __EMX__
+ mPc, mTop, mPrev, mClose, mNull, mLast, mNext, mNull,
+#else
+ mNull, mTop, mPrev, mClose, mNull, mLast, mNext, mNull,
+#endif
+/* C-h C-i C-j C-k C-l C-m C-n C-o */
+ mCancel,mNull, mOk, mNull, mNull, mOk, mDown, mNull,
+/* C-p C-q C-r C-s C-t C-u C-v C-w */
+ mUp, mNull, mSrchB, mSrchF, mNull, mNull, mNext, mNull,
+/* C-x C-y C-z C-[ C-\ C-] C-^ C-_ */
+ mNull, mNull, mSusp, mEsc, mNull, mNull, mNull, mNull,
+/* SPC ! " # $ % & ' */
+ mOk, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* ( ) * + , - . / */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mSrchF,
+/* 0 1 2 3 4 5 6 7 */
+ mNull, mNull, mNull, mNull, mNull, mNull , mNull, mNull,
+/* 8 9 : ; < = > ? */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mSrchB,
+/* @ A B C D E F G */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* H I J K L M N O */
+ mNull, mNull, mLineU, mLineD, mNull, mNull, mSrchP, mNull,
+/* P Q R S T U V W */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* X Y Z [ \ ] ^ _ */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* ` a b c d e f g */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* h i j k l m n o */
+ mCancel,mNull, mDown, mUp, mOk, mNull, mSrchN, mNull,
+/* p q r s t u v w */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* x y z { | } ~ DEL */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mCancel,
+};
+static int (*MenuEscKeymap[128]) (char c) = {
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* O */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mEscB,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* [ */
+ mNull, mNull, mNull, mEscB, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* v */
+ mNull, mNull, mNull, mNull, mNull, mNull, mPrev, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+};
+static int (*MenuEscBKeymap[128]) (char c) = {
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* A B C D E */
+ mNull, mUp, mDown, mOk, mCancel,mClose, mNull, mNull,
+/* L M */
+ mNull, mNull, mNull, mNull, mClose, mMouse, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+};
+static int (*MenuEscDKeymap[128]) (char c) = {
+/* 0 1 INS 3 4 PgUp, PgDn 7 */
+ mNull, mNull, mClose, mNull, mNull, mBack, mFore, mNull,
+/* 8 9 10 F1 F2 F3 F4 F5 */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* 16 F6 F7 F8 F9 F10 22 23 */
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+/* 24 25 26 27 HELP 29 30 31 */
+ mNull, mNull, mNull, mNull, mClose, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+};
+
+#ifdef __EMX__
+static int (*MenuPcKeymap[256])(char c)={
+// Null
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// S-Tab
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-q A-w A-E A-r A-t A-y A-u A-i
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-o A-p A-[ A-] A-a A-s
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-d A-f A-g A-h A-j A-k A-l A-;
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-' A-' A-\ A-x A-c A-v
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mPrev,
+// A-b A-n A-m A-, A-. A-/ A-+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// F1 F2 F3 F4 F5
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// F6 F7 F8 F9 F10 Home
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mTop,
+// Up PgUp A-/ Left 5 Right C-* End
+ mUp, mUp, mNull, mCancel,mNull, mOk, mNull, mLast,
+// Down PgDn Ins Del S-F1 S-F2 S-F3 S-F4
+ mDown, mDown, mClose, mCancel,mNull, mNull, mNull, mNull,
+// S-F5 S-F6 S-F7 S-F8 S-F9 S-F10 C-F1 C-F2
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// C-F3 C-F4 C-F5 C-F6 C-F7 C-F8 C-F9 C-F10
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-F1 A-F2 A-F3 A-F4 A-F5 A-F6 A-F7 A-F8
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-F9 A-F10 PrtSc C-Left C-Right C-End C-PgDn C-Home
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-1 A-2 A-3 A-4 A-5 A-6 A-7/8 A-9
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A-0 A - A-= C-PgUp F11 F12 S-F11
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// S-F12 C-F11 C-F12 A-F11 A-F12 C-Up C-/ C-5
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// S-* C-Down C-Ins C-Del C-Tab C - C-+
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull,
+// A - A-Tab A-Enter
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 160
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 168
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 176
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 184
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 192
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 200
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 208
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 216
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 224
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 232
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull, // 240
+ mNull, mNull, mNull, mNull, mNull, mNull, mNull, mNull // 248
+};
+#endif
+/* *INDENT-ON* */
+/* --- SelectMenu --- */
+
+static Menu SelectMenu;
+static int SelectV = 0;
+static void initSelectMenu(void);
+static void smChBuf(void);
+static int smDelBuf(char c);
+
+/* --- SelectMenu (END) --- */
+
+/* --- SelTabMenu --- */
+
+static Menu SelTabMenu;
+static int SelTabV = 0;
+static void initSelTabMenu(void);
+static void smChTab(void);
+static int smDelTab(char c);
+
+/* --- SelTabMenu (END) --- */
+
+/* --- MainMenu --- */
+
+static Menu MainMenu;
+#ifdef USE_M17N
+/* FIXME: gettextize here */
+static wc_ces MainMenuCharset = WC_CES_US_ASCII; /* FIXME: charset of source code */
+static int MainMenuEncode = FALSE;
+#endif
+
+static MenuItem MainMenuItem[] = {
+ /* type label variable value func popup keys data */
+ {MENU_FUNC, N_(" Back (b) "), NULL, 0, backBf, NULL, "b", NULL},
+ {MENU_POPUP, N_(" Select Buffer(s) "), NULL, 0, NULL, &SelectMenu, "s",
+ NULL},
+ {MENU_POPUP, N_(" Select Tab (t) "), NULL, 0, NULL, &SelTabMenu, "tT",
+ NULL},
+ {MENU_FUNC, N_(" View Source (v) "), NULL, 0, vwSrc, NULL, "vV", NULL},
+ {MENU_FUNC, N_(" Edit Source (e) "), NULL, 0, editBf, NULL, "eE", NULL},
+ {MENU_FUNC, N_(" Save Source (S) "), NULL, 0, svSrc, NULL, "S", NULL},
+ {MENU_FUNC, N_(" Reload (r) "), NULL, 0, reload, NULL, "rR", NULL},
+ {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
+ {MENU_FUNC, N_(" Go Link (a) "), NULL, 0, followA, NULL, "a", NULL},
+ {MENU_FUNC, N_(" on New Tab (n) "), NULL, 0, tabA, NULL, "nN", NULL},
+ {MENU_FUNC, N_(" Save Link (A) "), NULL, 0, svA, NULL, "A", NULL},
+ {MENU_FUNC, N_(" View Image (i) "), NULL, 0, followI, NULL, "i", NULL},
+ {MENU_FUNC, N_(" Save Image (I) "), NULL, 0, svI, NULL, "I", NULL},
+ {MENU_FUNC, N_(" View Frame (f) "), NULL, 0, rFrame, NULL, "fF", NULL},
+ {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
+ {MENU_FUNC, N_(" Bookmark (B) "), NULL, 0, ldBmark, NULL, "B", NULL},
+ {MENU_FUNC, N_(" Help (h) "), NULL, 0, ldhelp, NULL, "hH", NULL},
+ {MENU_FUNC, N_(" Option (o) "), NULL, 0, ldOpt, NULL, "oO", NULL},
+ {MENU_NOP, N_(" ---------------- "), NULL, 0, nulcmd, NULL, "", NULL},
+ {MENU_FUNC, N_(" Quit (q) "), NULL, 0, qquitfm, NULL, "qQ", NULL},
+ {MENU_END, "", NULL, 0, nulcmd, NULL, "", NULL},
+};
+
+/* --- MainMenu (END) --- */
+
+static MenuList *w3mMenuList;
+
+static Menu *CurrentMenu = NULL;
+
+#define mvaddch(y, x, c) (move(y, x), addch(c))
+#define mvaddstr(y, x, str) (move(y, x), addstr(str))
+#define mvaddnstr(y, x, str, n) (move(y, x), addnstr_sup(str, n))
+
+void
+new_menu(Menu *menu, MenuItem *item)
+{
+ int i, l;
+ char *p;
+
+ menu->cursorX = 0;
+ menu->cursorY = 0;
+ menu->x = 0;
+ menu->y = 0;
+ menu->nitem = 0;
+ menu->item = item;
+ menu->initial = 0;
+ menu->select = 0;
+ menu->offset = 0;
+ menu->active = 0;
+
+ if (item == NULL)
+ return;
+
+ for (i = 0; item[i].type != MENU_END; i++) ;
+ menu->nitem = i;
+ menu->height = menu->nitem;
+ for (i = 0; i < 128; i++)
+ menu->keymap[i] = MenuKeymap[i];
+ menu->width = 0;
+ for (i = 0; i < menu->nitem; i++) {
+ if ((p = item[i].keys) != NULL) {
+ while (*p) {
+ if (IS_ASCII(*p)) {
+ menu->keymap[(int)*p] = mSelect;
+ menu->keyselect[(int)*p] = i;
+ }
+ p++;
+ }
+ }
+ l = get_strwidth(item[i].label);
+ if (l > menu->width)
+ menu->width = l;
+ }
+}
+
+void
+geom_menu(Menu *menu, int x, int y, int mselect)
+{
+ int win_x, win_y, win_w, win_h;
+
+ menu->select = mselect;
+
+ if (menu->width % FRAME_WIDTH)
+ menu->width = (menu->width / FRAME_WIDTH + 1) * FRAME_WIDTH;
+ win_x = menu->x - FRAME_WIDTH;
+ win_w = menu->width + 2 * FRAME_WIDTH;
+ if (win_x + win_w > COLS)
+ win_x = COLS - win_w;
+ if (win_x < 0) {
+ win_x = 0;
+ if (win_w > COLS) {
+ menu->width = COLS - 2 * FRAME_WIDTH;
+ menu->width -= menu->width % FRAME_WIDTH;
+ win_w = menu->width + 2 * FRAME_WIDTH;
+ }
+ }
+ menu->x = win_x + FRAME_WIDTH;
+
+ win_y = menu->y - mselect - 1;
+ win_h = menu->height + 2;
+ if (win_y + win_h > LASTLINE)
+ win_y = LASTLINE - win_h;
+ if (win_y < 0) {
+ win_y = 0;
+ if (win_y + win_h > LASTLINE) {
+ win_h = LASTLINE - win_y;
+ menu->height = win_h - 2;
+ if (menu->height <= mselect)
+ menu->offset = mselect - menu->height + 1;
+ }
+ }
+ menu->y = win_y + 1;
+}
+
+void
+draw_all_menu(Menu *menu)
+{
+ if (menu->parent != NULL)
+ draw_all_menu(menu->parent);
+ draw_menu(menu);
+}
+
+void
+draw_menu(Menu *menu)
+{
+ int x, y, w;
+ int i, j;
+
+ x = menu->x - FRAME_WIDTH;
+ w = menu->width + 2 * FRAME_WIDTH;
+ y = menu->y - 1;
+
+ if (menu->offset == 0) {
+ G_start;
+ mvaddstr(y, x, FRAME[3]);
+ for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
+ mvaddstr(y, x + i, FRAME[10]);
+ mvaddstr(y, x + i, FRAME[6]);
+ G_end;
+ }
+ else {
+ G_start;
+ mvaddstr(y, x, FRAME[5]);
+ G_end;
+ for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
+ mvaddstr(y, x + i, " ");
+ G_start;
+ mvaddstr(y, x + i, FRAME[5]);
+ G_end;
+ i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
+ mvaddstr(y, x + i, ":");
+ }
+
+ for (j = 0; j < menu->height; j++) {
+ y++;
+ G_start;
+ mvaddstr(y, x, FRAME[5]);
+ G_end;
+ draw_menu_item(menu, menu->offset + j);
+ G_start;
+ mvaddstr(y, x + w - FRAME_WIDTH, FRAME[5]);
+ G_end;
+ }
+ y++;
+ if (menu->offset + menu->height == menu->nitem) {
+ G_start;
+ mvaddstr(y, x, FRAME[9]);
+ for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
+ mvaddstr(y, x + i, FRAME[10]);
+ mvaddstr(y, x + i, FRAME[12]);
+ G_end;
+ }
+ else {
+ G_start;
+ mvaddstr(y, x, FRAME[5]);
+ G_end;
+ for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i++)
+ mvaddstr(y, x + i, " ");
+ G_start;
+ mvaddstr(y, x + i, FRAME[5]);
+ G_end;
+ i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
+ mvaddstr(y, x + i, ":");
+ }
+}
+
+void
+draw_menu_item(Menu *menu, int mselect)
+{
+ mvaddnstr(menu->y + mselect - menu->offset, menu->x,
+ menu->item[mselect].label, menu->width);
+}
+
+int
+select_menu(Menu *menu, int mselect)
+{
+ if (mselect < 0 || mselect >= menu->nitem)
+ return (MENU_NOTHING);
+ if (mselect < menu->offset)
+ up_menu(menu, menu->offset - mselect);
+ else if (mselect >= menu->offset + menu->height)
+ down_menu(menu, mselect - menu->offset - menu->height + 1);
+
+ if (menu->select >= menu->offset &&
+ menu->select < menu->offset + menu->height)
+ draw_menu_item(menu, menu->select);
+ menu->select = mselect;
+ standout();
+ draw_menu_item(menu, menu->select);
+ standend();
+ /*
+ * move(menu->cursorY, menu->cursorX); */
+ move(menu->y + mselect - menu->offset, menu->x);
+ toggle_stand();
+ refresh();
+
+ return (menu->select);
+}
+
+void
+goto_menu(Menu *menu, int mselect, int down)
+{
+ int select_in;
+ if (mselect >= menu->nitem)
+ mselect = menu->nitem - 1;
+ else if (mselect < 0)
+ mselect = 0;
+ select_in = mselect;
+ while (menu->item[mselect].type == MENU_NOP) {
+ if (down > 0) {
+ if (++mselect >= menu->nitem) {
+ down_menu(menu, select_in - menu->select);
+ mselect = menu->select;
+ break;
+ }
+ }
+ else if (down < 0) {
+ if (--mselect < 0) {
+ up_menu(menu, menu->select - select_in);
+ mselect = menu->select;
+ break;
+ }
+ }
+ else {
+ return;
+ }
+ }
+ select_menu(menu, mselect);
+}
+
+void
+up_menu(Menu *menu, int n)
+{
+ if (n < 0 || menu->offset == 0)
+ return;
+ menu->offset -= n;
+ if (menu->offset < 0)
+ menu->offset = 0;
+
+ draw_menu(menu);
+}
+
+void
+down_menu(Menu *menu, int n)
+{
+ if (n < 0 || menu->offset + menu->height == menu->nitem)
+ return;
+ menu->offset += n;
+ if (menu->offset + menu->height > menu->nitem)
+ menu->offset = menu->nitem - menu->height;
+
+ draw_menu(menu);
+}
+
+int
+action_menu(Menu *menu)
+{
+ char c;
+ int mselect;
+ MenuItem item;
+
+ if (menu->active == 0) {
+ if (menu->parent != NULL)
+ menu->parent->active = 0;
+ return (0);
+ }
+ draw_all_menu(menu);
+ select_menu(menu, menu->select);
+
+ while (1) {
+#ifdef USE_MOUSE
+ if (use_mouse)
+ mouse_active();
+#endif /* USE_MOUSE */
+ c = getch();
+#ifdef USE_MOUSE
+ if (use_mouse)
+ mouse_inactive();
+#if defined(USE_GPM) || defined(USE_SYSMOUSE)
+ if (c == X_MOUSE_SELECTED) {
+ mselect = X_Mouse_Selection;
+ if (mselect != MENU_NOTHING)
+ break;
+ }
+#endif /* defined(USE_GPM) || defined(USE_SYSMOUSE) */
+#endif /* USE_MOUSE */
+ if (IS_ASCII(c)) { /* Ascii */
+ mselect = (*menu->keymap[(int)c]) (c);
+ if (mselect != MENU_NOTHING)
+ break;
+ }
+ }
+ if (mselect >= 0 && mselect < menu->nitem) {
+ item = menu->item[mselect];
+ if (item.type & MENU_POPUP) {
+ popup_menu(menu, item.popup);
+ return (1);
+ }
+ if (menu->parent != NULL)
+ menu->parent->active = 0;
+ if (item.type & MENU_VALUE)
+ *item.variable = item.value;
+ if (item.type & MENU_FUNC) {
+ CurrentKey = -1;
+ CurrentKeyData = NULL;
+ CurrentCmdData = item.data;
+ (*item.func) ();
+ CurrentCmdData = NULL;
+ }
+ }
+ else if (mselect == MENU_CLOSE) {
+ if (menu->parent != NULL)
+ menu->parent->active = 0;
+ }
+ return (0);
+}
+
+void
+popup_menu(Menu *parent, Menu *menu)
+{
+ int active = 1;
+
+ if (menu->item == NULL || menu->nitem == 0)
+ return;
+ if (menu->active)
+ return;
+
+#ifdef USE_MOUSE
+#ifdef USE_GPM
+ gpm_handler = gpm_process_menu_mouse;
+#endif /* USE_GPM */
+#ifdef USE_SYSMOUSE
+ sysm_handler = sysm_process_menu_mouse;
+#endif /* USE_SYSMOUSE */
+#endif /* USE_MOUSE */
+ menu->parent = parent;
+ menu->select = menu->initial;
+ menu->offset = 0;
+ menu->active = 1;
+ if (parent != NULL) {
+ menu->cursorX = parent->cursorX;
+ menu->cursorY = parent->cursorY;
+ guess_menu_xy(parent, menu->width, &menu->x, &menu->y);
+ }
+ geom_menu(menu, menu->x, menu->y, menu->select);
+
+ CurrentMenu = menu;
+ while (active) {
+ active = action_menu(CurrentMenu);
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ }
+ menu->active = 0;
+ CurrentMenu = parent;
+#ifdef USE_MOUSE
+#ifdef USE_GPM
+ if (CurrentMenu == NULL)
+ gpm_handler = gpm_process_mouse;
+#endif /* USE_GPM */
+#ifdef USE_SYSMOUSE
+ if (CurrentMenu == NULL)
+ sysm_handler = sysm_process_mouse;
+#endif /* USE_SYSMOUSE */
+#endif /* USE_MOUSE */
+}
+
+void
+guess_menu_xy(Menu *parent, int width, int *x, int *y)
+{
+ *x = parent->x + parent->width + FRAME_WIDTH - 1;
+ if (*x + width + FRAME_WIDTH > COLS) {
+ *x = COLS - width - FRAME_WIDTH;
+ if ((parent->x + parent->width / 2 > *x) &&
+ (parent->x + parent->width / 2 > COLS / 2))
+ *x = parent->x - width - FRAME_WIDTH + 1;
+ }
+ *y = parent->y + parent->select - parent->offset;
+}
+
+void
+new_option_menu(Menu *menu, char **label, int *variable, void (*func) ())
+{
+ int i, nitem;
+ char **p;
+ MenuItem *item;
+
+ if (label == NULL || *label == NULL)
+ return;
+
+ for (i = 0, p = label; *p != NULL; i++, p++) ;
+ nitem = i;
+
+ item = New_N(MenuItem, nitem + 1);
+
+ for (i = 0, p = label; i < nitem; i++, p++) {
+ if (func != NULL)
+ item[i].type = MENU_VALUE | MENU_FUNC;
+ else
+ item[i].type = MENU_VALUE;
+ item[i].label = *p;
+ item[i].variable = variable;
+ item[i].value = i;
+ item[i].func = func;
+ item[i].popup = NULL;
+ item[i].keys = "";
+ }
+ item[nitem].type = MENU_END;
+
+ new_menu(menu, item);
+}
+
+static void
+set_menu_frame(void)
+{
+ if (graph_ok()) {
+ graph_mode = TRUE;
+ FRAME_WIDTH = 1;
+ FRAME = graph_symbol;
+ }
+ else {
+ graph_mode = FALSE;
+#ifdef USE_M17N
+ FRAME_WIDTH = 0;
+ FRAME = get_symbol(DisplayCharset, &FRAME_WIDTH);
+ if (!WcOption.use_wide)
+ FRAME_WIDTH = 1;
+#else
+ FRAME_WIDTH = 1;
+ FRAME = get_symbol();
+#endif
+ }
+}
+
+/* --- MenuFunctions --- */
+
+#ifdef __EMX__
+static int
+mPc(char c)
+{
+ c = getch();
+ return (MenuPcKeymap[(int)c] (c));
+}
+#endif
+
+static int
+mEsc(char c)
+{
+ c = getch();
+ return (MenuEscKeymap[(int)c] (c));
+}
+
+static int
+mEscB(char c)
+{
+ c = getch();
+ if (IS_DIGIT(c))
+ return (mEscD(c));
+ else
+ return (MenuEscBKeymap[(int)c] (c));
+}
+
+static int
+mEscD(char c)
+{
+ int d;
+
+ d = (int)c - (int)'0';
+ c = getch();
+ if (IS_DIGIT(c)) {
+ d = d * 10 + (int)c - (int)'0';
+ c = getch();
+ }
+ if (c == '~')
+ return (MenuEscDKeymap[d] (c));
+ else
+ return (MENU_NOTHING);
+}
+
+static int
+mNull(char c)
+{
+ return (MENU_NOTHING);
+}
+
+static int
+mSelect(char c)
+{
+ if (IS_ASCII(c))
+ return (select_menu(CurrentMenu, CurrentMenu->keyselect[(int)c]));
+ else
+ return (MENU_NOTHING);
+}
+
+static int
+mDown(char c)
+{
+ if (CurrentMenu->select >= CurrentMenu->nitem - 1)
+ return (MENU_NOTHING);
+ goto_menu(CurrentMenu, CurrentMenu->select + 1, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+mUp(char c)
+{
+ if (CurrentMenu->select <= 0)
+ return (MENU_NOTHING);
+ goto_menu(CurrentMenu, CurrentMenu->select - 1, -1);
+ return (MENU_NOTHING);
+}
+
+static int
+mLast(char c)
+{
+ goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
+ return (MENU_NOTHING);
+}
+
+static int
+mTop(char c)
+{
+ goto_menu(CurrentMenu, 0, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+mNext(char c)
+{
+ int mselect = CurrentMenu->select + CurrentMenu->height;
+
+ if (mselect >= CurrentMenu->nitem)
+ return mLast(c);
+ down_menu(CurrentMenu, CurrentMenu->height);
+ goto_menu(CurrentMenu, mselect, -1);
+ return (MENU_NOTHING);
+}
+
+static int
+mPrev(char c)
+{
+ int mselect = CurrentMenu->select - CurrentMenu->height;
+
+ if (mselect < 0)
+ return mTop(c);
+ up_menu(CurrentMenu, CurrentMenu->height);
+ goto_menu(CurrentMenu, mselect, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+mFore(char c)
+{
+ if (CurrentMenu->select >= CurrentMenu->nitem - 1)
+ return (MENU_NOTHING);
+ goto_menu(CurrentMenu, (CurrentMenu->select + CurrentMenu->height - 1),
+ (CurrentMenu->height + 1));
+ return (MENU_NOTHING);
+}
+
+static int
+mBack(char c)
+{
+ if (CurrentMenu->select <= 0)
+ return (MENU_NOTHING);
+ goto_menu(CurrentMenu, (CurrentMenu->select - CurrentMenu->height + 1),
+ (-1 - CurrentMenu->height));
+ return (MENU_NOTHING);
+}
+
+static int
+mLineU(char c)
+{
+ int mselect = CurrentMenu->select;
+
+ if (mselect >= CurrentMenu->nitem)
+ return mLast(c);
+ if (CurrentMenu->offset + CurrentMenu->height >= CurrentMenu->nitem)
+ mselect++;
+ else {
+ down_menu(CurrentMenu, 1);
+ if (mselect < CurrentMenu->offset)
+ mselect++;
+ }
+ goto_menu(CurrentMenu, mselect, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+mLineD(char c)
+{
+ int mselect = CurrentMenu->select;
+
+ if (mselect <= 0)
+ return mTop(c);
+ if (CurrentMenu->offset <= 0)
+ mselect--;
+ else {
+ up_menu(CurrentMenu, 1);
+ if (mselect >= CurrentMenu->offset + CurrentMenu->height)
+ mselect--;
+ }
+ goto_menu(CurrentMenu, mselect, -1);
+ return (MENU_NOTHING);
+}
+
+static int
+mOk(char c)
+{
+ int mselect = CurrentMenu->select;
+
+ if (CurrentMenu->item[mselect].type == MENU_NOP)
+ return (MENU_NOTHING);
+ return (mselect);
+}
+
+static int
+mCancel(char c)
+{
+ return (MENU_CANCEL);
+}
+
+static int
+mClose(char c)
+{
+ return (MENU_CLOSE);
+}
+
+static int
+mSusp(char c)
+{
+ susp();
+ draw_all_menu(CurrentMenu);
+ select_menu(CurrentMenu, CurrentMenu->select);
+ return (MENU_NOTHING);
+}
+
+static char *SearchString = NULL;
+
+int (*menuSearchRoutine) (Menu *, char *, int);
+
+static int
+menuForwardSearch(Menu *menu, char *str, int from)
+{
+ int i;
+ char *p;
+ if ((p = regexCompile(str, IgnoreCase)) != NULL) {
+ message(p, 0, 0);
+ return -1;
+ }
+ if (from < 0)
+ from = 0;
+ for (i = from; i < menu->nitem; i++)
+ if (menu->item[i].type != MENU_NOP &&
+ regexMatch(menu->item[i].label, -1, 1) == 1)
+ return i;
+ return -1;
+}
+
+static int
+menu_search_forward(Menu *menu, int from)
+{
+ char *str;
+ int found;
+ str = inputStrHist("Forward: ", NULL, TextHist);
+ if (str != NULL && *str == '\0')
+ str = SearchString;
+ if (str == NULL || *str == '\0')
+ return -1;
+ SearchString = str;
+ str = conv_search_string(str, DisplayCharset);
+ menuSearchRoutine = menuForwardSearch;
+ found = menuForwardSearch(menu, str, from + 1);
+ if (WrapSearch && found == -1)
+ found = menuForwardSearch(menu, str, 0);
+ if (found >= 0)
+ return found;
+ disp_message("Not found", TRUE);
+ return -1;
+}
+
+static int
+mSrchF(char c)
+{
+ int mselect;
+ mselect = menu_search_forward(CurrentMenu, CurrentMenu->select);
+ if (mselect >= 0)
+ goto_menu(CurrentMenu, mselect, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+menuBackwardSearch(Menu *menu, char *str, int from)
+{
+ int i;
+ char *p;
+ if ((p = regexCompile(str, IgnoreCase)) != NULL) {
+ message(p, 0, 0);
+ return -1;
+ }
+ if (from >= menu->nitem)
+ from = menu->nitem - 1;
+ for (i = from; i >= 0; i--)
+ if (menu->item[i].type != MENU_NOP &&
+ regexMatch(menu->item[i].label, -1, 1) == 1)
+ return i;
+ return -1;
+}
+
+static int
+menu_search_backward(Menu *menu, int from)
+{
+ char *str;
+ int found;
+ str = inputStrHist("Backward: ", NULL, TextHist);
+ if (str != NULL && *str == '\0')
+ str = SearchString;
+ if (str == NULL || *str == '\0')
+ return -1;
+ SearchString = str;
+ str = conv_search_string(str, DisplayCharset);
+ menuSearchRoutine = menuBackwardSearch;
+ found = menuBackwardSearch(menu, str, from - 1);
+ if (WrapSearch && found == -1)
+ found = menuBackwardSearch(menu, str, menu->nitem);
+ if (found >= 0)
+ return found;
+ disp_message("Not found", TRUE);
+ return -1;
+}
+
+static int
+mSrchB(char c)
+{
+ int mselect;
+ mselect = menu_search_backward(CurrentMenu, CurrentMenu->select);
+ if (mselect >= 0)
+ goto_menu(CurrentMenu, mselect, -1);
+ return (MENU_NOTHING);
+}
+
+static int
+menu_search_next_previous(Menu *menu, int from, int reverse)
+{
+ int found;
+ static int (*routine[2]) (Menu *, char *, int) = {
+ menuForwardSearch, menuBackwardSearch};
+ char *str;
+
+ if (menuSearchRoutine == NULL) {
+ disp_message("No previous regular expression", TRUE);
+ return -1;
+ }
+ str = conv_search_string(SearchString, DisplayCharset);
+ if (reverse != 0)
+ reverse = 1;
+ if (menuSearchRoutine == menuBackwardSearch)
+ reverse ^= 1;
+ from += reverse ? -1 : 1;
+ found = (*routine[reverse]) (menu, str, from);
+ if (WrapSearch && found == -1)
+ found = (*routine[reverse]) (menu, str, reverse * menu->nitem);
+ if (found >= 0)
+ return found;
+ disp_message("Not found", TRUE);
+ return -1;
+}
+
+static int
+mSrchN(char c)
+{
+ int mselect;
+ mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 0);
+ if (mselect >= 0)
+ goto_menu(CurrentMenu, mselect, 1);
+ return (MENU_NOTHING);
+}
+
+static int
+mSrchP(char c)
+{
+ int mselect;
+ mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 1);
+ if (mselect >= 0)
+ goto_menu(CurrentMenu, mselect, -1);
+ return (MENU_NOTHING);
+}
+
+#ifdef USE_MOUSE
+#define MOUSE_BTN1_DOWN 0
+#define MOUSE_BTN2_DOWN 1
+#define MOUSE_BTN3_DOWN 2
+#define MOUSE_BTN4_DOWN_RXVT 3
+#define MOUSE_BTN5_DOWN_RXVT 4
+#define MOUSE_BTN4_DOWN_XTERM 64
+#define MOUSE_BTN5_DOWN_XTERM 65
+#define MOUSE_BTN_UP 3
+#define MOUSE_BTN_RESET -1
+
+static int
+mMouse_scroll_line(void)
+{
+ int i = 0;
+ if (relative_wheel_scroll)
+ i = (relative_wheel_scroll_ratio * CurrentMenu->height + 99) / 100;
+ else
+ i = fixed_wheel_scroll_count;
+ return i ? i : 1;
+}
+
+static int
+process_mMouse(int btn, int x, int y)
+{
+ Menu *menu;
+ int mselect, i;
+ static int press_btn = MOUSE_BTN_RESET, press_x, press_y;
+ char c = ' ';
+
+ menu = CurrentMenu;
+
+ if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
+ return (MENU_NOTHING);
+
+ if (btn == MOUSE_BTN_UP) {
+ switch (press_btn) {
+ case MOUSE_BTN1_DOWN:
+ case MOUSE_BTN3_DOWN:
+ if (x < menu->x - FRAME_WIDTH ||
+ x >= menu->x + menu->width + FRAME_WIDTH ||
+ y < menu->y - 1 || y >= menu->y + menu->height + 1) {
+ return (MENU_CANCEL);
+ }
+ else if ((x >= menu->x - FRAME_WIDTH &&
+ x < menu->x) ||
+ (x >= menu->x + menu->width &&
+ x < menu->x + menu->width + FRAME_WIDTH)) {
+ return (MENU_NOTHING);
+ }
+ else if (press_y > y) {
+ for (i = 0; i < press_y - y; i++)
+ mLineU(c);
+ return (MENU_NOTHING);
+ }
+ else if (press_y < y) {
+ for (i = 0; i < y - press_y; i++)
+ mLineD(c);
+ return (MENU_NOTHING);
+ }
+ else if (y == menu->y - 1) {
+ mPrev(c);
+ return (MENU_NOTHING);
+ }
+ else if (y == menu->y + menu->height) {
+ mNext(c);
+ return (MENU_NOTHING);
+ }
+ else {
+ mselect = y - menu->y + menu->offset;
+ if (menu->item[mselect].type == MENU_NOP)
+ return (MENU_NOTHING);
+ return (select_menu(menu, mselect));
+ }
+ break;
+ case MOUSE_BTN4_DOWN_RXVT:
+ for (i = 0; i < mMouse_scroll_line(); i++)
+ mLineD(c);
+ break;
+ case MOUSE_BTN5_DOWN_RXVT:
+ for (i = 0; i < mMouse_scroll_line(); i++)
+ mLineU(c);
+ break;
+ }
+ }
+ else if (btn == MOUSE_BTN4_DOWN_XTERM) {
+ for (i = 0; i < mMouse_scroll_line(); i++)
+ mLineD(c);
+ }
+ else if (btn == MOUSE_BTN5_DOWN_XTERM) {
+ for (i = 0; i < mMouse_scroll_line(); i++)
+ mLineU(c);
+ }
+
+ if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) {
+ press_btn = btn;
+ press_x = x;
+ press_y = y;
+ }
+ else {
+ press_btn = MOUSE_BTN_RESET;
+ }
+ return (MENU_NOTHING);
+}
+
+static int
+mMouse(char c)
+{
+ int btn, x, y;
+
+ btn = (unsigned char)getch() - 32;
+#if defined(__CYGWIN__)
+ if (cygwin_mouse_btn_swapped) {
+ if (btn == MOUSE_BTN2_DOWN)
+ btn = MOUSE_BTN3_DOWN;
+ else if (btn == MOUSE_BTN3_DOWN)
+ btn = MOUSE_BTN2_DOWN;
+ }
+#endif
+ x = (unsigned char)getch() - 33;
+ if (x < 0)
+ x += 0x100;
+ y = (unsigned char)getch() - 33;
+ if (y < 0)
+ y += 0x100;
+
+ /*
+ * if (x < 0 || x >= COLS || y < 0 || y > LASTLINE) return; */
+ return process_mMouse(btn, x, y);
+}
+
+#ifdef USE_GPM
+static int
+gpm_process_menu_mouse(Gpm_Event * event, void *data)
+{
+ int btn = MOUSE_BTN_RESET, x, y;
+ if (event->type & GPM_UP)
+ btn = MOUSE_BTN_UP;
+ else if (event->type & GPM_DOWN) {
+ switch (event->buttons) {
+ case GPM_B_LEFT:
+ btn = MOUSE_BTN1_DOWN;
+ break;
+ case GPM_B_MIDDLE:
+ btn = MOUSE_BTN2_DOWN;
+ break;
+ case GPM_B_RIGHT:
+ btn = MOUSE_BTN3_DOWN;
+ break;
+ }
+ }
+ else {
+ GPM_DRAWPOINTER(event);
+ return 0;
+ }
+ x = event->x;
+ y = event->y;
+ X_Mouse_Selection = process_mMouse(btn, x - 1, y - 1);
+ return X_MOUSE_SELECTED;
+}
+#endif /* USE_GPM */
+
+#ifdef USE_SYSMOUSE
+static int
+sysm_process_menu_mouse(int x, int y, int nbs, int obs)
+{
+ int btn;
+ int bits;
+
+ if (obs & ~nbs)
+ btn = MOUSE_BTN_UP;
+ else if (nbs & ~obs) {
+ bits = nbs & ~obs;
+ btn = bits & 0x1 ? MOUSE_BTN1_DOWN :
+ (bits & 0x2 ? MOUSE_BTN2_DOWN :
+ (bits & 0x4 ? MOUSE_BTN3_DOWN : 0));
+ }
+ else /* nbs == obs */
+ return 0;
+ X_Mouse_Selection = process_mMouse(btn, x, y);
+ return X_MOUSE_SELECTED;
+}
+#endif /* USE_SYSMOUSE */
+#else /* not USE_MOUSE */
+static int
+mMouse(char c)
+{
+ return (MENU_NOTHING);
+}
+#endif /* not USE_MOUSE */
+
+/* --- MenuFunctions (END) --- */
+
+/* --- MainMenu --- */
+
+void
+popupMenu(int x, int y, Menu *menu)
+{
+ set_menu_frame();
+
+ initSelectMenu();
+ initSelTabMenu();
+
+ menu->cursorX = Currentbuf->cursorX + Currentbuf->rootX;
+ menu->cursorY = Currentbuf->cursorY + Currentbuf->rootY;
+ menu->x = x + FRAME_WIDTH + 1;
+ menu->y = y + 2;
+
+ popup_menu(NULL, menu);
+}
+
+void
+mainMenu(int x, int y)
+{
+ popupMenu(x, y, &MainMenu);
+}
+
+DEFUN(mainMn, MAIN_MENU MENU, "Popup menu")
+{
+ Menu *menu = &MainMenu;
+ char *data;
+ int n;
+ int x = Currentbuf->cursorX + Currentbuf->rootX,
+ y = Currentbuf->cursorY + Currentbuf->rootY;
+
+ data = searchKeyData();
+ if (data != NULL) {
+ n = getMenuN(w3mMenuList, data);
+ if (n < 0)
+ return;
+ menu = w3mMenuList[n].menu;
+ }
+#ifdef USE_MOUSE
+ if (mouse_action.in_action) {
+ x = mouse_action.cursorX;
+ y = mouse_action.cursorY;
+ }
+#endif
+ popupMenu(x, y, menu);
+}
+
+/* --- MainMenu (END) --- */
+
+/* --- SelectMenu --- */
+
+DEFUN(selMn, SELECT_MENU, "Popup buffer selection menu")
+{
+ int x = Currentbuf->cursorX + Currentbuf->rootX,
+ y = Currentbuf->cursorY + Currentbuf->rootY;
+
+#ifdef USE_MOUSE
+ if (mouse_action.in_action) {
+ x = mouse_action.cursorX;
+ y = mouse_action.cursorY;
+ }
+#endif
+ popupMenu(x, y, &SelectMenu);
+}
+
+static void
+initSelectMenu(void)
+{
+ int i, nitem, len = 0, l;
+ Buffer *buf;
+ Str str;
+ char **label;
+ char *p;
+ static char *comment = " SPC for select / D for delete buffer ";
+
+ SelectV = -1;
+ for (i = 0, buf = Firstbuf; buf != NULL; i++, buf = buf->nextBuffer) {
+ if (buf == Currentbuf)
+ SelectV = i;
+ }
+ nitem = i;
+
+ label = New_N(char *, nitem + 2);
+ for (i = 0, buf = Firstbuf; i < nitem; i++, buf = buf->nextBuffer) {
+ str = Sprintf("<%s>", buf->buffername);
+ if (buf->filename != NULL) {
+ switch (buf->currentURL.scheme) {
+ case SCM_LOCAL:
+ if (strcmp(buf->currentURL.file, "-")) {
+ Strcat_char(str, ' ');
+ Strcat_charp(str,
+ conv_from_system(buf->currentURL.real_file));
+ }
+ break;
+ /* case SCM_UNKNOWN: */
+ case SCM_MISSING:
+ break;
+ default:
+ Strcat_char(str, ' ');
+ p = parsedURL2Str(&buf->currentURL)->ptr;
+ if (DecodeURL)
+ p = url_unquote_conv(p, 0);
+ Strcat_charp(str, p);
+ break;
+ }
+ }
+ label[i] = str->ptr;
+ if (len < str->length)
+ len = str->length;
+ }
+ l = get_strwidth(comment);
+ if (len < l + 4)
+ len = l + 4;
+ if (len > COLS - 2 * FRAME_WIDTH)
+ len = COLS - 2 * FRAME_WIDTH;
+ len = (len > 1) ? ((len - l + 1) / 2) : 0;
+ str = Strnew();
+ for (i = 0; i < len; i++)
+ Strcat_char(str, '-');
+ Strcat_charp(str, comment);
+ for (i = 0; i < len; i++)
+ Strcat_char(str, '-');
+ label[nitem] = str->ptr;
+ label[nitem + 1] = NULL;
+
+ new_option_menu(&SelectMenu, label, &SelectV, smChBuf);
+ SelectMenu.initial = SelectV;
+ SelectMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
+ SelectMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
+ SelectMenu.keymap['D'] = smDelBuf;
+ SelectMenu.item[nitem].type = MENU_NOP;
+}
+
+static void
+smChBuf(void)
+{
+ int i;
+ Buffer *buf;
+
+ if (SelectV < 0 || SelectV >= SelectMenu.nitem)
+ return;
+ for (i = 0, buf = Firstbuf; i < SelectV; i++, buf = buf->nextBuffer) ;
+ Currentbuf = buf;
+ for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) {
+ if (buf == Currentbuf)
+ continue;
+#ifdef USE_IMAGE
+ deleteImage(buf);
+#endif
+ if (clear_buffer)
+ tmpClearBuffer(buf);
+ }
+}
+
+static int
+smDelBuf(char c)
+{
+ int i, x, y, mselect;
+ Buffer *buf;
+
+ if (CurrentMenu->select < 0 || CurrentMenu->select >= SelectMenu.nitem)
+ return (MENU_NOTHING);
+ for (i = 0, buf = Firstbuf; i < CurrentMenu->select;
+ i++, buf = buf->nextBuffer) ;
+ if (Currentbuf == buf)
+ Currentbuf = buf->nextBuffer;
+ Firstbuf = deleteBuffer(Firstbuf, buf);
+ if (!Currentbuf)
+ Currentbuf = nthBuffer(Firstbuf, i - 1);;
+ if (Firstbuf == NULL) {
+ Firstbuf = nullBuffer();
+ Currentbuf = Firstbuf;
+ }
+
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ mselect = CurrentMenu->select;
+
+ initSelectMenu();
+
+ CurrentMenu->x = x;
+ CurrentMenu->y = y;
+
+ geom_menu(CurrentMenu, x, y, 0);
+
+ CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
+ : (CurrentMenu->nitem - 2);
+
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ draw_all_menu(CurrentMenu);
+ select_menu(CurrentMenu, CurrentMenu->select);
+ return (MENU_NOTHING);
+}
+
+/* --- SelectMenu (END) --- */
+
+/* --- SelTabMenu --- */
+
+DEFUN(tabMn, TAB_MENU, "Popup tab selection menu")
+{
+ int x = Currentbuf->cursorX + Currentbuf->rootX,
+ y = Currentbuf->cursorY + Currentbuf->rootY;
+
+#ifdef USE_MOUSE
+ if (mouse_action.in_action) {
+ x = mouse_action.cursorX;
+ y = mouse_action.cursorY;
+ }
+#endif
+ popupMenu(x, y, &SelTabMenu);
+}
+
+static void
+initSelTabMenu(void)
+{
+ int i, nitem, len = 0, l;
+ TabBuffer *tab;
+ Buffer *buf;
+ Str str;
+ char **label;
+ char *p;
+ static char *comment = " SPC for select / D for delete tab ";
+
+ SelTabV = -1;
+ for (i = 0, tab = LastTab; tab != NULL; i++, tab = tab->prevTab) {
+ if (tab == CurrentTab)
+ SelTabV = i;
+ }
+ nitem = i;
+
+ label = New_N(char *, nitem + 2);
+ for (i = 0, tab = LastTab; i < nitem; i++, tab = tab->prevTab) {
+ buf = tab->currentBuffer;
+ str = Sprintf("<%s>", buf->buffername);
+ if (buf->filename != NULL) {
+ switch (buf->currentURL.scheme) {
+ case SCM_LOCAL:
+ if (strcmp(buf->currentURL.file, "-")) {
+ Strcat_char(str, ' ');
+ Strcat_charp(str,
+ conv_from_system(buf->currentURL.real_file));
+ }
+ break;
+ /* case SCM_UNKNOWN: */
+ case SCM_MISSING:
+ break;
+ default:
+ p = parsedURL2Str(&buf->currentURL)->ptr;
+ if (DecodeURL)
+ p = url_unquote_conv(p, 0);
+ Strcat_charp(str, p);
+ break;
+ }
+ }
+ label[i] = str->ptr;
+ if (len < str->length)
+ len = str->length;
+ }
+ l = strlen(comment);
+ if (len < l + 4)
+ len = l + 4;
+ if (len > COLS - 2 * FRAME_WIDTH)
+ len = COLS - 2 * FRAME_WIDTH;
+ len = (len > 1) ? ((len - l + 1) / 2) : 0;
+ str = Strnew();
+ for (i = 0; i < len; i++)
+ Strcat_char(str, '-');
+ Strcat_charp(str, comment);
+ for (i = 0; i < len; i++)
+ Strcat_char(str, '-');
+ label[nitem] = str->ptr;
+ label[nitem + 1] = NULL;
+
+ new_option_menu(&SelTabMenu, label, &SelTabV, smChTab);
+ SelTabMenu.initial = SelTabV;
+ SelTabMenu.cursorX = Currentbuf->cursorX + Currentbuf->rootX;
+ SelTabMenu.cursorY = Currentbuf->cursorY + Currentbuf->rootY;
+ SelTabMenu.keymap['D'] = smDelTab;
+ SelTabMenu.item[nitem].type = MENU_NOP;
+}
+
+static void
+smChTab(void)
+{
+ int i;
+ TabBuffer *tab;
+ Buffer *buf;
+
+ if (SelTabV < 0 || SelTabV >= SelTabMenu.nitem)
+ return;
+ for (i = 0, tab = LastTab; i < SelTabV && tab != NULL;
+ i++, tab = tab->prevTab) ;
+ CurrentTab = tab;
+ for (tab = LastTab; tab != NULL; tab = tab->prevTab) {
+ if (tab == CurrentTab)
+ continue;
+ buf = tab->currentBuffer;
+#ifdef USE_IMAGE
+ deleteImage(buf);
+#endif
+ if (clear_buffer)
+ tmpClearBuffer(buf);
+ }
+}
+
+static int
+smDelTab(char c)
+{
+ int i, x, y, mselect;
+ TabBuffer *tab;
+
+ if (CurrentMenu->select < 0 || CurrentMenu->select >= SelTabMenu.nitem)
+ return (MENU_NOTHING);
+ for (i = 0, tab = LastTab; i < CurrentMenu->select && tab != NULL;
+ i++, tab = tab->prevTab) ;
+ deleteTab(tab);
+
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ mselect = CurrentMenu->select;
+
+ initSelTabMenu();
+
+ CurrentMenu->x = x;
+ CurrentMenu->y = y;
+
+ geom_menu(CurrentMenu, x, y, 0);
+
+ CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
+ : (CurrentMenu->nitem - 2);
+
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ draw_all_menu(CurrentMenu);
+ select_menu(CurrentMenu, CurrentMenu->select);
+ return (MENU_NOTHING);
+}
+
+/* --- SelectMenu (END) --- */
+
+/* --- OptionMenu --- */
+
+void
+optionMenu(int x, int y, char **label, int *variable, int initial,
+ void (*func) ())
+{
+ Menu menu;
+
+ set_menu_frame();
+
+ new_option_menu(&menu, label, variable, func);
+ menu.cursorX = COLS - 1;
+ menu.cursorY = LASTLINE;
+ menu.x = x;
+ menu.y = y;
+ menu.initial = initial;
+
+ popup_menu(NULL, &menu);
+}
+
+/* --- OptionMenu (END) --- */
+
+/* --- InitMenu --- */
+
+static void
+interpret_menu(FILE * mf)
+{
+ Str line;
+ char *p, *s;
+ int in_menu = 0, nmenu = 0, nitem = 0, type;
+ MenuItem *item = NULL;
+#ifdef USE_M17N
+ wc_ces charset = SystemCharset;
+#endif
+
+ while (!feof(mf)) {
+ line = Strfgets(mf);
+ Strchop(line);
+ Strremovefirstspaces(line);
+ if (line->length == 0)
+ continue;
+#ifdef USE_M17N
+ line = wc_Str_conv(line, charset, InnerCharset);
+#endif
+ p = line->ptr;
+ s = getWord(&p);
+ if (*s == '#') /* comment */
+ continue;
+ if (in_menu) {
+ type = setMenuItem(&item[nitem], s, p);
+ if (type == -1)
+ continue; /* error */
+ if (type == MENU_END)
+ in_menu = 0;
+ else {
+ nitem++;
+ item = New_Reuse(MenuItem, item, (nitem + 1));
+ w3mMenuList[nmenu].item = item;
+ item[nitem].type = MENU_END;
+ }
+ }
+ else if (!strcmp(s, "menu")) {
+ s = getQWord(&p);
+ if (*s == '\0') /* error */
+ continue;
+ in_menu = 1;
+ if ((nmenu = getMenuN(w3mMenuList, s)) != -1)
+ w3mMenuList[nmenu].item = New(MenuItem);
+ else
+ nmenu = addMenuList(&w3mMenuList, s);
+ item = w3mMenuList[nmenu].item;
+ nitem = 0;
+ item[nitem].type = MENU_END;
+ }
+#ifdef USE_M17N
+ else if (!strcmp(s, "charset") || !strcmp(s, "encoding")) {
+ s = getQWord(&p);
+ if (*s == '\0') /* error */
+ continue;
+ charset = wc_guess_charset(s, charset);
+ }
+#endif
+ }
+}
+
+void
+initMenu(void)
+{
+ FILE *mf;
+ MenuList *list;
+
+ w3mMenuList = New_N(MenuList, 3);
+ w3mMenuList[0].id = "Main";
+ w3mMenuList[0].menu = &MainMenu;
+ w3mMenuList[0].item = MainMenuItem;
+ w3mMenuList[1].id = "Select";
+ w3mMenuList[1].menu = &SelectMenu;
+ w3mMenuList[1].item = NULL;
+ w3mMenuList[2].id = "SelectTab";
+ w3mMenuList[2].menu = &SelTabMenu;
+ w3mMenuList[2].item = NULL;
+ w3mMenuList[3].id = NULL;
+
+#ifdef USE_M17N
+ if (!MainMenuEncode) {
+ MenuItem *item;
+#if ENABLE_NLS
+ /* FIXME: charset that gettext(3) returns */
+ MainMenuCharset = SystemCharset;
+#endif
+ for (item = MainMenuItem; item->type != MENU_END; item++)
+ item->label =
+ wc_conv(gettext(item->label), MainMenuCharset,
+ InnerCharset)->ptr;
+ MainMenuEncode = TRUE;
+ }
+#endif
+ if ((mf = fopen(confFile(MENU_FILE), "rt")) != NULL) {
+ interpret_menu(mf);
+ fclose(mf);
+ }
+ if ((mf = fopen(rcFile(MENU_FILE), "rt")) != NULL) {
+ interpret_menu(mf);
+ fclose(mf);
+ }
+
+ for (list = w3mMenuList; list->id != NULL; list++) {
+ if (list->item == NULL)
+ continue;
+ new_menu(list->menu, list->item);
+ }
+}
+
+int
+setMenuItem(MenuItem *item, char *type, char *line)
+{
+ char *label, *func, *popup, *keys, *data;
+ int f;
+ int n;
+
+ if (type == NULL || *type == '\0') /* error */
+ return -1;
+ if (strcmp(type, "end") == 0) {
+ item->type = MENU_END;
+ return MENU_END;
+ }
+ else if (strcmp(type, "nop") == 0) {
+ item->type = MENU_NOP;
+ item->label = getQWord(&line);
+ return MENU_NOP;
+ }
+ else if (strcmp(type, "func") == 0) {
+ label = getQWord(&line);
+ func = getWord(&line);
+ keys = getQWord(&line);
+ data = getQWord(&line);
+ if (*func == '\0') /* error */
+ return -1;
+ item->type = MENU_FUNC;
+ item->label = label;
+ f = getFuncList(func);
+ item->func = w3mFuncList[(f >= 0) ? f : FUNCNAME_nulcmd].func;
+ item->keys = keys;
+ item->data = data;
+ return MENU_FUNC;
+ }
+ else if (strcmp(type, "popup") == 0) {
+ label = getQWord(&line);
+ popup = getQWord(&line);
+ keys = getQWord(&line);
+ if (*popup == '\0') /* error */
+ return -1;
+ item->type = MENU_POPUP;
+ item->label = label;
+ if ((n = getMenuN(w3mMenuList, popup)) == -1)
+ n = addMenuList(&w3mMenuList, popup);
+ item->popup = w3mMenuList[n].menu;
+ item->keys = keys;
+ return MENU_POPUP;
+ }
+ return -1; /* error */
+}
+
+int
+addMenuList(MenuList **mlist, char *id)
+{
+ int n;
+ MenuList *list = *mlist;
+
+ for (n = 0; list->id != NULL; list++, n++) ;
+ *mlist = New_Reuse(MenuList, *mlist, (n + 2));
+ list = *mlist + n;
+ list->id = id;
+ list->menu = New(Menu);
+ list->item = New(MenuItem);
+ (list + 1)->id = NULL;
+ return n;
+}
+
+int
+getMenuN(MenuList *list, char *id)
+{
+ int n;
+
+ for (n = 0; list->id != NULL; list++, n++) {
+ if (strcmp(id, list->id) == 0)
+ return n;
+ }
+ return -1;
+}
+
+/* --- InitMenu (END) --- */
+
+LinkList *
+link_menu(Buffer *buf)
+{
+ Menu menu;
+ LinkList *l;
+ int i, nitem, len = 0, linkV = -1;
+ char **label;
+ Str str;
+ char *p;
+
+ if (!buf->linklist)
+ return NULL;
+
+ for (i = 0, l = buf->linklist; l; i++, l = l->next) ;
+ nitem = i;
+
+ label = New_N(char *, nitem + 1);
+ for (i = 0, l = buf->linklist; l; i++, l = l->next) {
+ str = Strnew_charp(l->title ? l->title : "(empty)");
+ if (l->type == LINK_TYPE_REL)
+ Strcat_charp(str, " [Rel] ");
+ else if (l->type == LINK_TYPE_REV)
+ Strcat_charp(str, " [Rev] ");
+ else
+ Strcat_charp(str, " ");
+ if (!l->url)
+ p = "";
+ else if (DecodeURL)
+ p = url_unquote_conv(l->url, buf->document_charset);
+ else
+ p = l->url;
+ Strcat_charp(str, p);
+ label[i] = str->ptr;
+ if (len < str->length)
+ len = str->length;
+ }
+ label[nitem] = NULL;
+
+ set_menu_frame();
+ new_option_menu(&menu, label, &linkV, NULL);
+
+ menu.initial = 0;
+ menu.cursorX = buf->cursorX + buf->rootX;
+ menu.cursorY = buf->cursorY + buf->rootY;
+ menu.x = menu.cursorX + FRAME_WIDTH + 1;
+ menu.y = menu.cursorY + 2;
+
+ popup_menu(NULL, &menu);
+
+ if (linkV < 0)
+ return NULL;
+ for (i = 0, l = buf->linklist; l; i++, l = l->next) {
+ if (i == linkV)
+ return l;
+ }
+ return NULL;
+}
+
+/* --- LinkMenu (END) --- */
+
+Anchor *
+accesskey_menu(Buffer *buf)
+{
+ Menu menu;
+ AnchorList *al = buf->href;
+ Anchor *a;
+ Anchor **ap;
+ int i, n, nitem = 0, key = -1;
+ char **label;
+ char *t;
+ unsigned char c;
+
+ if (!al)
+ return NULL;
+ for (i = 0; i < al->nanchor; i++) {
+ a = &al->anchors[i];
+ if (!a->slave && a->accesskey && IS_ASCII(a->accesskey))
+ nitem++;
+ }
+ if (!nitem)
+ return NULL;
+
+ label = New_N(char *, nitem + 1);
+ ap = New_N(Anchor *, nitem);
+ for (i = 0, n = 0; i < al->nanchor; i++) {
+ a = &al->anchors[i];
+ if (!a->slave && a->accesskey && IS_ASCII(a->accesskey)) {
+ t = getAnchorText(buf, al, a);
+ label[n] = Sprintf("%c: %s", a->accesskey, t ? t : "")->ptr;
+ ap[n] = a;
+ n++;
+ }
+ }
+ label[nitem] = NULL;
+
+ new_option_menu(&menu, label, &key, NULL);
+
+ menu.initial = 0;
+ menu.cursorX = buf->cursorX + buf->rootX;
+ menu.cursorY = buf->cursorY + buf->rootY;
+ menu.x = menu.cursorX + FRAME_WIDTH + 1;
+ menu.y = menu.cursorY + 2;
+ for (i = 0; i < 128; i++)
+ menu.keyselect[i] = -1;
+ for (i = 0; i < nitem; i++) {
+ c = ap[i]->accesskey;
+ menu.keymap[(int)c] = mSelect;
+ menu.keyselect[(int)c] = i;
+ }
+ for (i = 0; i < nitem; i++) {
+ c = ap[i]->accesskey;
+ if (!IS_ALPHA(c) || menu.keyselect[n] >= 0)
+ continue;
+ c = TOLOWER(c);
+ menu.keymap[(int)c] = mSelect;
+ menu.keyselect[(int)c] = i;
+ c = TOUPPER(c);
+ menu.keymap[(int)c] = mSelect;
+ menu.keyselect[(int)c] = i;
+ }
+
+ a = retrieveCurrentAnchor(buf);
+ if (a && a->accesskey && IS_ASCII(a->accesskey)) {
+ for (i = 0; i < nitem; i++) {
+ if (a->hseq == ap[i]->hseq) {
+ menu.initial = i;
+ break;
+ }
+ }
+ }
+
+ popup_menu(NULL, &menu);
+
+ return (key >= 0) ? ap[key] : NULL;
+}
+
+static char lmKeys[] = "abcdefgimopqrstuvwxyz";
+static char lmKeys2[] = "1234567890ABCDEFGHILMOPQRSTUVWXYZ";
+#define nlmKeys (sizeof(lmKeys) - 1)
+#define nlmKeys2 (sizeof(lmKeys2) - 1)
+
+static int
+lmGoto(char c)
+{
+ if (IS_ASCII(c) && CurrentMenu->keyselect[(int)c] >= 0) {
+ goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
+ goto_menu(CurrentMenu, CurrentMenu->keyselect[(int)c] * nlmKeys, 1);
+ }
+ return (MENU_NOTHING);
+}
+
+static int
+lmSelect(char c)
+{
+ if (IS_ASCII(c))
+ return select_menu(CurrentMenu, (CurrentMenu->select / nlmKeys) *
+ nlmKeys + CurrentMenu->keyselect[(int)c]);
+ else
+ return (MENU_NOTHING);
+}
+
+Anchor *
+list_menu(Buffer *buf)
+{
+ Menu menu;
+ AnchorList *al = buf->href;
+ Anchor *a;
+ Anchor **ap;
+ int i, n, nitem = 0, key = -1, two = FALSE;
+ char **label;
+ char *t;
+ unsigned char c;
+
+ if (!al)
+ return NULL;
+ for (i = 0; i < al->nanchor; i++) {
+ a = &al->anchors[i];
+ if (!a->slave)
+ nitem++;
+ }
+ if (!nitem)
+ return NULL;
+
+ if (nitem >= nlmKeys)
+ two = TRUE;
+ label = New_N(char *, nitem + 1);
+ ap = New_N(Anchor *, nitem);
+ for (i = 0, n = 0; i < al->nanchor; i++) {
+ a = &al->anchors[i];
+ if (!a->slave) {
+ t = getAnchorText(buf, al, a);
+ if (!t)
+ t = "";
+ if (two && n >= nlmKeys2 * nlmKeys)
+ label[n] = Sprintf(" : %s", t)->ptr;
+ else if (two)
+ label[n] = Sprintf("%c%c: %s", lmKeys2[n / nlmKeys],
+ lmKeys[n % nlmKeys], t)->ptr;
+ else
+ label[n] = Sprintf("%c: %s", lmKeys[n], t)->ptr;
+ ap[n] = a;
+ n++;
+ }
+ }
+ label[nitem] = NULL;
+
+ set_menu_frame();
+ set_menu_frame();
+ new_option_menu(&menu, label, &key, NULL);
+
+ menu.initial = 0;
+ menu.cursorX = buf->cursorX + buf->rootX;
+ menu.cursorY = buf->cursorY + buf->rootY;
+ menu.x = menu.cursorX + FRAME_WIDTH + 1;
+ menu.y = menu.cursorY + 2;
+ for (i = 0; i < 128; i++)
+ menu.keyselect[i] = -1;
+ if (two) {
+ for (i = 0; i < nlmKeys2; i++) {
+ c = lmKeys2[i];
+ menu.keymap[(int)c] = lmGoto;
+ menu.keyselect[(int)c] = i;
+ }
+ for (i = 0; i < nlmKeys; i++) {
+ c = lmKeys[i];
+ menu.keymap[(int)c] = lmSelect;
+ menu.keyselect[(int)c] = i;
+ }
+ }
+ else {
+ for (i = 0; i < nitem; i++) {
+ c = lmKeys[i];
+ menu.keymap[(int)c] = mSelect;
+ menu.keyselect[(int)c] = i;
+ }
+ }
+
+ a = retrieveCurrentAnchor(buf);
+ if (a) {
+ for (i = 0; i < nitem; i++) {
+ if (a->hseq == ap[i]->hseq) {
+ menu.initial = i;
+ break;
+ }
+ }
+ }
+
+ popup_menu(NULL, &menu);
+
+ return (key >= 0) ? ap[key] : NULL;
+}
+
+#endif /* USE_MENU */