checklist.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * checklist.c -- implements the checklist box
  3. *
  4. * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
  5. * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
  6. * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
  7. * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
  8. *
  9. * SPDX-License-Identifier: GPL-2.0+
  10. */
  11. #include "dialog.h"
  12. static int list_width, check_x, item_x;
  13. /*
  14. * Print list item
  15. */
  16. static void print_item(WINDOW * win, int choice, int selected)
  17. {
  18. int i;
  19. char *list_item = malloc(list_width + 1);
  20. strncpy(list_item, item_str(), list_width - item_x);
  21. list_item[list_width - item_x] = '\0';
  22. /* Clear 'residue' of last item */
  23. wattrset(win, dlg.menubox.atr);
  24. wmove(win, choice, 0);
  25. for (i = 0; i < list_width; i++)
  26. waddch(win, ' ');
  27. wmove(win, choice, check_x);
  28. wattrset(win, selected ? dlg.check_selected.atr
  29. : dlg.check.atr);
  30. if (!item_is_tag(':'))
  31. wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
  32. wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
  33. mvwaddch(win, choice, item_x, list_item[0]);
  34. wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
  35. waddstr(win, list_item + 1);
  36. if (selected) {
  37. wmove(win, choice, check_x + 1);
  38. wrefresh(win);
  39. }
  40. free(list_item);
  41. }
  42. /*
  43. * Print the scroll indicators.
  44. */
  45. static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
  46. int y, int x, int height)
  47. {
  48. wmove(win, y, x);
  49. if (scroll > 0) {
  50. wattrset(win, dlg.uarrow.atr);
  51. waddch(win, ACS_UARROW);
  52. waddstr(win, "(-)");
  53. } else {
  54. wattrset(win, dlg.menubox.atr);
  55. waddch(win, ACS_HLINE);
  56. waddch(win, ACS_HLINE);
  57. waddch(win, ACS_HLINE);
  58. waddch(win, ACS_HLINE);
  59. }
  60. y = y + height + 1;
  61. wmove(win, y, x);
  62. if ((height < item_no) && (scroll + choice < item_no - 1)) {
  63. wattrset(win, dlg.darrow.atr);
  64. waddch(win, ACS_DARROW);
  65. waddstr(win, "(+)");
  66. } else {
  67. wattrset(win, dlg.menubox_border.atr);
  68. waddch(win, ACS_HLINE);
  69. waddch(win, ACS_HLINE);
  70. waddch(win, ACS_HLINE);
  71. waddch(win, ACS_HLINE);
  72. }
  73. }
  74. /*
  75. * Display the termination buttons
  76. */
  77. static void print_buttons(WINDOW * dialog, int height, int width, int selected)
  78. {
  79. int x = width / 2 - 11;
  80. int y = height - 2;
  81. print_button(dialog, gettext("Select"), y, x, selected == 0);
  82. print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
  83. wmove(dialog, y, x + 1 + 14 * selected);
  84. wrefresh(dialog);
  85. }
  86. /*
  87. * Display a dialog box with a list of options that can be turned on or off
  88. * in the style of radiolist (only one option turned on at a time).
  89. */
  90. int dialog_checklist(const char *title, const char *prompt, int height,
  91. int width, int list_height)
  92. {
  93. int i, x, y, box_x, box_y;
  94. int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
  95. WINDOW *dialog, *list;
  96. /* which item to highlight */
  97. item_foreach() {
  98. if (item_is_tag('X'))
  99. choice = item_n();
  100. if (item_is_selected()) {
  101. choice = item_n();
  102. break;
  103. }
  104. }
  105. do_resize:
  106. if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
  107. return -ERRDISPLAYTOOSMALL;
  108. if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
  109. return -ERRDISPLAYTOOSMALL;
  110. max_choice = MIN(list_height, item_count());
  111. /* center dialog box on screen */
  112. x = (getmaxx(stdscr) - width) / 2;
  113. y = (getmaxy(stdscr) - height) / 2;
  114. draw_shadow(stdscr, y, x, height, width);
  115. dialog = newwin(height, width, y, x);
  116. keypad(dialog, TRUE);
  117. draw_box(dialog, 0, 0, height, width,
  118. dlg.dialog.atr, dlg.border.atr);
  119. wattrset(dialog, dlg.border.atr);
  120. mvwaddch(dialog, height - 3, 0, ACS_LTEE);
  121. for (i = 0; i < width - 2; i++)
  122. waddch(dialog, ACS_HLINE);
  123. wattrset(dialog, dlg.dialog.atr);
  124. waddch(dialog, ACS_RTEE);
  125. print_title(dialog, title, width);
  126. wattrset(dialog, dlg.dialog.atr);
  127. print_autowrap(dialog, prompt, width - 2, 1, 3);
  128. list_width = width - 6;
  129. box_y = height - list_height - 5;
  130. box_x = (width - list_width) / 2 - 1;
  131. /* create new window for the list */
  132. list = subwin(dialog, list_height, list_width, y + box_y + 1,
  133. x + box_x + 1);
  134. keypad(list, TRUE);
  135. /* draw a box around the list items */
  136. draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
  137. dlg.menubox_border.atr, dlg.menubox.atr);
  138. /* Find length of longest item in order to center checklist */
  139. check_x = 0;
  140. item_foreach()
  141. check_x = MAX(check_x, strlen(item_str()) + 4);
  142. check_x = MIN(check_x, list_width);
  143. check_x = (list_width - check_x) / 2;
  144. item_x = check_x + 4;
  145. if (choice >= list_height) {
  146. scroll = choice - list_height + 1;
  147. choice -= scroll;
  148. }
  149. /* Print the list */
  150. for (i = 0; i < max_choice; i++) {
  151. item_set(scroll + i);
  152. print_item(list, i, i == choice);
  153. }
  154. print_arrows(dialog, choice, item_count(), scroll,
  155. box_y, box_x + check_x + 5, list_height);
  156. print_buttons(dialog, height, width, 0);
  157. wnoutrefresh(dialog);
  158. wnoutrefresh(list);
  159. doupdate();
  160. while (key != KEY_ESC) {
  161. key = wgetch(dialog);
  162. for (i = 0; i < max_choice; i++) {
  163. item_set(i + scroll);
  164. if (toupper(key) == toupper(item_str()[0]))
  165. break;
  166. }
  167. if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
  168. key == '+' || key == '-') {
  169. if (key == KEY_UP || key == '-') {
  170. if (!choice) {
  171. if (!scroll)
  172. continue;
  173. /* Scroll list down */
  174. if (list_height > 1) {
  175. /* De-highlight current first item */
  176. item_set(scroll);
  177. print_item(list, 0, FALSE);
  178. scrollok(list, TRUE);
  179. wscrl(list, -1);
  180. scrollok(list, FALSE);
  181. }
  182. scroll--;
  183. item_set(scroll);
  184. print_item(list, 0, TRUE);
  185. print_arrows(dialog, choice, item_count(),
  186. scroll, box_y, box_x + check_x + 5, list_height);
  187. wnoutrefresh(dialog);
  188. wrefresh(list);
  189. continue; /* wait for another key press */
  190. } else
  191. i = choice - 1;
  192. } else if (key == KEY_DOWN || key == '+') {
  193. if (choice == max_choice - 1) {
  194. if (scroll + choice >= item_count() - 1)
  195. continue;
  196. /* Scroll list up */
  197. if (list_height > 1) {
  198. /* De-highlight current last item before scrolling up */
  199. item_set(scroll + max_choice - 1);
  200. print_item(list,
  201. max_choice - 1,
  202. FALSE);
  203. scrollok(list, TRUE);
  204. wscrl(list, 1);
  205. scrollok(list, FALSE);
  206. }
  207. scroll++;
  208. item_set(scroll + max_choice - 1);
  209. print_item(list, max_choice - 1, TRUE);
  210. print_arrows(dialog, choice, item_count(),
  211. scroll, box_y, box_x + check_x + 5, list_height);
  212. wnoutrefresh(dialog);
  213. wrefresh(list);
  214. continue; /* wait for another key press */
  215. } else
  216. i = choice + 1;
  217. }
  218. if (i != choice) {
  219. /* De-highlight current item */
  220. item_set(scroll + choice);
  221. print_item(list, choice, FALSE);
  222. /* Highlight new item */
  223. choice = i;
  224. item_set(scroll + choice);
  225. print_item(list, choice, TRUE);
  226. wnoutrefresh(dialog);
  227. wrefresh(list);
  228. }
  229. continue; /* wait for another key press */
  230. }
  231. switch (key) {
  232. case 'H':
  233. case 'h':
  234. case '?':
  235. button = 1;
  236. /* fall-through */
  237. case 'S':
  238. case 's':
  239. case ' ':
  240. case '\n':
  241. item_foreach()
  242. item_set_selected(0);
  243. item_set(scroll + choice);
  244. item_set_selected(1);
  245. delwin(list);
  246. delwin(dialog);
  247. return button;
  248. case TAB:
  249. case KEY_LEFT:
  250. case KEY_RIGHT:
  251. button = ((key == KEY_LEFT ? --button : ++button) < 0)
  252. ? 1 : (button > 1 ? 0 : button);
  253. print_buttons(dialog, height, width, button);
  254. wrefresh(dialog);
  255. break;
  256. case 'X':
  257. case 'x':
  258. key = KEY_ESC;
  259. break;
  260. case KEY_ESC:
  261. key = on_key_esc(dialog);
  262. break;
  263. case KEY_RESIZE:
  264. delwin(list);
  265. delwin(dialog);
  266. on_key_resize();
  267. goto do_resize;
  268. }
  269. /* Now, update everything... */
  270. doupdate();
  271. }
  272. delwin(list);
  273. delwin(dialog);
  274. return key; /* ESC pressed */
  275. }