diff options
Diffstat (limited to '')
-rw-r--r-- | menu.c | 2073 |
1 files changed, 2073 insertions, 0 deletions
@@ -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 */ |