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