18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  checklist.c -- implements the checklist box
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
68c2ecf20Sopenharmony_ci *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
78c2ecf20Sopenharmony_ci *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
88c2ecf20Sopenharmony_ci *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "dialog.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic int list_width, check_x, item_x;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * Print list item
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_cistatic void print_item(WINDOW * win, int choice, int selected)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	int i;
218c2ecf20Sopenharmony_ci	char *list_item = malloc(list_width + 1);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	strncpy(list_item, item_str(), list_width - item_x);
248c2ecf20Sopenharmony_ci	list_item[list_width - item_x] = '\0';
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	/* Clear 'residue' of last item */
278c2ecf20Sopenharmony_ci	wattrset(win, dlg.menubox.atr);
288c2ecf20Sopenharmony_ci	wmove(win, choice, 0);
298c2ecf20Sopenharmony_ci	for (i = 0; i < list_width; i++)
308c2ecf20Sopenharmony_ci		waddch(win, ' ');
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	wmove(win, choice, check_x);
338c2ecf20Sopenharmony_ci	wattrset(win, selected ? dlg.check_selected.atr
348c2ecf20Sopenharmony_ci		 : dlg.check.atr);
358c2ecf20Sopenharmony_ci	if (!item_is_tag(':'))
368c2ecf20Sopenharmony_ci		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
398c2ecf20Sopenharmony_ci	mvwaddch(win, choice, item_x, list_item[0]);
408c2ecf20Sopenharmony_ci	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
418c2ecf20Sopenharmony_ci	waddstr(win, list_item + 1);
428c2ecf20Sopenharmony_ci	if (selected) {
438c2ecf20Sopenharmony_ci		wmove(win, choice, check_x + 1);
448c2ecf20Sopenharmony_ci		wrefresh(win);
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci	free(list_item);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * Print the scroll indicators.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistatic void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
538c2ecf20Sopenharmony_ci	     int y, int x, int height)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	wmove(win, y, x);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (scroll > 0) {
588c2ecf20Sopenharmony_ci		wattrset(win, dlg.uarrow.atr);
598c2ecf20Sopenharmony_ci		waddch(win, ACS_UARROW);
608c2ecf20Sopenharmony_ci		waddstr(win, "(-)");
618c2ecf20Sopenharmony_ci	} else {
628c2ecf20Sopenharmony_ci		wattrset(win, dlg.menubox.atr);
638c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
648c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
658c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
668c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	y = y + height + 1;
708c2ecf20Sopenharmony_ci	wmove(win, y, x);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if ((height < item_no) && (scroll + choice < item_no - 1)) {
738c2ecf20Sopenharmony_ci		wattrset(win, dlg.darrow.atr);
748c2ecf20Sopenharmony_ci		waddch(win, ACS_DARROW);
758c2ecf20Sopenharmony_ci		waddstr(win, "(+)");
768c2ecf20Sopenharmony_ci	} else {
778c2ecf20Sopenharmony_ci		wattrset(win, dlg.menubox_border.atr);
788c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
798c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
808c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
818c2ecf20Sopenharmony_ci		waddch(win, ACS_HLINE);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/*
868c2ecf20Sopenharmony_ci *  Display the termination buttons
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_cistatic void print_buttons(WINDOW * dialog, int height, int width, int selected)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int x = width / 2 - 11;
918c2ecf20Sopenharmony_ci	int y = height - 2;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	print_button(dialog, "Select", y, x, selected == 0);
948c2ecf20Sopenharmony_ci	print_button(dialog, " Help ", y, x + 14, selected == 1);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	wmove(dialog, y, x + 1 + 14 * selected);
978c2ecf20Sopenharmony_ci	wrefresh(dialog);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/*
1018c2ecf20Sopenharmony_ci * Display a dialog box with a list of options that can be turned on or off
1028c2ecf20Sopenharmony_ci * in the style of radiolist (only one option turned on at a time).
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_ciint dialog_checklist(const char *title, const char *prompt, int height,
1058c2ecf20Sopenharmony_ci		     int width, int list_height)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int i, x, y, box_x, box_y;
1088c2ecf20Sopenharmony_ci	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
1098c2ecf20Sopenharmony_ci	WINDOW *dialog, *list;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* which item to highlight */
1128c2ecf20Sopenharmony_ci	item_foreach() {
1138c2ecf20Sopenharmony_ci		if (item_is_tag('X'))
1148c2ecf20Sopenharmony_ci			choice = item_n();
1158c2ecf20Sopenharmony_ci		if (item_is_selected()) {
1168c2ecf20Sopenharmony_ci			choice = item_n();
1178c2ecf20Sopenharmony_ci			break;
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cido_resize:
1228c2ecf20Sopenharmony_ci	if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
1238c2ecf20Sopenharmony_ci		return -ERRDISPLAYTOOSMALL;
1248c2ecf20Sopenharmony_ci	if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
1258c2ecf20Sopenharmony_ci		return -ERRDISPLAYTOOSMALL;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	max_choice = MIN(list_height, item_count());
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* center dialog box on screen */
1308c2ecf20Sopenharmony_ci	x = (getmaxx(stdscr) - width) / 2;
1318c2ecf20Sopenharmony_ci	y = (getmaxy(stdscr) - height) / 2;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	draw_shadow(stdscr, y, x, height, width);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	dialog = newwin(height, width, y, x);
1368c2ecf20Sopenharmony_ci	keypad(dialog, TRUE);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	draw_box(dialog, 0, 0, height, width,
1398c2ecf20Sopenharmony_ci		 dlg.dialog.atr, dlg.border.atr);
1408c2ecf20Sopenharmony_ci	wattrset(dialog, dlg.border.atr);
1418c2ecf20Sopenharmony_ci	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
1428c2ecf20Sopenharmony_ci	for (i = 0; i < width - 2; i++)
1438c2ecf20Sopenharmony_ci		waddch(dialog, ACS_HLINE);
1448c2ecf20Sopenharmony_ci	wattrset(dialog, dlg.dialog.atr);
1458c2ecf20Sopenharmony_ci	waddch(dialog, ACS_RTEE);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	print_title(dialog, title, width);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	wattrset(dialog, dlg.dialog.atr);
1508c2ecf20Sopenharmony_ci	print_autowrap(dialog, prompt, width - 2, 1, 3);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	list_width = width - 6;
1538c2ecf20Sopenharmony_ci	box_y = height - list_height - 5;
1548c2ecf20Sopenharmony_ci	box_x = (width - list_width) / 2 - 1;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* create new window for the list */
1578c2ecf20Sopenharmony_ci	list = subwin(dialog, list_height, list_width, y + box_y + 1,
1588c2ecf20Sopenharmony_ci		      x + box_x + 1);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	keypad(list, TRUE);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* draw a box around the list items */
1638c2ecf20Sopenharmony_ci	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
1648c2ecf20Sopenharmony_ci		 dlg.menubox_border.atr, dlg.menubox.atr);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Find length of longest item in order to center checklist */
1678c2ecf20Sopenharmony_ci	check_x = 0;
1688c2ecf20Sopenharmony_ci	item_foreach()
1698c2ecf20Sopenharmony_ci		check_x = MAX(check_x, strlen(item_str()) + 4);
1708c2ecf20Sopenharmony_ci	check_x = MIN(check_x, list_width);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	check_x = (list_width - check_x) / 2;
1738c2ecf20Sopenharmony_ci	item_x = check_x + 4;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (choice >= list_height) {
1768c2ecf20Sopenharmony_ci		scroll = choice - list_height + 1;
1778c2ecf20Sopenharmony_ci		choice -= scroll;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Print the list */
1818c2ecf20Sopenharmony_ci	for (i = 0; i < max_choice; i++) {
1828c2ecf20Sopenharmony_ci		item_set(scroll + i);
1838c2ecf20Sopenharmony_ci		print_item(list, i, i == choice);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	print_arrows(dialog, choice, item_count(), scroll,
1878c2ecf20Sopenharmony_ci		     box_y, box_x + check_x + 5, list_height);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	print_buttons(dialog, height, width, 0);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	wnoutrefresh(dialog);
1928c2ecf20Sopenharmony_ci	wnoutrefresh(list);
1938c2ecf20Sopenharmony_ci	doupdate();
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	while (key != KEY_ESC) {
1968c2ecf20Sopenharmony_ci		key = wgetch(dialog);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		for (i = 0; i < max_choice; i++) {
1998c2ecf20Sopenharmony_ci			item_set(i + scroll);
2008c2ecf20Sopenharmony_ci			if (toupper(key) == toupper(item_str()[0]))
2018c2ecf20Sopenharmony_ci				break;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
2058c2ecf20Sopenharmony_ci		    key == '+' || key == '-') {
2068c2ecf20Sopenharmony_ci			if (key == KEY_UP || key == '-') {
2078c2ecf20Sopenharmony_ci				if (!choice) {
2088c2ecf20Sopenharmony_ci					if (!scroll)
2098c2ecf20Sopenharmony_ci						continue;
2108c2ecf20Sopenharmony_ci					/* Scroll list down */
2118c2ecf20Sopenharmony_ci					if (list_height > 1) {
2128c2ecf20Sopenharmony_ci						/* De-highlight current first item */
2138c2ecf20Sopenharmony_ci						item_set(scroll);
2148c2ecf20Sopenharmony_ci						print_item(list, 0, FALSE);
2158c2ecf20Sopenharmony_ci						scrollok(list, TRUE);
2168c2ecf20Sopenharmony_ci						wscrl(list, -1);
2178c2ecf20Sopenharmony_ci						scrollok(list, FALSE);
2188c2ecf20Sopenharmony_ci					}
2198c2ecf20Sopenharmony_ci					scroll--;
2208c2ecf20Sopenharmony_ci					item_set(scroll);
2218c2ecf20Sopenharmony_ci					print_item(list, 0, TRUE);
2228c2ecf20Sopenharmony_ci					print_arrows(dialog, choice, item_count(),
2238c2ecf20Sopenharmony_ci						     scroll, box_y, box_x + check_x + 5, list_height);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci					wnoutrefresh(dialog);
2268c2ecf20Sopenharmony_ci					wrefresh(list);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci					continue;	/* wait for another key press */
2298c2ecf20Sopenharmony_ci				} else
2308c2ecf20Sopenharmony_ci					i = choice - 1;
2318c2ecf20Sopenharmony_ci			} else if (key == KEY_DOWN || key == '+') {
2328c2ecf20Sopenharmony_ci				if (choice == max_choice - 1) {
2338c2ecf20Sopenharmony_ci					if (scroll + choice >= item_count() - 1)
2348c2ecf20Sopenharmony_ci						continue;
2358c2ecf20Sopenharmony_ci					/* Scroll list up */
2368c2ecf20Sopenharmony_ci					if (list_height > 1) {
2378c2ecf20Sopenharmony_ci						/* De-highlight current last item before scrolling up */
2388c2ecf20Sopenharmony_ci						item_set(scroll + max_choice - 1);
2398c2ecf20Sopenharmony_ci						print_item(list,
2408c2ecf20Sopenharmony_ci							    max_choice - 1,
2418c2ecf20Sopenharmony_ci							    FALSE);
2428c2ecf20Sopenharmony_ci						scrollok(list, TRUE);
2438c2ecf20Sopenharmony_ci						wscrl(list, 1);
2448c2ecf20Sopenharmony_ci						scrollok(list, FALSE);
2458c2ecf20Sopenharmony_ci					}
2468c2ecf20Sopenharmony_ci					scroll++;
2478c2ecf20Sopenharmony_ci					item_set(scroll + max_choice - 1);
2488c2ecf20Sopenharmony_ci					print_item(list, max_choice - 1, TRUE);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci					print_arrows(dialog, choice, item_count(),
2518c2ecf20Sopenharmony_ci						     scroll, box_y, box_x + check_x + 5, list_height);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci					wnoutrefresh(dialog);
2548c2ecf20Sopenharmony_ci					wrefresh(list);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci					continue;	/* wait for another key press */
2578c2ecf20Sopenharmony_ci				} else
2588c2ecf20Sopenharmony_ci					i = choice + 1;
2598c2ecf20Sopenharmony_ci			}
2608c2ecf20Sopenharmony_ci			if (i != choice) {
2618c2ecf20Sopenharmony_ci				/* De-highlight current item */
2628c2ecf20Sopenharmony_ci				item_set(scroll + choice);
2638c2ecf20Sopenharmony_ci				print_item(list, choice, FALSE);
2648c2ecf20Sopenharmony_ci				/* Highlight new item */
2658c2ecf20Sopenharmony_ci				choice = i;
2668c2ecf20Sopenharmony_ci				item_set(scroll + choice);
2678c2ecf20Sopenharmony_ci				print_item(list, choice, TRUE);
2688c2ecf20Sopenharmony_ci				wnoutrefresh(dialog);
2698c2ecf20Sopenharmony_ci				wrefresh(list);
2708c2ecf20Sopenharmony_ci			}
2718c2ecf20Sopenharmony_ci			continue;	/* wait for another key press */
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci		switch (key) {
2748c2ecf20Sopenharmony_ci		case 'H':
2758c2ecf20Sopenharmony_ci		case 'h':
2768c2ecf20Sopenharmony_ci		case '?':
2778c2ecf20Sopenharmony_ci			button = 1;
2788c2ecf20Sopenharmony_ci			/* fall-through */
2798c2ecf20Sopenharmony_ci		case 'S':
2808c2ecf20Sopenharmony_ci		case 's':
2818c2ecf20Sopenharmony_ci		case ' ':
2828c2ecf20Sopenharmony_ci		case '\n':
2838c2ecf20Sopenharmony_ci			item_foreach()
2848c2ecf20Sopenharmony_ci				item_set_selected(0);
2858c2ecf20Sopenharmony_ci			item_set(scroll + choice);
2868c2ecf20Sopenharmony_ci			item_set_selected(1);
2878c2ecf20Sopenharmony_ci			delwin(list);
2888c2ecf20Sopenharmony_ci			delwin(dialog);
2898c2ecf20Sopenharmony_ci			return button;
2908c2ecf20Sopenharmony_ci		case TAB:
2918c2ecf20Sopenharmony_ci		case KEY_LEFT:
2928c2ecf20Sopenharmony_ci		case KEY_RIGHT:
2938c2ecf20Sopenharmony_ci			button = ((key == KEY_LEFT ? --button : ++button) < 0)
2948c2ecf20Sopenharmony_ci			    ? 1 : (button > 1 ? 0 : button);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci			print_buttons(dialog, height, width, button);
2978c2ecf20Sopenharmony_ci			wrefresh(dialog);
2988c2ecf20Sopenharmony_ci			break;
2998c2ecf20Sopenharmony_ci		case 'X':
3008c2ecf20Sopenharmony_ci		case 'x':
3018c2ecf20Sopenharmony_ci			key = KEY_ESC;
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci		case KEY_ESC:
3048c2ecf20Sopenharmony_ci			key = on_key_esc(dialog);
3058c2ecf20Sopenharmony_ci			break;
3068c2ecf20Sopenharmony_ci		case KEY_RESIZE:
3078c2ecf20Sopenharmony_ci			delwin(list);
3088c2ecf20Sopenharmony_ci			delwin(dialog);
3098c2ecf20Sopenharmony_ci			on_key_resize();
3108c2ecf20Sopenharmony_ci			goto do_resize;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		/* Now, update everything... */
3148c2ecf20Sopenharmony_ci		doupdate();
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci	delwin(list);
3178c2ecf20Sopenharmony_ci	delwin(dialog);
3188c2ecf20Sopenharmony_ci	return key;		/* ESC pressed */
3198c2ecf20Sopenharmony_ci}
320