162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  checklist.c -- implements the checklist box
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
662306a36Sopenharmony_ci *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
762306a36Sopenharmony_ci *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
862306a36Sopenharmony_ci *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "dialog.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic int list_width, check_x, item_x;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Print list item
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_cistatic void print_item(WINDOW * win, int choice, int selected)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	int i;
2162306a36Sopenharmony_ci	char *list_item = malloc(list_width + 1);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	strncpy(list_item, item_str(), list_width - item_x);
2462306a36Sopenharmony_ci	list_item[list_width - item_x] = '\0';
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	/* Clear 'residue' of last item */
2762306a36Sopenharmony_ci	wattrset(win, dlg.menubox.atr);
2862306a36Sopenharmony_ci	wmove(win, choice, 0);
2962306a36Sopenharmony_ci	for (i = 0; i < list_width; i++)
3062306a36Sopenharmony_ci		waddch(win, ' ');
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	wmove(win, choice, check_x);
3362306a36Sopenharmony_ci	wattrset(win, selected ? dlg.check_selected.atr
3462306a36Sopenharmony_ci		 : dlg.check.atr);
3562306a36Sopenharmony_ci	if (!item_is_tag(':'))
3662306a36Sopenharmony_ci		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
3962306a36Sopenharmony_ci	mvwaddch(win, choice, item_x, list_item[0]);
4062306a36Sopenharmony_ci	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
4162306a36Sopenharmony_ci	waddstr(win, list_item + 1);
4262306a36Sopenharmony_ci	if (selected) {
4362306a36Sopenharmony_ci		wmove(win, choice, check_x + 1);
4462306a36Sopenharmony_ci		wrefresh(win);
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci	free(list_item);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * Print the scroll indicators.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
5362306a36Sopenharmony_ci	     int y, int x, int height)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	wmove(win, y, x);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (scroll > 0) {
5862306a36Sopenharmony_ci		wattrset(win, dlg.uarrow.atr);
5962306a36Sopenharmony_ci		waddch(win, ACS_UARROW);
6062306a36Sopenharmony_ci		waddstr(win, "(-)");
6162306a36Sopenharmony_ci	} else {
6262306a36Sopenharmony_ci		wattrset(win, dlg.menubox.atr);
6362306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
6462306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
6562306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
6662306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	y = y + height + 1;
7062306a36Sopenharmony_ci	wmove(win, y, x);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if ((height < item_no) && (scroll + choice < item_no - 1)) {
7362306a36Sopenharmony_ci		wattrset(win, dlg.darrow.atr);
7462306a36Sopenharmony_ci		waddch(win, ACS_DARROW);
7562306a36Sopenharmony_ci		waddstr(win, "(+)");
7662306a36Sopenharmony_ci	} else {
7762306a36Sopenharmony_ci		wattrset(win, dlg.menubox_border.atr);
7862306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
7962306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
8062306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
8162306a36Sopenharmony_ci		waddch(win, ACS_HLINE);
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci *  Display the termination buttons
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic void print_buttons(WINDOW * dialog, int height, int width, int selected)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int x = width / 2 - 11;
9162306a36Sopenharmony_ci	int y = height - 2;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	print_button(dialog, "Select", y, x, selected == 0);
9462306a36Sopenharmony_ci	print_button(dialog, " Help ", y, x + 14, selected == 1);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	wmove(dialog, y, x + 1 + 14 * selected);
9762306a36Sopenharmony_ci	wrefresh(dialog);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * Display a dialog box with a list of options that can be turned on or off
10262306a36Sopenharmony_ci * in the style of radiolist (only one option turned on at a time).
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_ciint dialog_checklist(const char *title, const char *prompt, int height,
10562306a36Sopenharmony_ci		     int width, int list_height)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	int i, x, y, box_x, box_y;
10862306a36Sopenharmony_ci	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
10962306a36Sopenharmony_ci	WINDOW *dialog, *list;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* which item to highlight */
11262306a36Sopenharmony_ci	item_foreach() {
11362306a36Sopenharmony_ci		if (item_is_tag('X'))
11462306a36Sopenharmony_ci			choice = item_n();
11562306a36Sopenharmony_ci		if (item_is_selected()) {
11662306a36Sopenharmony_ci			choice = item_n();
11762306a36Sopenharmony_ci			break;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cido_resize:
12262306a36Sopenharmony_ci	if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
12362306a36Sopenharmony_ci		return -ERRDISPLAYTOOSMALL;
12462306a36Sopenharmony_ci	if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
12562306a36Sopenharmony_ci		return -ERRDISPLAYTOOSMALL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	max_choice = MIN(list_height, item_count());
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* center dialog box on screen */
13062306a36Sopenharmony_ci	x = (getmaxx(stdscr) - width) / 2;
13162306a36Sopenharmony_ci	y = (getmaxy(stdscr) - height) / 2;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	draw_shadow(stdscr, y, x, height, width);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	dialog = newwin(height, width, y, x);
13662306a36Sopenharmony_ci	keypad(dialog, TRUE);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	draw_box(dialog, 0, 0, height, width,
13962306a36Sopenharmony_ci		 dlg.dialog.atr, dlg.border.atr);
14062306a36Sopenharmony_ci	wattrset(dialog, dlg.border.atr);
14162306a36Sopenharmony_ci	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
14262306a36Sopenharmony_ci	for (i = 0; i < width - 2; i++)
14362306a36Sopenharmony_ci		waddch(dialog, ACS_HLINE);
14462306a36Sopenharmony_ci	wattrset(dialog, dlg.dialog.atr);
14562306a36Sopenharmony_ci	waddch(dialog, ACS_RTEE);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	print_title(dialog, title, width);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	wattrset(dialog, dlg.dialog.atr);
15062306a36Sopenharmony_ci	print_autowrap(dialog, prompt, width - 2, 1, 3);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	list_width = width - 6;
15362306a36Sopenharmony_ci	box_y = height - list_height - 5;
15462306a36Sopenharmony_ci	box_x = (width - list_width) / 2 - 1;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* create new window for the list */
15762306a36Sopenharmony_ci	list = subwin(dialog, list_height, list_width, y + box_y + 1,
15862306a36Sopenharmony_ci		      x + box_x + 1);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	keypad(list, TRUE);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* draw a box around the list items */
16362306a36Sopenharmony_ci	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
16462306a36Sopenharmony_ci		 dlg.menubox_border.atr, dlg.menubox.atr);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Find length of longest item in order to center checklist */
16762306a36Sopenharmony_ci	check_x = 0;
16862306a36Sopenharmony_ci	item_foreach()
16962306a36Sopenharmony_ci		check_x = MAX(check_x, strlen(item_str()) + 4);
17062306a36Sopenharmony_ci	check_x = MIN(check_x, list_width);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	check_x = (list_width - check_x) / 2;
17362306a36Sopenharmony_ci	item_x = check_x + 4;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (choice >= list_height) {
17662306a36Sopenharmony_ci		scroll = choice - list_height + 1;
17762306a36Sopenharmony_ci		choice -= scroll;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* Print the list */
18162306a36Sopenharmony_ci	for (i = 0; i < max_choice; i++) {
18262306a36Sopenharmony_ci		item_set(scroll + i);
18362306a36Sopenharmony_ci		print_item(list, i, i == choice);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	print_arrows(dialog, choice, item_count(), scroll,
18762306a36Sopenharmony_ci		     box_y, box_x + check_x + 5, list_height);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	print_buttons(dialog, height, width, 0);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	wnoutrefresh(dialog);
19262306a36Sopenharmony_ci	wnoutrefresh(list);
19362306a36Sopenharmony_ci	doupdate();
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	while (key != KEY_ESC) {
19662306a36Sopenharmony_ci		key = wgetch(dialog);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		for (i = 0; i < max_choice; i++) {
19962306a36Sopenharmony_ci			item_set(i + scroll);
20062306a36Sopenharmony_ci			if (toupper(key) == toupper(item_str()[0]))
20162306a36Sopenharmony_ci				break;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
20562306a36Sopenharmony_ci		    key == '+' || key == '-') {
20662306a36Sopenharmony_ci			if (key == KEY_UP || key == '-') {
20762306a36Sopenharmony_ci				if (!choice) {
20862306a36Sopenharmony_ci					if (!scroll)
20962306a36Sopenharmony_ci						continue;
21062306a36Sopenharmony_ci					/* Scroll list down */
21162306a36Sopenharmony_ci					if (list_height > 1) {
21262306a36Sopenharmony_ci						/* De-highlight current first item */
21362306a36Sopenharmony_ci						item_set(scroll);
21462306a36Sopenharmony_ci						print_item(list, 0, FALSE);
21562306a36Sopenharmony_ci						scrollok(list, TRUE);
21662306a36Sopenharmony_ci						wscrl(list, -1);
21762306a36Sopenharmony_ci						scrollok(list, FALSE);
21862306a36Sopenharmony_ci					}
21962306a36Sopenharmony_ci					scroll--;
22062306a36Sopenharmony_ci					item_set(scroll);
22162306a36Sopenharmony_ci					print_item(list, 0, TRUE);
22262306a36Sopenharmony_ci					print_arrows(dialog, choice, item_count(),
22362306a36Sopenharmony_ci						     scroll, box_y, box_x + check_x + 5, list_height);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci					wnoutrefresh(dialog);
22662306a36Sopenharmony_ci					wrefresh(list);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci					continue;	/* wait for another key press */
22962306a36Sopenharmony_ci				} else
23062306a36Sopenharmony_ci					i = choice - 1;
23162306a36Sopenharmony_ci			} else if (key == KEY_DOWN || key == '+') {
23262306a36Sopenharmony_ci				if (choice == max_choice - 1) {
23362306a36Sopenharmony_ci					if (scroll + choice >= item_count() - 1)
23462306a36Sopenharmony_ci						continue;
23562306a36Sopenharmony_ci					/* Scroll list up */
23662306a36Sopenharmony_ci					if (list_height > 1) {
23762306a36Sopenharmony_ci						/* De-highlight current last item before scrolling up */
23862306a36Sopenharmony_ci						item_set(scroll + max_choice - 1);
23962306a36Sopenharmony_ci						print_item(list,
24062306a36Sopenharmony_ci							    max_choice - 1,
24162306a36Sopenharmony_ci							    FALSE);
24262306a36Sopenharmony_ci						scrollok(list, TRUE);
24362306a36Sopenharmony_ci						wscrl(list, 1);
24462306a36Sopenharmony_ci						scrollok(list, FALSE);
24562306a36Sopenharmony_ci					}
24662306a36Sopenharmony_ci					scroll++;
24762306a36Sopenharmony_ci					item_set(scroll + max_choice - 1);
24862306a36Sopenharmony_ci					print_item(list, max_choice - 1, TRUE);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci					print_arrows(dialog, choice, item_count(),
25162306a36Sopenharmony_ci						     scroll, box_y, box_x + check_x + 5, list_height);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci					wnoutrefresh(dialog);
25462306a36Sopenharmony_ci					wrefresh(list);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci					continue;	/* wait for another key press */
25762306a36Sopenharmony_ci				} else
25862306a36Sopenharmony_ci					i = choice + 1;
25962306a36Sopenharmony_ci			}
26062306a36Sopenharmony_ci			if (i != choice) {
26162306a36Sopenharmony_ci				/* De-highlight current item */
26262306a36Sopenharmony_ci				item_set(scroll + choice);
26362306a36Sopenharmony_ci				print_item(list, choice, FALSE);
26462306a36Sopenharmony_ci				/* Highlight new item */
26562306a36Sopenharmony_ci				choice = i;
26662306a36Sopenharmony_ci				item_set(scroll + choice);
26762306a36Sopenharmony_ci				print_item(list, choice, TRUE);
26862306a36Sopenharmony_ci				wnoutrefresh(dialog);
26962306a36Sopenharmony_ci				wrefresh(list);
27062306a36Sopenharmony_ci			}
27162306a36Sopenharmony_ci			continue;	/* wait for another key press */
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci		switch (key) {
27462306a36Sopenharmony_ci		case 'H':
27562306a36Sopenharmony_ci		case 'h':
27662306a36Sopenharmony_ci		case '?':
27762306a36Sopenharmony_ci			button = 1;
27862306a36Sopenharmony_ci			/* fall-through */
27962306a36Sopenharmony_ci		case 'S':
28062306a36Sopenharmony_ci		case 's':
28162306a36Sopenharmony_ci		case ' ':
28262306a36Sopenharmony_ci		case '\n':
28362306a36Sopenharmony_ci			item_foreach()
28462306a36Sopenharmony_ci				item_set_selected(0);
28562306a36Sopenharmony_ci			item_set(scroll + choice);
28662306a36Sopenharmony_ci			item_set_selected(1);
28762306a36Sopenharmony_ci			delwin(list);
28862306a36Sopenharmony_ci			delwin(dialog);
28962306a36Sopenharmony_ci			return button;
29062306a36Sopenharmony_ci		case TAB:
29162306a36Sopenharmony_ci		case KEY_LEFT:
29262306a36Sopenharmony_ci		case KEY_RIGHT:
29362306a36Sopenharmony_ci			button = ((key == KEY_LEFT ? --button : ++button) < 0)
29462306a36Sopenharmony_ci			    ? 1 : (button > 1 ? 0 : button);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci			print_buttons(dialog, height, width, button);
29762306a36Sopenharmony_ci			wrefresh(dialog);
29862306a36Sopenharmony_ci			break;
29962306a36Sopenharmony_ci		case 'X':
30062306a36Sopenharmony_ci		case 'x':
30162306a36Sopenharmony_ci			key = KEY_ESC;
30262306a36Sopenharmony_ci			break;
30362306a36Sopenharmony_ci		case KEY_ESC:
30462306a36Sopenharmony_ci			key = on_key_esc(dialog);
30562306a36Sopenharmony_ci			break;
30662306a36Sopenharmony_ci		case KEY_RESIZE:
30762306a36Sopenharmony_ci			delwin(list);
30862306a36Sopenharmony_ci			delwin(dialog);
30962306a36Sopenharmony_ci			on_key_resize();
31062306a36Sopenharmony_ci			goto do_resize;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		/* Now, update everything... */
31462306a36Sopenharmony_ci		doupdate();
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	delwin(list);
31762306a36Sopenharmony_ci	delwin(dialog);
31862306a36Sopenharmony_ci	return key;		/* ESC pressed */
31962306a36Sopenharmony_ci}
320