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