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