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) 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 continue; 49 } 50 51 break; 52 } 53 54 ui_browser__hide(menu); 55 return key; 56 } 57 58 int ui__popup_menu(int argc, char * const argv[]) 59 { 60 struct ui_browser menu = { 61 .entries = (void *)argv, 62 .refresh = ui_browser__argv_refresh, 63 .seek = ui_browser__argv_seek, 64 .write = ui_browser__argv_write, 65 .nr_entries = argc, 66 }; 67 68 return popup_menu__run(&menu); 69 } 70 71 int ui_browser__input_window(const char *title, const char *text, char *input, 72 const char *exit_msg, int delay_secs) 73 { 74 int x, y, len, key; 75 int max_len = 60, nr_lines = 0; 76 static char buf[50]; 77 const char *t; 78 79 t = text; 80 while (1) { 81 const char *sep = strchr(t, '\n'); 82 83 if (sep == NULL) 84 sep = strchr(t, '\0'); 85 len = sep - t; 86 if (max_len < len) 87 max_len = len; 88 ++nr_lines; 89 if (*sep == '\0') 90 break; 91 t = sep + 1; 92 } 93 94 pthread_mutex_lock(&ui__lock); 95 96 max_len += 2; 97 nr_lines += 8; 98 y = SLtt_Screen_Rows / 2 - nr_lines / 2; 99 x = SLtt_Screen_Cols / 2 - max_len / 2; 100 101 SLsmg_set_color(0); 102 SLsmg_draw_box(y, x++, nr_lines, max_len); 103 if (title) { 104 SLsmg_gotorc(y, x + 1); 105 SLsmg_write_string((char *)title); 106 } 107 SLsmg_gotorc(++y, x); 108 nr_lines -= 7; 109 max_len -= 2; 110 SLsmg_write_wrapped_string((unsigned char *)text, y, x, 111 nr_lines, max_len, 1); 112 y += nr_lines; 113 len = 5; 114 while (len--) { 115 SLsmg_gotorc(y + len - 1, x); 116 SLsmg_write_nstring((char *)" ", max_len); 117 } 118 SLsmg_draw_box(y++, x + 1, 3, max_len - 2); 119 120 SLsmg_gotorc(y + 3, x); 121 SLsmg_write_nstring((char *)exit_msg, max_len); 122 SLsmg_refresh(); 123 124 pthread_mutex_unlock(&ui__lock); 125 126 x += 2; 127 len = 0; 128 key = ui__getch(delay_secs); 129 while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 130 pthread_mutex_lock(&ui__lock); 131 132 if (key == K_BKSPC) { 133 if (len == 0) { 134 pthread_mutex_unlock(&ui__lock); 135 goto next_key; 136 } 137 SLsmg_gotorc(y, x + --len); 138 SLsmg_write_char(' '); 139 } else { 140 buf[len] = key; 141 SLsmg_gotorc(y, x + len++); 142 SLsmg_write_char(key); 143 } 144 SLsmg_refresh(); 145 146 pthread_mutex_unlock(&ui__lock); 147 148 /* XXX more graceful overflow handling needed */ 149 if (len == sizeof(buf) - 1) { 150 ui_helpline__push("maximum size of symbol name reached!"); 151 key = K_ENTER; 152 break; 153 } 154 next_key: 155 key = ui__getch(delay_secs); 156 } 157 158 buf[len] = '\0'; 159 strncpy(input, buf, len+1); 160 return key; 161 } 162 163 void __ui__info_window(const char *title, const char *text, const char *exit_msg) 164 { 165 int x, y; 166 int max_len = 0, nr_lines = 0; 167 const char *t; 168 169 t = text; 170 while (1) { 171 const char *sep = strchr(t, '\n'); 172 int len; 173 174 if (sep == NULL) 175 sep = strchr(t, '\0'); 176 len = sep - t; 177 if (max_len < len) 178 max_len = len; 179 ++nr_lines; 180 if (*sep == '\0') 181 break; 182 t = sep + 1; 183 } 184 185 max_len += 2; 186 nr_lines += 2; 187 if (exit_msg) 188 nr_lines += 2; 189 y = SLtt_Screen_Rows / 2 - nr_lines / 2, 190 x = SLtt_Screen_Cols / 2 - max_len / 2; 191 192 SLsmg_set_color(0); 193 SLsmg_draw_box(y, x++, nr_lines, max_len); 194 if (title) { 195 SLsmg_gotorc(y, x + 1); 196 SLsmg_write_string((char *)title); 197 } 198 SLsmg_gotorc(++y, x); 199 if (exit_msg) 200 nr_lines -= 2; 201 max_len -= 2; 202 SLsmg_write_wrapped_string((unsigned char *)text, y, x, 203 nr_lines, max_len, 1); 204 if (exit_msg) { 205 SLsmg_gotorc(y + nr_lines - 2, x); 206 SLsmg_write_nstring((char *)" ", max_len); 207 SLsmg_gotorc(y + nr_lines - 1, x); 208 SLsmg_write_nstring((char *)exit_msg, max_len); 209 } 210 } 211 212 void ui__info_window(const char *title, const char *text) 213 { 214 pthread_mutex_lock(&ui__lock); 215 __ui__info_window(title, text, NULL); 216 SLsmg_refresh(); 217 pthread_mutex_unlock(&ui__lock); 218 } 219 220 int ui__question_window(const char *title, const char *text, 221 const char *exit_msg, int delay_secs) 222 { 223 pthread_mutex_lock(&ui__lock); 224 __ui__info_window(title, text, exit_msg); 225 SLsmg_refresh(); 226 pthread_mutex_unlock(&ui__lock); 227 return ui__getch(delay_secs); 228 } 229 230 int ui__help_window(const char *text) 231 { 232 return ui__question_window("Help", text, "Press any key...", 0); 233 } 234 235 int ui__dialog_yesno(const char *msg) 236 { 237 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); 238 } 239 240 static int __ui__warning(const char *title, const char *format, va_list args) 241 { 242 char *s; 243 244 if (vasprintf(&s, format, args) > 0) { 245 int key; 246 247 key = ui__question_window(title, s, "Press any key...", 0); 248 free(s); 249 return key; 250 } 251 252 fprintf(stderr, "%s\n", title); 253 vfprintf(stderr, format, args); 254 return K_ESC; 255 } 256 257 static int perf_tui__error(const char *format, va_list args) 258 { 259 return __ui__warning("Error:", format, args); 260 } 261 262 static int perf_tui__warning(const char *format, va_list args) 263 { 264 return __ui__warning("Warning:", format, args); 265 } 266 267 struct perf_error_ops perf_tui_eops = { 268 .error = perf_tui__error, 269 .warning = perf_tui__warning, 270 }; 271