| // SPDX-License-Identifier: GPL-2.0 |
| #include <signal.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/ttydefaults.h> |
| |
| #include "../browser.h" |
| #include "../keysyms.h" |
| #include "../helpline.h" |
| #include "../ui.h" |
| #include "../util.h" |
| #include "../libslang.h" |
| |
| static void ui_browser__argv_write(struct ui_browser *browser, |
| void *entry, int row) |
| { |
| char **arg = entry; |
| bool current_entry = ui_browser__is_current_entry(browser, row); |
| |
| ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
| HE_COLORSET_NORMAL); |
| ui_browser__write_nstring(browser, *arg, browser->width); |
| } |
| |
| static int popup_menu__run(struct ui_browser *menu, int *keyp) |
| { |
| int key; |
| |
| if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) |
| return -1; |
| |
| while (1) { |
| key = ui_browser__run(menu, 0); |
| |
| switch (key) { |
| case K_RIGHT: |
| case K_ENTER: |
| key = menu->index; |
| break; |
| case K_LEFT: |
| case K_ESC: |
| case 'q': |
| case CTRL('c'): |
| key = -1; |
| break; |
| default: |
| if (keyp) { |
| *keyp = key; |
| key = menu->nr_entries; |
| break; |
| } |
| continue; |
| } |
| |
| break; |
| } |
| |
| ui_browser__hide(menu); |
| return key; |
| } |
| |
| int ui__popup_menu(int argc, char * const argv[], int *keyp) |
| { |
| struct ui_browser menu = { |
| .entries = (void *)argv, |
| .refresh = ui_browser__argv_refresh, |
| .seek = ui_browser__argv_seek, |
| .write = ui_browser__argv_write, |
| .nr_entries = argc, |
| }; |
| return popup_menu__run(&menu, keyp); |
| } |
| |
| int ui_browser__input_window(const char *title, const char *text, char *input, |
| const char *exit_msg, int delay_secs) |
| { |
| int x, y, len, key; |
| int max_len = 60, nr_lines = 0; |
| static char buf[50]; |
| const char *t; |
| |
| t = text; |
| while (1) { |
| const char *sep = strchr(t, '\n'); |
| |
| if (sep == NULL) |
| sep = strchr(t, '\0'); |
| len = sep - t; |
| if (max_len < len) |
| max_len = len; |
| ++nr_lines; |
| if (*sep == '\0') |
| break; |
| t = sep + 1; |
| } |
| |
| mutex_lock(&ui__lock); |
| |
| max_len += 2; |
| nr_lines += 8; |
| y = SLtt_Screen_Rows / 2 - nr_lines / 2; |
| x = SLtt_Screen_Cols / 2 - max_len / 2; |
| |
| SLsmg_set_color(0); |
| SLsmg_draw_box(y, x++, nr_lines, max_len); |
| if (title) { |
| SLsmg_gotorc(y, x + 1); |
| SLsmg_write_string(title); |
| } |
| SLsmg_gotorc(++y, x); |
| nr_lines -= 7; |
| max_len -= 2; |
| SLsmg_write_wrapped_string((unsigned char *)text, y, x, |
| nr_lines, max_len, 1); |
| y += nr_lines; |
| len = 5; |
| while (len--) { |
| SLsmg_gotorc(y + len - 1, x); |
| SLsmg_write_nstring(" ", max_len); |
| } |
| SLsmg_draw_box(y++, x + 1, 3, max_len - 2); |
| |
| SLsmg_gotorc(y + 3, x); |
| SLsmg_write_nstring(exit_msg, max_len); |
| SLsmg_refresh(); |
| |
| mutex_unlock(&ui__lock); |
| |
| x += 2; |
| len = 0; |
| key = ui__getch(delay_secs); |
| while (key != K_TIMER && key != K_ENTER && key != K_ESC) { |
| mutex_lock(&ui__lock); |
| |
| if (key == K_BKSPC) { |
| if (len == 0) { |
| mutex_unlock(&ui__lock); |
| goto next_key; |
| } |
| SLsmg_gotorc(y, x + --len); |
| SLsmg_write_char(' '); |
| } else { |
| buf[len] = key; |
| SLsmg_gotorc(y, x + len++); |
| SLsmg_write_char(key); |
| } |
| SLsmg_refresh(); |
| |
| mutex_unlock(&ui__lock); |
| |
| /* XXX more graceful overflow handling needed */ |
| if (len == sizeof(buf) - 1) { |
| ui_helpline__push("maximum size of symbol name reached!"); |
| key = K_ENTER; |
| break; |
| } |
| next_key: |
| key = ui__getch(delay_secs); |
| } |
| |
| buf[len] = '\0'; |
| strncpy(input, buf, len+1); |
| return key; |
| } |
| |
| void __ui__info_window(const char *title, const char *text, const char *exit_msg) |
| { |
| int x, y; |
| int max_len = 0, nr_lines = 0; |
| const char *t; |
| |
| t = text; |
| while (1) { |
| const char *sep = strchr(t, '\n'); |
| int len; |
| |
| if (sep == NULL) |
| sep = strchr(t, '\0'); |
| len = sep - t; |
| if (max_len < len) |
| max_len = len; |
| ++nr_lines; |
| if (*sep == '\0') |
| break; |
| t = sep + 1; |
| } |
| |
| max_len += 2; |
| nr_lines += 2; |
| if (exit_msg) |
| nr_lines += 2; |
| y = SLtt_Screen_Rows / 2 - nr_lines / 2, |
| x = SLtt_Screen_Cols / 2 - max_len / 2; |
| |
| SLsmg_set_color(0); |
| SLsmg_draw_box(y, x++, nr_lines, max_len); |
| if (title) { |
| SLsmg_gotorc(y, x + 1); |
| SLsmg_write_string(title); |
| } |
| SLsmg_gotorc(++y, x); |
| if (exit_msg) |
| nr_lines -= 2; |
| max_len -= 2; |
| SLsmg_write_wrapped_string((unsigned char *)text, y, x, |
| nr_lines, max_len, 1); |
| if (exit_msg) { |
| SLsmg_gotorc(y + nr_lines - 2, x); |
| SLsmg_write_nstring(" ", max_len); |
| SLsmg_gotorc(y + nr_lines - 1, x); |
| SLsmg_write_nstring(exit_msg, max_len); |
| } |
| } |
| |
| void ui__info_window(const char *title, const char *text) |
| { |
| mutex_lock(&ui__lock); |
| __ui__info_window(title, text, NULL); |
| SLsmg_refresh(); |
| mutex_unlock(&ui__lock); |
| } |
| |
| int ui__question_window(const char *title, const char *text, |
| const char *exit_msg, int delay_secs) |
| { |
| mutex_lock(&ui__lock); |
| __ui__info_window(title, text, exit_msg); |
| SLsmg_refresh(); |
| mutex_unlock(&ui__lock); |
| return ui__getch(delay_secs); |
| } |
| |
| int ui__help_window(const char *text) |
| { |
| return ui__question_window("Help", text, "Press any key...", 0); |
| } |
| |
| int ui__dialog_yesno(const char *msg) |
| { |
| return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); |
| } |
| |
| static int __ui__warning(const char *title, const char *format, va_list args) |
| { |
| char *s; |
| |
| if (vasprintf(&s, format, args) > 0) { |
| int key; |
| |
| key = ui__question_window(title, s, "Press any key...", 0); |
| free(s); |
| return key; |
| } |
| |
| fprintf(stderr, "%s\n", title); |
| vfprintf(stderr, format, args); |
| return K_ESC; |
| } |
| |
| static int perf_tui__error(const char *format, va_list args) |
| { |
| return __ui__warning("Error:", format, args); |
| } |
| |
| static int perf_tui__warning(const char *format, va_list args) |
| { |
| return __ui__warning("Warning:", format, args); |
| } |
| |
| struct perf_error_ops perf_tui_eops = { |
| .error = perf_tui__error, |
| .warning = perf_tui__warning, |
| }; |