Пример #1
0
void print_menu(uint8_t menu)
{
	lcd_clrscr();
	print_arrows(0);
	lcd_gotoxy(1, 0);
	lcd_puts_p(menuStrings[menu - 1]);

	switch (menu)
	{
	case SET_TIME:
		print_time(t);
		break;
	case SET_ALARM1:
		print_time(alarmTime);
		break;
	//case SET_ALARM2:
	//	print_time(alarmTime);
	//	break;
	case SET_RETURN:
		break;
	}
}
Пример #2
0
/*
 * Display a menu for choosing among a number of options
 */
int dialog_menu(const char *title, const char *prompt,
                const void *selected, int *s_scroll)
{
	int i, j, x, y, box_x, box_y;
	int height, width, menu_height;
	int key = 0, button = 0, scroll = 0, choice = 0;
	int first_item =  0, max_choice;
	WINDOW *dialog, *menu;

do_resize:
	height = getmaxy(stdscr);
	width = getmaxx(stdscr);
	if (height < 15 || width < 65)
		return -ERRDISPLAYTOOSMALL;

	height -= 4;
	width  -= 5;
	menu_height = height - 10;

	max_choice = MIN(menu_height, item_count());

	/* center dialog box on screen */
	x = (COLS - width) / 2;
	y = (LINES - height) / 2;

	draw_shadow(stdscr, y, x, height, width);

	dialog = newwin(height, width, y, x);
	keypad(dialog, TRUE);

	draw_box(dialog, 0, 0, height, width,
		 dlg.dialog.atr, dlg.border.atr);
	wattrset(dialog, dlg.border.atr);
	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
	for (i = 0; i < width - 2; i++)
		waddch(dialog, ACS_HLINE);
	wattrset(dialog, dlg.dialog.atr);
	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
	waddch(dialog, ACS_RTEE);

	print_title(dialog, title, width);

	wattrset(dialog, dlg.dialog.atr);
	print_autowrap(dialog, prompt, width - 2, 1, 3);

	menu_width = width - 6;
	box_y = height - menu_height - 5;
	box_x = (width - menu_width) / 2 - 1;

	/* create new window for the menu */
	menu = subwin(dialog, menu_height, menu_width,
		      y + box_y + 1, x + box_x + 1);
	keypad(menu, TRUE);

	/* draw a box around the menu items */
	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
		 dlg.menubox_border.atr, dlg.menubox.atr);

	if (menu_width >= 80)
		item_x = (menu_width - 70) / 2;
	else
		item_x = 4;

	/* Set choice to default item */
	item_foreach()
		if (selected && (selected == item_data()))
			choice = item_n();
	/* get the saved scroll info */
	scroll = *s_scroll;
	if ((scroll <= choice) && (scroll + max_choice > choice) &&
	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
		first_item = scroll;
		choice = choice - scroll;
	} else {
		scroll = 0;
	}
	if ((choice >= max_choice)) {
		if (choice >= item_count() - max_choice / 2)
			scroll = first_item = item_count() - max_choice;
		else
			scroll = first_item = choice - max_choice / 2;
		choice = choice - scroll;
	}

	/* Print the menu */
	for (i = 0; i < max_choice; i++) {
		print_item(first_item + i, i, i == choice);
	}

	wnoutrefresh(menu);

	print_arrows(dialog, item_count(), scroll,
		     box_y, box_x + item_x + 1, menu_height);

	print_buttons(dialog, height, width, 0);
	wmove(menu, choice, item_x + 1);
	wrefresh(menu);

	while (key != KEY_ESC) {
		key = wgetch(menu);

		if (key < 256 && isalpha(key))
			key = tolower(key);

		if (strchr("ynmh", key))
			i = max_choice;
		else {
			for (i = choice + 1; i < max_choice; i++) {
				item_set(scroll + i);
				j = first_alpha(item_str(), "YyNnMmHh");
				if (key == tolower(item_str()[j]))
					break;
			}
			if (i == max_choice)
				for (i = 0; i < max_choice; i++) {
					item_set(scroll + i);
					j = first_alpha(item_str(), "YyNnMmHh");
					if (key == tolower(item_str()[j]))
						break;
				}
		}

		if (i < max_choice ||
		    key == KEY_UP || key == KEY_DOWN ||
		    key == '-' || key == '+' ||
		    key == KEY_PPAGE || key == KEY_NPAGE) {
			/* Remove highligt of current item */
			print_item(scroll + choice, choice, FALSE);

			if (key == KEY_UP || key == '-') {
				if (choice < 2 && scroll) {
					/* Scroll menu down */
					do_scroll(menu, &scroll, -1);

					print_item(scroll, 0, FALSE);
				} else
					choice = MAX(choice - 1, 0);

			} else if (key == KEY_DOWN || key == '+') {
				print_item(scroll+choice, choice, FALSE);

				if ((choice > max_choice - 3) &&
				    (scroll + max_choice < item_count())) {
					/* Scroll menu up */
					do_scroll(menu, &scroll, 1);

					print_item(scroll+max_choice - 1,
						   max_choice - 1, FALSE);
				} else
					choice = MIN(choice + 1, max_choice - 1);

			} else if (key == KEY_PPAGE) {
				scrollok(menu, TRUE);
				for (i = 0; (i < max_choice); i++) {
					if (scroll > 0) {
						do_scroll(menu, &scroll, -1);
						print_item(scroll, 0, FALSE);
					} else {
						if (choice > 0)
							choice--;
					}
				}

			} else if (key == KEY_NPAGE) {
				for (i = 0; (i < max_choice); i++) {
					if (scroll + max_choice < item_count()) {
						do_scroll(menu, &scroll, 1);
						print_item(scroll+max_choice-1,
							   max_choice - 1, FALSE);
					} else {
						if (choice + 1 < max_choice)
							choice++;
					}
				}
			} else
				choice = i;

			print_item(scroll + choice, choice, TRUE);

			print_arrows(dialog, item_count(), scroll,
				     box_y, box_x + item_x + 1, menu_height);

			wnoutrefresh(dialog);
			wrefresh(menu);

			continue;	/* wait for another key press */
		}

		switch (key) {
		case KEY_LEFT:
		case TAB:
		case KEY_RIGHT:
			button = ((key == KEY_LEFT ? --button : ++button) < 0)
			    ? 2 : (button > 2 ? 0 : button);

			print_buttons(dialog, height, width, button);
			wrefresh(menu);
			break;
		case ' ':
		case 's':
		case 'y':
		case 'n':
		case 'm':
		case '/':
			/* save scroll info */
			*s_scroll = scroll;
			delwin(menu);
			delwin(dialog);
			item_set(scroll + choice);
			item_set_selected(1);
			switch (key) {
			case 's':
				return 3;
			case 'y':
				return 3;
			case 'n':
				return 4;
			case 'm':
				return 5;
			case ' ':
				return 6;
			case '/':
				return 7;
			}
			return 0;
		case 'h':
		case '?':
			button = 2;
		case '\n':
			*s_scroll = scroll;
			delwin(menu);
			delwin(dialog);
			item_set(scroll + choice);
			item_set_selected(1);
			return button;
		case 'e':
		case 'x':
			key = KEY_ESC;
			break;
		case KEY_ESC:
			key = on_key_esc(menu);
			break;
#ifdef NCURSES_VERSION
		case KEY_RESIZE:
			on_key_resize();
			delwin(menu);
			delwin(dialog);
			goto do_resize;
#endif
		}
	}
	delwin(menu);
	delwin(dialog);
	return key;		/* ESC pressed */
}
Пример #3
0
int dialog_checklist(const char *title, const char *prompt, int height,
		     int width, int list_height)
{
	int i, x, y, box_x, box_y;
	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
	WINDOW *dialog, *list;

	/*                         */
	item_foreach() {
		if (item_is_tag('X'))
			choice = item_n();
		if (item_is_selected()) {
			choice = item_n();
			break;
		}
	}

do_resize:
	if (getmaxy(stdscr) < (height + 6))
		return -ERRDISPLAYTOOSMALL;
	if (getmaxx(stdscr) < (width + 6))
		return -ERRDISPLAYTOOSMALL;

	max_choice = MIN(list_height, item_count());

	/*                             */
	x = (COLS - width) / 2;
	y = (LINES - height) / 2;

	draw_shadow(stdscr, y, x, height, width);

	dialog = newwin(height, width, y, x);
	keypad(dialog, TRUE);

	draw_box(dialog, 0, 0, height, width,
		 dlg.dialog.atr, dlg.border.atr);
	wattrset(dialog, dlg.border.atr);
	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
	for (i = 0; i < width - 2; i++)
		waddch(dialog, ACS_HLINE);
	wattrset(dialog, dlg.dialog.atr);
	waddch(dialog, ACS_RTEE);

	print_title(dialog, title, width);

	wattrset(dialog, dlg.dialog.atr);
	print_autowrap(dialog, prompt, width - 2, 1, 3);

	list_width = width - 6;
	box_y = height - list_height - 5;
	box_x = (width - list_width) / 2 - 1;

	/*                                */
	list = subwin(dialog, list_height, list_width, y + box_y + 1,
	              x + box_x + 1);

	keypad(list, TRUE);

	/*                                  */
	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
	         dlg.menubox_border.atr, dlg.menubox.atr);

	/*                                                          */
	check_x = 0;
	item_foreach()
		check_x = MAX(check_x, strlen(item_str()) + 4);
	check_x = MIN(check_x, list_width);

	check_x = (list_width - check_x) / 2;
	item_x = check_x + 4;

	if (choice >= list_height) {
		scroll = choice - list_height + 1;
		choice -= scroll;
	}

	/*                */
	for (i = 0; i < max_choice; i++) {
		item_set(scroll + i);
		print_item(list, i, i == choice);
	}

	print_arrows(dialog, choice, item_count(), scroll,
		     box_y, box_x + check_x + 5, list_height);

	print_buttons(dialog, height, width, 0);

	wnoutrefresh(dialog);
	wnoutrefresh(list);
	doupdate();

	while (key != KEY_ESC) {
		key = wgetch(dialog);

		for (i = 0; i < max_choice; i++) {
			item_set(i + scroll);
			if (toupper(key) == toupper(item_str()[0]))
				break;
		}

		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
		    key == '+' || key == '-') {
			if (key == KEY_UP || key == '-') {
				if (!choice) {
					if (!scroll)
						continue;
					/*                  */
					if (list_height > 1) {
						/*                                 */
						item_set(scroll);
						print_item(list, 0, FALSE);
						scrollok(list, TRUE);
						wscrl(list, -1);
						scrollok(list, FALSE);
					}
					scroll--;
					item_set(scroll);
					print_item(list, 0, TRUE);
					print_arrows(dialog, choice, item_count(),
						     scroll, box_y, box_x + check_x + 5, list_height);

					wnoutrefresh(dialog);
					wrefresh(list);

					continue;	/*                            */
				} else
					i = choice - 1;
			} else if (key == KEY_DOWN || key == '+') {
				if (choice == max_choice - 1) {
					if (scroll + choice >= item_count() - 1)
						continue;
					/*                */
					if (list_height > 1) {
						/*                                                    */
						item_set(scroll + max_choice - 1);
						print_item(list,
							    max_choice - 1,
							    FALSE);
						scrollok(list, TRUE);
						wscrl(list, 1);
						scrollok(list, FALSE);
					}
					scroll++;
					item_set(scroll + max_choice - 1);
					print_item(list, max_choice - 1, TRUE);

					print_arrows(dialog, choice, item_count(),
						     scroll, box_y, box_x + check_x + 5, list_height);

					wnoutrefresh(dialog);
					wrefresh(list);

					continue;	/*                            */
				} else
					i = choice + 1;
			}
			if (i != choice) {
				/*                           */
				item_set(scroll + choice);
				print_item(list, choice, FALSE);
				/*                    */
				choice = i;
				item_set(scroll + choice);
				print_item(list, choice, TRUE);
				wnoutrefresh(dialog);
				wrefresh(list);
			}
			continue;	/*                            */
		}
		switch (key) {
		case 'H':
		case 'h':
		case '?':
			button = 1;
			/*              */
		case 'S':
		case 's':
		case ' ':
		case '\n':
			item_foreach()
				item_set_selected(0);
			item_set(scroll + choice);
			item_set_selected(1);
			delwin(list);
			delwin(dialog);
			return button;
		case TAB:
		case KEY_LEFT:
		case KEY_RIGHT:
			button = ((key == KEY_LEFT ? --button : ++button) < 0)
			    ? 1 : (button > 1 ? 0 : button);

			print_buttons(dialog, height, width, button);
			wrefresh(dialog);
			break;
		case 'X':
		case 'x':
			key = KEY_ESC;
			break;
		case KEY_ESC:
			key = on_key_esc(dialog);
			break;
		case KEY_RESIZE:
			delwin(list);
			delwin(dialog);
			on_key_resize();
			goto do_resize;
		}

		/*                           */
		doupdate();
	}
	delwin(list);
	delwin(dialog);
	return key;		/*             */
}
Пример #4
0
/*
 * Display a dialog box with a list of options that can be turned on or off
 */
int
dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width,
		 int list_height, int cnt, void *it, unsigned char *result)
{
    int i, j, x, y, cur_x, cur_y, old_x, old_y, box_x, box_y, key = 0, button,
	choice, l, k, scroll, max_choice, item_no = 0, *status;
    int redraw_menu = FALSE, cursor_reset = FALSE;
    int rval = 0, onlist = 1, ok_space, cancel_space;
    char okButton, cancelButton;
    WINDOW *dialog, *list;
    unsigned char **items = NULL;
    dialogMenuItem *ditems;
    int list_width, check_x, item_x;

    /* Allocate space for storing item on/off status */
    if ((status = alloca(sizeof(int) * abs(cnt))) == NULL) {
	endwin();
	fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n");
	exit(-1);
    }
    
draw:
    choice = scroll = button = 0;
    /* Previous calling syntax, e.g. just a list of strings? */
    if (cnt >= 0) {
	items = it;
	ditems = NULL;
	item_no = cnt;
	/* Initializes status */
	for (i = 0; i < item_no; i++)
	    status[i] = !strcasecmp(items[i*3 + 2], "on");
    }
    /* It's the new specification format - fake the rest of the code out */
    else {
	item_no = abs(cnt);
	ditems = it;
	if (!items)
	    items = (unsigned char **)alloca((item_no * 3) * sizeof(unsigned char *));
	
	/* Initializes status */
	for (i = 0; i < item_no; i++) {
	    status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
	    items[i*3] = ditems[i].prompt;
	    items[i*3 + 1] = ditems[i].title;
	    items[i*3 + 2] = status[i] ? "on" : "off";
	}
    }
    max_choice = MIN(list_height, item_no);
    
    check_x = 0;
    item_x = 0;
    /* Find length of longest item in order to center checklist */
    for (i = 0; i < item_no; i++) {
	l = strlen(items[i*3]);
	for (j = 0; j < item_no; j++) {
	    k = strlen(items[j*3 + 1]);
	    check_x = MAX(check_x, l + k + 6);
	}
	item_x = MAX(item_x, l);
    }
    if (height < 0)
	height = strheight(prompt)+list_height+4+2;
    if (width < 0) {
	i = strwidth(prompt);
	j = ((title != NULL) ? strwidth(title) : 0);
	width = MAX(i,j);
	width = MAX(width,check_x+4)+4;
    }
    width = MAX(width,24);
    
    if (width > COLS)
	width = COLS;
    if (height > LINES)
	height = LINES;
    /* center dialog box on screen */
    x = (COLS - width)/2;
    y = (LINES - height)/2;

#ifdef HAVE_NCURSES
    if (use_shadow)
	draw_shadow(stdscr, y, x, height, width);
#endif
    dialog = newwin(height, width, y, x);
    if (dialog == NULL) {
	endwin();
	fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width, y, x);
	return -1;
    }
    keypad(dialog, TRUE);
    
    draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
    wattrset(dialog, border_attr);
    wmove(dialog, height-3, 0);
    waddch(dialog, ACS_LTEE);
    for (i = 0; i < width-2; i++)
	waddch(dialog, ACS_HLINE);
    wattrset(dialog, dialog_attr);
    waddch(dialog, ACS_RTEE);
    wmove(dialog, height-2, 1);
    for (i = 0; i < width-2; i++)
	waddch(dialog, ' ');
    
    if (title != NULL) {
	wattrset(dialog, title_attr);
	wmove(dialog, 0, (width - strlen(title))/2 - 1);
	waddch(dialog, ' ');
	waddstr(dialog, title);
	waddch(dialog, ' ');
    }
    wattrset(dialog, dialog_attr);
    wmove(dialog, 1, 2);
    print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE);
    
    list_width = width - 6;
    getyx(dialog, cur_y, cur_x);
    box_y = cur_y + 1;
    box_x = (width - list_width) / 2 - 1;
    
    /* create new window for the list */
    list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1);
    if (list == NULL) {
	delwin(dialog);
	endwin();
	fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height, list_width,
		y + box_y + 1, x + box_x + 1);
	return -1;
    }
    keypad(list, TRUE);
    
    /* draw a box around the list items */
    draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);
    
    check_x = (list_width - check_x) / 2;
    item_x = check_x + item_x + 6;
    
    /* Print the list */
    for (i = 0; i < max_choice; i++)
	print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x);
    wnoutrefresh(list);
    print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
    
    display_helpline(dialog, height - 1, width);
    
    x = width / 2 - 11;
    y = height - 2;
    /* Is this a fancy new style argument string where we get to override
     * the buttons, or an old style one where they're fixed?
     */
    if (ditems && result) {
	cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]);
	print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE);
	okButton = toupper(ditems[OK_BUTTON].prompt[0]);
	print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE);
    }
    else {
	cancelButton = 'C';
	print_button(dialog, "Cancel", y, x + 14, FALSE);
	okButton = 'O';
	print_button(dialog, "  OK  ", y, x, TRUE);
    }
    wnoutrefresh(dialog);
    wmove(list, choice, check_x+1);
    wrefresh(list);

    /*
     *	XXX Black magic voodoo that allows printing to the checklist
     *	window. For some reason, if this "refresh" code is not in
     *	place, printing to the window from the selected callback
     *	prints "behind" the checklist window. There is probably a
     *	better way to do this.
     */
    draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);

    for (i = 0; i < max_choice; i++)
	print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x);
    print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);

    wmove(list, choice, check_x+1);
    wnoutrefresh(dialog);
    wrefresh(list);
    /* XXX Black magic XXX */
    
    while (key != ESC) {
	key = wgetch(dialog);
	
	/* Shortcut to OK? */
	if (toupper(key) == okButton) {
	    if (ditems) {
		if (result && ditems[OK_BUTTON].fire) {
		    int st;
		    WINDOW *save;

		    save = dupwin(newscr);
		    st = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]);
		    if (st & DITEM_RESTORE) {
			touchwin(save);
			wrefresh(save);
		    }
		    delwin(save);
		}
	    }
	    else if (result) {
		*result = '\0';
		for (i = 0; i < item_no; i++) {
		    if (status[i]) {
			strcat(result, items[i*3]);
			strcat(result, "\n");
		    }
		}
	    }
	    rval = 0;
	    key = ESC;	/* Lemme out! */
	    break;
	}

	/* Shortcut to cancel? */
	if (toupper(key) == cancelButton) {
	    if (ditems && result && ditems[CANCEL_BUTTON].fire) {
		int st;
		WINDOW *save;

		save = dupwin(newscr);
		st = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]);
		if (st & DITEM_RESTORE) {
		    touchwin(save);
		    wrefresh(save);
		    wmove(dialog, cur_y, cur_x);
		}
		delwin(save);
	    }
	    rval = 1;
	    key = ESC;	/* I gotta go! */
	    break;
	}
	
	/* Check if key pressed matches first character of any item tag in list */
	for (i = 0; i < max_choice; i++)
	    if (key != ' ' && key < 0x100 && toupper(key) == toupper(items[(scroll+i)*3][0]))
		break;

	if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) ||
	    KEY_IS_UP(key) || KEY_IS_DOWN(key) || ((key == ' ' || key == '\n' ||
	    key == '\r') && onlist)) {

	    /* if moving from buttons to the list, reset and redraw buttons */
	    if (!onlist) {
		onlist = 1;
		button = 0;

	        if (ditems && result) {
		    print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
		    print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
		}
		else {
		    print_button(dialog, "Cancel", y, x + 14, button);
		    print_button(dialog, "  OK  ", y, x, !button);
		}
		wmove(list, choice, check_x+1);
		wnoutrefresh(dialog);
		wrefresh(list);
	    }

	    if (key >= '1' && key <= MIN('9', '0'+max_choice))
		i = key - '1';
	    
	    else if (KEY_IS_UP(key)) {
		if (!choice) {
		    if (scroll) {
			/* Scroll list down */
			getyx(dialog, cur_y, cur_x);    /* Save cursor position */
			if (list_height > 1) {
			    /* De-highlight current first item before scrolling down */
			    print_item(list, items[scroll * 3], items[scroll * 3 + 1], status[scroll], 0,
				       FALSE, DREF(ditems, scroll), list_width, item_x, check_x);
			    scrollok(list, TRUE);
			    wscrl(list, -1);
			    scrollok(list, FALSE);
			}
			scroll--;
			print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0,
				   TRUE, DREF(ditems, scroll), list_width, item_x, check_x);
			print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
			wmove(list, choice, check_x+1);
			wnoutrefresh(dialog);
			wrefresh(list);
		    }
		    continue;    /* wait for another key press */
		}
		else
		    i = choice - 1;
	    }
	    else if (KEY_IS_DOWN(key)) {
		if (choice == max_choice - 1) {
		    if (scroll + choice < item_no - 1) {
			/* Scroll list up */
			getyx(dialog, cur_y, cur_x);    /* Save cursor position */
			if (list_height > 1) {
			    /* De-highlight current last item before scrolling up */
			    print_item(list, items[(scroll + max_choice - 1) * 3],
				       items[(scroll + max_choice - 1) * 3 + 1],
				       status[scroll + max_choice - 1], max_choice - 1,
				       FALSE, DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
			    scrollok(list, TRUE);
			    scroll(list);
			    scrollok(list, FALSE);
			}
			scroll++;
			print_item(list, items[(scroll + max_choice - 1) * 3],
				   items[(scroll + max_choice - 1) * 3 + 1],
				   status[scroll + max_choice - 1], max_choice - 1, TRUE,
				   DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
			print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
			wmove(list, choice, check_x+1);
			wnoutrefresh(dialog);
			wrefresh(list);
		    }
		    continue;    /* wait for another key press */
		}
		else
		    i = choice + 1;
	    }
	    else if ((key == ' ' || key == '\n' || key == '\r') && onlist) {    /* Toggle item status */
		char lbra = 0, rbra = 0, mark = 0;

		getyx(list, old_y, old_x);    /* Save cursor position */
		
		if (ditems) {
		    if (ditems[scroll + choice].fire) {
			int st;
			WINDOW *save;

			save = dupwin(newscr);
			st = ditems[scroll + choice].fire(&ditems[scroll + choice]);	/* Call "fire" action */
			if (st & DITEM_RESTORE) {
			    touchwin(save);
			    wrefresh(save);
			}
			delwin(save);
			if (st & DITEM_REDRAW) {
			    wclear(list);
			    for (i = 0; i < item_no; i++)
				status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
			    for (i = 0; i < max_choice; i++) {
				print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1],
					   status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
			    }
			    wnoutrefresh(list);
			    print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4,
					 cur_x, cur_y);
			    wrefresh(dialog);
			}
			if (st & DITEM_LEAVE_MENU) {
			    /* Allow a fire action to take us out of the menu */
			    key = ESC;
			    rval = 0;
			    break;
			}
			else if (st & DITEM_RECREATE) {
			    delwin(list);
			    delwin(dialog);
			    dialog_clear();
			    goto draw;
			}
		    }
		    status[scroll + choice] = ditems[scroll + choice].checked ?
			ditems[scroll + choice].checked(&ditems[scroll + choice]) : FALSE;
		    lbra = ditems[scroll + choice].lbra;
		    rbra = ditems[scroll + choice].rbra;
		    mark = ditems[scroll + choice].mark;
		}
		else
		    status[scroll + choice] = !status[scroll + choice];
		wmove(list, choice, check_x);
		wattrset(list, check_selected_attr);
		if (!lbra)
		    lbra = '[';
		if (!rbra)
		    rbra = ']';
		if (!mark)
		    mark = 'X';
		wprintw(list, "%c%c%c", lbra, status[scroll + choice] ? mark : ' ', rbra);
		wmove(list, old_y, old_x);  /* Restore cursor to previous position */
		wrefresh(list);
		continue;    /* wait for another key press */
	    }
	    
	    if (i != choice) {
		/* De-highlight current item */
		getyx(dialog, cur_y, cur_x);    /* Save cursor position */
		print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1],
			   status[scroll + choice], choice, FALSE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
		
		/* Highlight new item */
		choice = i;
		print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
		wmove(list, choice, check_x+1);	  /* Restore cursor to previous position */
		wrefresh(list);
	    }
	    continue;    /* wait for another key press */
	}
	
	switch (key) {
	case KEY_PPAGE:	/* can we go up? */
	    if (scroll > height - 4)
		scroll -= (height-4);
	    else
		scroll = 0;
	    redraw_menu = TRUE;
	    if (!onlist) {
		onlist = 1;
		button = 0;
	    }
	    break;
	    
	case KEY_NPAGE:      /* can we go down a full page? */
	    if (scroll + list_height >= item_no-1 - list_height) {
		scroll = item_no - list_height;
		if (scroll < 0)
		    scroll = 0;
	    }
	    else
		scroll += list_height;
	    redraw_menu = TRUE;
	    if (!onlist) {
 		onlist = 1;
		button = 0;
	    }
	    break;
	    
	case KEY_HOME:      /* go to the top */
	    scroll = 0;
	    choice = 0;
	    redraw_menu = TRUE;
	    cursor_reset = TRUE;
	    onlist = 1;
	    break;
	    
	case KEY_END:      /* Go to the bottom */
	    scroll = item_no - list_height;
	    if (scroll < 0)
		scroll = 0;
	    choice = max_choice - 1;
	    redraw_menu = TRUE;
	    cursor_reset = TRUE;
	    onlist = 1;
	    break;
	    
	case TAB:
	case KEY_BTAB:
	    /* move to next component */
	    if (onlist) {       /* on list, next is ok button */
		onlist = 0;
		if (ditems && result) {
		    print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
		    print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
		    ok_space = 1;
		    cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
		}
		else {
		    print_button(dialog, "Cancel", y, x + 14, button);
		    print_button(dialog, "  OK  ", y, x, !button);
		    ok_space = 3;
		    cancel_space = 15;
		}
		if (button)
		    wmove(dialog, y, x + cancel_space);
		else
		    wmove(dialog, y, x + ok_space);
		wrefresh(dialog);
		break;
	    }
	    else if (button) {     /* on cancel button, next is list */
		button = 0;
		onlist = 1;
		redraw_menu = TRUE;
		break; 
	    }
	    /* on ok button, next is cancel button, same as left/right case */

	case KEY_LEFT:
	case KEY_RIGHT:
	    onlist = 0;
	    button = !button;
	    if (ditems && result) {
		print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
		print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ?  ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
		ok_space = 1;
		cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
	    }
	    else {
		print_button(dialog, "Cancel", y, x + 14, button);
		print_button(dialog, "  OK  ", y, x, !button);
		ok_space = 3;
		cancel_space = 15;
	    }
	    if (button)
		wmove(dialog, y, x + cancel_space);
	    else
		wmove(dialog, y, x + ok_space);
	    wrefresh(dialog);
	    break;

	case ' ':
	case '\n':
	case '\r':
	    if (!onlist) {
		if (ditems) {
		    if (result && ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire) {
			int st;
			WINDOW *save = dupwin(newscr);

			st = ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire(&ditems[button ? CANCEL_BUTTON : OK_BUTTON]);
			if (st & DITEM_RESTORE) {
			    touchwin(save);
			    wrefresh(save);
			}
			delwin(save);
			if (st == DITEM_FAILURE)
			continue;
		    }
		}
		else if (result) {
		    *result = '\0';
		    for (i = 0; i < item_no; i++) {
			if (status[i]) {
			    strcat(result, items[i*3]);
			    strcat(result, "\n");
			}
		    }
		}
		rval = button;
		key = ESC;	/* Bail out! */
		break;
	    }
	    
	    /* Let me outta here! */
	case ESC:
	    rval = -1;
	    break;
	    
	    /* Help! */
	case KEY_F(1):
	case '?':
	    display_helpfile();
	    break;
	}
	
	if (redraw_menu) {
	    getyx(list, old_y, old_x);
	    wclear(list);

    	    /*
	     * Re-draw a box around the list items.  It is required
	     * if amount of list items is smaller than height of listbox.
	     * Otherwise un-redrawn field will be filled with default
	     * screen attributes instead of dialog attributes.
	     */
	    draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);

	    for (i = 0; i < max_choice; i++)
		print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
	    print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);

	    /* redraw buttons to fix highlighting */
	    if (ditems && result) {
		print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
		print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
	    }
	    else {
		print_button(dialog, "Cancel", y, x + 14, button);
		print_button(dialog, "  OK  ", y, x, !button);
	    }
	    wnoutrefresh(dialog);
	    if (cursor_reset) {
		wmove(list, choice, check_x+1);
		cursor_reset = FALSE;
	    }
	    else {
		wmove(list, old_y, old_x);
	    }
	    wrefresh(list);
	    redraw_menu = FALSE;
	}
    }
    delwin(list);
    delwin(dialog);
    return rval;
}
Пример #5
0
/*
 * Display a menu for choosing among a number of options
 */
int
dialog_menu (const char *title, const char *prompt, int height, int width,
		int menu_height, const char *current, int item_no,
		const char * const * items)

{
    int i, j, x, y, box_x, box_y;
    int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
    WINDOW *dialog, *menu;
    FILE *f;

    max_choice = MIN (menu_height, item_no);

    /* center dialog box on screen */
    x = (COLS - width) / 2;
    y = (LINES - height) / 2;

    draw_shadow (stdscr, y, x, height, width);

    dialog = newwin (height, width, y, x);
    keypad (dialog, TRUE);

    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
    wattrset (dialog, border_attr);
    mvwaddch (dialog, height - 3, 0, ACS_LTEE);
    for (i = 0; i < width - 2; i++)
	waddch (dialog, ACS_HLINE);
    wattrset (dialog, dialog_attr);
    wbkgdset (dialog, dialog_attr & A_COLOR);
    waddch (dialog, ACS_RTEE);

    if (title != NULL && strlen(title) >= width-2 ) {
	/* truncate long title -- mec */
	char * title2 = malloc(width-2+1);
	memcpy( title2, title, width-2 );
	title2[width-2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset (dialog, title_attr);
	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
	waddstr (dialog, (char *)title);
	waddch (dialog, ' ');
    }

    wattrset (dialog, dialog_attr);
    print_autowrap (dialog, prompt, width - 2, 1, 3);

    menu_width = width - 6;
    box_y = height - menu_height - 5;
    box_x = (width - menu_width) / 2 - 1;

    /* create new window for the menu */
    menu = subwin (dialog, menu_height, menu_width,
		y + box_y + 1, x + box_x + 1);
    keypad (menu, TRUE);

    /* draw a box around the menu items */
    draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2,
	      menubox_border_attr, menubox_attr);

    /*
     * Find length of longest item in order to center menu.
     * Set 'choice' to default item. 
     */
    item_x = 0;
    for (i = 0; i < item_no; i++) {
	item_x = MAX (item_x, MIN(menu_width, strlen (items[i * 2 + 1]) + 2));
	if (strcmp(current, items[i*2]) == 0) choice = i;
    }

    item_x = (menu_width - item_x) / 2;

    /* get the scroll info from the temp file */
    if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) {
	if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) &&
	     (scroll+max_choice > choice) && (scroll >= 0) &&
	     (scroll+max_choice <= item_no) ) {
	    first_item = scroll;
	    choice = choice - scroll;
	    fclose(f);
	} else {
	    scroll=0;
	    remove("lxdialog.scrltmp");
	    fclose(f);
	    f=NULL;
	}
    }
    if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) {
	if (choice >= item_no-max_choice/2)
	    scroll = first_item = item_no-max_choice;
	else
	    scroll = first_item = choice - max_choice/2;
	choice = choice - scroll;
    }

    /* Print the menu */
    for (i=0; i < max_choice; i++) {
	print_item (menu, items[(first_item + i) * 2 + 1], i, i == choice,
                    (items[(first_item + i)*2][0] != ':'));
    }

    wnoutrefresh (menu);

    print_arrows(dialog, item_no, scroll,
		 box_y, box_x+item_x+1, menu_height);

    print_buttons (dialog, height, width, 0);

    while (key != ESC) {
	key = wgetch(dialog);

	if (key < 256 && isalpha(key)) key = tolower(key);

	if (strchr("ynm", key))
		i = max_choice;
	else {
        for (i = choice+1; i < max_choice; i++) {
		j = first_alpha(items[(scroll+i)*2+1], "YyNnMm");
		if (key == tolower(items[(scroll+i)*2+1][j]))
                	break;
	}
	if (i == max_choice)
       		for (i = 0; i < max_choice; i++) {
			j = first_alpha(items[(scroll+i)*2+1], "YyNnMm");
			if (key == tolower(items[(scroll+i)*2+1][j]))
                		break;
		}
	}

	if (i < max_choice || 
            key == KEY_UP || key == KEY_DOWN ||
            key == '-' || key == '+' ||
            key == KEY_PPAGE || key == KEY_NPAGE) {

            print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
                       (items[(scroll+choice)*2][0] != ':'));

	    if (key == KEY_UP || key == '-') {
                if (choice < 2 && scroll) {
	            /* Scroll menu down */
                    scrollok (menu, TRUE);
                    wscrl (menu, -1);
                    scrollok (menu, FALSE);

                    scroll--;

                    print_item (menu, items[scroll * 2 + 1], 0, FALSE,
                               (items[scroll*2][0] != ':'));
		} else
		    choice = MAX(choice - 1, 0);

	    } else if (key == KEY_DOWN || key == '+')  {

		print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
                                (items[(scroll+choice)*2][0] != ':'));

                if ((choice > max_choice-3) &&
                    (scroll + max_choice < item_no)
                   ) {
		    /* Scroll menu up */
		    scrollok (menu, TRUE);
                    scroll (menu);
                    scrollok (menu, FALSE);

                    scroll++;

                    print_item (menu, items[(scroll+max_choice-1)*2+1],
                               max_choice-1, FALSE,
                               (items[(scroll+max_choice-1)*2][0] != ':'));
                } else
                    choice = MIN(choice+1, max_choice-1);

	    } else if (key == KEY_PPAGE) {
	        scrollok (menu, TRUE);
                for (i=0; (i < max_choice); i++) {
                    if (scroll > 0) {
                	wscrl (menu, -1);
                	scroll--;
                	print_item (menu, items[scroll * 2 + 1], 0, FALSE,
                	(items[scroll*2][0] != ':'));
                    } else {
                        if (choice > 0)
                            choice--;
                    }
                }
                scrollok (menu, FALSE);

            } else if (key == KEY_NPAGE) {
                for (i=0; (i < max_choice); i++) {
                    if (scroll+max_choice < item_no) {
			scrollok (menu, TRUE);
			scroll(menu);
			scrollok (menu, FALSE);
                	scroll++;
                	print_item (menu, items[(scroll+max_choice-1)*2+1],
			            max_choice-1, FALSE,
			            (items[(scroll+max_choice-1)*2][0] != ':'));
		    } else {
			if (choice+1 < max_choice)
			    choice++;
		    }
                }

            } else
                choice = i;

            print_item (menu, items[(scroll+choice)*2+1], choice, TRUE,
                       (items[(scroll+choice)*2][0] != ':'));

            print_arrows(dialog, item_no, scroll,
                         box_y, box_x+item_x+1, menu_height);

            wnoutrefresh (menu);
            wrefresh (dialog);

	    continue;		/* wait for another key press */
        }

	switch (key) {
	case KEY_LEFT:
	case TAB:
	case KEY_RIGHT:
	    button = ((key == KEY_LEFT ? --button : ++button) < 0)
			? 2 : (button > 2 ? 0 : button);

	    print_buttons(dialog, height, width, button);
	    wrefresh (dialog);
	    break;
	case ' ':
	case 's':
	case 'y':
	case 'n':
	case 'm':
	    /* save scroll info */
	    if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
		fprintf(f,"%d\n",scroll);
		fclose(f);
	    }
	    delwin (dialog);
            fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
            switch (key) {
            case 's': return 3;
            case 'y': return 3;
            case 'n': return 4;
            case 'm': return 5;
            case ' ': return 6;
            }
	    return 0;
	case 'h':
	case '?':
	    button = 2;
	case '\n':
	    delwin (dialog);
	    if (button == 2) 
            	fprintf(stderr, "%s \"%s\"\n", 
			items[(scroll + choice) * 2],
			items[(scroll + choice) * 2 + 1] +
			first_alpha(items[(scroll + choice) * 2 + 1],""));
	    else
            	fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);

	    remove("lxdialog.scrltmp");
	    return button;
	case 'e':
	case 'x':
	    key = ESC;
	case ESC:
	    break;
	}
    }

    delwin (dialog);
    remove("lxdialog.scrltmp");
    return -1;			/* ESC pressed */
}
Пример #6
0
/*
 * Display a dialog box with a list of options that can be turned on or off
 * The `flag' parameter is used to select between radiolist and checklist.
 */
int
dialog_checklist (const char *title, const char *prompt, int height, int width,
	int list_height, int item_no, const char * const * items, int flag)
	
{
    int i, x, y, box_x, box_y;
    int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
    WINDOW *dialog, *list;

    checkflag = flag;

    /* Allocate space for storing item on/off status */
    if ((status = malloc (sizeof (int) * item_no)) == NULL) {
	endwin ();
	fprintf (stderr,
		 "\nCan't allocate memory in dialog_checklist().\n");
	exit (-1);
    }

    /* Initializes status */
    for (i = 0; i < item_no; i++) {
	status[i] = !strcasecmp (items[i * 3 + 2], "on");
	if (!choice && status[i])
            choice = i;
    }

    max_choice = MIN (list_height, item_no);

    /* center dialog box on screen */
    x = (COLS - width) / 2;
    y = (LINES - height) / 2;

    draw_shadow (stdscr, y, x, height, width);

    dialog = newwin (height, width, y, x);
    keypad (dialog, TRUE);

    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
    wattrset (dialog, border_attr);
    mvwaddch (dialog, height-3, 0, ACS_LTEE);
    for (i = 0; i < width - 2; i++)
	waddch (dialog, ACS_HLINE);
    wattrset (dialog, dialog_attr);
    waddch (dialog, ACS_RTEE);

    if (title != NULL && strlen(title) >= width-2 ) {
	/* truncate long title -- mec */
	char * title2 = malloc(width-2+1);
	memcpy( title2, title, width-2 );
	title2[width-2] = '\0';
	title = title2;
    }

    if (title != NULL) {
	wattrset (dialog, title_attr);
	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
	waddstr (dialog, (char *)title);
	waddch (dialog, ' ');
    }

    wattrset (dialog, dialog_attr);
    print_autowrap (dialog, prompt, width - 2, 1, 3);

    list_width = width - 6;
    box_y = height - list_height - 5;
    box_x = (width - list_width) / 2 - 1;

    /* create new window for the list */
    list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1);

    keypad (list, TRUE);

    /* draw a box around the list items */
    draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2,
	      menubox_border_attr, menubox_attr);

    /* Find length of longest item in order to center checklist */
    check_x = 0;
    for (i = 0; i < item_no; i++) 
	check_x = MAX (check_x, + strlen (items[i * 3 + 1]) + 4);

    check_x = (list_width - check_x) / 2;
    item_x = check_x + 4;

    if (choice >= list_height) {
	scroll = choice - list_height + 1;
	choice -= scroll;
    }

    /* Print the list */
    for (i = 0; i < max_choice; i++) {
	print_item (list, items[(scroll+i) * 3 + 1],
		    status[i+scroll], i, i == choice);
    }

    print_arrows(dialog, choice, item_no, scroll,
			box_y, box_x + check_x + 5, list_height);

    print_buttons(dialog, height, width, 0);

    wnoutrefresh (list);
    wnoutrefresh (dialog);
    doupdate ();

    while (key != ESC) {
	key = wgetch (dialog);

    	for (i = 0; i < max_choice; i++)
            if (toupper(key) == toupper(items[(scroll+i)*3+1][0]))
                break;


	if ( i < max_choice || key == KEY_UP || key == KEY_DOWN || 
	    key == '+' || key == '-' ) {
	    if (key == KEY_UP || key == '-') {
		if (!choice) {
		    if (!scroll)
			continue;
		    /* Scroll list down */
		    if (list_height > 1) {
			/* De-highlight current first item */
			print_item (list, items[scroll * 3 + 1],
					status[scroll], 0, FALSE);
			scrollok (list, TRUE);
			wscrl (list, -1);
			scrollok (list, FALSE);
		    }
		    scroll--;
		    print_item (list, items[scroll * 3 + 1],
				status[scroll], 0, TRUE);
		    wnoutrefresh (list);

    		    print_arrows(dialog, choice, item_no, scroll,
				box_y, box_x + check_x + 5, list_height);

		    wrefresh (dialog);

		    continue;	/* wait for another key press */
		} else
		    i = choice - 1;
	    } else if (key == KEY_DOWN || key == '+') {
		if (choice == max_choice - 1) {
		    if (scroll + choice >= item_no - 1)
			continue;
		    /* Scroll list up */
		    if (list_height > 1) {
			/* De-highlight current last item before scrolling up */
			print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
				    status[scroll + max_choice - 1],
				    max_choice - 1, FALSE);
			scrollok (list, TRUE);
			scroll (list);
			scrollok (list, FALSE);
		    }
		    scroll++;
		    print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
				status[scroll + max_choice - 1],
				max_choice - 1, TRUE);
		    wnoutrefresh (list);

    		    print_arrows(dialog, choice, item_no, scroll,
				box_y, box_x + check_x + 5, list_height);

		    wrefresh (dialog);

		    continue;	/* wait for another key press */
		} else
		    i = choice + 1;
	    }
	    if (i != choice) {
		/* De-highlight current item */
		print_item (list, items[(scroll + choice) * 3 + 1],
			    status[scroll + choice], choice, FALSE);
		/* Highlight new item */
		choice = i;
		print_item (list, items[(scroll + choice) * 3 + 1],
			    status[scroll + choice], choice, TRUE);
		wnoutrefresh (list);
		wrefresh (dialog);
	    }
	    continue;		/* wait for another key press */
	}
	switch (key) {
	case 'H':
	case 'h':
	case '?':
	    delwin (dialog);
	    free (status);
	    return 1;
	case 'S':
	case 's':
	case ' ':
	case '\n':
	    if (!button) {
		if (flag == FLAG_CHECK) {
		    status[scroll + choice] = !status[scroll + choice];
		    wmove (list, choice, check_x);
		    wattrset (list, check_selected_attr);
		    wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
		} else {
		    if (!status[scroll + choice]) {
			for (i = 0; i < item_no; i++)
			    status[i] = 0;
			status[scroll + choice] = 1;
			for (i = 0; i < max_choice; i++)
			    print_item (list, items[(scroll + i) * 3 + 1],
					status[scroll + i], i, i == choice);
		    }
		}
		wnoutrefresh (list);
		wrefresh (dialog);
            
		for (i = 0; i < item_no; i++) {
		    if (status[i]) {
			if (flag == FLAG_CHECK) {
			    fprintf (stderr, "\"%s\" ", items[i * 3]);
			} else {
			    fprintf (stderr, "%s", items[i * 3]);
			}

		    }
		}
            }
	    delwin (dialog);
	    free (status);
	    return button;
	case 'X':
	case 'x':
	    key = ESC;
	case ESC:
	    break;
	}

	/* Now, update everything... */
	doupdate ();
    }
    

    delwin (dialog);
    free (status);
    return -1;			/* ESC pressed */
}
Пример #7
0
/*
 * This is an alternate interface to 'checklist' which allows the application
 * to read the list item states back directly without putting them in the
 * output buffer.  It also provides for more than two states over which the
 * check/radio box can display.
 */
int
dlg_checklist(const char *title,
	      const char *cprompt,
	      int height,
	      int width,
	      int list_height,
	      int item_no,
	      DIALOG_LISTITEM * items,
	      const char *states,
	      int flag,
	      int *current_item)
{
    /* *INDENT-OFF* */
    static DLG_KEYS_BINDING binding[] = {
	HELPKEY_BINDINGS,
	ENTERKEY_BINDINGS,
	DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
	DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ),
	DLG_KEYS_DATA( DLGK_ITEM_LAST,	KEY_END ),
	DLG_KEYS_DATA( DLGK_ITEM_LAST,	KEY_LL ),
	DLG_KEYS_DATA( DLGK_ITEM_NEXT,	'+' ),
	DLG_KEYS_DATA( DLGK_ITEM_NEXT,	KEY_DOWN ),
	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ),
	DLG_KEYS_DATA( DLGK_ITEM_PREV,	'-' ),
	DLG_KEYS_DATA( DLGK_ITEM_PREV,	KEY_UP ),
	DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ),
	DLG_KEYS_DATA( DLGK_PAGE_NEXT,	KEY_NPAGE ),
	DLG_KEYS_DATA( DLGK_PAGE_NEXT,	DLGK_MOUSE(KEY_NPAGE) ),
	DLG_KEYS_DATA( DLGK_PAGE_PREV,	KEY_PPAGE ),
	DLG_KEYS_DATA( DLGK_PAGE_PREV,	DLGK_MOUSE(KEY_PPAGE) ),
	END_KEYS_BINDING
    };
    /* *INDENT-ON* */

#ifdef KEY_RESIZE
    int old_height = height;
    int old_width = width;
#endif
    int i, j, key2, found, x, y, cur_x, cur_y, box_x, box_y;
    int key = 0, fkey;
    int button = dialog_state.visit_items ? -1 : dlg_defaultno_button();
    int choice = dlg_default_listitem(items);
    int scrollamt = 0;
    int max_choice;
    int was_mouse;
    int use_height;
    int use_width, name_width, text_width;
    int result = DLG_EXIT_UNKNOWN;
    int num_states;
    WINDOW *dialog, *list;
    char *prompt = dlg_strclone(cprompt);
    const char **buttons = dlg_ok_labels();

    dlg_does_output();
    dlg_tab_correct_str(prompt);

    /*
     * If this is a radiobutton list, ensure that no more than one item is
     * selected initially.  Allow none to be selected, since some users may
     * wish to provide this flavor.
     */
    if (flag == FLAG_RADIO) {
	bool first = TRUE;

	for (i = 0; i < item_no; i++) {
	    if (items[i].state) {
		if (first) {
		    first = FALSE;
		} else {
		    items[i].state = 0;
		}
	    }
	}
    }
#ifdef KEY_RESIZE
  retry:
#endif

    use_height = list_height;
    if (use_height == 0) {
	use_width = dlg_calc_list_width(item_no, items) + 10;
	/* calculate height without items (4) */
	dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, MAX(26, use_width));
	dlg_calc_listh(&height, &use_height, item_no);
    } else {
	dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, 26);
    }
    dlg_button_layout(buttons, &width);
    dlg_print_size(height, width);
    dlg_ctl_size(height, width);

    /* we need at least two states */
    if (states == 0 || strlen(states) < 2)
	states = " *";
    num_states = (int) strlen(states);

    checkflag = flag;

    x = dlg_box_x_ordinate(width);
    y = dlg_box_y_ordinate(height);

    dialog = dlg_new_window(height, width, y, x);
    dlg_register_window(dialog, "checklist", binding);
    dlg_register_buttons(dialog, "checklist", buttons);

    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);

    list_width = width - 6;
    getyx(dialog, cur_y, cur_x);
    box_y = cur_y + 1;
    box_x = (width - list_width) / 2 - 1;

    /*
     * After displaying the prompt, we know how much space we really have.
     * Limit the list to avoid overwriting the ok-button.
     */
    if (use_height + MIN_HIGH > height - cur_y)
	use_height = height - MIN_HIGH - cur_y;
    if (use_height <= 0)
	use_height = 1;

    max_choice = MIN(use_height, item_no);

    /* create new window for the list */
    list = dlg_sub_window(dialog, use_height, list_width,
			  y + box_y + 1, x + box_x + 1);

    /* draw a box around the list items */
    dlg_draw_box(dialog, box_y, box_x,
		 use_height + 2 * MARGIN,
		 list_width + 2 * MARGIN,
		 menubox_border_attr, menubox_attr);

    text_width = 0;
    name_width = 0;
    /* Find length of longest item to center checklist */
    for (i = 0; i < item_no; i++) {
	text_width = MAX(text_width, dlg_count_columns(items[i].text));
	name_width = MAX(name_width, dlg_count_columns(items[i].name));
    }

    /* 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 = (list_width - 6);
    if (text_width + name_width > use_width) {
	int need = (int) (0.25 * use_width);
	if (name_width > need) {
	    int want = (int) (use_width * ((double) name_width) /
			      (text_width + name_width));
	    name_width = (want > need) ? want : need;
	}
	text_width = use_width - name_width;
    }

    check_x = (use_width - (text_width + name_width)) / 2;
    item_x = name_width + check_x + 6;

    /* ensure we are scrolled to show the current choice */
    if (choice >= (max_choice + scrollamt)) {
	scrollamt = choice - max_choice + 1;
	choice = max_choice - 1;
    }
    /* Print the list */
    for (i = 0; i < max_choice; i++) {
	print_item(list,
		   &items[i + scrollamt],
		   states,
		   i, i == choice);
    }
    (void) wnoutrefresh(list);

    /* register the new window, along with its borders */
    dlg_mouse_mkbigregion(box_y + 1, box_x, use_height, list_width + 2,
			  KEY_MAX, 1, 1, 1 /* by lines */ );

    print_arrows(dialog,
		 box_x, box_y,
		 scrollamt, max_choice, item_no, use_height);

    dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);

    while (result == DLG_EXIT_UNKNOWN) {
	if (button < 0)		/* --visit-items */
	    wmove(dialog, box_y + choice + 1, box_x + check_x + 2);

	key = dlg_mouse_wgetch(dialog, &fkey);
	if (dlg_result_key(key, fkey, &result))
	    break;

	was_mouse = (fkey && is_DLGK_MOUSE(key));
	if (was_mouse)
	    key -= M_EVENT;

	if (was_mouse && (key >= KEY_MAX)) {
	    getyx(dialog, cur_y, cur_x);
	    i = (key - KEY_MAX);
	    if (i < max_choice) {
		/* De-highlight current item */
		print_item(list,
			   &items[scrollamt + choice],
			   states,
			   choice, FALSE);
		/* Highlight new item */
		choice = (key - KEY_MAX);
		print_item(list,
			   &items[scrollamt + choice],
			   states,
			   choice, TRUE);
		(void) wnoutrefresh(list);
		(void) wmove(dialog, cur_y, cur_x);

		key = ' ';	/* force the selected item to toggle */
	    } else {
		beep();
		continue;
	    }
	    fkey = FALSE;
	} else if (was_mouse && key >= KEY_MIN) {
	    key = dlg_lookup_key(dialog, key, &fkey);
	}

	/*
	 * A space toggles the item status.  We handle either a checklist
	 * (any number of items can be selected) or radio list (zero or one
	 * items can be selected).
	 */
	if (key == ' ') {
	    int current = scrollamt + choice;
	    int next = items[current].state + 1;

	    if (next >= num_states)
		next = 0;

	    getyx(dialog, cur_y, cur_x);
	    if (flag == FLAG_CHECK) {	/* checklist? */
		items[current].state = next;
		print_item(list,
			   &items[scrollamt + choice],
			   states,
			   choice, TRUE);
	    } else {		/* radiolist */
		for (i = 0; i < item_no; i++) {
		    if (i != current) {
			items[i].state = 0;
		    }
		}
		if (items[current].state) {
		    items[current].state = next ? next : 1;
		    print_item(list,
			       &items[current],
			       states,
			       choice, TRUE);
		} else {
		    items[current].state = 1;
		    for (i = 0; i < max_choice; i++)
			print_item(list,
				   &items[scrollamt + i],
				   states,
				   i, i == choice);
		}
	    }
	    (void) wnoutrefresh(list);
	    (void) wmove(dialog, cur_y, cur_x);
	    wrefresh(dialog);
	    continue;		/* wait for another key press */
	}

	/*
	 * 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.
	 */
	found = FALSE;
	if (!fkey) {
	    if (button < 0 || !dialog_state.visit_items) {
		for (j = scrollamt + choice + 1; j < item_no; j++) {
		    if (dlg_match_char(dlg_last_getc(), items[j].name)) {
			found = TRUE;
			i = j - scrollamt;
			break;
		    }
		}
		if (!found) {
		    for (j = 0; j <= scrollamt + choice; j++) {
			if (dlg_match_char(dlg_last_getc(), items[j].name)) {
			    found = TRUE;
			    i = j - scrollamt;
			    break;
			}
		    }
		}
		if (found)
		    dlg_flush_getc();
	    } else if ((j = dlg_char_to_button(key, buttons)) >= 0) {
		button = j;
		ungetch('\n');
		continue;
	    }
	}

	/*
	 * 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) {
	    if (fkey) {
		found = TRUE;
		switch (key) {
		case DLGK_ITEM_FIRST:
		    i = -scrollamt;
		    break;
		case DLGK_ITEM_LAST:
		    i = item_no - 1 - scrollamt;
		    break;
		case DLGK_PAGE_PREV:
		    if (choice)
			i = 0;
		    else if (scrollamt != 0)
			i = -MIN(scrollamt, max_choice);
		    else
			continue;
		    break;
		case DLGK_PAGE_NEXT:
		    i = MIN(choice + max_choice, item_no - scrollamt - 1);
		    break;
		case DLGK_ITEM_PREV:
		    i = choice - 1;
		    if (choice == 0 && scrollamt == 0)
			continue;
		    break;
		case DLGK_ITEM_NEXT:
		    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 (use_height > 1) {
			    /* De-highlight current first item */
			    print_item(list,
				       &items[scrollamt],
				       states,
				       0, FALSE);
			    scrollok(list, TRUE);
			    wscrl(list, -1);
			    scrollok(list, FALSE);
			}
			scrollamt--;
			print_item(list,
				   &items[scrollamt],
				   states,
				   0, TRUE);
		    } else if (i == max_choice) {
			if (use_height > 1) {
			    /* De-highlight current last item before scrolling up */
			    print_item(list,
				       &items[scrollamt + max_choice - 1],
				       states,
				       max_choice - 1, FALSE);
			    scrollok(list, TRUE);
			    wscrl(list, 1);
			    scrollok(list, FALSE);
			}
			scrollamt++;
			print_item(list,
				   &items[scrollamt + max_choice - 1],
				   states,
				   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(list,
				       &items[scrollamt + i],
				       states,
				       i, i == choice);
			}
		    }
		    (void) wnoutrefresh(list);
		    print_arrows(dialog,
				 box_x, box_y,
				 scrollamt, max_choice, item_no, use_height);
		} else {
		    /* De-highlight current item */
		    print_item(list,
			       &items[scrollamt + choice],
			       states,
			       choice, FALSE);
		    /* Highlight new item */
		    choice = i;
		    print_item(list,
			       &items[scrollamt + choice],
			       states,
			       choice, TRUE);
		    (void) wnoutrefresh(list);
		    print_arrows(dialog,
				 box_x, box_y,
				 scrollamt, max_choice, item_no, use_height);
		    (void) wmove(dialog, cur_y, cur_x);
		    wrefresh(dialog);
		}
	    }
	    continue;		/* wait for another key press */
	}

	if (fkey) {
	    switch (key) {
	    case DLGK_ENTER:
		result = dlg_enter_buttoncode(button);
		break;
	    case DLGK_FIELD_PREV:
		button = dlg_prev_button(buttons, button);
		dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
				 FALSE, width);
		break;
	    case DLGK_FIELD_NEXT:
		button = dlg_next_button(buttons, button);
		dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
				 FALSE, width);
		break;
#ifdef KEY_RESIZE
	    case KEY_RESIZE:
		/* reset data */
		height = old_height;
		width = old_width;
		/* repaint */
		dlg_clear();
		dlg_del_window(dialog);
		refresh();
		dlg_mouse_free_regions();
		goto retry;
#endif
	    default:
		if (was_mouse) {
		    if ((key2 = dlg_ok_buttoncode(key)) >= 0) {
			result = key2;
			break;
		    }
		    beep();
		}
	    }
	} else {
	    beep();
	}
    }

    dlg_del_window(dialog);
    dlg_mouse_free_regions();
    free(prompt);
    *current_item = (scrollamt + choice);
    return result;
}