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