1 /* bfu.c
2  * (c) 2002 Mikulas Patocka
3  * This file is a part of the Links program, released under GPL.
4  */
5 
6 #include "links.h"
7 
8 static void menu_func(struct window *, struct links_event *, int);
9 static void mainmenu_func(struct window *, struct links_event *, int);
10 
getml(void * p,...)11 struct memory_list *getml(void *p, ...)
12 {
13 	struct memory_list *ml;
14 	va_list ap;
15 	int n = 0;
16 	void *q = p;
17 	va_start(ap, p);
18 	while (q) {
19 		if (n == MAXINT) overalloc();
20 		n++, q = va_arg(ap, void *);
21 	}
22 	if ((unsigned)n > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
23 	ml = mem_alloc(sizeof(struct memory_list) + n * sizeof(void *));
24 	ml->n = n;
25 	n = 0;
26 	q = p;
27 	va_end(ap);
28 	va_start(ap, p);
29 	while (q) ml->p[n++] = q, q = va_arg(ap, void *);
30 	va_end(ap);
31 	return ml;
32 }
33 
add_to_ml(struct memory_list ** ml,...)34 void add_to_ml(struct memory_list **ml, ...)
35 {
36 	struct memory_list *nml;
37 	va_list ap;
38 	int n = 0;
39 	void *q;
40 	if (!*ml) {
41 		*ml = mem_alloc(sizeof(struct memory_list));
42 		(*ml)->n = 0;
43 	}
44 	va_start(ap, ml);
45 	while ((q = va_arg(ap, void *))) {
46 		if (n == MAXINT) overalloc();
47 		n++;
48 	}
49 	if ((unsigned)n + (unsigned)((*ml)->n) > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
50 	nml = mem_realloc(*ml, sizeof(struct memory_list) + (n + (*ml)->n) * sizeof(void *));
51 	va_end(ap);
52 	va_start(ap, ml);
53 	while ((q = va_arg(ap, void *))) nml->p[nml->n++] = q;
54 	*ml = nml;
55 	va_end(ap);
56 }
57 
freeml(struct memory_list * ml)58 void freeml(struct memory_list *ml)
59 {
60 	int i;
61 	if (!ml) return;
62 	for (i = 0; i < ml->n; i++) mem_free(ml->p[i]);
63 	mem_free(ml);
64 }
65 
is_utf_8(struct terminal * term)66 static inline int is_utf_8(struct terminal *term)
67 {
68 #ifdef G
69 	if (F) return 1;
70 #endif
71 #ifdef ENABLE_UTF8
72 	if (term_charset(term) == utf8_table) return 1;
73 #endif
74 	return 0;
75 }
76 
ttxtlen(struct terminal * term,unsigned char * s)77 static inline int ttxtlen(struct terminal *term, unsigned char *s)
78 {
79 #ifdef ENABLE_UTF8
80 	if (term_charset(term) == utf8_table)
81 		return strlen_utf8(s);
82 #endif
83 	return (int)strlen(cast_const_char s);
84 }
85 
txtlen(struct terminal * term,unsigned char * s)86 static inline int txtlen(struct terminal *term, unsigned char *s)
87 {
88 #ifdef G
89 	if (F)
90 		return g_text_width(bfu_style_wb, s);
91 	else
92 #endif
93 		return ttxtlen(term, s);
94 }
95 
96 #ifdef G
97 struct style *bfu_style_wb, *bfu_style_wb_b, *bfu_style_bw, *bfu_style_bw_u;
98 struct style *bfu_style_bw_mono;
99 struct style *bfu_style_wb_mono, *bfu_style_wb_mono_u;
100 
101 long bfu_fg_color, bfu_bg_color;
102 
init_bfu(void)103 void init_bfu(void)
104 {
105 	if (!F) return;
106 	bfu_bg_color = dip_get_color_sRGB(G_BFU_BG_COLOR);
107 	bfu_fg_color = dip_get_color_sRGB(G_BFU_FG_COLOR);
108 	bfu_style_wb = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, 0);
109 	bfu_style_wb_b = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, 0);
110 	bfu_style_bw = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, 0);
111 	bfu_style_bw_u = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, FF_UNDERLINE);
112 	bfu_style_bw_mono = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, FF_MONOSPACED);
113 	bfu_style_wb_mono = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, FF_MONOSPACED);
114 	bfu_style_wb_mono_u = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, FF_UNDERLINE | FF_MONOSPACED);
115 }
116 
117 #define G_DIALOG_FIELD_WIDTH g_char_width(bfu_style_wb_mono, ' ')
118 
shutdown_bfu(void)119 void shutdown_bfu(void)
120 {
121 	if (!F) return;
122 	g_free_style(bfu_style_wb);
123 	g_free_style(bfu_style_wb_b);
124 	g_free_style(bfu_style_bw);
125 	g_free_style(bfu_style_bw_u);
126 	g_free_style(bfu_style_bw_mono);
127 	g_free_style(bfu_style_wb_mono);
128 	g_free_style(bfu_style_wb_mono_u);
129 }
130 
131 #else
132 
init_bfu(void)133 void init_bfu(void) {}
shutdown_bfu(void)134 void shutdown_bfu(void) {}
135 
136 #endif
137 
138 unsigned char m_bar = 0;
139 
select_hotkey(struct terminal * term,unsigned char * text,unsigned char * hotkey,unsigned * hotkeys,int n)140 static unsigned select_hotkey(struct terminal *term, unsigned char *text, unsigned char *hotkey, unsigned *hotkeys, int n)
141 {
142 	unsigned c;
143 	if (hotkey == M_BAR) return 0;
144 	if (text) {
145 		text = stracpy(get_text_translation(text, term));
146 		charset_upcase_string(&text, term_charset(term));
147 	}
148 	hotkey = get_text_translation(hotkey, term);
149 	while (1) {
150 		int i;
151 		c = GET_TERM_CHAR(term, &hotkey);
152 		if (!c) break;
153 		c = charset_upcase(c, term_charset(term));
154 		for (i = 0; i < n; i++) if (hotkeys[i] == c) goto cont;
155 		if (!text || cp_strchr(term_charset(term), text, c)) break;
156 		cont:;
157 	}
158 	if (text) mem_free(text);
159 	return c;
160 }
161 
do_menu_selected(struct terminal * term,struct menu_item * items,void * data,int selected,void (* free_function)(void *),void * free_data)162 void do_menu_selected(struct terminal *term, struct menu_item *items, void *data, int selected, void (*free_function)(void *), void *free_data)
163 {
164 	int i;
165 	struct menu *menu;
166 	for (i = 0; items[i].text; i++) if (i == (MAXINT - sizeof(struct menu)) / sizeof(unsigned)) overalloc();
167 	menu = mem_alloc(sizeof(struct menu) + (!i ? 0 : i - 1) * sizeof(unsigned));
168 	menu->selected = selected;
169 	menu->view = 0;
170 	menu->ni = i;
171 	menu->items = items;
172 	menu->data = data;
173 	menu->free_function = free_function;
174 	menu->free_data = free_data;
175 	for (i = 0; i < menu->ni; i++)
176 		menu->hotkeys[i] = select_hotkey(term, !term->spec->braille ? items[i].text : NULL, items[i].hotkey, menu->hotkeys, i);
177 #ifdef G
178 	if (F) {
179 		if ((unsigned)menu->ni > MAXINT / sizeof(unsigned char *)) overalloc();
180 		menu->hktxt1 = mem_calloc(menu->ni * sizeof(unsigned char *));
181 		menu->hktxt2 = mem_calloc(menu->ni * sizeof(unsigned char *));
182 		menu->hktxt3 = mem_calloc(menu->ni * sizeof(unsigned char *));
183 		for (i = 0; i < menu->ni; i++) {
184 			unsigned char *txt = get_text_translation(items[i].text, term);
185 			unsigned char *txt2, *txt3 = txt;
186 			if (items[i].hotkey != M_BAR) while (*txt3) {
187 				unsigned u;
188 				txt2 = txt3;
189 				GET_UTF_8(txt3, u);
190 				u = uni_upcase(u);
191 				if (u == menu->hotkeys[i]) {
192 					menu->hktxt1[i] = memacpy(txt, txt2 - txt);
193 					menu->hktxt2[i] = memacpy(txt2, txt3 - txt2);
194 					menu->hktxt3[i] = stracpy(txt3);
195 					goto x;
196 				}
197 			}
198 			menu->hktxt1[i] = stracpy(txt);
199 			menu->hktxt2[i] = stracpy(cast_uchar "");
200 			menu->hktxt3[i] = stracpy(cast_uchar "");
201 			x:;
202 		}
203 	}
204 #endif
205 	add_window(term, menu_func, menu);
206 }
207 
do_menu(struct terminal * term,struct menu_item * items,void * data)208 void do_menu(struct terminal *term, struct menu_item *items, void *data)
209 {
210 	do_menu_selected(term, items, data, 0, NULL, NULL);
211 }
212 
select_menu(struct terminal * term,struct menu * menu)213 static void select_menu(struct terminal *term, struct menu *menu)
214 {
215 	struct menu_item *it;
216 	void (*func)(struct terminal *, void *, void *);
217 	void *data1;
218 	void *data2;
219 	if (menu->selected < 0 || menu->selected >= menu->ni) return;
220 	it = &menu->items[menu->selected];
221 	func = it->func;
222 	data1 = it->data;
223 	data2 = menu->data;
224 	if (it->hotkey == M_BAR) return;
225 	flush_terminal(term);
226 	if (!it->in_m) {
227 		struct window *win;
228 		struct list_head *lwin;
229 		foreach(struct window, win, lwin, term->windows) {
230 			if (win->handler != menu_func && win->handler != mainmenu_func)
231 				break;
232 			lwin = lwin->prev;
233 			delete_window(win);
234 		}
235 	}
236 	func(term, data1, data2);
237 }
238 
get_rtext(unsigned char * rtext)239 static unsigned char *get_rtext(unsigned char *rtext)
240 {
241 	if (!strcmp(cast_const_char rtext, ">")) return MENU_SUBMENU;
242 	return rtext;
243 }
244 
count_menu_size(struct terminal * term,struct menu * menu)245 static void count_menu_size(struct terminal *term, struct menu *menu)
246 {
247 	int sx = term->x;
248 	int sy = term->y;
249 	int mx = gf_val(4, 2 * (G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER));
250 	int my;
251 	for (my = 0; my < menu->ni; my++) {
252 		int s;
253 #ifdef G
254 		if (menu->items[my].free_i & MENU_FONT_LIST)  {
255 			struct style *st = g_get_style_font(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE,
256 				(menu->items[my].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
257 				(menu->items[my].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
258 				menu->items[my].data);
259 			s = g_text_width(st, menu->items[my].text);
260 			g_free_style(st);
261 		} else
262 #endif
263 			s = txtlen(term, get_text_translation(menu->items[my].text, term)) + txtlen(term, get_text_translation(get_rtext(menu->items[my].rtext), term)) + gf_val(MENU_HOTKEY_SPACE, G_MENU_HOTKEY_SPACE) * (get_text_translation(get_rtext(menu->items[my].rtext), term)[0] != 0);
264 		s += gf_val(4, 2 * (G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER));
265 		if (s > mx) mx = s;
266 	}
267 	my = gf_val(my, my * G_BFU_FONT_SIZE);
268 	my += gf_val(2, 2 * G_MENU_TOP_BORDER);
269 	if (mx > sx) mx = sx;
270 	if (my > sy) my = sy;
271 #ifdef G
272 	if (F) {
273 		my -= 2 * G_MENU_TOP_BORDER;
274 		my -= my % G_BFU_FONT_SIZE;
275 		my += 2 * G_MENU_TOP_BORDER;
276 	}
277 #endif
278 	menu->nview = gf_val(my - 2, (my - 2 * G_MENU_TOP_BORDER) / G_BFU_FONT_SIZE);
279 	menu->xw = mx;
280 	menu->yw = my;
281 	if ((menu->x = menu->xp) < 0) menu->x = 0;
282 	if ((menu->y = menu->yp) < 0) menu->y = 0;
283 	if (menu->x + mx > sx) menu->x = sx - mx;
284 	if (menu->y + my > sy) menu->y = sy - my;
285 	if (term->spec->braille) {
286 		menu->x = -1;
287 		menu->y = -1;
288 		menu->xw = term->x + 2;
289 		menu->yw = term->y + 2;
290 		menu->nview = term->y;
291 	}
292 #ifdef G
293 	if (F) set_window_pos(menu->win, menu->x, menu->y, menu->x + menu->xw, menu->y + menu->yw);
294 #endif
295 }
296 
scroll_menu(struct menu * menu,int d)297 static void scroll_menu(struct menu *menu, int d)
298 {
299 	int c = 0;
300 	int w = menu->nview;
301 	int scr_i = SCROLL_ITEMS > (w-1)/2 ? (w-1)/2 : SCROLL_ITEMS;
302 	if (scr_i < 0) scr_i = 0;
303 	if (w < 0) w = 0;
304 	menu->selected += d;
305 	while (1) {
306 		if (c++ > menu->ni) {
307 			menu->selected = -1;
308 			menu->view = 0;
309 			return;
310 		}
311 		if (menu->selected < 0) menu->selected = 0;
312 		if (menu->selected >= menu->ni) menu->selected = menu->ni - 1;
313 		if (menu->ni && menu->items[menu->selected].hotkey != M_BAR) break;
314 		menu->selected += d;
315 	}
316 	if (menu->selected < menu->view + scr_i) menu->view = menu->selected - scr_i;
317 	if (menu->selected >= menu->view + w - scr_i - 1) menu->view = menu->selected - w + scr_i + 1;
318 	if (menu->view > menu->ni - w) menu->view = menu->ni - w;
319 	if (menu->view < 0) menu->view = 0;
320 }
321 
display_menu_txt(struct terminal * term,void * menu_)322 static void display_menu_txt(struct terminal *term, void *menu_)
323 {
324 	struct menu *menu = (struct menu *)menu_;
325 	int p, s;
326 	int setc = 0;
327 	fill_area(term, menu->x+1, menu->y+1, menu->xw-2, menu->yw-2, ' ', COLOR_MENU_TEXT);
328 	draw_frame(term, menu->x, menu->y, menu->xw, menu->yw, COLOR_MENU_FRAME, 1);
329 	set_window_ptr(menu->win, menu->x, menu->y);
330 	for (p = menu->view, s = menu->y + 1; p < menu->ni && p < menu->view + menu->yw - 2; p++, s++) {
331 		int x;
332 		int h = 0;
333 		unsigned c;
334 		unsigned char *tmptext = get_text_translation(menu->items[p].text, term);
335 		unsigned char co = p == menu->selected ? h = 1, COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
336 		if (h) {
337 			setc = 1;
338 			set_cursor(term, menu->x + 1 + !!term->spec->braille, s, term->x - 1, term->y - 1);
339 			/*set_window_ptr(menu->win, menu->x+3, s+1);*/
340 			set_window_ptr(menu->win, menu->x+menu->xw, s);
341 			fill_area(term, menu->x+1, s, menu->xw-2, 1, ' ', co);
342 		}
343 		if (term->spec->braille) h = 1;
344 		if (menu->items[p].hotkey != M_BAR || (tmptext[0])) {
345 			unsigned char *rt = get_text_translation(get_rtext(menu->items[p].rtext), term);
346 			int l = ttxtlen(term, rt);
347 			for (x = 0;; x++) {
348 				c = GET_TERM_CHAR(term, &rt);
349 				if (!c) break;
350 				if (!term->spec->braille) {
351 					if (menu->xw - 4 >= l - x)
352 						set_char(term, menu->x + menu->xw - 2 - l + x, s, c, co);
353 				} else {
354 					set_char(term, menu->x + ttxtlen(term, tmptext) + 4 + x + 2, s, c, COLOR_MENU_HOTKEY);
355 				}
356 			}
357 			for (x = 0; x < menu->xw - 4; x++) {
358 				c = GET_TERM_CHAR(term, &tmptext);
359 				if (!c) break;
360 				set_char(term, menu->x + x + 2 + 2 * !!term->spec->braille, s, c, !h && charset_upcase(c, term_charset(term)) == menu->hotkeys[p] ? h = 1, COLOR_MENU_HOTKEY : co);
361 			}
362 			if (term->spec->braille && menu->hotkeys[p]) {
363 				set_char(term, menu->x + 2, s, menu->hotkeys[p], COLOR_MENU_HOTKEY);
364 			}
365 		} else {
366 			set_char(term, menu->x, s, 0xc3, COLOR_MENU_FRAME | ATTR_FRAME);
367 			fill_area(term, menu->x+1, s, menu->xw-2, 1, 0xc4, COLOR_MENU_FRAME | ATTR_FRAME);
368 			set_char(term, menu->x+menu->xw-1, s, 0xb4, COLOR_MENU_FRAME | ATTR_FRAME);
369 		}
370 	}
371 	if (!setc && term->spec->braille) {
372 		set_cursor(term, menu->x + 1, menu->y + 1, term->x - 1, term->y - 1);
373 	}
374 }
375 
376 static int menu_oldview = -1;
377 static int menu_oldsel = -1;
378 
379 #ifdef G
380 
381 static int menu_ptr_set;
382 
display_menu_item_gfx(struct terminal * term,struct menu * menu,int it)383 static void display_menu_item_gfx(struct terminal *term, struct menu *menu, int it)
384 {
385 	struct menu_item *item = &menu->items[it];
386 	struct graphics_device *dev = term->dev;
387 	int y;
388 	if (it < menu->view || it >= menu->ni || it >= menu->view + menu->nview) return;
389 	y = menu->y + G_MENU_TOP_BORDER + (it - menu->view) * G_BFU_FONT_SIZE;
390 	if (item->hotkey == M_BAR && !get_text_translation(item->text, term)[0]) {
391 		drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + (G_BFU_FONT_SIZE - 1) / 2, bfu_bg_color);
392 		drv->draw_hline(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y + (G_BFU_FONT_SIZE - 1) / 2, menu->x + menu->xw - G_MENU_LEFT_BORDER / 2, bfu_fg_color);
393 		drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y + (G_BFU_FONT_SIZE - 1) / 2 + 1, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
394 	} else {
395 		int p;
396 		struct rect r;
397 		unsigned char *rtext = get_text_translation(get_rtext(item->rtext), term);
398 		if (it != menu->selected) {
399 			drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE, bfu_bg_color);
400 		} else {
401 			menu->xl1 = menu->x;
402 			menu->yl1 = y;
403 			menu->xl2 = menu->x + menu->xw;
404 			menu->yl2 = y + G_BFU_FONT_SIZE;
405 			menu_ptr_set = 1;
406 			set_window_ptr(menu->win, menu->x + menu->xw, y);
407 			drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_bg_color);
408 			drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
409 			drv->fill_area(dev, menu->x + G_MENU_LEFT_BORDER, y, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
410 		}
411 		restrict_clip_area(dev, &r, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE);
412 		if (it == menu->selected) {
413 			struct style *style_wb;
414 			if (menu->items[it].free_i & MENU_FONT_LIST) {
415 				style_wb = g_get_style_font(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE,
416 					(menu->items[it].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
417 					(menu->items[it].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
418 					menu->items[it].data);
419 			} else {
420 				style_wb = bfu_style_wb;
421 			}
422 			p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER;
423 			g_print_text(dev, p, y, style_wb, menu->hktxt1[it], &p);
424 			g_print_text(dev, p, y, style_wb, menu->hktxt2[it], &p);
425 			g_print_text(dev, p, y, style_wb, menu->hktxt3[it], &p);
426 			if (menu->items[it].free_i & MENU_FONT_LIST) {
427 				g_free_style(style_wb);
428 			}
429 		} else {
430 			struct style *style_bw, *style_bw_u;
431 			if (menu->items[it].free_i & MENU_FONT_LIST) {
432 				style_bw = style_bw_u = g_get_style_font(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE,
433 					(menu->items[it].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
434 					(menu->items[it].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
435 					menu->items[it].data);
436 			} else {
437 				style_bw = bfu_style_bw;
438 				style_bw_u = bfu_style_bw_u;
439 			}
440 			p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER;
441 			g_print_text(dev, p, y, style_bw, menu->hktxt1[it], &p);
442 			g_print_text(dev, p, y, style_bw_u, menu->hktxt2[it], &p);
443 			g_print_text(dev, p, y, style_bw, menu->hktxt3[it], &p);
444 			if (menu->items[it].free_i & MENU_FONT_LIST) {
445 				g_free_style(style_bw);
446 			}
447 		}
448 		if (!*rtext) {
449 			set_clip_area(dev, &r);
450 			if (p > menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER) p = menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER;
451 			if (it != menu->selected)
452 				drv->fill_area(dev, p, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
453 			else
454 				drv->fill_area(dev, p, y, menu->x + menu->xw - G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
455 		} else {
456 			int s = menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER - g_text_width(bfu_style_wb, rtext);
457 			if (s < p) s = p;
458 			drv->fill_area(dev, p, y, s, y + G_BFU_FONT_SIZE, it != menu->selected ? bfu_bg_color : bfu_fg_color);
459 			g_print_text(dev, s, y, it != menu->selected ? bfu_style_bw : bfu_style_wb, rtext, NULL);
460 			set_clip_area(dev, &r);
461 			if (it != menu->selected)
462 				drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
463 			else
464 				drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
465 		}
466 	}
467 }
468 
display_menu_gfx(struct terminal * term,void * menu_)469 static void display_menu_gfx(struct terminal *term, void *menu_)
470 {
471 	struct menu *menu = (struct menu *)menu_;
472 	int p;
473 	struct graphics_device *dev = term->dev;
474 	if (menu_oldview == menu->view) {
475 		if (menu_oldsel >= 0 && menu_oldsel < menu->ni && menu_oldsel < menu->view + menu->nview) display_menu_item_gfx(term, menu, menu_oldsel);
476 		if (menu->selected >= 0 && menu->selected < menu->ni && menu->selected < menu->view + menu->nview) display_menu_item_gfx(term, menu, menu->selected);
477 		return;
478 	}
479 #define PX1 (menu->x + (G_MENU_LEFT_BORDER - 1) / 2)
480 #define PX2 (menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2)
481 #define PY1 (menu->y + (G_MENU_TOP_BORDER - 1) / 2)
482 #define PY2 (menu->y + menu->yw - (G_MENU_TOP_BORDER + 1) / 2)
483 	drv->fill_area(dev, menu->x, menu->y, menu->x + menu->xw, PY1, bfu_bg_color);
484 	drv->fill_area(dev, menu->x, PY1, PX1, PY2 + 1, bfu_bg_color);
485 	drv->fill_area(dev, PX2 + 1, PY1, menu->x + menu->xw, PY2 + 1, bfu_bg_color);
486 	drv->fill_area(dev, menu->x, PY2 + 1, menu->x + menu->xw, menu->y + menu->yw, bfu_bg_color);
487 	drv->draw_hline(dev, PX1, PY1, PX2 + 1, bfu_fg_color);
488 	drv->draw_hline(dev, PX1, PY2, PX2 + 1, bfu_fg_color);
489 	drv->draw_vline(dev, PX1, PY1 + 1, PY2, bfu_fg_color);
490 	drv->draw_vline(dev, PX2, PY1 + 1, PY2, bfu_fg_color);
491 	drv->fill_area(dev, PX1 + 1, PY1 + 1, PX2, menu->y + G_MENU_TOP_BORDER, bfu_bg_color);
492 	drv->fill_area(dev, PX1 + 1, menu->y + menu->yw - G_MENU_TOP_BORDER, PX2, PY2, bfu_bg_color);
493 	menu->xl1 = menu->yl1 = menu->xl2 = menu->yl2 = 0;
494 	menu_ptr_set = 0;
495 	for (p = menu->view; p < menu->ni && p < menu->view + menu->nview; p++) display_menu_item_gfx(term, menu, p);
496 	if (!menu_ptr_set) set_window_ptr(menu->win, menu->x, menu->y);
497 }
498 
499 #endif
500 
menu_func(struct window * win,struct links_event * ev,int fwd)501 static void menu_func(struct window *win, struct links_event *ev, int fwd)
502 {
503 	int s = 0;
504 	int xp, yp;
505 	struct menu *menu = win->data;
506 	menu->win = win;
507 	switch ((int)ev->ev) {
508 		case EV_INIT:
509 		case EV_RESIZE:
510 			get_parent_ptr(win, &menu->xp, &menu->yp);
511 			count_menu_size(win->term, menu);
512 			goto xxx;
513 		case EV_REDRAW:
514 			get_parent_ptr(win, &xp, &yp);
515 			if (xp != menu->xp || yp != menu->yp) {
516 				menu->xp = xp;
517 				menu->yp = yp;
518 				count_menu_size(win->term, menu);
519 			}
520 			xxx:
521 			menu->selected--;
522 			scroll_menu(menu, 1);
523 			draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
524 			break;
525 		case EV_MOUSE:
526 			if ((ev->b & BM_ACT) == B_MOVE) break;
527 			if ((ev->b & BM_BUTT) == B_FOURTH ||
528 			    (ev->b & BM_BUTT) == B_FIFTH) {
529 				if ((ev->b & BM_ACT) == B_DOWN) goto go_lr;
530 				break;
531 			}
532 			if ((ev->b & BM_BUTT) == B_SIXTH) {
533 				break;
534 			}
535 			if (ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y || ev->y >= menu->y+menu->yw) {
536 				int f = 1;
537 				struct window *w1;
538 				struct list_head *w1l;
539 				foreachfrom(struct window, w1, w1l, win->term->windows, &win->list_entry) {
540 					struct menu *m1;
541 					if (w1->handler == mainmenu_func) {
542 #ifdef G
543 						struct mainmenu *m2 = w1->data;
544 						if (F && !f && ev->x >= m2->xl1 && ev->x < m2->xl2 && ev->y >= m2->yl1 && ev->y < m2->yl2) goto bbb;
545 #endif
546 						if (ev->y < LL) goto del;
547 						break;
548 					}
549 					if (w1->handler != menu_func) break;
550 					m1 = w1->data;
551 #ifdef G
552 					if (F && !f && ev->x >= m1->xl1 && ev->x < m1->xl2 && ev->y >= m1->yl1 && ev->y < m1->yl2) goto bbb;
553 #endif
554 					if (ev->x > m1->x && ev->x < m1->x+m1->xw-1 && ev->y > m1->y && ev->y < m1->y+m1->yw-1) goto del;
555 					f--;
556 				}
557 				if ((ev->b & BM_ACT) == B_DOWN) goto del;
558 				if (0) del:delete_window_ev(win, ev);
559 #ifdef G
560 				bbb:;
561 #endif
562 			} else {
563 				if (!(ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y + gf_val(1, G_MENU_TOP_BORDER) || ev->y >= menu->y + menu->yw - gf_val(1, G_MENU_TOP_BORDER))) {
564 					int s = gf_val(ev->y - menu->y-1 + menu->view, (ev->y - menu->y - G_MENU_TOP_BORDER) / G_BFU_FONT_SIZE + menu->view);
565 					if (s >= 0 && s < menu->ni && menu->items[s].hotkey != M_BAR) {
566 						menu_oldview = menu->view;
567 						menu_oldsel = menu->selected;
568 						menu->selected = s;
569 						scroll_menu(menu, 0);
570 						draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
571 						menu_oldview = menu_oldsel = -1;
572 						if ((ev->b & BM_ACT) == B_UP /*|| menu->items[s].in_m*/) select_menu(win->term, menu);
573 					}
574 				}
575 			}
576 			break;
577 		case EV_KBD:
578 			if (ev->y & KBD_PASTING) break;
579 			if (ev->x == KBD_LEFT || ev->x == KBD_RIGHT) {
580 go_lr:
581 				if (win->list_entry.next == &win->term->windows)
582 					goto mm;
583 				if (list_struct(win->list_entry.next, struct window)->handler == mainmenu_func)
584 					goto mm;
585 				if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_FIFTH) goto mm;
586 				if (ev->ev == EV_KBD && ev->x == KBD_RIGHT) goto enter;
587 				delete_window(win);
588 				break;
589 			}
590 			if (ev->x == KBD_ESC) {
591 				if (win->list_entry.next == &win->term->windows)
592 					ev = NULL;
593 				else if (list_struct(win->list_entry.next, struct window)->handler != mainmenu_func)
594 					ev = NULL;
595 				delete_window_ev(win, ev);
596 				break;
597 			}
598 			if (KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT) {
599 				mm:
600 				delete_window_ev(win, ev);
601 				break;
602 			}
603 			menu_oldview = menu->view;
604 			menu_oldsel = menu->selected;
605 			if (ev->x == KBD_UP) scroll_menu(menu, -1);
606 			else if (ev->x == KBD_DOWN) scroll_menu(menu, 1);
607 			else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) menu->selected = -1, scroll_menu(menu, 1);
608 			else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) menu->selected = menu->ni, scroll_menu(menu, -1);
609 			else if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
610 				if ((menu->selected -= menu->yw / LL - 3) < -1) menu->selected = -1;
611 				if ((menu->view -= menu->yw / LL - 2) < 0) menu->view = 0;
612 				scroll_menu(menu, -1);
613 			}
614 			else if (ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) {
615 				if ((menu->selected += menu->yw / LL - 3) > menu->ni) menu->selected = menu->ni;
616 				if ((menu->view += menu->yw / LL - 2) >= menu->ni - menu->yw + 2) menu->view = menu->ni - menu->yw + 2;
617 				scroll_menu(menu, 1);
618 			}
619 			else if (ev->x > ' ') {
620 				int i;
621 				for (i = 0; i < menu->ni; i++) {
622 					if (charset_upcase(ev->x, term_charset(win->term)) == menu->hotkeys[i]) {
623 						menu->selected = i;
624 						scroll_menu(menu, 0);
625 						s = 1;
626 					}
627 				}
628 			}
629 			draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
630 			if (s || ev->x == KBD_ENTER || ev->x == ' ') {
631 				enter:
632 				menu_oldview = menu_oldsel = -1;
633 				select_menu(win->term, menu);
634 			}
635 			menu_oldview = menu_oldsel = -1;
636 			break;
637 		case EV_ABORT:
638 #ifdef G
639 			if (F) {
640 				int i;
641 				for (i = 0; i < menu->ni; i++) {
642 					mem_free(menu->hktxt1[i]);
643 					mem_free(menu->hktxt2[i]);
644 					mem_free(menu->hktxt3[i]);
645 				}
646 				mem_free(menu->hktxt1);
647 				mem_free(menu->hktxt2);
648 				mem_free(menu->hktxt3);
649 			}
650 #endif
651 			if (menu->items->free_i) {
652 				int i;
653 				for (i = 0; i < menu->ni; i++) {
654 					if (menu->items[i].free_i & MENU_FREE_TEXT) mem_free(menu->items[i].text);
655 					if (menu->items[i].free_i & MENU_FREE_RTEXT) mem_free(menu->items[i].rtext);
656 					if (menu->items[i].free_i & MENU_FREE_HOTKEY) mem_free(menu->items[i].hotkey);
657 				}
658 				if (menu->items->free_i & MENU_FREE_ITEMS)
659 					mem_free(menu->items);
660 			}
661 			if (menu->free_function)
662 				register_bottom_half(menu->free_function, menu->free_data);
663 			break;
664 	}
665 }
666 
do_mainmenu(struct terminal * term,struct menu_item * items,void * data,int sel)667 void do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel)
668 {
669 	int i;
670 	struct mainmenu *menu;
671 	for (i = 0; items[i].text; i++) if (i == (MAXINT - sizeof(struct mainmenu)) / sizeof(unsigned)) overalloc();
672 	menu = mem_alloc(sizeof(struct mainmenu) + (!i ? 0 : i - 1) * sizeof(unsigned));
673 	menu->selected = sel == -1 ? 0 : sel;
674 	menu->ni = i;
675 	menu->items = items;
676 	menu->data = data;
677 	for (i = 0; i < menu->ni; i++)
678 		menu->hotkeys[i] = select_hotkey(term, NULL, items[i].hotkey, menu->hotkeys, i);
679 	add_window(term, mainmenu_func, menu);
680 	if (sel != -1) {
681 		/* icc_volatile is workaround for some weird bug in icc or linker,
682 		   it results in unaligned sse load */
683 		icc_volatile struct links_event ev = {EV_KBD, KBD_ENTER, 0, 0};
684 		struct window *win = list_struct(term->windows.next, struct window);
685 		win->handler(win, (struct links_event *)&ev, 0);
686 	}
687 }
688 
display_mainmenu(struct terminal * term,void * menu_)689 static void display_mainmenu(struct terminal *term, void *menu_)
690 {
691 	struct mainmenu *menu = (struct mainmenu *)menu_;
692 	if (!F) {
693 		int i;
694 		int p = 2;
695 		fill_area(term, 0, 0, term->x, 1, ' ', COLOR_MAINMENU);
696 		for (i = 0; i < menu->ni; i++) {
697 			int s = 0;
698 			unsigned c;
699 			unsigned char *tmptext = get_text_translation(menu->items[i].text, term);
700 			unsigned char co = i == menu->selected ? s = 1, COLOR_MAINMENU_SELECTED : COLOR_MAINMENU;
701 			if (i == menu->selected) {
702 				fill_area(term, p, 0, 2, 1, ' ', co);
703 				menu->sp = p;
704 				set_cursor(term, p, 0, term->x - 1, term->y - 1);
705 				set_window_ptr(menu->win, p, 1);
706 			}
707 			if (term->spec->braille) {
708 				s = 1;
709 				if (menu->hotkeys[i]) set_char(term, p, 0, menu->hotkeys[i], COLOR_MAINMENU_HOTKEY);
710 			}
711 			p += 2;
712 			for (;; p++) {
713 				c = GET_TERM_CHAR(term, &tmptext);
714 				if (!c) break;
715 				set_char(term, p, 0, c, !s && charset_upcase(c, term_charset(term)) == menu->hotkeys[i] ? s = 1, COLOR_MAINMENU_HOTKEY : co);
716 			}
717 			if (i == menu->selected) {
718 				fill_area(term, p, 0, 2, 1, ' ', co);
719 			}
720 			p += 2;
721 		}
722 #ifdef G
723 	} else {
724 		struct graphics_device *dev = term->dev;
725 		int i, p;
726 		drv->fill_area(dev, 0, 0, p = G_MAINMENU_LEFT_BORDER, G_BFU_FONT_SIZE, bfu_bg_color);
727 		for (i = 0; i < menu->ni; i++) {
728 			int s = i == menu->selected;
729 			unsigned char *text = get_text_translation(menu->items[i].text, term);
730 			if (s) {
731 				menu->xl1 = p;
732 				menu->yl1 = 0;
733 				set_window_ptr(menu->win, p, G_BFU_FONT_SIZE);
734 			}
735 			drv->fill_area(dev, p, 0, p + G_MAINMENU_BORDER, G_BFU_FONT_SIZE, s ? bfu_fg_color : bfu_bg_color);
736 			p += G_MAINMENU_BORDER;
737 			g_print_text(dev, p, 0, s ? bfu_style_wb : bfu_style_bw, text, &p);
738 			drv->fill_area(dev, p, 0, p + G_MAINMENU_BORDER, G_BFU_FONT_SIZE, s ? bfu_fg_color : bfu_bg_color);
739 			p += G_MAINMENU_BORDER;
740 			if (s) {
741 				menu->xl2 = p;
742 				menu->yl2 = G_BFU_FONT_SIZE;
743 			}
744 		}
745 		drv->fill_area(dev, p, 0, term->x, G_BFU_FONT_SIZE, bfu_bg_color);
746 #endif
747 	}
748 }
749 
select_mainmenu(struct terminal * term,struct mainmenu * menu)750 static void select_mainmenu(struct terminal *term, struct mainmenu *menu)
751 {
752 	struct menu_item *it;
753 	if (menu->selected < 0 || menu->selected >= menu->ni) return;
754 	it = &menu->items[menu->selected];
755 	if (it->hotkey == M_BAR) return;
756 	if (!it->in_m) {
757 		struct window *win;
758 		struct list_head *lwin;
759 		foreach(struct window, win, lwin, term->windows) {
760 			if (win->handler != menu_func && win->handler != mainmenu_func)
761 				break;
762 			lwin = lwin->prev;
763 			delete_window(win);
764 		}
765 	}
766 	it->func(term, it->data, menu->data);
767 }
768 
mainmenu_func(struct window * win,struct links_event * ev,int fwd)769 static void mainmenu_func(struct window *win, struct links_event *ev, int fwd)
770 {
771 	int s = 0;
772 	int in_menu;
773 	struct mainmenu *menu = win->data;
774 	menu->win = win;
775 	switch ((int)ev->ev) {
776 		case EV_INIT:
777 		case EV_RESIZE:
778 #ifdef G
779 			if (F) set_window_pos(win, 0, 0, win->term->x, G_BFU_FONT_SIZE);
780 #endif
781 			/*-fallthrough*/
782 		case EV_REDRAW:
783 			draw_to_window(win, display_mainmenu, menu);
784 			break;
785 		case EV_MOUSE:
786 			in_menu = ev->x >= 0 && ev->x < win->term->x && ev->y >= 0 && ev->y < LL;
787 			if ((ev->b & BM_ACT) == B_MOVE) break;
788 			if ((ev->b & BM_BUTT) == B_FOURTH) {
789 				if ((ev->b & BM_ACT) == B_DOWN) goto go_left;
790 				break;
791 			}
792 			if ((ev->b & BM_BUTT) == B_FIFTH) {
793 				if ((ev->b & BM_ACT) == B_DOWN) goto go_right;
794 				break;
795 			}
796 			if ((ev->b & BM_BUTT) == B_SIXTH) {
797 				break;
798 			}
799 			if ((ev->b & BM_ACT) == B_DOWN && !in_menu) delete_window_ev(win, ev);
800 			else if (in_menu) {
801 				int i;
802 				int p = gf_val(2, G_MAINMENU_LEFT_BORDER);
803 				for (i = 0; i < menu->ni; i++) {
804 					int o = p;
805 					unsigned char *tmptext = get_text_translation(menu->items[i].text, win->term);
806 					p += txtlen(win->term, tmptext) + gf_val(4, 2 * G_MAINMENU_BORDER);
807 					if (ev->x >= o && ev->x < p) {
808 						menu->selected = i;
809 						draw_to_window(win, display_mainmenu, menu);
810 						if ((ev->b & BM_ACT) == B_UP || (menu->items[s].in_m && !win->term->spec->braille)) select_mainmenu(win->term, menu);
811 						break;
812 					}
813 				}
814 			}
815 			break;
816 		case EV_KBD:
817 			if (ev->y & KBD_PASTING) break;
818 			if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL) || ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
819 				select_mainmenu(win->term, menu);
820 				break;
821 			} else if (ev->x == KBD_LEFT) {
822 go_left:
823 				if (!menu->selected--) menu->selected = menu->ni - 1;
824 				s = 1;
825 				if (fwd) s = 2;
826 			} else if (ev->x == KBD_RIGHT) {
827 go_right:
828 				if (++menu->selected >= menu->ni) menu->selected = 0;
829 				s = 1;
830 				if (fwd) s = 2;
831 			} else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
832 				menu->selected = 0;
833 				s = 1;
834 			} else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
835 				menu->selected = menu->ni - 1;
836 				s = 1;
837 			} else if (ev->x > ' ') {
838 				int i;
839 				s = 1;
840 				for (i = 0; i < menu->ni; i++) {
841 					if (charset_upcase(ev->x, term_charset(win->term)) == menu->hotkeys[i]) {
842 						menu->selected = i;
843 						s = 2;
844 					}
845 				}
846 			}
847 			if (!s) {
848 				delete_window_ev(win, KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT ? ev : NULL);
849 				break;
850 			}
851 			draw_to_window(win, display_mainmenu, menu);
852 			if (s == 2) select_mainmenu(win->term, menu);
853 			break;
854 		case EV_ABORT:
855 			break;
856 	}
857 }
858 
new_menu(int free_i)859 struct menu_item *new_menu(int free_i)
860 {
861 	struct menu_item *mi;
862 	mi = mem_calloc(sizeof(struct menu_item));
863 	mi->free_i = free_i;
864 	return mi;
865 }
866 
add_to_menu(struct menu_item ** mi,unsigned char * text,unsigned char * rtext,unsigned char * hotkey,void (* func)(struct terminal *,void *,void *),void * data,int in_m,int pos)867 void add_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext, unsigned char *hotkey, void (*func)(struct terminal *, void *, void *), void *data, int in_m, int pos)
868 {
869 	struct menu_item *mii;
870 	int n;
871 	if (pos != -1) {
872 		n = pos;
873 		if ((*mi)[n].text) internal_error("invalid menu position %d", n);
874 	} else {
875 		for (n = 0; (*mi)[n].text; n++) if (n == MAXINT) overalloc();
876 	}
877 	if (((unsigned)n + 2) > MAXINT / sizeof(struct menu_item)) overalloc();
878 	mii = mem_realloc(*mi, (n + 2) * sizeof(struct menu_item));
879 	*mi = mii;
880 	memcpy(mii + n + 1, mii + n, sizeof(struct menu_item));
881 	mii[n].text = text;
882 	mii[n].rtext = rtext;
883 	mii[n].hotkey = hotkey;
884 	mii[n].func = func;
885 	mii[n].data = data;
886 	mii[n].in_m = in_m;
887 }
888 
do_dialog(struct terminal * term,struct dialog * dlg,struct memory_list * ml)889 void do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml)
890 {
891 	struct dialog_data *dd;
892 	struct dialog_item *d;
893 	int n = 0;
894 	for (d = dlg->items; d->type != D_END; d++) {
895 		if (n == MAXINT) overalloc();
896 		n++;
897 	}
898 	if ((unsigned)n > (MAXINT - sizeof(struct dialog_data)) / sizeof(struct dialog_item_data)) overalloc();
899 	dd = mem_calloc(sizeof(struct dialog_data) + sizeof(struct dialog_item_data) * n);
900 	dd->dlg = dlg;
901 	dd->n = n;
902 	dd->ml = ml;
903 	add_window(term, dialog_func, dd);
904 }
905 
display_dlg_item(struct dialog_data * dlg,struct dialog_item_data * di,int sel)906 void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
907 {
908 	struct terminal *term = dlg->win->term;
909 	if (!F) switch (di->item->type) {
910 		unsigned char co;
911 		unsigned char *text, *t;
912 		int vposlen, cposlen;
913 		case D_CHECKBOX:
914 			/* radio or checkbox */
915 			if (di->checked) print_text(term, di->x, di->y, 3, cast_uchar "[X]", COLOR_DIALOG_CHECKBOX);
916 			else print_text(term, di->x, di->y, 3, cast_uchar "[ ]", COLOR_DIALOG_CHECKBOX);
917 			if (sel) {
918 				set_cursor(term, di->x + 1, di->y, di->x + 1, di->y);
919 				set_window_ptr(dlg->win, di->x, di->y);
920 			}
921 			break;
922 		case D_FIELD:
923 		case D_FIELD_PASS:
924 			fill_area(term, di->x, di->y, di->l, 1, ' ', COLOR_DIALOG_FIELD);
925 			if (di->vpos > di->cpos) di->vpos = di->cpos;
926 			vposlen = ttxtlen(term, di->cdata + di->vpos);
927 			cposlen = ttxtlen(term, di->cdata + di->cpos);
928 			if (!di->l) {
929 				di->vpos = di->cpos;
930 				vposlen = cposlen;
931 			} else {
932 				while (vposlen - cposlen > di->l - 1) {
933 					t = di->cdata + di->vpos;
934 					GET_TERM_CHAR(term, &t);
935 					di->vpos = (int)(t - di->cdata);
936 					vposlen--;
937 				}
938 			}
939 			if (di->item->type == D_FIELD_PASS) {
940 				t = mem_alloc(vposlen + 1);
941 				memset(t, '*', vposlen);
942 				t[vposlen] = 0;
943 			} else {
944 				t = di->cdata + di->vpos;
945 			}
946 			print_text(term, di->x, di->y, di->l, t, COLOR_DIALOG_FIELD_TEXT);
947 			if (di->item->type == D_FIELD_PASS) mem_free(t);
948 			if (sel) {
949 				set_cursor(term, di->x + vposlen - cposlen, di->y, di->x + vposlen - cposlen, di->y);
950 				set_window_ptr(dlg->win, di->x, di->y);
951 			}
952 			break;
953 		case D_BUTTON:
954 			co = sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_BUTTON;
955 			text = get_text_translation(di->item->text, term);
956 			print_text(term, di->x, di->y, 2, cast_uchar "[ ", co);
957 			print_text(term, di->x + 2, di->y, ttxtlen(term, text), text, co);
958 			print_text(term, di->x + 2 + ttxtlen(term, text), di->y, 2, cast_uchar " ]", co);
959 			if (sel) {
960 				set_cursor(term, di->x + 2, di->y, di->x + 2, di->y);
961 				set_window_ptr(dlg->win, di->x, di->y);
962 			}
963 			break;
964 		default:
965 			internal_error("display_dlg_item: unknown item: %d", di->item->type);
966 #ifdef G
967 	} else {
968 		struct rect rr;
969 		struct graphics_device *dev = term->dev;
970 		if (!dlg->s) restrict_clip_area(dev, &rr, dlg->rr.x1, dlg->rr.y1, dlg->rr.x2, dlg->rr.y2);
971 		switch (di->item->type) {
972 			int p, pp;
973 			struct style *st;
974 			unsigned char *text, *text2, *text3, *tt, *t;
975 			struct rect r;
976 			case D_CHECKBOX:
977 				p = di->x;
978 				if (di->checked) {
979 					if (!sel) g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar(G_DIALOG_RADIO_L G_DIALOG_RADIO_X G_DIALOG_RADIO_R):cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R), &p);
980 					else {
981 						g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_L:cast_uchar G_DIALOG_CHECKBOX_L, &p);
982 						g_print_text(dev, p, di->y, bfu_style_bw_u, di->item->gid?cast_uchar G_DIALOG_RADIO_X:cast_uchar G_DIALOG_CHECKBOX_X, &p);
983 						g_print_text(dev, p, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_R:cast_uchar G_DIALOG_CHECKBOX_R, &p);
984 					}
985 				} else {
986 					int s = g_text_width(bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_X:cast_uchar G_DIALOG_CHECKBOX_X);
987 					g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_L:cast_uchar G_DIALOG_CHECKBOX_L, &p);
988 					if (!sel) drv->fill_area(dev, p, di->y, p + s, di->y + G_BFU_FONT_SIZE, bfu_bg_color), p += s;
989 					else {
990 						restrict_clip_area(dev, &r, p, di->y, p + s, di->y + G_BFU_FONT_SIZE);
991 						g_print_text(dev, p, di->y, bfu_style_bw_u, cast_uchar "          ", NULL);
992 						p += s;
993 						set_clip_area(dev, &r);
994 					}
995 					g_print_text(dev, p, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_R:cast_uchar G_DIALOG_CHECKBOX_R, &p);
996 				}
997 				di->l = p - di->x;
998 				if (sel) set_window_ptr(dlg->win, di->x, di->y + G_BFU_FONT_SIZE);
999 				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, p, di->y + G_BFU_FONT_SIZE);
1000 				break;
1001 			case D_FIELD:
1002 			case D_FIELD_PASS:
1003 				text = memacpy(di->cdata, di->cpos);
1004 				if (*(text2 = text3 = di->cdata + di->cpos)) {
1005 					GET_UTF_8(text3, p);
1006 					text2 = memacpy(text2, text3 - text2);
1007 				} else {
1008 					text2 = stracpy(cast_uchar " ");
1009 					text3 = cast_uchar "";
1010 				}
1011 				if (!text2) {
1012 					mem_free(text);
1013 					break;
1014 				}
1015 				text3 = stracpy(text3);
1016 				if (di->item->type == D_FIELD_PASS) {
1017 					unsigned d;
1018 					for (tt = t = text; *tt; ) {
1019 						t = tt;
1020 						GET_UTF_8(tt, d);
1021 						*t++ = '*';
1022 					}
1023 					*t = 0;
1024 					if (di->cdata[di->cpos]) {
1025 						for (tt = t = text2; *tt; ) {
1026 							t = tt;
1027 							GET_UTF_8(tt, d);
1028 							*t++ = '*';
1029 						}
1030 						*t = 0;
1031 						for (tt = t = text3; *tt; ) {
1032 							t = tt;
1033 							GET_UTF_8(tt, d);
1034 							*t++ = '*';
1035 						}
1036 						*t = 0;
1037 					}
1038 				}
1039 				p = g_text_width(bfu_style_wb_mono, text);
1040 				pp = g_text_width(bfu_style_wb_mono, text2);
1041 				if (di->vpos + di->l < p + pp) di->vpos = p + pp - di->l;
1042 				if (di->vpos > p) di->vpos = p;
1043 				if (di->vpos < 0) di->vpos = 0;
1044 
1045 				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
1046 				restrict_clip_area(dev, &r, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
1047 				p = di->x - di->vpos;
1048 				g_print_text(dev, p, di->y, bfu_style_wb_mono, text, &p);
1049 				g_print_text(dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p);
1050 				g_print_text(dev, p, di->y, bfu_style_wb_mono, text3, &p);
1051 				drv->fill_area(dev, p, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE, bfu_fg_color);
1052 				set_clip_area(dev, &r);
1053 				mem_free(text);
1054 				mem_free(text2);
1055 				mem_free(text3);
1056 				if (sel) {
1057 					set_window_ptr(dlg->win, di->x, di->y);
1058 				}
1059 
1060 				break;
1061 			case D_BUTTON:
1062 				st = sel ? bfu_style_wb_b : bfu_style_bw;
1063 				text = get_text_translation(di->item->text, term);
1064 				text2 = mem_alloc(strlen(cast_const_char text) + 5);
1065 				strcpy(cast_char text2, cast_const_char G_DIALOG_BUTTON_L);
1066 				strcpy(cast_char(text2 + 2), cast_const_char text);
1067 				strcat(cast_char text2, cast_const_char G_DIALOG_BUTTON_R);
1068 				di->l = 0;
1069 				g_print_text(dev, di->x, di->y, st, text2, &di->l);
1070 				mem_free(text2);
1071 				if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
1072 				if (sel) set_window_ptr(dlg->win, di->x, di->y + G_BFU_FONT_SIZE);
1073 				break;
1074 			default:
1075 				internal_error("display_dlg_item: unknown item: %d", di->item->type);
1076 		}
1077 		if (!dlg->s) set_clip_area(dev, &rr);
1078 #endif
1079 	}
1080 }
1081 
1082 struct dspd {
1083 	struct dialog_data *dlg;
1084 	struct dialog_item_data *di;
1085 	int sel;
1086 };
1087 
u_display_dlg_item(struct terminal * term,void * p)1088 static void u_display_dlg_item(struct terminal *term, void *p)
1089 {
1090 	struct dspd *d = p;
1091 	display_dlg_item(d->dlg, d->di, d->sel);
1092 }
1093 
x_display_dlg_item(struct dialog_data * dlg,struct dialog_item_data * di,int sel)1094 static void x_display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
1095 {
1096 	struct dspd dspd;
1097 	dspd.dlg = dlg, dspd.di = di, dspd.sel = sel;
1098 	draw_to_window(dlg->win, u_display_dlg_item, &dspd);
1099 }
1100 
dlg_select_item(struct dialog_data * dlg,struct dialog_item_data * di)1101 static void dlg_select_item(struct dialog_data *dlg, struct dialog_item_data *di)
1102 {
1103 	if (di->item->type == D_CHECKBOX) {
1104 		if (!di->item->gid) di -> checked = *(int *)di->cdata = !*(int *)di->cdata;
1105 		else {
1106 			int i;
1107 			for (i = 0; i < dlg->n; i++) {
1108 				if (dlg->items[i].item->type == D_CHECKBOX && dlg->items[i].item->gid == di->item->gid) {
1109 					*(int *)dlg->items[i].cdata = di->item->gnum;
1110 					dlg->items[i].checked = 0;
1111 					x_display_dlg_item(dlg, &dlg->items[i], 0);
1112 				}
1113 			}
1114 			di->checked = 1;
1115 		}
1116 		x_display_dlg_item(dlg, di, 1);
1117 	}
1118 	else if (di->item->type == D_BUTTON) di->item->fn(dlg, di);
1119 }
1120 
dlg_get_history_string(struct terminal * term,struct history_item * hi,int l)1121 static unsigned char *dlg_get_history_string(struct terminal *term, struct history_item *hi, int l)
1122 {
1123 	unsigned char *s;
1124 	int ch = term_charset(term);
1125 	s = convert(utf8_table, ch, hi->str, NULL);
1126 	if (strlen(cast_const_char s) >= (size_t)l)
1127 		s[l - 1] = 0;
1128 	if (ch == utf8_table) {
1129 		int r = (int)strlen(cast_const_char s);
1130 		unsigned char *p = s;
1131 		while (r) {
1132 			int chl = utf8chrlen(*p);
1133 			if (chl > r) {
1134 				*p = 0;
1135 				break;
1136 			}
1137 			p += chl;
1138 			r -= chl;
1139 		}
1140 	}
1141 	return s;
1142 }
1143 
dlg_set_history(struct terminal * term,struct dialog_item_data * di)1144 static void dlg_set_history(struct terminal *term, struct dialog_item_data *di)
1145 {
1146 	unsigned char *s;
1147 	if (di->cur_hist == &di->history) s = stracpy(cast_uchar "");
1148 	else s = dlg_get_history_string(term, list_struct(di->cur_hist, struct history_item), di->item->dlen);
1149 	strcpy(cast_char di->cdata, cast_const_char s);
1150 	di->cpos = (int)strlen(cast_const_char s);
1151 	di->vpos = 0;
1152 	mem_free(s);
1153 }
1154 
dlg_mouse(struct dialog_data * dlg,struct dialog_item_data * di,struct links_event * ev)1155 static int dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di, struct links_event *ev)
1156 {
1157 	switch (di->item->type) {
1158 		case D_BUTTON:
1159 			if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + gf_val(ttxtlen(dlg->win->term, get_text_translation(di->item->text, dlg->win->term)) + 4, di->l)) return 0;
1160 			if (dlg->selected != di - dlg->items) {
1161 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1162 				dlg->selected = (int)(di - dlg->items);
1163 				x_display_dlg_item(dlg, di, 1);
1164 			}
1165 			if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
1166 			return 1;
1167 		case D_FIELD:
1168 		case D_FIELD_PASS:
1169 			if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + di->l) return 0;
1170 			if (!is_utf_8(dlg->win->term)) {
1171 				if ((size_t)(di->cpos = di->vpos + ev->x - di->x) > strlen(cast_const_char di->cdata)) di->cpos = (int)strlen(cast_const_char di->cdata);
1172 			} else {
1173 				int p, u;
1174 				unsigned char *t = di->cdata;
1175 				p = di->x - di->vpos;
1176 				while (1) {
1177 					di->cpos = (int)(t - di->cdata);
1178 					if (!*t) break;
1179 					GET_UTF_8(t, u);
1180 					if (!u) continue;
1181 					if (!F) p++;
1182 #ifdef G
1183 					else p += g_char_width(bfu_style_wb_mono, u);
1184 #endif
1185 					if (p > ev->x) break;
1186 				}
1187 			}
1188 			if (dlg->selected != di - dlg->items) {
1189 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1190 				dlg->selected = (int)(di - dlg->items);
1191 				x_display_dlg_item(dlg, di, 1);
1192 			} else x_display_dlg_item(dlg, di, 1);
1193 			return 1;
1194 		case D_CHECKBOX:
1195 			if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + gf_val(3, di->l)) return 0;
1196 			if (dlg->selected != di - dlg->items) {
1197 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1198 				dlg->selected = (int)(di - dlg->items);
1199 				x_display_dlg_item(dlg, di, 1);
1200 			}
1201 			if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
1202 			return 1;
1203 	}
1204 	return 0;
1205 }
1206 
redraw_dialog_items(struct terminal * term,void * dlg_)1207 static void redraw_dialog_items(struct terminal *term, void *dlg_)
1208 {
1209 	struct dialog_data *dlg = (struct dialog_data *)dlg_;
1210 	int i;
1211 	for (i = 0; i < dlg->n; i++) display_dlg_item(dlg, &dlg->items[i], i == dlg->selected);
1212 }
1213 
dlg_is_braille_moving(struct dialog_data * dlg)1214 static int dlg_is_braille_moving(struct dialog_data *dlg)
1215 {
1216 	return dlg->win->term->spec->braille && (dlg->dlg->fn == msg_box_fn || dlg->dlg->fn == download_window_function);
1217 }
1218 
redraw_dialog(struct terminal * term,void * dlg_)1219 static void redraw_dialog(struct terminal *term, void *dlg_)
1220 {
1221 	struct dialog_data *dlg = (struct dialog_data *)dlg_;
1222 #ifdef G
1223 	int i;
1224 #endif
1225 	dlg->dlg->fn(dlg);
1226 	redraw_dialog_items(term, dlg);
1227 	if (dlg_is_braille_moving(dlg)) {
1228 		if (dlg->brl_y < dlg->items[0].y - 3)
1229 			set_cursor(term, dlg->x + 6, dlg->y + 3 + dlg->brl_y, dlg->x + 6, dlg->y + 3 + dlg->brl_y);
1230 	}
1231 #ifdef G
1232 	if (F) {
1233 		set_clip_area(term->dev, &dlg->r);
1234 		for (i = 0; i < dlg->s->m; i++) if (is_rect_valid(&dlg->s->r[i]))
1235 			drv->fill_area(term->dev, dlg->s->r[i].x1, dlg->s->r[i].y1, dlg->s->r[i].x2, dlg->s->r[i].y2, bfu_bg_color);
1236 		mem_free(dlg->s);
1237 		dlg->s = NULL;
1238 	}
1239 #endif
1240 }
1241 
tab_compl(struct terminal * term,void * hi_,void * win_)1242 static void tab_compl(struct terminal *term, void *hi_, void *win_)
1243 {
1244 	struct history_item *hi = (struct history_item *)hi_;
1245 	struct window *win = (struct window *)win_;
1246 	struct links_event ev = {EV_REDRAW, 0, 0, 0};
1247 	struct dialog_item_data *di = &((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected];
1248 	unsigned char *s = dlg_get_history_string(term, hi, di->item->dlen);
1249 	strcpy(cast_char di->cdata, cast_const_char s);
1250 	di->cpos = (int)strlen(cast_const_char s);
1251 	di->vpos = 0;
1252 	mem_free(s);
1253 	ev.x = term->x;
1254 	ev.y = term->y;
1255 	dialog_func(win, &ev, 0);
1256 }
1257 
do_tab_compl(struct terminal * term,struct list_head * history,struct window * win)1258 static void do_tab_compl(struct terminal *term, struct list_head *history, struct window *win)
1259 {
1260 	unsigned char *cdata = ((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected].cdata;
1261 	int l = (int)strlen(cast_const_char cdata), n = 0;
1262 	struct history_item *hi;
1263 	struct list_head *lhi;
1264 	struct menu_item *items = DUMMY;
1265 	foreach(struct history_item, hi, lhi, *history) {
1266 		unsigned char *s = dlg_get_history_string(term, hi, MAXINT);
1267 		if (!strncmp(cast_const_char cdata, cast_const_char s, l)) {
1268 			if (!(n & (ALLOC_GR - 1))) {
1269 				if ((unsigned)n > MAXINT / sizeof(struct menu_item) - ALLOC_GR - 1) overalloc();
1270 				items = mem_realloc(items, (n + ALLOC_GR + 1) * sizeof(struct menu_item));
1271 			}
1272 			items[n].text = s;
1273 			items[n].rtext = cast_uchar "";
1274 			items[n].hotkey = cast_uchar "";
1275 			items[n].func = tab_compl;
1276 			items[n].rtext = cast_uchar "";
1277 			items[n].data = hi;
1278 			items[n].in_m = 0;
1279 			items[n].free_i = MENU_FREE_ITEMS | MENU_FREE_TEXT;
1280 			if (n == MAXINT) overalloc();
1281 			n++;
1282 		} else {
1283 			mem_free(s);
1284 		}
1285 	}
1286 	if (n == 1) {
1287 		tab_compl(term, items->data, win);
1288 		mem_free(items->text);
1289 		mem_free(items);
1290 		return;
1291 	}
1292 	if (n) {
1293 		memset(&items[n], 0, sizeof(struct menu_item));
1294 		do_menu_selected(term, items, win, n - 1, NULL, NULL);
1295 	}
1296 }
1297 
dialog_func(struct window * win,struct links_event * ev,int fwd)1298 void dialog_func(struct window *win, struct links_event *ev, int fwd)
1299 {
1300 	int i;
1301 	struct terminal *term = win->term;
1302 	struct dialog_data *dlg = win->data;
1303 	struct dialog_item_data *di;
1304 
1305 	dlg->win = win;
1306 
1307 	/* Use nonstandard event handlers */
1308 	if (dlg->dlg->handle_event && dlg->dlg->handle_event(dlg, ev) == EVENT_PROCESSED) {
1309 		return;
1310 	}
1311 
1312 	switch ((int)ev->ev) {
1313 		case EV_INIT:
1314 			for (i = 0; i < dlg->n; i++) {
1315 				/* highc_volatile because of a compiler bug */
1316 				struct dialog_item_data * highc_volatile di = &dlg->items[i];
1317 				memset(di, 0, sizeof(struct dialog_item_data));
1318 				di->item = &dlg->dlg->items[i];
1319 				di->cdata = mem_alloc(di->item->dlen);
1320 				if (di->item->dlen)
1321 					memcpy(di->cdata, di->item->data, di->item->dlen);
1322 				if (di->item->type == D_CHECKBOX) {
1323 					if (di->item->gid) {
1324 						if (*(int *)di->cdata == di->item->gnum) di->checked = 1;
1325 					} else if (*(int *)di->cdata) di->checked = 1;
1326 				}
1327 				init_list(di->history);
1328 				di->cur_hist = &di->history;
1329 				if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
1330 					if (di->item->history) {
1331 						struct history_item *j;
1332 						struct list_head *lj;
1333 						foreach(struct history_item, j, lj, di->item->history->items) {
1334 							struct history_item *hi;
1335 							size_t sl = strlen(cast_const_char j->str);
1336 							if (sl > MAXINT - sizeof(struct history_item)) overalloc();
1337 							hi = mem_alloc(sizeof(struct history_item) + sl);
1338 							strcpy(cast_char hi->str, cast_const_char j->str);
1339 							add_to_list(di->history, hi);
1340 						}
1341 					}
1342 					di->cpos = (int)strlen(cast_const_char di->cdata);
1343 				}
1344 			}
1345 			dlg->selected = 0;
1346 			/*-fallthrough*/
1347 		case EV_RESIZE:
1348 				/* this must be really called twice !!! */
1349 			draw_to_window(dlg->win, redraw_dialog, dlg);
1350 			/*-fallthrough*/
1351 		case EV_REDRAW:
1352 			redraw:
1353 			draw_to_window(dlg->win, redraw_dialog, dlg);
1354 			break;
1355 		case EV_MOUSE:
1356 			if ((ev->b & BM_ACT) == B_MOVE) break;
1357 			if ((ev->b & BM_BUTT) == B_FOURTH) {
1358 				if ((ev->b & BM_ACT) == B_DOWN) goto go_prev;
1359 				break;
1360 			}
1361 			if ((ev->b & BM_BUTT) == B_FIFTH) {
1362 				if ((ev->b & BM_ACT) == B_DOWN) goto go_next;
1363 				break;
1364 			}
1365 			if ((ev->b & BM_BUTT) == B_SIXTH) {
1366 				if ((ev->b & BM_ACT) == B_DOWN) goto go_enter;
1367 				break;
1368 			}
1369 			for (i = 0; i < dlg->n; i++) if (dlg_mouse(dlg, &dlg->items[i], ev)) break;
1370 			if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_MIDDLE) {
1371 				di = &dlg->items[dlg->selected];  /* don't delete this!!! it's here because of jump from mouse event */
1372 				if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) goto clipbd_paste;
1373 			}
1374 			break;
1375 		case EV_KBD:
1376 			di = &dlg->items[dlg->selected];
1377 			if (ev->y & KBD_PASTING) {
1378 				if (!((di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) &&
1379 				      (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT)))))
1380 					break;
1381 			}
1382 			if (ev->x == KBD_UP && dlg_is_braille_moving(dlg)) {
1383 				if (dlg->brl_y) dlg->brl_y--;
1384 				goto redraw;
1385 			}
1386 			if (ev->x == KBD_DOWN && dlg_is_braille_moving(dlg)) {
1387 				if (dlg->brl_y < dlg->items[0].y - 3) dlg->brl_y++;
1388 				goto redraw;
1389 			}
1390 			if ((ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL) || ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
1391 				dlg->brl_y = 0;
1392 				goto redraw;
1393 			}
1394 			if ((ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
1395 				dlg->brl_y = dlg->items[0].y - 4;
1396 				goto redraw;
1397 			}
1398 			if ((ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
1399 				dlg->brl_y = dlg->items[0].y - 3;
1400 				goto redraw;
1401 			}
1402 			if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
1403 				if (ev->x == KBD_UP && di->cur_hist->prev != &di->history) {
1404 					di->cur_hist = di->cur_hist->prev;
1405 					dlg_set_history(term, di);
1406 					goto dsp_f;
1407 				}
1408 				if (ev->x == KBD_DOWN && di->cur_hist != &di->history) {
1409 					di->cur_hist = di->cur_hist->next;
1410 					dlg_set_history(term, di);
1411 					goto dsp_f;
1412 				}
1413 				if (ev->x == KBD_RIGHT) {
1414 					if ((size_t)di->cpos < strlen(cast_const_char di->cdata)) {
1415 						if (!is_utf_8(term)) di->cpos++;
1416 						else {
1417 							int u;
1418 							unsigned char *p = di->cdata + di->cpos;
1419 							GET_UTF_8(p, u);
1420 							di->cpos = (int)(p - di->cdata);
1421 						}
1422 					}
1423 					goto dsp_f;
1424 				}
1425 				if (ev->x == KBD_LEFT) {
1426 					if (di->cpos > 0) {
1427 						if (!is_utf_8(term)) di->cpos--;
1428 						else {
1429 							unsigned char *p = di->cdata + di->cpos;
1430 							BACK_UTF_8(p, di->cdata);
1431 							di->cpos = (int)(p - di->cdata);
1432 						}
1433 					}
1434 					goto dsp_f;
1435 				}
1436 				if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
1437 					di->cpos = 0;
1438 					goto dsp_f;
1439 				}
1440 				if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
1441 					di->cpos = (int)strlen(cast_const_char di->cdata);
1442 					goto dsp_f;
1443 				}
1444 				if (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
1445 					unsigned char *u;
1446 					unsigned char p[2] = { 0, 0 };
1447 					if (cp2u(ev->x, term_charset(term)) == -1)
1448 						break;
1449 					if (!is_utf_8(term)) {
1450 						p[0] = (unsigned char)ev->x, u = p;
1451 					} else {
1452 						u = encode_utf_8(ev->x);
1453 					}
1454 					if (strlen(cast_const_char di->cdata) + strlen(cast_const_char u) < (size_t)di->item->dlen) {
1455 						memmove(di->cdata + di->cpos + strlen(cast_const_char u), di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + 1);
1456 						memcpy(&di->cdata[di->cpos], u, strlen(cast_const_char u));
1457 						di->cpos += (int)strlen(cast_const_char u);
1458 					}
1459 					goto dsp_f;
1460 				}
1461 				if (ev->x == KBD_BS) {
1462 					if (di->cpos) {
1463 						int s = 1;
1464 						if (is_utf_8(term)) {
1465 							unsigned u;
1466 							unsigned char *p, *pp;
1467 							p = di->cdata;
1468 							a:
1469 							pp = p;
1470 							GET_UTF_8(p, u);
1471 							if (p < di->cdata + di->cpos) goto a;
1472 							s = (int)(p - pp);
1473 						}
1474 						memmove(di->cdata + di->cpos - s, di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + s);
1475 						di->cpos -= s;
1476 					}
1477 					goto dsp_f;
1478 				}
1479 				if (ev->x == KBD_DEL || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) {
1480 					if ((size_t)di->cpos < strlen(cast_const_char di->cdata)) {
1481 						int s = 1;
1482 						if (is_utf_8(term)) {
1483 							unsigned u;
1484 							unsigned char *p = di->cdata + di->cpos;
1485 							GET_UTF_8(p, u);
1486 							s = (int)(p - (di->cdata + di->cpos));
1487 						}
1488 						memmove(di->cdata + di->cpos, di->cdata + di->cpos + s, strlen(cast_const_char di->cdata) - di->cpos + s);
1489 					}
1490 					goto dsp_f;
1491 				}
1492 				if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) {
1493 					unsigned char *a = memacpy(di->cdata, di->cpos);
1494 					if (a) {
1495 						set_clipboard_text(term, a);
1496 						mem_free(a);
1497 					}
1498 					memmove(di->cdata, di->cdata + di->cpos, strlen(cast_const_char di->cdata + di->cpos) + 1);
1499 					di->cpos = 0;
1500 					goto dsp_f;
1501 				}
1502 				if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) {
1503 					set_clipboard_text(term, di->cdata + di->cpos);
1504 					di->cdata[di->cpos] = 0;
1505 					goto dsp_f;
1506 				}
1507 				/* Copy to clipboard */
1508 				if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) || ev->x == KBD_COPY) {
1509 					set_clipboard_text(term, di->cdata);
1510 					break;	/* We don't need to redraw */
1511 				}
1512 				/* FIXME -- why keyboard shortcuts with shift don't works??? */
1513 				/* Cut to clipboard */
1514 				if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) || ev->x == KBD_CUT) {
1515 					set_clipboard_text(term, di->cdata);
1516 					di->cdata[0] = 0;
1517 					di->cpos = 0;
1518 					goto dsp_f;
1519 				}
1520 				/* Paste from clipboard */
1521 				if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) || ev->x == KBD_PASTE) {
1522 					unsigned char *clipboard;
1523 clipbd_paste:
1524 					clipboard = get_clipboard_text(term);
1525 					if (clipboard) {
1526 						unsigned char *nl = clipboard;
1527 						while ((nl = cast_uchar strchr(cast_const_char nl, '\n'))) *nl = ' ';
1528 						if (strlen(cast_const_char di->cdata) + strlen(cast_const_char clipboard) < (size_t)di->item->dlen ||
1529 						    strlen(cast_const_char di->cdata) + strlen(cast_const_char clipboard) < strlen(cast_const_char di->cdata)) {
1530 							memmove(di->cdata + di->cpos + strlen(cast_const_char clipboard), di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + 1);
1531 							memcpy(&di->cdata[di->cpos], clipboard, strlen(cast_const_char clipboard));
1532 							di->cpos += (int)strlen(cast_const_char clipboard);
1533 						}
1534 						mem_free(clipboard);
1535 					}
1536 					goto dsp_f;
1537 				}
1538 				if ((upcase(ev->x) == 'W' && ev->y & KBD_CTRL) || ev->x == KBD_FIND) {
1539 					do_tab_compl(term, &di->history, win);
1540 					goto dsp_f;
1541 				}
1542 				goto gh;
1543 				dsp_f:
1544 				x_display_dlg_item(dlg, di, 1);
1545 				break;
1546 			}
1547 			if ((ev->x == KBD_ENTER && di->item->type == D_BUTTON) || ev->x == ' ') {
1548 				dlg_select_item(dlg, di);
1549 				break;
1550 			}
1551 			gh:
1552 			if (ev->x > ' ') for (i = 0; i < dlg->n; i++) {
1553 				unsigned char *tx = get_text_translation(dlg->dlg->items[i].text, term);
1554 				if (dlg->dlg->items[i].type == D_BUTTON && charset_upcase(GET_TERM_CHAR(term, &tx), term_charset(term)) == charset_upcase(ev->x, term_charset(term))) goto sel;
1555 			}
1556 			if (ev->x == KBD_ENTER) {
1557 go_enter:
1558 				for (i = 0; i < dlg->n; i++)
1559 					if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ENTER) goto sel;
1560 				break;
1561 			}
1562 			if (ev->x == KBD_ESC) {
1563 				for (i = 0; i < dlg->n; i++)
1564 					if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ESC) goto sel;
1565 				break;
1566 			}
1567 			if (0) {
1568 				sel:
1569 				if (dlg->selected != i) {
1570 					x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1571 					x_display_dlg_item(dlg, &dlg->items[i], 1);
1572 					dlg->selected = i;
1573 				}
1574 				dlg_select_item(dlg, &dlg->items[i]);
1575 				break;
1576 			}
1577 			if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN || ev->x == KBD_RIGHT) && (dlg->n > 1 || term->spec->braille)) {
1578 go_next:
1579 				if (term->spec->braille) dlg->brl_y = dlg->items[0].y - 3;
1580 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1581 				if ((++dlg->selected) >= dlg->n) dlg->selected = 0;
1582 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
1583 				break;
1584 			}
1585 			if (((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP || ev->x == KBD_LEFT) && (dlg->n > 1 || term->spec->braille)) {
1586 go_prev:
1587 				if (term->spec->braille) dlg->brl_y = dlg->items[0].y - 3;
1588 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
1589 				if ((--dlg->selected) < 0) dlg->selected = dlg->n - 1;
1590 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
1591 				break;
1592 			}
1593 			break;
1594 		case EV_ABORT:
1595 		/* Moved this line up so that the dlg would have access to its
1596 		   member vars before they get freed. */
1597 			if (dlg->dlg->abort) dlg->dlg->abort(dlg);
1598 			for (i = 0; i < dlg->n; i++) {
1599 				struct dialog_item_data *di = &dlg->items[i];
1600 				if (di->cdata) mem_free(di->cdata);
1601 				free_list(struct history_item, di->history);
1602 			}
1603 			freeml(dlg->ml);
1604 	}
1605 }
1606 
1607 /* gid and gnum are 100 times greater than boundaries (e.g. if gid==1 boundary is 0.01) */
check_float(struct dialog_data * dlg,struct dialog_item_data * di)1608 int check_float(struct dialog_data *dlg, struct dialog_item_data *di)
1609 {
1610 	char *end;
1611 	double d = strtod(cast_const_char di->cdata, &end);
1612 	if (!*di->cdata || *end || di->cdata[strspn(cast_const_char di->cdata, "0123456789.")] || *di->cdata == (unsigned char)'.') {
1613 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1614 		return 1;
1615 	}
1616 	if (d < 0 || d > di->item->gnum || 100 * d < di->item->gid || 100 * d > di->item->gnum) {
1617 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1618 		return 1;
1619 	}
1620 	return 0;
1621 }
1622 
check_number(struct dialog_data * dlg,struct dialog_item_data * di)1623 int check_number(struct dialog_data *dlg, struct dialog_item_data *di)
1624 {
1625 	char *end;
1626 	long l = strtol(cast_const_char di->cdata, &end, 10);
1627 	if (!*di->cdata || *end) {
1628 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1629 		return 1;
1630 	}
1631 	if (l < di->item->gid || l > di->item->gnum) {
1632 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1633 		return 1;
1634 	}
1635 	return 0;
1636 }
1637 
check_hex_number(struct dialog_data * dlg,struct dialog_item_data * di)1638 int check_hex_number(struct dialog_data *dlg, struct dialog_item_data *di)
1639 {
1640 	char *end;
1641 	long l = strtol(cast_const_char di->cdata, &end, 16);
1642 	if (!*di->cdata || *end) {
1643 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1644 		return 1;
1645 	}
1646 	if (l < di->item->gid || l > di->item->gnum) {
1647 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1648 		return 1;
1649 	}
1650 	return 0;
1651 }
1652 
check_nonempty(struct dialog_data * dlg,struct dialog_item_data * di)1653 int check_nonempty(struct dialog_data *dlg, struct dialog_item_data *di)
1654 {
1655 	unsigned char *p;
1656 	for (p = di->cdata; *p; p++) if (*p > ' ') return 0;
1657 	msg_box(dlg->win->term, NULL, TEXT_(T_BAD_STRING), AL_CENTER, TEXT_(T_EMPTY_STRING_NOT_ALLOWED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1658 	return 1;
1659 }
1660 
check_local_ip_address_internal(struct dialog_data * dlg,struct dialog_item_data * di,int pf)1661 static int check_local_ip_address_internal(struct dialog_data *dlg, struct dialog_item_data *di, int pf)
1662 {
1663 	int s;
1664 	int rs;
1665 	unsigned char *p = di->cdata;
1666 	if (!*p) {
1667 		return 0;
1668 	}
1669 #ifdef SUPPORT_IPV6
1670 	if (pf == PF_INET6) rs = numeric_ipv6_address(p, NULL, NULL);
1671 	else
1672 #endif
1673 		rs = numeric_ip_address(p, NULL);
1674 	if (rs) {
1675 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_IP_ADDRESS), AL_CENTER, TEXT_(T_INVALID_IP_ADDRESS_SYNTAX), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1676 		return 1;
1677 	}
1678 	s = socket_and_bind(pf, p);
1679 	if (s != -1) {
1680 		EINTRLOOP(rs, close(s));
1681 	} else {
1682 		if (1
1683 #ifdef ENFILE
1684 			&& errno != ENFILE
1685 #endif
1686 #ifdef EMFILE
1687 			&& errno != EMFILE
1688 #endif
1689 #ifdef ENOBUFS
1690 			&& errno != ENOBUFS
1691 #endif
1692 #ifdef ENOMEM
1693 			&& errno != ENOMEM
1694 #endif
1695 			) {
1696 				unsigned char *er = strerror_alloc(errno, dlg->win->term);
1697 				unsigned char *ad = stracpy(p);
1698 				msg_box(dlg->win->term, getml(er, ad, NULL), TEXT_(T_BAD_IP_ADDRESS), AL_CENTER, TEXT_(T_UNABLE_TO_USE_LOCAL_IP_ADDRESS), cast_uchar " ", ad, cast_uchar ": ", er, MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
1699 				return 1;
1700 		}
1701 	}
1702 	return 0;
1703 }
1704 
check_local_ip_address(struct dialog_data * dlg,struct dialog_item_data * di)1705 int check_local_ip_address(struct dialog_data *dlg, struct dialog_item_data *di)
1706 {
1707 	return check_local_ip_address_internal(dlg, di, PF_INET);
1708 }
1709 
check_local_ipv6_address(struct dialog_data * dlg,struct dialog_item_data * di)1710 int check_local_ipv6_address(struct dialog_data *dlg, struct dialog_item_data *di)
1711 {
1712 #ifdef SUPPORT_IPV6
1713 	return check_local_ip_address_internal(dlg, di, PF_INET6);
1714 #else
1715 	return 0;
1716 #endif
1717 }
1718 
cancel_dialog(struct dialog_data * dlg,struct dialog_item_data * di)1719 int cancel_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
1720 {
1721 	delete_window(dlg->win);
1722 	return 0;
1723 }
1724 
check_dialog(struct dialog_data * dlg)1725 int check_dialog(struct dialog_data *dlg)
1726 {
1727 	int i;
1728 	for (i = 0; i < dlg->n; i++)
1729 		if (dlg->dlg->items[i].type == D_CHECKBOX || dlg->dlg->items[i].type == D_FIELD || dlg->dlg->items[i].type == D_FIELD_PASS)
1730 			if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
1731 				dlg->selected = i;
1732 				draw_to_window(dlg->win, redraw_dialog_items, dlg);
1733 				return 1;
1734 			}
1735 	return 0;
1736 }
1737 
get_dialog_data(struct dialog_data * dlg)1738 void get_dialog_data(struct dialog_data *dlg)
1739 {
1740 	int i;
1741 	for (i = 0; i < dlg->n; i++) {
1742 		/* highc_volatile because of a compiler bug */
1743 		void * highc_volatile p1 = dlg->dlg->items[i].data;
1744 		void * highc_volatile p2 = dlg->items[i].cdata;
1745 		highc_volatile int l = dlg->dlg->items[i].dlen;
1746 		if (l)
1747 			memcpy(p1, p2, l);
1748 	}
1749 }
1750 
ok_dialog(struct dialog_data * dlg,struct dialog_item_data * di)1751 int ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
1752 {
1753 	void (*fn)(void *) = dlg->dlg->refresh;
1754 	void *data = dlg->dlg->refresh_data;
1755 	if (check_dialog(dlg)) return 1;
1756 	get_dialog_data(dlg);
1757 	if (fn) fn(data);
1758 	return cancel_dialog(dlg, di);
1759 }
1760 
center_dlg(struct dialog_data * dlg)1761 void center_dlg(struct dialog_data *dlg)
1762 {
1763 	if (!dlg->win->term->spec->braille) {
1764 		dlg->x = (dlg->win->term->x - dlg->xw) / 2;
1765 		dlg->y = (dlg->win->term->y - dlg->yw) / 2;
1766 	} else {
1767 		dlg->x = -6;
1768 		dlg->y = -1;
1769 		dlg->xw = dlg->win->term->x + 12;
1770 		dlg->yw = dlg->win->term->y + 3;
1771 	}
1772 }
1773 
draw_dlg(struct dialog_data * dlg)1774 void draw_dlg(struct dialog_data *dlg)
1775 {
1776 	if (!F) {
1777 		int i, tpos;
1778 		struct terminal *term = dlg->win->term;
1779 		fill_area(term, dlg->x, dlg->y, dlg->xw, dlg->yw, ' ', COLOR_DIALOG);
1780 		draw_frame(term, dlg->x + DIALOG_LEFT_BORDER, dlg->y + DIALOG_TOP_BORDER, dlg->xw - 2 * DIALOG_LEFT_BORDER, dlg->yw - 2 * DIALOG_TOP_BORDER, COLOR_DIALOG_FRAME, DIALOG_FRAME);
1781 		i = ttxtlen(term, get_text_translation(dlg->dlg->title, term));
1782 		tpos = (dlg->xw - i) / 2;
1783 		if (term->spec->braille) tpos = 9;
1784 		print_text(term, tpos + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1, cast_uchar " ", COLOR_DIALOG_TITLE);
1785 		print_text(term, tpos + dlg->x, dlg->y + DIALOG_TOP_BORDER, i, get_text_translation(dlg->dlg->title, term), COLOR_DIALOG_TITLE);
1786 		print_text(term, tpos + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1, cast_uchar " ", COLOR_DIALOG_TITLE);
1787 #ifdef G
1788 	} else {
1789 		struct graphics_device *dev = dlg->win->term->dev;
1790 		struct rect r;
1791 		struct rect rt;
1792 		unsigned char *text = get_text_translation(dlg->dlg->title, dlg->win->term);
1793 		int xtl = txtlen(dlg->win->term, text);
1794 		int tl = xtl + 2 * G_DIALOG_TITLE_BORDER;
1795 		int TXT_X, TXT_Y;
1796 		if (tl > dlg->xw - 2 * G_DIALOG_LEFT_BORDER - 2 * G_DIALOG_VLINE_SPACE) tl = dlg->xw - 2 * G_DIALOG_LEFT_BORDER - 2 * G_DIALOG_VLINE_SPACE;
1797 		TXT_X = dlg->x + (dlg->xw - tl) / 2;
1798 		TXT_Y = dlg->y + G_DIALOG_TOP_BORDER + (G_DIALOG_HLINE_SPACE + 1) / 2 - G_BFU_FONT_SIZE / 2;
1799 		if (TXT_Y < dlg->y) TXT_Y = dlg->y;
1800 		if (TXT_Y < dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1 - G_BFU_FONT_SIZE) TXT_Y = dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1 - G_BFU_FONT_SIZE;
1801 		set_window_pos(dlg->win, dlg->x, dlg->y, dlg->x + dlg->xw, dlg->y + dlg->yw);
1802 
1803 		restrict_clip_area(dev, &r, TXT_X, TXT_Y, TXT_X + tl, TXT_Y + G_BFU_FONT_SIZE);
1804 		rt.x1 = TXT_X;
1805 		rt.x2 = TXT_X + tl;
1806 		rt.y1 = TXT_Y;
1807 		rt.y2 = TXT_Y + G_BFU_FONT_SIZE;
1808 		if (xtl > tl) g_print_text(dev, TXT_X, TXT_Y, bfu_style_wb, text, NULL);
1809 		else {
1810 			drv->fill_area(dev, TXT_X, TXT_Y, TXT_X + (tl - xtl) / 2, TXT_Y + G_BFU_FONT_SIZE, bfu_fg_color);
1811 			g_print_text(dev, TXT_X + (tl - xtl) / 2, TXT_Y, bfu_style_wb, text, NULL);
1812 			drv->fill_area(dev, TXT_X + (tl - xtl) / 2 + xtl, TXT_Y, TXT_X + tl, TXT_Y + G_BFU_FONT_SIZE, bfu_fg_color);
1813 		}
1814 		set_clip_area(dev, &r);
1815 
1816 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER, TXT_X, bfu_fg_color);
1817 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, TXT_X, bfu_fg_color);
1818 		drv->draw_hline(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, bfu_fg_color);
1819 		drv->draw_hline(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, bfu_fg_color);
1820 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, bfu_fg_color);
1821 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, bfu_fg_color);
1822 
1823 		drv->draw_vline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_fg_color);
1824 		drv->draw_vline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, bfu_fg_color);
1825 		drv->draw_vline(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_fg_color);
1826 		drv->draw_vline(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, bfu_fg_color);
1827 
1828 		drv->fill_area(dev, dlg->x, dlg->y, TXT_X, dlg->y + G_DIALOG_TOP_BORDER, bfu_bg_color);
1829 		drv->fill_area(dev, TXT_X, dlg->y, TXT_X + tl, TXT_Y, bfu_bg_color);
1830 		drv->fill_area(dev, TXT_X + tl, dlg->y, dlg->x + dlg->xw, dlg->y + G_DIALOG_TOP_BORDER, bfu_bg_color);
1831 		drv->fill_area(dev, dlg->x, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, bfu_bg_color);
1832 		drv->fill_area(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + dlg->xw, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, bfu_bg_color);
1833 		drv->fill_area(dev, dlg->x, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, dlg->x + dlg->xw, dlg->y + dlg->yw, bfu_bg_color);
1834 
1835 		drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + G_DIALOG_TOP_BORDER + 1, TXT_X, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, bfu_bg_color);
1836 		drv->fill_area(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, bfu_bg_color);
1837 		drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, bfu_bg_color);
1838 		drv->fill_area(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, bfu_bg_color);
1839 		drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_bg_color);
1840 
1841 		dlg->s = init_rect_set();
1842 		dlg->rr.x1 = dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE + 1;
1843 		dlg->rr.x2 = dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1;
1844 		dlg->rr.y1 = dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1;
1845 		dlg->rr.y2 = dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1;
1846 		add_to_rect_set(&dlg->s, &dlg->rr);
1847 		exclude_rect_from_set(&dlg->s, &rt);
1848 		restrict_clip_area(dev, &dlg->r, dlg->rr.x1, dlg->rr.y1, dlg->rr.x2, dlg->rr.y2);
1849 #endif
1850 	}
1851 }
1852 
max_text_width(struct terminal * term,unsigned char * text,int * width,int align)1853 void max_text_width(struct terminal *term, unsigned char *text, int *width, int align)
1854 {
1855 	if (term->spec->braille) *width = term->x;
1856 	text = get_text_translation(text, term);
1857 	do {
1858 		int c = 0;
1859 		while (*text && *text != '\n') {
1860 			if (!is_utf_8(term)) text++, c++;
1861 			else {
1862 				int u;
1863 				GET_UTF_8(text, u);
1864 				if (!F) c++;
1865 #ifdef G
1866 				else c += g_char_width(align & AL_MONO ? bfu_style_wb_mono : bfu_style_wb, u);
1867 #endif
1868 			}
1869 		}
1870 		if (c > *width) *width = c;
1871 	} while (*(text++));
1872 }
1873 
min_text_width(struct terminal * term,unsigned char * text,int * width,int align)1874 void min_text_width(struct terminal *term, unsigned char *text, int *width, int align)
1875 {
1876 	if (term->spec->braille) *width = term->x;
1877 	text = get_text_translation(text, term);
1878 	do {
1879 		int c = 0;
1880 		while (*text && *text != '\n' && *text != ' ') {
1881 			if (!is_utf_8(term)) text++, c++;
1882 			else {
1883 				int u;
1884 				GET_UTF_8(text, u);
1885 				if (!F) c++;
1886 #ifdef G
1887 				else c += g_char_width(align & AL_MONO ? bfu_style_wb_mono : bfu_style_wb, u);
1888 #endif
1889 			}
1890 		}
1891 		if (c > *width) *width = c;
1892 	} while (*(text++));
1893 }
1894 
dlg_format_text(struct dialog_data * dlg,struct terminal * term,unsigned char * text,int x,int * y,int w,int * rw,unsigned char co,int align)1895 int dlg_format_text(struct dialog_data *dlg, struct terminal *term, unsigned char *text, int x, int *y, int w, int *rw, unsigned char co, int align)
1896 {
1897 	int xx = x;
1898 #ifdef G
1899 	unsigned char *tx2;
1900 #endif
1901 	text = get_text_translation(text, dlg->win->term);
1902 	if (dlg->win->term->spec->braille && !(align & AL_NOBRLEXP)) w = dlg->win->term->x;
1903 	if (!F) while (1) {
1904 		unsigned char *t1;
1905 		unsigned ch;
1906 		int cx, lbr;
1907 
1908 		t1 = text;
1909 		cx = 0;
1910 		lbr = 0;
1911 		next_chr:
1912 		ch = GET_TERM_CHAR(dlg->win->term, &t1);
1913 		if (ch == ' ') {
1914 			lbr = cx;
1915 		}
1916 		if (ch && ch != '\n') {
1917 			if (cx == w) {
1918 				if (!lbr) lbr = cx;
1919 				goto print_line;
1920 			}
1921 			cx++;
1922 			goto next_chr;
1923 		}
1924 		if (!ch && !cx)
1925 			break;
1926 		lbr = cx;
1927 		print_line:
1928 		if (rw && lbr > *rw) *rw = lbr;
1929 		xx = x;
1930 		if ((align & AL_MASK) == AL_CENTER && !dlg->win->term->spec->braille) {
1931 			xx += (w - lbr) / 2;
1932 		}
1933 		for (; lbr--; xx++) {
1934 			ch = GET_TERM_CHAR(dlg->win->term, &text);
1935 			if (term) set_char(term, xx, *y, ch, co);
1936 		}
1937 		xx++;
1938 		if (*text == ' ' || *text == '\n') text++;
1939 		(*y)++;
1940 	}
1941 #ifdef G
1942 	else if ((tx2 = cast_uchar strchr(cast_const_char text, '\n'))) {
1943 		unsigned char *txt = stracpy(text);
1944 		unsigned char *tx1 = txt;
1945 		tx2 = txt + (tx2 - text);
1946 		do {
1947 			*tx2 = 0;
1948 			dlg_format_text(dlg, term, tx1, x, y, w, rw, co, align);
1949 			tx1 = tx2 + 1;
1950 		} while ((tx2 = cast_uchar strchr(cast_const_char tx1, '\n')));
1951 		dlg_format_text(dlg, term, tx1, x, y, w, rw, co, align);
1952 		mem_free(txt);
1953 	} else {
1954 		int www;
1955 		unsigned char *txt;
1956 		struct wrap_struct ww;
1957 		int r;
1958 		ww.style = align & AL_MONO ? bfu_style_bw_mono : bfu_style_bw;
1959 		ww.width = w;
1960 		new_ln:
1961 		ww.text = text;
1962 		ww.obj = NULL;
1963 		ww.pos = 0;
1964 		ww.last_wrap = NULL;
1965 		ww.last_wrap_obj = NULL;
1966 		ww.force_break = 1;
1967 		r = g_wrap_text(&ww);
1968 		if (!r) {
1969 			txt = memacpy(text, ww.last_wrap - text);
1970 			www = g_text_width(ww.style, txt);
1971 			if (!term) mem_free(txt);
1972 			text = ww.last_wrap;
1973 			if (*text == ' ') text++;
1974 		} else {
1975 			www = ww.pos;
1976 			txt = text;
1977 		}
1978 		if (term) {
1979 			int xx = (align & AL_MASK) == AL_CENTER ? x + (w - www) / 2 : x;
1980 			g_print_text(dlg->win->term->dev, xx, *y, ww.style, txt, NULL);
1981 			if (dlg->s) exclude_from_set(&dlg->s, xx, *y, xx + www, *y + G_BFU_FONT_SIZE);
1982 			if (!r) mem_free(txt);
1983 		}
1984 		if (www > w) www = w;
1985 		if (rw && www > *rw) *rw = www;
1986 		*y += G_BFU_FONT_SIZE;
1987 		if (!r) goto new_ln;
1988 	}
1989 #endif
1990 	return xx - x;
1991 }
1992 
max_buttons_width(struct terminal * term,struct dialog_item_data * butt,int n,int * width)1993 void max_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
1994 {
1995 	int w = gf_val(-2, -G_DIALOG_BUTTON_SPACE);
1996 	int i;
1997 	if (term->spec->braille) *width = term->x;
1998 	for (i = 0; i < n; i++) w += txtlen(term, get_text_translation((butt++)->item->text, term)) + gf_val(6, G_DIALOG_BUTTON_SPACE + txtlen(term, cast_uchar G_DIALOG_BUTTON_L) + txtlen(term, cast_uchar G_DIALOG_BUTTON_R));
1999 	if (w > *width) *width = w;
2000 }
2001 
min_buttons_width(struct terminal * term,struct dialog_item_data * butt,int n,int * width)2002 void min_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
2003 {
2004 	int i;
2005 	if (term->spec->braille) *width = term->x;
2006 	for (i = 0; i < n; i++) {
2007 		int w = txtlen(term, get_text_translation((butt++)->item->text, term)) + gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)));
2008 		if (w > *width) *width = w;
2009 	}
2010 }
2011 
dlg_format_buttons(struct dialog_data * dlg,struct terminal * term,struct dialog_item_data * butt,int n,int x,int * y,int w,int * rw,int align)2012 void dlg_format_buttons(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *butt, int n, int x, int *y, int w, int *rw, int align)
2013 {
2014 	int i1 = 0;
2015 	if (dlg->win->term->spec->braille) w = dlg->win->term->x;
2016 	while (i1 < n) {
2017 		int i2 = i1 + 1;
2018 		int mw;
2019 		while (i2 < n) {
2020 			mw = 0;
2021 			max_buttons_width(dlg->win->term, butt + i1, i2 - i1 + 1, &mw);
2022 			if (mw <= w) i2++;
2023 			else break;
2024 		}
2025 		mw = 0;
2026 		max_buttons_width(dlg->win->term, butt + i1, i2 - i1, &mw);
2027 		if (rw && mw > *rw) if ((*rw = mw) > w) *rw = w;
2028 		if (term) {
2029 			int i;
2030 			int p = x + ((align & AL_MASK) == AL_CENTER ? (w - mw) / 2 : 0);
2031 			for (i = i1; i < i2; i++) {
2032 				butt[i].x = p;
2033 				butt[i].y = *y;
2034 				p += (butt[i].l = txtlen(dlg->win->term, get_text_translation(butt[i].item->text, dlg->win->term)) + gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) + gf_val(2, G_DIALOG_BUTTON_SPACE);
2035 			}
2036 		}
2037 		*y += 2 * LL;
2038 		i1 = i2;
2039 	}
2040 }
2041 
dlg_format_checkbox(struct dialog_data * dlg,struct terminal * term,struct dialog_item_data * chkb,int x,int * y,int w,int * rw,unsigned char * text)2042 void dlg_format_checkbox(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *chkb, int x, int *y, int w, int *rw, unsigned char *text)
2043 {
2044 	int k = gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE);
2045 	if (term) {
2046 		chkb->x = x;
2047 		chkb->y = *y;
2048 	}
2049 	if (rw) *rw -= k;
2050 	dlg_format_text(dlg, term, text, x + k, y, w - k, rw, COLOR_DIALOG_CHECKBOX_TEXT, AL_LEFT | AL_NOBRLEXP);
2051 	if (rw) *rw += k;
2052 }
2053 
dlg_format_checkboxes(struct dialog_data * dlg,struct terminal * term,struct dialog_item_data * chkb,int n,int x,int * y,int w,int * rw,unsigned char * const * texts)2054 void dlg_format_checkboxes(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *chkb, int n, int x, int *y, int w, int *rw, unsigned char * const *texts)
2055 {
2056 	if (dlg->win->term->spec->braille) w = dlg->win->term->x;
2057 	while (n) {
2058 		dlg_format_checkbox(dlg, term, chkb, x, y, w, rw, texts[0]);
2059 		texts++; chkb++; n--;
2060 	}
2061 }
2062 
checkboxes_width(struct terminal * term,unsigned char * const * texts,int n,int * w,void (* fn)(struct terminal *,unsigned char *,int *,int))2063 void checkboxes_width(struct terminal *term, unsigned char * const *texts, int n, int *w, void (*fn)(struct terminal *, unsigned char *, int *, int))
2064 {
2065 	int k = gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE);
2066 	while (n--) {
2067 		*w -= k;
2068 		fn(term, get_text_translation(texts[0], term), w, 0);
2069 		*w += k;
2070 		texts++;
2071 	}
2072 }
2073 
dlg_format_field(struct dialog_data * dlg,struct terminal * term,struct dialog_item_data * item,int x,int * y,int w,int * rw,int align)2074 void dlg_format_field(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align)
2075 {
2076 	if (dlg->win->term->spec->braille) w = dlg->win->term->x;
2077 	if (term) {
2078 		int l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
2079 		item->x = x;
2080 		item->y = *y;
2081 		item->l = w;
2082 		if (item->l > l)
2083 			item->l = l;
2084 		if (rw && item->l > *rw) *rw = item->l;
2085 	}
2086 	(*y) += LL;
2087 }
2088 
dlg_format_text_and_field(struct dialog_data * dlg,struct terminal * term,unsigned char * text,struct dialog_item_data * item,int x,int * y,int w,int * rw,unsigned char co,int align)2089 void dlg_format_text_and_field(struct dialog_data *dlg, struct terminal *term, unsigned char *text, struct dialog_item_data *item, int x, int *y, int w, int *rw, unsigned char co, int align)
2090 {
2091 	if (!dlg->win->term->spec->braille) {
2092 		dlg_format_text(dlg, term, text, x, y, w, rw, co, align);
2093 		dlg_format_field(dlg, term, item, x, y, w, rw, align);
2094 	} else {
2095 		int pos = dlg_format_text(dlg, term, text, x, y, w, rw, co, align);
2096 		if (pos >= w - 4) (*y)++, pos = 0;
2097 		if (term) {
2098 			item->x = x + pos;
2099 			item->y = *y - 1;
2100 			item->l = w - pos;
2101 		}
2102 	}
2103 }
2104 
2105 
2106 #if 0
2107 /* Layout for generic boxes */
2108 void dlg_format_box(struct terminal *term, struct terminal *t2, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align) {
2109 	item->x = x;
2110 	item->y = *y;
2111 	item->l = w;
2112 	if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w;
2113 	(*y) += item->item->gid;
2114 }
2115 #endif
2116 
max_group_width(struct terminal * term,unsigned char * const * texts,struct dialog_item_data * item,int n,int * w)2117 void max_group_width(struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int *w)
2118 {
2119 	int ww = 0;
2120 	if (term->spec->braille) *w = term->x;
2121 	while (n--) {
2122 		int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE) :
2123 			item->item->type == D_BUTTON ? txtlen(term, get_text_translation(item->item->text, term)) + (gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
2124 			gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
2125 		wx += txtlen(term, get_text_translation(texts[0], term)) + gf_val(1, G_DIALOG_GROUP_TEXT_SPACE);
2126 		if (n) gf_val(wx++, wx += G_DIALOG_GROUP_SPACE);
2127 		ww += wx;
2128 		texts++;
2129 		item++;
2130 	}
2131 	if (ww > *w) *w = ww;
2132 }
2133 
min_group_width(struct terminal * term,unsigned char * const * texts,struct dialog_item_data * item,int n,int * w)2134 void min_group_width(struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int *w)
2135 {
2136 	if (term->spec->braille) *w = term->x;
2137 	while (n--) {
2138 		int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE) :
2139 			item->item->type == D_BUTTON ? txtlen(term, get_text_translation(item->item->text, term)) + (gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
2140 			gf_val(item->item->dlen + 1, (item->item->dlen + 1) * G_DIALOG_FIELD_WIDTH);
2141 		wx += txtlen(term, get_text_translation(texts[0], term));
2142 		if (wx > *w) *w = wx;
2143 		texts++;
2144 		item++;
2145 	}
2146 }
2147 
dlg_format_group(struct dialog_data * dlg,struct terminal * term,unsigned char * const * texts,struct dialog_item_data * item,int n,int x,int * y,int w,int * rw)2148 void dlg_format_group(struct dialog_data *dlg, struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int x, int *y, int w, int *rw)
2149 {
2150 	int f = 1;
2151 	int nx = 0;
2152 	if (dlg->win->term->spec->braille) w = dlg->win->term->x;
2153 	while (n--) {
2154 		int wx = item->item->type == D_CHECKBOX ? gf_val(3, txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R))) :
2155 			item->item->type == D_BUTTON ? txtlen(dlg->win->term, get_text_translation(item->item->text, dlg->win->term)) + (gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
2156 			gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
2157 		int sl;
2158 		if (get_text_translation(texts[0], dlg->win->term)[0]) sl = txtlen(dlg->win->term, get_text_translation(texts[0], dlg->win->term)) + gf_val(1, G_DIALOG_GROUP_TEXT_SPACE);
2159 		else sl = 0;
2160 		wx += sl;
2161 		if (dlg->win->term->spec->braille) {
2162 			if (!f) {
2163 				nx = 0;
2164 				(*y) += LL;
2165 			} else f = 0;
2166 		} else if (nx && nx + wx > w) {
2167 			nx = 0;
2168 			(*y) += 2 * LL;
2169 		}
2170 		if (term) {
2171 			if (!F) print_text(term, x + nx + 4 * (item->item->type == D_CHECKBOX), *y, ttxtlen(term, get_text_translation(texts[0], dlg->win->term)), get_text_translation(texts[0], dlg->win->term), COLOR_DIALOG_TEXT);
2172 #ifdef G
2173 			else {
2174 				int l, ll;
2175 				l = ll = x + nx + (item->item->type == D_CHECKBOX ? txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_GROUP_TEXT_SPACE : 0);
2176 				g_print_text(term->dev, ll, *y, bfu_style_bw, get_text_translation(texts[0], dlg->win->term), &ll);
2177 				exclude_from_set(&dlg->s, l, *y, ll, *y + G_BFU_FONT_SIZE);
2178 			}
2179 #endif
2180 			item->x = x + nx + sl * (item->item->type != D_CHECKBOX);
2181 			item->y = *y;
2182 			if (item->item->type == D_FIELD || item->item->type == D_FIELD_PASS) item->l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
2183 		}
2184 		if (rw && nx + wx > *rw) if ((*rw = nx + wx) > w) *rw = w;
2185 		nx += wx + gf_val(1, G_DIALOG_GROUP_SPACE);
2186 		texts++;
2187 		item++;
2188 	}
2189 	(*y) += LL;
2190 }
2191 
checkbox_list_fn(struct dialog_data * dlg)2192 void checkbox_list_fn(struct dialog_data *dlg)
2193 {
2194 	struct terminal *term = dlg->win->term;
2195 	int n_checkboxes;
2196 	int max = 0, min = 0;
2197 	int w, rw;
2198 	int y = 0;
2199 	for (n_checkboxes = 0; ((unsigned char **)dlg->dlg->udata)[n_checkboxes]; n_checkboxes++)
2200 		;
2201 	checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &max, max_text_width);
2202 	checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &min, min_text_width);
2203 	max_buttons_width(term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, &max);
2204 	min_buttons_width(term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, &min);
2205 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
2206 	if (w > max) w = max;
2207 	if (w < min) w = min;
2208 	if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
2209 	if (w < 5) w = 5;
2210 	rw = 0;
2211 	dlg_format_checkboxes(dlg, NULL, dlg->items, n_checkboxes, 0, &y, w, &rw, dlg->dlg->udata);
2212 	y += LL;
2213 	dlg_format_buttons(dlg, NULL, dlg->items + n_checkboxes, dlg->n - n_checkboxes, 0, &y, w, &rw, AL_CENTER);
2214 	w = rw;
2215 	dlg->xw = rw + 2 * DIALOG_LB;
2216 	dlg->yw = y + 2 * DIALOG_TB;
2217 	center_dlg(dlg);
2218 	draw_dlg(dlg);
2219 	y = dlg->y + DIALOG_TB + LL;
2220 	dlg_format_checkboxes(dlg, term, dlg->items, n_checkboxes, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
2221 	y += LL;
2222 	dlg_format_buttons(dlg, term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
2223 }
2224 
group_fn(struct dialog_data * dlg)2225 void group_fn(struct dialog_data *dlg)
2226 {
2227 	struct terminal *term = dlg->win->term;
2228 	int max = 0, min = 0;
2229 	int w, rw;
2230 	int y = 0;
2231 	max_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &max);
2232 	min_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &min);
2233 	max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
2234 	min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
2235 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
2236 	if (w > max) w = max;
2237 	if (w < min) w = min;
2238 	if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
2239 	if (w < 1) w = 1;
2240 	rw = 0;
2241 	dlg_format_group(dlg, NULL, dlg->dlg->udata, dlg->items, dlg->n - 2, 0, &y, w, &rw);
2242 	y += LL;
2243 	dlg_format_buttons(dlg, NULL, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
2244 	w = rw;
2245 	dlg->xw = rw + 2 * DIALOG_LB;
2246 	dlg->yw = y + 2 * DIALOG_TB;
2247 	center_dlg(dlg);
2248 	draw_dlg(dlg);
2249 	y = dlg->y + DIALOG_TB + LL;
2250 	dlg_format_group(dlg, term, dlg->dlg->udata, dlg->items, dlg->n - 2, dlg->x + DIALOG_LB, &y, w, NULL);
2251 	y += LL;
2252 	dlg_format_buttons(dlg, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
2253 }
2254 
msg_box_fn(struct dialog_data * dlg)2255 void msg_box_fn(struct dialog_data *dlg)
2256 {
2257 	struct terminal *term = dlg->win->term;
2258 	int max = 0, min = 0;
2259 	int w, rw;
2260 	int y = 0;
2261 	unsigned char **ptr;
2262 	unsigned char *text = init_str();
2263 	int textl = 0;
2264 	for (ptr = dlg->dlg->udata; *ptr; ptr++) add_to_str(&text, &textl, get_text_translation(*ptr, term));
2265 	max_text_width(term, text, &max, dlg->dlg->align);
2266 	min_text_width(term, text, &min, dlg->dlg->align);
2267 	max_buttons_width(term, dlg->items, dlg->n, &max);
2268 	min_buttons_width(term, dlg->items, dlg->n, &min);
2269 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
2270 	if (w > max) w = max;
2271 	if (w < min) w = min;
2272 	if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
2273 	if (w < 1) w = 1;
2274 	rw = 0;
2275 	dlg_format_text(dlg, NULL, text, 0, &y, w, &rw, COLOR_DIALOG_TEXT, dlg->dlg->align);
2276 	y += LL;
2277 	dlg_format_buttons(dlg, NULL, dlg->items, dlg->n, 0, &y, w, &rw, AL_CENTER);
2278 	w = rw;
2279 	dlg->xw = rw + 2 * DIALOG_LB;
2280 	dlg->yw = y + 2 * DIALOG_TB;
2281 	center_dlg(dlg);
2282 	draw_dlg(dlg);
2283 	y = dlg->y + DIALOG_TB + LL;
2284 	dlg_format_text(dlg, term, text, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, dlg->dlg->align);
2285 	y += LL;
2286 	dlg_format_buttons(dlg, term, dlg->items, dlg->n, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
2287 	mem_free(text);
2288 }
2289 
msg_box_button(struct dialog_data * dlg,struct dialog_item_data * di)2290 static int msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di)
2291 {
2292 	msg_button_fn msg_fn = di->item->u.msg_fn;
2293 	void *data = dlg->dlg->udata2;
2294 	msg_fn(data);
2295 	cancel_dialog(dlg, di);
2296 	return 0;
2297 }
2298 
msg_box_null(void * data)2299 void msg_box_null(void *data)
2300 {
2301 }
2302 
2303 /* coverity[+free : arg-1] */
msg_box(struct terminal * term,struct memory_list * ml,unsigned char * title,int align,...)2304 void msg_box(struct terminal *term, struct memory_list *ml, unsigned char *title, int align, /*unsigned char *text, ..., void *data, int n,*/ ...)
2305 {
2306 	struct dialog *dlg;
2307 	int i;
2308 	int n;
2309 	unsigned char *text;
2310 	unsigned char **udata;
2311 	void *udata2;
2312 	int udatan;
2313 	va_list ap;
2314 	va_start(ap, align);
2315 	udata = DUMMY;
2316 	udatan = 0;
2317 	do {
2318 		text = va_arg(ap, unsigned char *);
2319 		udatan++;
2320 		if ((unsigned)udatan > MAXINT / sizeof(unsigned char *)) overalloc();
2321 		udata = mem_realloc(udata, udatan * sizeof(unsigned char *));
2322 		udata[udatan - 1] = text;
2323 	} while (text);
2324 	udata2 = va_arg(ap, void *);
2325 	n = va_arg(ap, int);
2326 	if ((unsigned)n > (MAXINT - sizeof(struct dialog)) / sizeof(struct dialog_item) - 1) overalloc();
2327 	dlg = mem_calloc(sizeof(struct dialog) + (n + 1) * sizeof(struct dialog_item));
2328 	dlg->title = title;
2329 	dlg->fn = msg_box_fn;
2330 	dlg->udata = udata;
2331 	dlg->udata2 = udata2;
2332 	dlg->align = align;
2333 	for (i = 0; i < n; i++) {
2334 		unsigned char *m;
2335 		msg_button_fn msg_fn;
2336 		int flags;
2337 		m = va_arg(ap, unsigned char *);
2338 		msg_fn = va_arg(ap, msg_button_fn);
2339 		flags = va_arg(ap, int);
2340 		if (!m) {
2341 			i--, n--;
2342 			continue;
2343 		}
2344 		dlg->items[i].type = D_BUTTON;
2345 		dlg->items[i].gid = flags;
2346 		dlg->items[i].fn = msg_box_button;
2347 		dlg->items[i].dlen = 0;
2348 		dlg->items[i].text = m;
2349 		dlg->items[i].u.msg_fn = msg_fn;
2350 	}
2351 	va_end(ap);
2352 	dlg->items[i].type = D_END;
2353 	add_to_ml(&ml, dlg, udata, NULL);
2354 	do_dialog(term, dlg, ml);
2355 }
2356 
add_to_history(struct terminal * term,struct history * h,unsigned char * t)2357 void add_to_history(struct terminal *term, struct history *h, unsigned char *t)
2358 {
2359 	unsigned char *s;
2360 	struct history_item *hi, *hs;
2361 	struct list_head *lhs;
2362 	size_t l;
2363 	if (!h || !t || !*t) return;
2364 	if (term) {
2365 		s = convert(term_charset(term), utf8_table, t, NULL);
2366 	} else {
2367 		s = t;
2368 	}
2369 	l = strlen(cast_const_char s);
2370 	if (l > MAXINT - sizeof(struct history_item)) overalloc();
2371 	hi = mem_alloc(sizeof(struct history_item) + l);
2372 	memcpy(hi->str, s, l + 1);
2373 	if (term)
2374 		mem_free(s);
2375 	if (term) foreach(struct history_item, hs, lhs, h->items) if (!strcmp(cast_const_char hs->str, cast_const_char hi->str)) {
2376 		lhs = lhs->prev;
2377 		del_from_list(hs);
2378 		mem_free(hs);
2379 		h->n--;
2380 	}
2381 	add_to_list(h->items, hi);
2382 	h->n++;
2383 	while (h->n > MAX_HISTORY_ITEMS) {
2384 		struct history_item *hd;
2385 		if (list_empty(h->items)) {
2386 			internal_error("history is empty");
2387 			h->n = 0;
2388 			return;
2389 		}
2390 		hd = list_struct(h->items.prev, struct history_item);
2391 		del_from_list(hd);
2392 		mem_free(hd);
2393 		h->n--;
2394 	}
2395 }
2396 
input_field_cancel(struct dialog_data * dlg,struct dialog_item_data * di)2397 static int input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di)
2398 {
2399 	input_field_button_fn fn = di->item->u.input_fn;
2400 	void *data = dlg->dlg->udata2;
2401 	unsigned char *text = dlg->items->cdata;
2402 	fn(data, text);
2403 	cancel_dialog(dlg, di);
2404 	return 0;
2405 }
2406 
input_field_ok(struct dialog_data * dlg,struct dialog_item_data * di)2407 static int input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di)
2408 {
2409 	input_field_button_fn fn = di->item->u.input_fn;
2410 	void *data = dlg->dlg->udata2;
2411 	unsigned char *text = dlg->items->cdata;
2412 	if (check_dialog(dlg)) return 1;
2413 	add_to_history(dlg->win->term, dlg->dlg->items->history, text);
2414 	fn(data, text);
2415 	ok_dialog(dlg, di);
2416 	return 0;
2417 }
2418 
input_field_fn(struct dialog_data * dlg)2419 static void input_field_fn(struct dialog_data *dlg)
2420 {
2421 	struct terminal *term = dlg->win->term;
2422 	int max = 0, min = 0;
2423 	int w, rw;
2424 	int y = gf_val(-1, -G_BFU_FONT_SIZE);
2425 	if (dlg->win->term->spec->braille) y += LL;
2426 	max_text_width(term, dlg->dlg->udata, &max, AL_LEFT);
2427 	min_text_width(term, dlg->dlg->udata, &min, AL_LEFT);
2428 	max_buttons_width(term, dlg->items + 1, dlg->n - 1, &max);
2429 	min_buttons_width(term, dlg->items + 1, dlg->n - 1, &min);
2430 	if (max < dlg->dlg->items->dlen) max = dlg->dlg->items->dlen;
2431 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
2432 	if (w > max) w = max;
2433 	if (w < min) w = min;
2434 	rw = w;
2435 	dlg_format_text_and_field(dlg, NULL, dlg->dlg->udata, dlg->items, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
2436 	y += LL;
2437 	dlg_format_buttons(dlg, NULL, dlg->items + 1, dlg->n - 1, 0, &y, w, &rw, AL_CENTER);
2438 	w = rw;
2439 	dlg->xw = rw + 2 * DIALOG_LB;
2440 	dlg->yw = y + 2 * DIALOG_TB;
2441 	center_dlg(dlg);
2442 	draw_dlg(dlg);
2443 	y = dlg->y + DIALOG_TB;
2444 	if (dlg->win->term->spec->braille) y += LL;
2445 	dlg_format_text_and_field(dlg, term, dlg->dlg->udata, dlg->items, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
2446 	y += LL;
2447 	dlg_format_buttons(dlg, term, dlg->items + 1, dlg->n - 1, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
2448 }
2449 
input_field_null(void * d_,unsigned char * s_)2450 void input_field_null(void *d_, unsigned char *s_)
2451 {
2452 }
2453 
2454 /* coverity[+free : arg-1] */
input_field(struct terminal * term,struct memory_list * ml,unsigned char * title,unsigned char * text,void * data,struct history * history,int l,unsigned char * def,int min,int max,int (* check)(struct dialog_data *,struct dialog_item_data *),int n,...)2455 void input_field(struct terminal *term, struct memory_list *ml, unsigned char *title, unsigned char *text, void *data, struct history *history, int l, unsigned char *def, int min, int max, int (*check)(struct dialog_data *, struct dialog_item_data *), int n, ...)
2456 {
2457 	struct dialog *dlg;
2458 	unsigned char *field;
2459 	va_list va;
2460 	int i;
2461 	if ((unsigned)n > MAXINT / sizeof(struct dialog_item) - 2) overalloc();
2462 	if ((unsigned)l > MAXINT - sizeof(struct dialog) - (2 + n) * sizeof(struct dialog_item)) overalloc();
2463 	dlg = mem_calloc(sizeof(struct dialog) + (2 + n) * sizeof(struct dialog_item) + l);
2464 	*(field = (unsigned char *)dlg + sizeof(struct dialog) + (2 + n) * sizeof(struct dialog_item)) = 0;
2465 	if (def) {
2466 		if (strlen(cast_const_char def) + 1 > (size_t)l) memcpy(field, def, l - 1);
2467 		else strcpy(cast_char field, cast_const_char def);
2468 	}
2469 	dlg->title = title;
2470 	dlg->fn = input_field_fn;
2471 	dlg->udata = text;
2472 	dlg->udata2 = data;
2473 	dlg->items[0].type = D_FIELD;
2474 	dlg->items[0].gid = min;
2475 	dlg->items[0].gnum = max;
2476 	dlg->items[0].fn = check;
2477 	dlg->items[0].history = history;
2478 	dlg->items[0].dlen = l;
2479 	dlg->items[0].data = field;
2480 	va_start(va, n);
2481 	for (i = 1; i <= n; i++) {
2482 		dlg->items[i].type = D_BUTTON;
2483 		dlg->items[i].gid = i == 1 ? B_ENTER : i == n ? B_ESC : 0;
2484 		dlg->items[i].fn = i != n || n == 1 ? input_field_ok : input_field_cancel;
2485 		dlg->items[i].dlen = 0;
2486 		dlg->items[i].text = va_arg(va, unsigned char *);
2487 		dlg->items[i].u.input_fn = va_arg(va, input_field_button_fn);
2488 	}
2489 	va_end(va);
2490 
2491 	dlg->items[i].type = D_END;
2492 	add_to_ml(&ml, dlg, NULL);
2493 	do_dialog(term, dlg, ml);
2494 }
2495 
find_msg_box(struct terminal * term,unsigned char * title,int (* sel)(void *,void *),void * data)2496 int find_msg_box(struct terminal *term, unsigned char *title, int (*sel)(void *, void *), void *data)
2497 {
2498 	struct window *win;
2499 	struct list_head *lwin;
2500 	foreach(struct window, win, lwin, term->windows) if (win->handler == dialog_func) {
2501 		struct dialog_data *dd = win->data;
2502 		struct dialog *d = dd->dlg;
2503 		if (d->fn != msg_box_fn)
2504 			continue;
2505 		if (d->title == title) {
2506 			if (sel && !sel(data, d->udata2))
2507 				continue;
2508 			return 1;
2509 		}
2510 	}
2511 	return 0;
2512 }
2513