18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <signal.h> 38c2ecf20Sopenharmony_ci#include <stdbool.h> 48c2ecf20Sopenharmony_ci#include <string.h> 58c2ecf20Sopenharmony_ci#include <stdlib.h> 68c2ecf20Sopenharmony_ci#include <sys/ttydefaults.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "../browser.h" 98c2ecf20Sopenharmony_ci#include "../keysyms.h" 108c2ecf20Sopenharmony_ci#include "../helpline.h" 118c2ecf20Sopenharmony_ci#include "../ui.h" 128c2ecf20Sopenharmony_ci#include "../util.h" 138c2ecf20Sopenharmony_ci#include "../libslang.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic void ui_browser__argv_write(struct ui_browser *browser, 168c2ecf20Sopenharmony_ci void *entry, int row) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci char **arg = entry; 198c2ecf20Sopenharmony_ci bool current_entry = ui_browser__is_current_entry(browser, row); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 228c2ecf20Sopenharmony_ci HE_COLORSET_NORMAL); 238c2ecf20Sopenharmony_ci ui_browser__write_nstring(browser, *arg, browser->width); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int popup_menu__run(struct ui_browser *menu, int *keyp) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int key; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) 318c2ecf20Sopenharmony_ci return -1; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci while (1) { 348c2ecf20Sopenharmony_ci key = ui_browser__run(menu, 0); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci switch (key) { 378c2ecf20Sopenharmony_ci case K_RIGHT: 388c2ecf20Sopenharmony_ci case K_ENTER: 398c2ecf20Sopenharmony_ci key = menu->index; 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci case K_LEFT: 428c2ecf20Sopenharmony_ci case K_ESC: 438c2ecf20Sopenharmony_ci case 'q': 448c2ecf20Sopenharmony_ci case CTRL('c'): 458c2ecf20Sopenharmony_ci key = -1; 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci default: 488c2ecf20Sopenharmony_ci if (keyp) { 498c2ecf20Sopenharmony_ci *keyp = key; 508c2ecf20Sopenharmony_ci key = menu->nr_entries; 518c2ecf20Sopenharmony_ci break; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci continue; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci break; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ui_browser__hide(menu); 608c2ecf20Sopenharmony_ci return key; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciint ui__popup_menu(int argc, char * const argv[], int *keyp) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct ui_browser menu = { 668c2ecf20Sopenharmony_ci .entries = (void *)argv, 678c2ecf20Sopenharmony_ci .refresh = ui_browser__argv_refresh, 688c2ecf20Sopenharmony_ci .seek = ui_browser__argv_seek, 698c2ecf20Sopenharmony_ci .write = ui_browser__argv_write, 708c2ecf20Sopenharmony_ci .nr_entries = argc, 718c2ecf20Sopenharmony_ci }; 728c2ecf20Sopenharmony_ci return popup_menu__run(&menu, keyp); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint ui_browser__input_window(const char *title, const char *text, char *input, 768c2ecf20Sopenharmony_ci const char *exit_msg, int delay_secs) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci int x, y, len, key; 798c2ecf20Sopenharmony_ci int max_len = 60, nr_lines = 0; 808c2ecf20Sopenharmony_ci static char buf[50]; 818c2ecf20Sopenharmony_ci const char *t; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci t = text; 848c2ecf20Sopenharmony_ci while (1) { 858c2ecf20Sopenharmony_ci const char *sep = strchr(t, '\n'); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (sep == NULL) 888c2ecf20Sopenharmony_ci sep = strchr(t, '\0'); 898c2ecf20Sopenharmony_ci len = sep - t; 908c2ecf20Sopenharmony_ci if (max_len < len) 918c2ecf20Sopenharmony_ci max_len = len; 928c2ecf20Sopenharmony_ci ++nr_lines; 938c2ecf20Sopenharmony_ci if (*sep == '\0') 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci t = sep + 1; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci pthread_mutex_lock(&ui__lock); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci max_len += 2; 1018c2ecf20Sopenharmony_ci nr_lines += 8; 1028c2ecf20Sopenharmony_ci y = SLtt_Screen_Rows / 2 - nr_lines / 2; 1038c2ecf20Sopenharmony_ci x = SLtt_Screen_Cols / 2 - max_len / 2; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci SLsmg_set_color(0); 1068c2ecf20Sopenharmony_ci SLsmg_draw_box(y, x++, nr_lines, max_len); 1078c2ecf20Sopenharmony_ci if (title) { 1088c2ecf20Sopenharmony_ci SLsmg_gotorc(y, x + 1); 1098c2ecf20Sopenharmony_ci SLsmg_write_string((char *)title); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci SLsmg_gotorc(++y, x); 1128c2ecf20Sopenharmony_ci nr_lines -= 7; 1138c2ecf20Sopenharmony_ci max_len -= 2; 1148c2ecf20Sopenharmony_ci SLsmg_write_wrapped_string((unsigned char *)text, y, x, 1158c2ecf20Sopenharmony_ci nr_lines, max_len, 1); 1168c2ecf20Sopenharmony_ci y += nr_lines; 1178c2ecf20Sopenharmony_ci len = 5; 1188c2ecf20Sopenharmony_ci while (len--) { 1198c2ecf20Sopenharmony_ci SLsmg_gotorc(y + len - 1, x); 1208c2ecf20Sopenharmony_ci SLsmg_write_nstring((char *)" ", max_len); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci SLsmg_draw_box(y++, x + 1, 3, max_len - 2); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci SLsmg_gotorc(y + 3, x); 1258c2ecf20Sopenharmony_ci SLsmg_write_nstring((char *)exit_msg, max_len); 1268c2ecf20Sopenharmony_ci SLsmg_refresh(); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci pthread_mutex_unlock(&ui__lock); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci x += 2; 1318c2ecf20Sopenharmony_ci len = 0; 1328c2ecf20Sopenharmony_ci key = ui__getch(delay_secs); 1338c2ecf20Sopenharmony_ci while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 1348c2ecf20Sopenharmony_ci pthread_mutex_lock(&ui__lock); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (key == K_BKSPC) { 1378c2ecf20Sopenharmony_ci if (len == 0) { 1388c2ecf20Sopenharmony_ci pthread_mutex_unlock(&ui__lock); 1398c2ecf20Sopenharmony_ci goto next_key; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci SLsmg_gotorc(y, x + --len); 1428c2ecf20Sopenharmony_ci SLsmg_write_char(' '); 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci buf[len] = key; 1458c2ecf20Sopenharmony_ci SLsmg_gotorc(y, x + len++); 1468c2ecf20Sopenharmony_ci SLsmg_write_char(key); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci SLsmg_refresh(); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci pthread_mutex_unlock(&ui__lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* XXX more graceful overflow handling needed */ 1538c2ecf20Sopenharmony_ci if (len == sizeof(buf) - 1) { 1548c2ecf20Sopenharmony_ci ui_helpline__push("maximum size of symbol name reached!"); 1558c2ecf20Sopenharmony_ci key = K_ENTER; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_cinext_key: 1598c2ecf20Sopenharmony_ci key = ui__getch(delay_secs); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci buf[len] = '\0'; 1638c2ecf20Sopenharmony_ci strncpy(input, buf, len+1); 1648c2ecf20Sopenharmony_ci return key; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_civoid __ui__info_window(const char *title, const char *text, const char *exit_msg) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int x, y; 1708c2ecf20Sopenharmony_ci int max_len = 0, nr_lines = 0; 1718c2ecf20Sopenharmony_ci const char *t; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci t = text; 1748c2ecf20Sopenharmony_ci while (1) { 1758c2ecf20Sopenharmony_ci const char *sep = strchr(t, '\n'); 1768c2ecf20Sopenharmony_ci int len; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (sep == NULL) 1798c2ecf20Sopenharmony_ci sep = strchr(t, '\0'); 1808c2ecf20Sopenharmony_ci len = sep - t; 1818c2ecf20Sopenharmony_ci if (max_len < len) 1828c2ecf20Sopenharmony_ci max_len = len; 1838c2ecf20Sopenharmony_ci ++nr_lines; 1848c2ecf20Sopenharmony_ci if (*sep == '\0') 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci t = sep + 1; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci max_len += 2; 1908c2ecf20Sopenharmony_ci nr_lines += 2; 1918c2ecf20Sopenharmony_ci if (exit_msg) 1928c2ecf20Sopenharmony_ci nr_lines += 2; 1938c2ecf20Sopenharmony_ci y = SLtt_Screen_Rows / 2 - nr_lines / 2, 1948c2ecf20Sopenharmony_ci x = SLtt_Screen_Cols / 2 - max_len / 2; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci SLsmg_set_color(0); 1978c2ecf20Sopenharmony_ci SLsmg_draw_box(y, x++, nr_lines, max_len); 1988c2ecf20Sopenharmony_ci if (title) { 1998c2ecf20Sopenharmony_ci SLsmg_gotorc(y, x + 1); 2008c2ecf20Sopenharmony_ci SLsmg_write_string((char *)title); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci SLsmg_gotorc(++y, x); 2038c2ecf20Sopenharmony_ci if (exit_msg) 2048c2ecf20Sopenharmony_ci nr_lines -= 2; 2058c2ecf20Sopenharmony_ci max_len -= 2; 2068c2ecf20Sopenharmony_ci SLsmg_write_wrapped_string((unsigned char *)text, y, x, 2078c2ecf20Sopenharmony_ci nr_lines, max_len, 1); 2088c2ecf20Sopenharmony_ci if (exit_msg) { 2098c2ecf20Sopenharmony_ci SLsmg_gotorc(y + nr_lines - 2, x); 2108c2ecf20Sopenharmony_ci SLsmg_write_nstring((char *)" ", max_len); 2118c2ecf20Sopenharmony_ci SLsmg_gotorc(y + nr_lines - 1, x); 2128c2ecf20Sopenharmony_ci SLsmg_write_nstring((char *)exit_msg, max_len); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_civoid ui__info_window(const char *title, const char *text) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci pthread_mutex_lock(&ui__lock); 2198c2ecf20Sopenharmony_ci __ui__info_window(title, text, NULL); 2208c2ecf20Sopenharmony_ci SLsmg_refresh(); 2218c2ecf20Sopenharmony_ci pthread_mutex_unlock(&ui__lock); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciint ui__question_window(const char *title, const char *text, 2258c2ecf20Sopenharmony_ci const char *exit_msg, int delay_secs) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci pthread_mutex_lock(&ui__lock); 2288c2ecf20Sopenharmony_ci __ui__info_window(title, text, exit_msg); 2298c2ecf20Sopenharmony_ci SLsmg_refresh(); 2308c2ecf20Sopenharmony_ci pthread_mutex_unlock(&ui__lock); 2318c2ecf20Sopenharmony_ci return ui__getch(delay_secs); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciint ui__help_window(const char *text) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci return ui__question_window("Help", text, "Press any key...", 0); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciint ui__dialog_yesno(const char *msg) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int __ui__warning(const char *title, const char *format, va_list args) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci char *s; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (vasprintf(&s, format, args) > 0) { 2498c2ecf20Sopenharmony_ci int key; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci key = ui__question_window(title, s, "Press any key...", 0); 2528c2ecf20Sopenharmony_ci free(s); 2538c2ecf20Sopenharmony_ci return key; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci fprintf(stderr, "%s\n", title); 2578c2ecf20Sopenharmony_ci vfprintf(stderr, format, args); 2588c2ecf20Sopenharmony_ci return K_ESC; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int perf_tui__error(const char *format, va_list args) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci return __ui__warning("Error:", format, args); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int perf_tui__warning(const char *format, va_list args) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci return __ui__warning("Warning:", format, args); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistruct perf_error_ops perf_tui_eops = { 2728c2ecf20Sopenharmony_ci .error = perf_tui__error, 2738c2ecf20Sopenharmony_ci .warning = perf_tui__warning, 2748c2ecf20Sopenharmony_ci}; 275