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