⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 menubox.c

📁 This version of dialog, formerly known as cdialog is based on the Debian package for dialog 0.9a (se
💻 C
字号:
/* *  $Id: menubox.c,v 1.64 2003/11/26 21:10:11 tom Exp $ * *  menubox.c -- implements the menu box * *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk) *     and: Thomas E. Dickey * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  as published by the Free Software Foundation; either version 2 *  of the License, or (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "dialog.h"static int menu_width, tag_x, item_x;#define INPUT_ROWS     3	/* rows per inputmenu entry */#define LLEN(n) ((n) * MENUBOX_TAGS)#define ItemData(i)    &items[LLEN(i)]#define ItemName(i)    items[LLEN(i)]#define ItemText(i)    items[LLEN(i) + 1]#define ItemHelp(i)    items[LLEN(i) + 2]#define RowHeight(i) (dialog_vars.input_menu ? ((i) * INPUT_ROWS) : ((i) * 1))#define ItemToRow(i) (dialog_vars.input_menu ? ((i) * INPUT_ROWS + 1) : (i))#define RowToItem(i) (dialog_vars.input_menu ? ((i) / INPUT_ROWS + 0) : (i))/* * Print the tag of a menu-item */static voidprint_tag(WINDOW *win,	  char **items,	  int choice, int selected){    int my_x = item_x;    int my_y = ItemToRow(choice);    int tag_width = (my_x - tag_x - GUTTER);    const int *cols;    const int *indx;    int limit;    unsigned prefix;    cols = dlg_index_columns(ItemName(0));    indx = dlg_index_wchars(ItemName(0));    limit = dlg_count_wchars(ItemName(0));    prefix = indx[1] - indx[0];    /* highlight first char of the tag to be special */    (void) wmove(win, my_y, tag_x);    wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);    if (strlen(ItemName(0)) != 0)	(void) waddnstr(win, ItemName(0), prefix);    /* print rest of the string */    wattrset(win, selected ? tag_selected_attr : tag_attr);    if (strlen(ItemName(0)) > prefix) {	limit = dlg_limit_columns(ItemName(0), tag_width, 1);	if (limit > 0)	    (void) waddnstr(win, ItemName(0) + indx[1], indx[limit] - indx[1]);    }}/* * Print menu item */static voidprint_item(WINDOW *win,	   char **items,	   int choice, int selected){    int n;    int my_width = menu_width;    int my_x = item_x;    int my_y = ItemToRow(choice);    chtype attr = A_NORMAL;    if (items == 0)	return;    /* Clear 'residue' of last item and mark current current item */    if (dialog_vars.input_menu) {	wattrset(win, selected ? item_selected_attr : item_attr);	for (n = my_y - 1; n < my_y + INPUT_ROWS - 1; n++) {	    wmove(win, n, 0);	    wprintw(win, "%*s", my_width, " ");	}    } else {	wattrset(win, menubox_attr);	wmove(win, my_y, 0);	wprintw(win, "%*s", my_width, " ");    }    print_tag(win, items, choice, selected);    /* Draw the input field box (only for inputmenu) */    (void) wmove(win, my_y, my_x);    if (dialog_vars.input_menu) {	my_width -= 1;	dlg_draw_box(win, my_y - 1, my_x, INPUT_ROWS, my_width - my_x - tag_x,		     selected ? item_selected_attr : item_attr,		     selected ? item_selected_attr : item_attr);	my_width -= 1;	++my_x;    }    /* print actual item */    wmove(win, my_y, my_x);    wattrset(win, selected ? item_selected_attr : item_attr);    dlg_print_text(win, ItemText(0), my_width - my_x, &attr);    if (selected) {	dlg_item_help(ItemHelp(0));    }}static char *input_menu_edit(WINDOW *win, char **items, int choice){    char *result;    int offset = 0;    int key = 0, fkey;    int first = TRUE;    /* see above */    int y = ItemToRow(choice);    result = malloc(dialog_vars.max_input);    assert_ptr(result, "input_menu_edit");    dialog_vars.max_input = dialog_vars.max_input;    /* original item is used to initialize the input string. */    result[0] = '\0';    strcpy(result, ItemText(0));    print_tag(win, items, choice, TRUE);    /* taken out of inputbox.c - but somewhat modified */    while (key != '\n' && key != '\r') {	if (!first)	    key = dlg_mouse_wgetch(win, &fkey);	if (dlg_edit_string(result, &offset, key, fkey, first)) {	    /* 	     * menu_width - 2 ..... it's the actual number of maximal	     *                      possible characters could be written	     *                      to the screen.	     *	     * item_x - tag_x - 2 . same as "name_width"	     *                      ( see in dialog_menu() )	     */	    dlg_show_string(win, result, offset, item_selected_attr,			    y, item_x + 1, menu_width - item_x - 3,			    FALSE, first);	    first = FALSE;	}    }    return result;}static inthandle_button(int code, char **items, int choice){    switch (code) {    case DLG_EXIT_OK:		/* FALLTHRU */    case DLG_EXIT_EXTRA:	dlg_add_result(ItemName(choice));	break;    case DLG_EXIT_HELP:	dlg_add_result("HELP ");	if (USE_ITEM_HELP(ItemHelp(choice))) {	    dlg_add_result(ItemHelp(choice));	    code = DLG_EXIT_OK;	/* this is inconsistent */	} else {	    dlg_add_result(ItemName(choice));	}	break;    }    return code;}/* * Display a menu for choosing among a number of options */intdialog_menu(const char *title, const char *cprompt, int height, int width,	    int menu_height, int item_no, char **items){    int i, j, x, y, cur_x, cur_y, box_x, box_y;    int key = 0, fkey;    int button = dlg_defaultno_button();    int choice = dlg_default_item(items, MENUBOX_TAGS);    int result = DLG_EXIT_UNKNOWN;    int scrollamt = 0;    int max_choice, min_width;    int found;    int use_width, name_width, text_width;    WINDOW *dialog, *menu;    char *prompt = dlg_strclone(cprompt);    const char **buttons = dlg_ok_labels();    dlg_tab_correct_str(prompt);    if (menu_height == 0) {	min_width = dlg_calc_listw(item_no, items, MENUBOX_TAGS) + 10;	/* calculate height without items (4) */	dlg_auto_size(title, prompt, &height, &width, 4, MAX(26, min_width));	dlg_calc_listh(&height, &menu_height, item_no);    } else {	dlg_auto_size(title, prompt, &height, &width, 4 + menu_height, 26);    }    dlg_print_size(height, width);    dlg_ctl_size(height, width);    /* Find out maximal number of displayable items at once. */    max_choice = MIN(menu_height,		     RowHeight(item_no));    if (dialog_vars.input_menu)	max_choice /= INPUT_ROWS;    x = dlg_box_x_ordinate(width);    y = dlg_box_y_ordinate(height);    dialog = dlg_new_window(height, width, y, x);    dlg_mouse_setbase(x, y);    dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);    dlg_draw_bottom_box(dialog);    dlg_draw_title(dialog, title);    wattrset(dialog, dialog_attr);    dlg_print_autowrap(dialog, prompt, height, width);    menu_width = width - 6;    getyx(dialog, cur_y, cur_x);    box_y = cur_y + 1;    box_x = (width - menu_width) / 2 - 1;    /* create new window for the menu */    menu = dlg_sub_window(dialog, menu_height, menu_width,			  y + box_y + 1,			  x + box_x + 1);    /* draw a box around the menu items */    dlg_draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,		 menubox_border_attr, menubox_attr);    name_width = 0;    text_width = 0;    /* Find length of longest item to center menu  *     * only if --menu was given, using --inputmenu *     * won't be centered.                         */    for (i = 0; i < item_no; i++) {	name_width = MAX(name_width, dlg_count_columns(ItemName(i)));	text_width = MAX(text_width, dlg_count_columns(ItemText(i)));    }    /* If the name+text is wider than the list is allowed, then truncate     * one or both of them.  If the name is no wider than 1/4 of the list,     * leave it intact.     */    use_width = (menu_width - GUTTER);    if (text_width + name_width > use_width) {	int need = 0.25 * use_width;	if (name_width > need) {	    int want = use_width * ((double) name_width) / (text_width + name_width);	    name_width = (want > need) ? want : need;	}	text_width = use_width - name_width;    }    tag_x = (dialog_vars.input_menu	     ? 0	     : (use_width - text_width - name_width) / 2);    item_x = name_width + tag_x + GUTTER;    if (choice - scrollamt >= max_choice) {	scrollamt = choice - (max_choice - 1);	choice = max_choice - 1;    }    /* Print the menu */    for (i = 0; i < max_choice; i++)	print_item(menu, ItemData(i + scrollamt), i, i == choice);    (void) wnoutrefresh(menu);    /* register the new window, along with its borders */    dlg_mouse_mkbigregion(box_y + 1, box_x, menu_height + 2, menu_width + 2,			  KEY_MAX, 1, 1, 1 /* by lines */ );    dlg_draw_arrows(dialog, scrollamt,		    scrollamt + max_choice < item_no,		    box_x + tag_x + 1,		    box_y,		    box_y + menu_height + 1);    dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);    wtimeout(dialog, WTIMEOUT_VAL);    while (result == DLG_EXIT_UNKNOWN) {	key = dlg_mouse_wgetch(dialog, &fkey);	if (!fkey) {	    fkey = TRUE;	    switch (key) {	    case '\n':	    case '\r':		key = KEY_ENTER;		break;	    case '-':		key = KEY_UP;		break;	    case '+':		key = KEY_DOWN;		break;	    case ' ':	    case TAB:		key = KEY_RIGHT;		break;	    case ESC:		result = DLG_EXIT_ESC;		continue;	    default:		fkey = FALSE;		break;	    }	}	found = FALSE;	if (fkey) {	    /*	     * Allow a mouse-click on a box to switch selection to that box.	     * Handling a button click is a little more complicated, since we	     * push a KEY_ENTER back onto the input stream so we'll put the	     * cursor at the right place before handling the "keypress".	     */	    if (key >= (M_EVENT + KEY_MAX)) {		key -= (M_EVENT + KEY_MAX);		i = RowToItem(key);		found = TRUE;	    } else if (key >= M_EVENT		       && dlg_ok_buttoncode(key - M_EVENT) >= 0) {		button = (key - M_EVENT);		ungetch('\n');		continue;	    }	} else {	    /*	     * Check if key pressed matches first character of any item tag in	     * list.  If there is more than one match, we will cycle through	     * each one as the same key is pressed repeatedly.	     */	    for (j = scrollamt + choice + 1; j < item_no; j++) {		if (dlg_match_char(dlg_last_getc(), ItemName(j))) {		    found = TRUE;		    i = j - scrollamt;		    break;		}	    }	    if (!found) {		for (j = 0; j <= scrollamt + choice; j++) {		    if (dlg_match_char(dlg_last_getc(), ItemName(j))) {			found = TRUE;			i = j - scrollamt;			break;		    }		}	    }	    if (found)		dlg_flush_getc();	    /*	     * A single digit (1-9) positions the selection to that line in the	     * current screen.	     */	    if (!found		&& (key <= '9')		&& (key > '0')		&& (key - '1' < max_choice)) {		found = TRUE;		i = key - '1';	    }	}	if (!found && fkey) {	    found = TRUE;	    switch (key) {	    case KEY_HOME:		i = -scrollamt;		break;	    case KEY_LL:	    case KEY_END:		i = item_no - 1 - scrollamt;		break;	    case M_EVENT + KEY_PPAGE:	    case KEY_PPAGE:		if (choice)		    i = 0;		else if (scrollamt != 0)		    i = -MIN(scrollamt, max_choice);		else		    continue;		break;	    case M_EVENT + KEY_NPAGE:	    case KEY_NPAGE:		i = MIN(choice + max_choice, item_no - scrollamt - 1);		break;	    case KEY_UP:		i = choice - 1;		if (choice == 0 && scrollamt == 0)		    continue;		break;	    case KEY_DOWN:		i = choice + 1;		if (scrollamt + choice >= item_no - 1)		    continue;		break;	    default:		found = FALSE;		break;	    }	}	if (found) {	    if (i != choice) {		getyx(dialog, cur_y, cur_x);		if (i < 0 || i >= max_choice) {#if defined(NCURSES_VERSION_MAJOR) && NCURSES_VERSION_MAJOR < 5		    /*		     * Using wscrl to assist ncurses scrolling is not needed		     * in version 5.x		     */		    if (i == -1) {			if (menu_height > 1) {			    /* De-highlight current first item */			    print_item(menu, ItemData(scrollamt), 0, FALSE);			    scrollok(menu, TRUE);			    wscrl(menu, -RowHeight(1));			    scrollok(menu, FALSE);			}			scrollamt--;			print_item(menu, ItemData(scrollamt), 0, TRUE);		    } else if (i == max_choice) {			if (menu_height > 1) {			    /* De-highlight current last item before scrolling up */			    print_item(menu,				       ItemData(scrollamt + max_choice - 1),				       max_choice - 1, FALSE);			    scrollok(menu, TRUE);			    wscrl(menu, RowHeight(1));			    scrollok(menu, FALSE);			}			scrollamt++;			print_item(menu,				   ItemData(scrollamt + max_choice - 1),				   max_choice - 1, TRUE);		    } else#endif		    {			if (i < 0) {			    scrollamt += i;			    choice = 0;			} else {			    choice = max_choice - 1;			    scrollamt += (i - max_choice + 1);			}			for (i = 0; i < max_choice; i++) {			    print_item(menu,				       ItemData(scrollamt + i),				       i, i == choice);			}		    }		    /* Clean bottom lines */		    if (dialog_vars.input_menu) {			int spare_lines, x_count;			spare_lines = menu_height % INPUT_ROWS;			wattrset(menu, menubox_attr);			for (; spare_lines; spare_lines--) {			    wmove(menu, menu_height - spare_lines, 0);			    for (x_count = 0; x_count < menu_width;				 x_count++) {				waddch(menu, ' ');			    }			}		    }		    (void) wnoutrefresh(menu);		    dlg_draw_arrows(dialog, scrollamt,				    scrollamt + choice < item_no - 1,				    box_x + tag_x + 1,				    box_y,				    box_y + menu_height + 1);		} else {		    /* De-highlight current item */		    print_item(menu,			       ItemData(scrollamt + choice),			       choice, FALSE);		    /* Highlight new item */		    choice = i;		    print_item(menu,			       ItemData(scrollamt + choice),			       choice, TRUE);		    (void) wnoutrefresh(menu);		    (void) wmove(dialog, cur_y, cur_x);		    wrefresh(dialog);		}	    }	    continue;		/* wait for another key press */	}	if (fkey) {	    switch (key) {	    case KEY_BTAB:	    case KEY_LEFT:		button = dlg_prev_button(buttons, button);		dlg_draw_buttons(dialog, height - 2, 0, buttons, button,				 FALSE, width);		break;	    case KEY_RIGHT:		button = dlg_next_button(buttons, button);		dlg_draw_buttons(dialog, height - 2, 0, buttons, button,				 FALSE, width);		break;	    case KEY_ENTER:		result = handle_button(dlg_ok_buttoncode(button),				       items,				       scrollamt + choice);		if (dialog_vars.input_menu && result == DLG_EXIT_EXTRA) {		    char *tmp;		    tmp = input_menu_edit(menu, ItemData(scrollamt + choice),					  choice);		    dialog_vars.input_result[0] = '\0';		    dlg_add_result("RENAMED ");		    dlg_add_result(ItemName(scrollamt + choice));		    dlg_add_result(" ");		    dlg_add_result(tmp);		    free(tmp);		    dlg_draw_buttons(dialog, height - 2, 0,				     buttons, button, FALSE, width);		}		break;	    default:		flash();		break;	    }	}    }    dlg_mouse_free_regions();    dlg_del_window(dialog);    free(prompt);    return result;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -