1 // SPDX-License-Identifier: GPL-2.0 2 #include <signal.h> 3 #include <stdbool.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <sys/ttydefaults.h> 7 8 #include "../browser.h" 9 #include "../keysyms.h" 10 #include "../helpline.h" 11 #include "../ui.h" 12 #include "../util.h" 13 #include "../libslang.h" 14 15 static void ui_browser__argv_write(struct ui_browser *browser, 16 void *entry, int row) 17 { 18 char **arg = entry; 19 bool current_entry = ui_browser__is_current_entry(browser, row); 20 21 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 22 HE_COLORSET_NORMAL); 23 ui_browser__write_nstring(browser, *arg, browser->width); 24 } 25 26 static int popup_menu__run(struct ui_browser *menu, int *keyp) 27 { 28 int key; 29 30 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) 31 return -1; 32 33 while (1) { 34 key = ui_browser__run(menu, 0); 35 36 switch (key) { 37 case K_RIGHT: 38 case K_ENTER: 39 key = menu->index; 40 break; 41 case K_LEFT: 42 case K_ESC: 43 case 'q': 44 case CTRL('c'): 45 key = -1; 46 break; 47 default: 48 if (keyp) { 49 *keyp = key; 50 key = menu->nr_entries; 51 break; 52 } 53 continue; 54 } 55 56 break; 57 } 58 59 ui_browser__hide(menu); 60 return key; 61 } 62 63 int ui__popup_menu(int argc, char * const argv[], int *keyp) 64 { 65 struct ui_browser menu = { 66 .entries = (void *)argv, 67 .refresh = ui_browser__argv_refresh, 68 .seek = ui_browser__argv_seek, 69 .write = ui_browser__argv_write, 70 .nr_entries = argc, 71 }; 72 return popup_menu__run(&menu, keyp); 73 } 74 75 int ui_browser__input_window(const char *title, const char *text, char *input, 76 const char *exit_msg, int delay_secs) 77 { 78 int x, y, len, key; 79 int max_len = 60, nr_lines = 0; 80 static char buf[50]; 81 const char *t; 82 83 t = text; 84 while (1) { 85 const char *sep = strchr(t, '\n'); 86 87 if (sep == NULL) 88 sep = strchr(t, '\0'); 89 len = sep - t; 90 if (max_len < len) 91 max_len = len; 92 ++nr_lines; 93 if (*sep == '\0') 94 break; 95 t = sep + 1; 96 } 97 98 mutex_lock(&ui__lock); 99 100 max_len += 2; 101 nr_lines += 8; 102 y = SLtt_Screen_Rows / 2 - nr_lines / 2; 103 x = SLtt_Screen_Cols / 2 - max_len / 2; 104 105 SLsmg_set_color(0); 106 SLsmg_draw_box(y, x++, nr_lines, max_len); 107 if (title) { 108 SLsmg_gotorc(y, x + 1); 109 SLsmg_write_string((char *)title); 110 } 111 SLsmg_gotorc(++y, x); 112 nr_lines -= 7; 113 max_len -= 2; 114 SLsmg_write_wrapped_string((unsigned char *)text, y, x, 115 nr_lines, max_len, 1); 116 y += nr_lines; 117 len = 5; 118 while (len--) { 119 SLsmg_gotorc(y + len - 1, x); 120 SLsmg_write_nstring((char *)" ", max_len); 121 } 122 SLsmg_draw_box(y++, x + 1, 3, max_len - 2); 123 124 SLsmg_gotorc(y + 3, x); 125 SLsmg_write_nstring((char *)exit_msg, max_len); 126 SLsmg_refresh(); 127 128 mutex_unlock(&ui__lock); 129 130 x += 2; 131 len = 0; 132 key = ui__getch(delay_secs); 133 while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 134 mutex_lock(&ui__lock); 135 136 if (key == K_BKSPC) { 137 if (len == 0) { 138 mutex_unlock(&ui__lock); 139 goto next_key; 140 } 141 SLsmg_gotorc(y, x + --len); 142 SLsmg_write_char(' '); 143 } else { 144 buf[len] = key; 145 SLsmg_gotorc(y, x + len++); 146 SLsmg_write_char(key); 147 } 148 SLsmg_refresh(); 149 150 mutex_unlock(&ui__lock); 151 152 /* XXX more graceful overflow handling needed */ 153 if (len == sizeof(buf) - 1) { 154 ui_helpline__push("maximum size of symbol name reached!"); 155 key = K_ENTER; 156 break; 157 } 158 next_key: 159 key = ui__getch(delay_secs); 160 } 161 162 buf[len] = '\0'; 163 strncpy(input, buf, len+1); 164 return key; 165 } 166 167 void __ui__info_window(const char *title, const char *text, const char *exit_msg) 168 { 169 int x, y; 170 int max_len = 0, nr_lines = 0; 171 const char *t; 172 173 t = text; 174 while (1) { 175 const char *sep = strchr(t, '\n'); 176 int len; 177 178 if (sep == NULL) 179 sep = strchr(t, '\0'); 180 len = sep - t; 181 if (max_len < len) 182 max_len = len; 183 ++nr_lines; 184 if (*sep == '\0') 185 break; 186 t = sep + 1; 187 } 188 189 max_len += 2; 190 nr_lines += 2; 191 if (exit_msg) 192 nr_lines += 2; 193 y = SLtt_Screen_Rows / 2 - nr_lines / 2, 194 x = SLtt_Screen_Cols / 2 - max_len / 2; 195 196 SLsmg_set_color(0); 197 SLsmg_draw_box(y, x++, nr_lines, max_len); 198 if (title) { 199 SLsmg_gotorc(y, x + 1); 200 SLsmg_write_string((char *)title); 201 } 202 SLsmg_gotorc(++y, x); 203 if (exit_msg) 204 nr_lines -= 2; 205 max_len -= 2; 206 SLsmg_write_wrapped_string((unsigned char *)text, y, x, 207 nr_lines, max_len, 1); 208 if (exit_msg) { 209 SLsmg_gotorc(y + nr_lines - 2, x); 210 SLsmg_write_nstring((char *)" ", max_len); 211 SLsmg_gotorc(y + nr_lines - 1, x); 212 SLsmg_write_nstring((char *)exit_msg, max_len); 213 } 214 } 215 216 void ui__info_window(const char *title, const char *text) 217 { 218 mutex_lock(&ui__lock); 219 __ui__info_window(title, text, NULL); 220 SLsmg_refresh(); 221 mutex_unlock(&ui__lock); 222 } 223 224 int ui__question_window(const char *title, const char *text, 225 const char *exit_msg, int delay_secs) 226 { 227 mutex_lock(&ui__lock); 228 __ui__info_window(title, text, exit_msg); 229 SLsmg_refresh(); 230 mutex_unlock(&ui__lock); 231 return ui__getch(delay_secs); 232 } 233 234 int ui__help_window(const char *text) 235 { 236 return ui__question_window("Help", text, "Press any key...", 0); 237 } 238 239 int ui__dialog_yesno(const char *msg) 240 { 241 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); 242 } 243 244 static int __ui__warning(const char *title, const char *format, va_list args) 245 { 246 char *s; 247 248 if (vasprintf(&s, format, args) > 0) { 249 int key; 250 251 key = ui__question_window(title, s, "Press any key...", 0); 252 free(s); 253 return key; 254 } 255 256 fprintf(stderr, "%s\n", title); 257 vfprintf(stderr, format, args); 258 return K_ESC; 259 } 260 261 static int perf_tui__error(const char *format, va_list args) 262 { 263 return __ui__warning("Error:", format, args); 264 } 265 266 static int perf_tui__warning(const char *format, va_list args) 267 { 268 return __ui__warning("Warning:", format, args); 269 } 270 271 struct perf_error_ops perf_tui_eops = { 272 .error = perf_tui__error, 273 .warning = perf_tui__warning, 274 }; 275