xref: /openbmc/linux/tools/perf/ui/tui/util.c (revision ccd51b9f)
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