1 /*  MikMod module player
2 	(c) 1998 - 2000 Miodrag Vallat and others - see file AUTHORS for
3 	complete list.
4 
5 	This program is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program; if not, write to the Free Software
17 	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 	02111-1307, USA.
19 */
20 
21 /*==============================================================================
22 
23   $Id: mwidget.c,v 1.1.1.1 2004/01/16 02:07:33 raph Exp $
24 
25   Widget and Dialog creation functions
26 
27 ==============================================================================*/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 
36 #include "display.h"
37 #include "player.h"
38 #include "mwindow.h"
39 #include "mwidget.h"
40 #include "keys.h"
41 #include "mutilities.h"
42 
43 #define STR_WIDTH_MAX 70
44 #define STR_WIDTH_MIN 20
45 #define INT_WIDTH_MAX 11
46 
47 #define LIST_WIDTH_DEFAULT 60
48 #define LIST_WIDTH_MIN 15
49 #define LIST_HEIGHT_DEFAULT 20
50 #define LIST_HEIGHT_MIN 5
51 
52 #define WWIN(w) ((w)->w.d->win)
53 
base_attr(DIALOG * d,ATTRS attrs)54 static ATTRS base_attr (DIALOG *d, ATTRS attrs)
55 {
56 	if (d->attrs >= 0) return d->attrs;
57 	return attrs;
58 }
59 
label_free(WID_LABEL * w)60 static void label_free(WID_LABEL *w)
61 {
62 	free(w->msg);
63 	free(w);
64 }
65 
label_paint(WID_LABEL * w)66 static void label_paint(WID_LABEL *w)
67 {
68 	char *start, *pos;
69 	int y = w->w.y;
70 
71 	win_attrset(base_attr(w->w.d,ATTR_DLG_LABEL));
72 	start = w->msg;
73 	for (pos = w->msg; *pos; pos++) {
74 		if (*pos == '\n') {
75 			*pos = '\0';
76 			win_print(WWIN(w),w->w.x, y, start);
77 			*pos = '\n';
78 			start = pos + 1;
79 			y++;
80 		}
81 	}
82 	win_print(WWIN(w),w->w.x, y, start);
83 }
84 
label_handle_event(WID_LABEL * w,WID_EVENT event,int ch)85 static int label_handle_event(WID_LABEL *w, WID_EVENT event, int ch)
86 {
87 	return 0;
88 }
89 
label_get_size(WID_LABEL * w,int * width,int * height)90 static void label_get_size(WID_LABEL *w, int *width, int *height)
91 {
92 	char *pos;
93 	int x = 0;
94 
95 	*width = 0;
96 	*height = 0;
97 	for (pos = w->msg; *pos; pos++) {
98 		if (*pos == '\n') {
99 			(*height)++;
100 			if (x > *width)
101 				*width = x;
102 			x = -1;
103 		}
104 		x++;
105 	}
106 	if (x > *width)
107 		*width = x;
108 	(*height)++;
109 }
110 
str_free(WID_STR * w)111 static void str_free(WID_STR *w)
112 {
113 	free(w->input);
114 	free(w);
115 }
116 
str_paint(WID_STR * w)117 static void str_paint(WID_STR *w)
118 {
119 	char hl[2] = " ", ch = ' ', *pos = &w->input[w->start];
120 	int dx = 0, len;
121 
122 	win_attrset(ATTR_DLG_STR_TEXT);
123 	if (w->w.has_focus) {
124 		hl[0] = ch = w->input[w->cur_pos];
125 		if (!hl[0])
126 			hl[0] = ' ';
127 		w->input[w->cur_pos] = '\0';
128 		if (*pos)
129 			win_print(WWIN(w),w->w.x, w->w.y, pos);
130 		dx = strlen(pos);
131 		win_attrset(ATTR_DLG_STR_CURSOR);
132 		win_print(WWIN(w),w->w.x + dx, w->w.y, hl);
133 		win_attrset(ATTR_DLG_STR_TEXT);
134 		pos += dx;
135 		dx++;
136 		*pos = ch;
137 		if (*pos)
138 			pos++;
139 	}
140 	len = strlen(pos);
141 	if (len + dx > w->w.width) {
142 		ch = w->input[w->w.width + w->start];
143 		w->input[w->w.width + w->start] = '\0';
144 	}
145 	win_print(WWIN(w),w->w.x + dx, w->w.y, pos);
146 	if (len + dx > w->w.width)
147 		w->input[w->w.width + w->start] = ch;
148 	else if (len + dx < w->w.width) {
149 		dx += len;
150 		for (len = 0; len < w->w.width - dx; len++)
151 			storage[len] = ' ';
152 		storage[len] = '\0';
153 		win_print(WWIN(w),w->w.x + dx, w->w.y, storage);
154 	}
155 }
156 
handle_focus(WIDGET * w,int ret,int from_activate)157 static int handle_focus(WIDGET *w, int ret, int from_activate)
158 {
159 	if (ret && (ret != EVENT_HANDLED) && w->handle_focus) {
160 		return w->handle_focus((WIDGET *) w, ret);
161 	} else {
162 		if (ret == FOCUS_ACTIVATE) {
163 			ret = from_activate;
164 			if (ret == EVENT_HANDLED)
165 				dialog_close(w->d);
166 		}
167 		return ret;
168 	}
169 }
170 
input_handle_event(WID_STR * w,WID_EVENT event,int ch,BOOL int_input)171 static int input_handle_event(WID_STR *w, WID_EVENT event,
172 							  int ch, BOOL int_input)
173 {
174 	char *pos;
175 	int i;
176 
177 	if (event == WID_HOTKEY)
178 		return 0;
179 	if (event == WID_GET_FOCUS)
180 		return EVENT_HANDLED;
181 	if ((event == WID_KEY) && w->w.handle_key) {
182 		i = w->w.handle_key((WIDGET *) w, ch);
183 		if (i)
184 			return i;
185 	}
186 
187 	switch (ch) {
188 	  case KEY_UP:
189 		return handle_focus((WIDGET*)w, FOCUS_PREV, 0);
190 	  case KEY_TAB:
191 	  case KEY_DOWN:
192 		return handle_focus((WIDGET*)w, FOCUS_NEXT, 0);
193 	  case KEY_LEFT:
194 	  case CTRL_B:
195 		if (w->cur_pos > 0)
196 			w->cur_pos--;
197 		break;
198 	  case KEY_RIGHT:
199 	  case CTRL_F:
200 		if (w->cur_pos < strlen(w->input))
201 			w->cur_pos++;
202 		break;
203 	  case KEY_HOME:
204 	  case KEY_PPAGE:
205 	  case CTRL_A:
206 		w->cur_pos = 0;
207 		break;
208 #ifdef KEY_END
209 	  case KEY_END:
210 #endif
211 	  case KEY_NPAGE:
212 	  case CTRL_E:
213 		w->cur_pos = strlen(w->input);
214 		break;
215 	  case CTRL_K:
216 		w->input[w->cur_pos] = '\0';
217 		break;
218 	  case CTRL_U:
219 		w->cur_pos = 0;
220 		w->input[w->cur_pos] = '\0';
221 		break;
222 	  case KEY_DC:
223 	  case CTRL_D:
224 #ifdef KEY_ASCII_DEL
225 	  case KEY_ASCII_DEL:
226 #endif
227 		if (w->cur_pos < strlen(w->input))
228 			for (pos = &w->input[w->cur_pos]; *pos; pos++)
229 				*pos = *(pos + 1);
230 		break;
231 	  case KEY_BACKSPACE:
232 #ifdef KEY_ASCII_BS
233 	  case KEY_ASCII_BS:
234 #endif
235 		if (w->cur_pos > 0) {
236 			for (pos = &w->input[w->cur_pos - 1]; *pos; pos++)
237 				*pos = *(pos + 1);
238 			w->cur_pos--;
239 		}
240 		break;
241 	  case KEY_ENTER:
242 	  case '\r':
243 		return handle_focus((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_NEXT);
244 	  default:
245 		if (ch >= 256 || ch < ' ')
246 			return 0;
247 
248 		if ((int_input && isdigit(ch)) || !int_input) {
249 			i = strlen(w->input);
250 			if (i < w->length) {
251 				for (; i >= w->cur_pos; i--)
252 					w->input[i + 1] = w->input[i];
253 				w->input[w->cur_pos] = ch;
254 				w->cur_pos++;
255 			}
256 		}
257 	}
258 	if (w->cur_pos < w->start)
259 		w->start = w->cur_pos;
260 	if (w->cur_pos >= w->start + w->w.width)
261 		w->start = w->cur_pos - w->w.width + 1;
262 	str_paint(w);
263 	return EVENT_HANDLED;
264 }
265 
str_handle_event(WID_STR * w,WID_EVENT event,int ch)266 static int str_handle_event(WID_STR *w, WID_EVENT event, int ch)
267 {
268 	return input_handle_event(w, event, ch, 0);
269 }
270 
str_get_size(WID_STR * w,int * width,int * height)271 static void str_get_size(WID_STR *w, int *width, int *height)
272 {
273 	if (*width > w->w.def_width)
274 		*width = w->w.def_width;
275 	if (*width > w->length)
276 		*width = w->length + 1;
277 	if (*width < STR_WIDTH_MIN)
278 		*width = STR_WIDTH_MIN;
279 
280 	w->start = w->cur_pos - *width + 1;
281 	if (w->start < 0)
282 		w->start = 0;
283 
284 	*height = 1;
285 }
286 
int_free(WID_INT * w)287 static void int_free(WID_INT *w)
288 {
289 	free(w->input);
290 	free(w);
291 }
292 
int_paint(WID_INT * w)293 static void int_paint(WID_INT *w)
294 {
295 	str_paint((WID_STR *) w);
296 }
297 
int_handle_event(WID_INT * w,WID_EVENT event,int ch)298 static BOOL int_handle_event(WID_INT *w, WID_EVENT event, int ch)
299 {
300 	return input_handle_event((WID_STR *) w, event, ch, 1);
301 }
302 
int_get_size(WID_INT * w,int * width,int * height)303 static void int_get_size(WID_INT *w, int *width, int *height)
304 {
305 	*width = w->w.def_width;
306 	*height = 1;
307 }
308 
button_free(WID_BUTTON * w)309 static void button_free(WID_BUTTON *w)
310 {
311 	free(w->button);
312 	free(w);
313 }
314 
button_paint(WID_BUTTON * w)315 static void button_paint(WID_BUTTON *w)
316 {
317 	int cur, x, cnt_hl = 0;
318 	char *pos, *hl_pos, *start, hl[2];
319 	BOOL end;
320 
321 	for (pos = w->button; *pos; pos++)
322 		if (*pos == '&')
323 			cnt_hl++;
324 	x = (w->w.d->win->width - 1 - w->w.x -
325 			((int)strlen(w->button) + 5 * w->cnt - 1 - cnt_hl)) / 2;
326 	cur = 0;
327 	hl_pos = NULL;
328 	hl[1] = '\0';
329 	start = w->button;
330 	end = 0;
331 	for (pos = w->button; !end; pos++) {
332 		end = !(*pos);
333 		if ((*pos == '|') || (*pos == '\0')) {
334 			*pos = '\0';
335 			if ((w->active != cur) || (!w->w.has_focus))
336 				win_attrset(ATTR_DLG_BUT_INACTIVE);
337 			else
338 				win_attrset(ATTR_DLG_BUT_ACTIVE);
339 			win_print(WWIN(w),w->w.x + x, w->w.y, "[ ");
340 			if ((w->active != cur) || (!w->w.has_focus))
341 				win_attrset(ATTR_DLG_BUT_ITEXT);
342 			else
343 				win_attrset(ATTR_DLG_BUT_ATEXT);
344 			win_print(WWIN(w),w->w.x + x + 2, w->w.y, start);
345 			x += strlen(start) + 2;
346 			if (hl_pos) {
347 				if ((w->active != cur) || (!w->w.has_focus))
348 					win_attrset(ATTR_DLG_BUT_IHOTKEY);
349 				else
350 					win_attrset(ATTR_DLG_BUT_AHOTKEY);
351 				win_print(WWIN(w),w->w.x + x, w->w.y, hl);
352 				if ((w->active != cur) || (!w->w.has_focus))
353 					win_attrset(ATTR_DLG_BUT_ITEXT);
354 				else
355 					win_attrset(ATTR_DLG_BUT_ATEXT);
356 				win_print(WWIN(w),w->w.x + x + 1, w->w.y, hl_pos);
357 				*(hl_pos - 2) = '&';
358 				x += strlen(hl_pos) + 1;
359 				hl_pos = NULL;
360 			}
361 			if ((w->active != cur) || (!w->w.has_focus))
362 				win_attrset(ATTR_DLG_BUT_INACTIVE);
363 			else
364 				win_attrset(ATTR_DLG_BUT_ACTIVE);
365 			win_print(WWIN(w),w->w.x + x, w->w.y, " ]");
366 			x += 4;
367 			*pos = '|';
368 			start = pos + 1;
369 			cur++;
370 		}
371 		if (*pos == '&') {
372 			*pos = '\0';
373 			pos++;
374 			hl_pos = pos + 1;
375 			hl[0] = *pos;
376 		}
377 	}
378 	*(pos-1) = '\0';
379 }
380 
button_handle_event(WID_BUTTON * w,WID_EVENT event,int ch)381 static BOOL button_handle_event(WID_BUTTON *w, WID_EVENT event, int ch)
382 {
383 	int cur;
384 	char *pos;
385 
386 	if (event == WID_GET_FOCUS) {
387 		if (ch < 0)
388 			w->active = w->cnt - 1;
389 		else
390 			w->active = 0;
391 		return EVENT_HANDLED;
392 	}
393 	if ((event == WID_KEY) && (w->w.handle_key)) {
394 		cur = w->w.handle_key((WIDGET *) w, ch);
395 		if (cur)
396 			return cur;
397 	}
398 	if ((ch < 256) && (isalpha(ch)))
399 		ch = toupper(ch);
400 	switch (ch) {
401 	  case KEY_UP:
402 	  case KEY_LEFT:
403 		if (event == WID_KEY) {
404 			w->active--;
405 			if (w->active < 0)
406 				return handle_focus ((WIDGET*)w, FOCUS_PREV, 0);
407 			button_paint(w);
408 		}
409 		break;
410 	  case KEY_DOWN:
411 	  case KEY_RIGHT:
412 	  case KEY_TAB:
413 		if (event == WID_KEY) {
414 			w->active++;
415 			if (w->active >= w->cnt)
416 				return handle_focus ((WIDGET*)w, FOCUS_NEXT, 0);
417 			button_paint(w);
418 		}
419 		break;
420 	  case KEY_ENTER:
421 	  case '\r':
422 		if (event == WID_KEY)
423 			return handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, EVENT_HANDLED);
424 		break;
425 	  default:
426 		cur = 0;
427 		for (pos = w->button; *pos; pos++) {
428 			if (*pos == '|')
429 				cur++;
430 			if (*pos == '&' && (toupper((int)*(pos+1)) == ch)) {
431 				w->active = cur;
432 				button_paint(w);
433 				return handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, EVENT_HANDLED);
434 			}
435 		}
436 		return 0;
437 	}
438 	return EVENT_HANDLED;
439 }
440 
button_get_size(WID_BUTTON * w,int * width,int * height)441 static void button_get_size(WID_BUTTON *w, int *width, int *height)
442 {
443 	char *pos;
444 	int hl_cnt = 0;
445 
446 	w->cnt = 1;
447 	for (pos = w->button; *pos; pos++) {
448 		if (*pos == '&')
449 			hl_cnt++;
450 		if (*pos == '|')
451 			w->cnt++;
452 	}
453 	*width = strlen(w->button) + 5 * w->cnt - 1 - hl_cnt;
454 	*height = 1;
455 }
456 
list_free(WID_LIST * w)457 static void list_free(WID_LIST *w)
458 {
459 	int i;
460 	for (i=0; i<w->cnt; i++)
461 		free (w->entries[i]);
462 	free (w->entries);
463 	if (w->title) free (w->title);
464 	free (w);
465 }
466 
list_paint(WID_LIST * w)467 static void list_paint(WID_LIST *w)
468 {
469 	int i,x,visible;
470 	char ch;
471 
472 	x = w->w.x+w->w.width-1;
473 	visible = w->w.height-2;
474 
475 	win_attrset(base_attr(w->w.d,ATTR_DLG_FRAME));
476 	win_box (WWIN(w),w->w.x, w->w.y, x, w->w.y+w->w.height-1);
477 	if (w->title) {
478 		if (strlen(w->title) > w->w.width-2) {
479 			ch = w->title[w->w.width-2];
480 			w->title[w->w.width-2] = '\0';
481 			win_print (WWIN(w),w->w.x+1, w->w.y, w->title);
482 			w->title[w->w.width-2] = ch;
483 		} else
484 			win_print (WWIN(w),w->w.x+1, w->w.y, w->title);
485 	}
486 
487 	if (w->first > 0)
488 		win_print (WWIN(w),x, w->w.y+1, "^");
489 	else
490 		win_print (WWIN(w),x, w->w.y+1, "-");
491 	if (w->first+visible < w->cnt)
492 		win_print (WWIN(w),x, w->w.y+w->w.height-2, "v");
493 	else
494 		win_print (WWIN(w),x, w->w.y+w->w.height-2, "-");
495 	if (visible>2) {
496 		i = 0;
497 		if (w->cnt > 1)
498 			i = w->cur*(visible-3)/(w->cnt-1);
499 		win_print (WWIN(w),x, w->w.y+i+2, "*");
500 	}
501 
502 	for (i=w->first; i<visible+w->first; i++) {
503 		storage[0] = '\0';
504 		if (i == w->cur) {
505 			if (w->w.has_focus)
506 				win_attrset(ATTR_DLG_LIST_FOCUS);
507 			else
508 				win_attrset(ATTR_DLG_LIST_NOFOCUS);
509 		} else
510 			win_attrset(base_attr(w->w.d,ATTR_DLG_FRAME));
511 		if (i < w->cnt) {
512 			strncpy (storage,w->entries[i],w->w.width-2);
513 			storage[w->w.width-2] = '\0';
514 		}
515 		for (x=strlen(storage); x<w->w.width-2; x++)
516 			storage[x] = ' ';
517 		storage[w->w.width-2] = '\0';
518 		win_print (WWIN(w),w->w.x+1, w->w.y+i-w->first+1, storage);
519 	}
520 }
521 
list_handle_event(WID_LIST * w,WID_EVENT event,int ch)522 static int list_handle_event(WID_LIST *w, WID_EVENT event, int ch)
523 {
524 	int i, old_cur;
525 
526 	if (event == WID_HOTKEY)
527 		return 0;
528 	if (event == WID_GET_FOCUS)
529 		return EVENT_HANDLED;
530 	if ((event == WID_KEY) && w->w.handle_key) {
531 		i = w->w.handle_key((WIDGET *) w, ch);
532 		if (i)
533 			return i;
534 	}
535 	old_cur = w->cur;
536 	switch (ch) {
537 		case KEY_UP:
538 			if (w->cur>0) w->cur--;
539 			break;
540 		case KEY_DOWN:
541 			if (w->cur<w->cnt-1) w->cur++;
542 			break;
543 		case KEY_PPAGE:
544 			w->cur -= w->w.height-3;
545 			if (w->cur<0) w->cur = 0;
546 			break;
547 		case KEY_NPAGE:
548 			w->cur += w->w.height-3;
549 			if (w->cur>=w->cnt)
550 				w->cur = w->cnt>0 ? w->cnt-1 : 0;
551 			break;
552 		case KEY_HOME:
553 			w->cur = 0;
554 			break;
555 #ifdef KEY_END
556 		case KEY_END:
557 			w->cur = w->cnt-1;
558 			break;
559 #endif
560 		case KEY_LEFT:
561 			return handle_focus((WIDGET*)w, FOCUS_PREV, 0);
562 		case KEY_RIGHT:
563 		case KEY_TAB:
564 			return handle_focus((WIDGET*)w, FOCUS_NEXT, 0);
565 		case KEY_ENTER:
566 		case '\r':
567 			return handle_focus((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
568 		default:
569 			return 0;
570 	}
571 	if (w->cur < w->first)
572 		w->first = w->cur;
573 	if (w->cur >= w->first + w->w.height-2)
574 		w->first = w->cur - w->w.height + 3;
575 	list_paint(w);
576 	if (w->sel_mode == WID_SEL_BROWSE && old_cur != w->cur)
577 		return handle_focus((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
578 
579 	return EVENT_HANDLED;
580 }
581 
list_get_size(WID_LIST * w,int * width,int * height)582 static void list_get_size(WID_LIST *w, int *width, int *height)
583 {
584 	if (*width > w->w.def_width)
585 		*width = w->w.def_width;
586 	if (*width < LIST_WIDTH_MIN)
587 		*width = LIST_WIDTH_MIN;
588 
589 	if (*height > w->w.def_height)
590 		*height = w->w.def_height;
591 	if (*height < LIST_HEIGHT_MIN)
592 		*height = LIST_HEIGHT_MIN;
593 }
594 
check_toggle_paint(WID_CHECK * w,BOOL toggle)595 static void check_toggle_paint(WID_CHECK *w, BOOL toggle)
596 {
597 	char *start, *pos, *hl_pos, hl[2], end;
598 	char marker[] = " x", help[STORAGELEN];
599 	int cur = 0, x, xx;
600 
601 	hl_pos = NULL;
602 	hl[1] = '\0';
603 	if (toggle)
604 		strcpy (help,"[ ] ");
605 	else {
606 		strcpy (help,"( ) ");
607 		marker[1] = '*';
608 	}
609 	help[w->w.width] = '\0';
610 	start = w->button;
611 
612 	pos = w->button-1;
613 	do {
614 		pos++;
615 		if ((*pos == '|') || (*pos == '\0')) {
616 			end = *pos;
617 			*pos = '\0';
618 			if ((w->active != cur) || (!w->w.has_focus))
619 				win_attrset(ATTR_DLG_BUT_ITEXT);
620 			else
621 				win_attrset(ATTR_DLG_BUT_ATEXT);
622 			help[1] = marker[BTST(w->selected,1<<cur)];
623 			strcpy (&help[4],start);
624 			x = strlen(start) + 4;
625 			if (hl_pos) {
626 				win_print(WWIN(w),w->w.x, w->w.y+cur, help);
627 				if ((w->active != cur) || (!w->w.has_focus))
628 					win_attrset(ATTR_DLG_BUT_IHOTKEY);
629 				else
630 					win_attrset(ATTR_DLG_BUT_AHOTKEY);
631 				win_print(WWIN(w),w->w.x + x, w->w.y+cur, hl);
632 				x++;
633 				if ((w->active != cur) || (!w->w.has_focus))
634 					win_attrset(ATTR_DLG_BUT_ITEXT);
635 				else
636 					win_attrset(ATTR_DLG_BUT_ATEXT);
637 				strcpy (&help[x],hl_pos);
638 				xx = x+strlen(hl_pos);
639 				if (xx != w->w.width)
640 					memset (&help[xx],' ',w->w.width-xx);
641 				win_print(WWIN(w),w->w.x + x, w->w.y+cur, &help[x]);
642 				*(hl_pos - 2) = '&';
643 				hl_pos = NULL;
644 			} else {
645 				if (x != w->w.width)
646 					memset (&help[x],' ',w->w.width-x);
647 				win_print(WWIN(w),w->w.x, w->w.y+cur, help);
648 			}
649 			*pos = end;
650 			start = pos + 1;
651 			cur++;
652 		} else if (*pos == '&') {
653 			*pos = '\0';
654 			pos++;
655 			hl_pos = pos + 1;
656 			hl[0] = *pos;
657 		}
658 	} while (*pos);
659 }
660 
check_toggle_handle_event(WID_CHECK * w,WID_EVENT event,int ch,BOOL toggle)661 static BOOL check_toggle_handle_event(WID_CHECK *w, WID_EVENT event,
662 									  int ch, BOOL toggle)
663 {
664 	static WID_EVENT last = WID_KEY;
665 	int cur;
666 	char *pos;
667 
668 	if (event == WID_GET_FOCUS) {
669 		if (last != WID_HOTKEY) {		/* active entry was already set */
670 			if (ch < 0)
671 				w->active = w->cnt - 1;
672 			else
673 				w->active = 0;
674 		}
675 		return EVENT_HANDLED;
676 	}
677 	last = event;
678 	if ((event == WID_KEY) && (w->w.handle_key)) {
679 		cur = w->w.handle_key((WIDGET *) w, ch);
680 		if (cur)
681 			return cur;
682 	}
683 	if ((ch < 256) && (isalpha(ch)))
684 		ch = toupper(ch);
685 	switch (ch) {
686 	  case KEY_UP:
687 	  case KEY_LEFT:
688 		if (event == WID_KEY) {
689 			w->active--;
690 			if (w->active < 0)
691 				return handle_focus ((WIDGET*)w, FOCUS_PREV, 0);
692 			check_toggle_paint(w,toggle);
693 		}
694 		break;
695 	  case KEY_DOWN:
696 	  case KEY_RIGHT:
697 	  case KEY_TAB:
698 		if (event == WID_KEY) {
699 			w->active++;
700 			if (w->active >= w->cnt)
701 				return handle_focus ((WIDGET*)w, FOCUS_NEXT, 0);
702 			check_toggle_paint(w,toggle);
703 		}
704 		break;
705 	  case KEY_ENTER:
706 	  case '\r':
707 		if (event == WID_KEY) {
708 			cur = handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, 0);
709 			if (cur && cur!=FOCUS_ACTIVATE && cur!=FOCUS_DONT)
710 				return cur;
711 			if (toggle)
712 				w->selected ^= 1<<w->active;
713 			else
714 				w->selected = 1<<w->active;
715 			check_toggle_paint(w,toggle);
716 		}
717 		break;
718 	  default:
719 		cur = 0;
720 		for (pos = w->button; *pos; pos++) {
721 			if (*pos == '|')
722 				cur++;
723 			if (*pos == '&' && (toupper((int)*(pos+1)) == ch)) {
724 				w->active = cur;
725 				check_toggle_paint(w,toggle);
726 				cur = handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
727 				if (cur!=FOCUS_ACTIVATE && cur!=FOCUS_DONT)
728 					return cur;
729 				if (toggle)
730 					w->selected ^= 1<<w->active;
731 				else
732 					w->selected = 1<<w->active;
733 				check_toggle_paint(w,toggle);
734 				return cur;
735 			}
736 		}
737 		return 0;
738 	}
739 	return EVENT_HANDLED;
740 }
741 
check_free(WID_CHECK * w)742 static void check_free(WID_CHECK *w)
743 {
744 	free(w->button);
745 	free(w);
746 }
747 
check_paint(WID_CHECK * w)748 static void check_paint(WID_CHECK *w)
749 {
750 	check_toggle_paint(w, 0);
751 }
752 
check_handle_event(WID_CHECK * w,WID_EVENT event,int ch)753 static BOOL check_handle_event(WID_CHECK *w, WID_EVENT event, int ch)
754 {
755 	return check_toggle_handle_event(w, event, ch, 0);
756 }
757 
check_get_size(WID_CHECK * w,int * width,int * height)758 static void check_get_size(WID_CHECK *w, int *width, int *height)
759 {
760 	char *pos;
761 	int x = 0, hl_cnt = 0;
762 
763 	*width = 0;
764 	*height = 0;
765 	w->cnt = 0;
766 	for (pos = w->button; *pos; pos++) {
767 		if (*pos == '&')
768 			hl_cnt++;
769 		if (*pos == '|') {
770 			w->cnt++;
771 			(*height)++;
772 			x += 4 - hl_cnt;
773 			if (x > *width)
774 				*width = x;
775 			hl_cnt = 0;
776 			x = -1;
777 		}
778 		x++;
779 	}
780 	w->cnt++;
781 	(*height)++;
782 	x += 4 - hl_cnt;
783 	if (x > *width)
784 		*width = x;
785 }
786 
toggle_free(WID_TOGGLE * w)787 static void toggle_free(WID_TOGGLE *w)
788 {
789 	free(w->button);
790 	free(w);
791 }
792 
toggle_paint(WID_TOGGLE * w)793 static void toggle_paint(WID_TOGGLE *w)
794 {
795 	check_toggle_paint((WID_CHECK *) w, 1);
796 }
797 
toggle_handle_event(WID_TOGGLE * w,WID_EVENT event,int ch)798 static BOOL toggle_handle_event(WID_TOGGLE *w, WID_EVENT event, int ch)
799 {
800 	return check_toggle_handle_event((WID_CHECK *) w, event, ch, 1);
801 }
802 
toggle_get_size(WID_TOGGLE * w,int * width,int * height)803 static void toggle_get_size(WID_TOGGLE *w, int *width, int *height)
804 {
805 	check_get_size((WID_CHECK *) w, width, height);
806 }
807 
colorsel_free(WID_COLORSEL * w)808 static void colorsel_free(WID_COLORSEL *w)
809 {
810 	free(w);
811 }
812 
colorsel_paint(WID_COLORSEL * w)813 static void colorsel_paint(WID_COLORSEL *w)
814 {
815 	int y = w->w.y, x = w->w.x;
816 	int act_x = (w->active & COLOR_BMASK) >> COLOR_BSHIFT;
817 	int act_y = (w->active & COLOR_FMASK) >> COLOR_FSHIFT;
818 	ATTRS border[COLOR_CNT+2][COLOR_CNT*3+2], b[12], attr;
819 
820 	win_attrset(base_attr(w->w.d, ATTR_DLG_FRAME));
821 	win_box (WWIN(w), w->w.x, w->w.y, w->w.x+COLOR_CNT*3+1, w->w.y+COLOR_CNT+1);
822 
823 	attr = (win_get_theme_color(ATTR_DLG_FRAME) & COLOR_BMASK) >> COLOR_BSHIFT;
824 	for (x=0; x<COLOR_CNT*3+2; x++)
825 		border[0][x] = border[COLOR_CNT+1][x] = attr;
826 	for (y=1; y<COLOR_CNT+1; y++)
827 		border[y][0] = border[y][COLOR_CNT*3+1] = attr;
828 
829 	for (y=0; y<COLOR_CNT; y++) {
830 		for (x=0; x<COLOR_CNT; x++) {
831 			border[y+1][x*3+1] = border[y+1][x*3+2] = border[y+1][x*3+3] = x;
832 			win_set_color ((x << COLOR_BSHIFT) + (y << COLOR_FSHIFT));
833 			win_print (WWIN(w),w->w.x+x*3+1, w->w.y+y+1, " X ");
834 		}
835 	}
836 	{
837 		ATTRS hotkey = w->w.has_focus ? ATTR_DLG_BUT_AHOTKEY:ATTR_DLG_BUT_IHOTKEY;
838 		ATTRS text = w->w.has_focus ? ATTR_DLG_BUT_ATEXT:ATTR_DLG_BUT_ITEXT;
839 		char key[2] = " ";
840 		const char *pat[2] = {".......< h      h >",
841 						"..^h  hv"};
842 		int p, h = 0;
843 
844 		for (p=0; p<2; p++) {
845 			for (x=0; x<strlen(pat[p]); x++) {
846 				if (pat[p][x] != '.') {
847 					border[x*p][x*(1-p)] =
848 						(win_get_theme_color(text) & COLOR_BMASK) >> COLOR_BSHIFT;
849 					win_attrset (text);
850 					key[0] = pat[p][x];
851 					if (pat[p][x] == 'h') {
852 						if (w->hkeys[h]) {
853 							border[x*p][x*(1-p)] =
854 								(win_get_theme_color(hotkey) & COLOR_BMASK) >> COLOR_BSHIFT;
855 							win_attrset (hotkey);
856 							key[0] = w->hkeys[h];
857 						}
858 						h++;
859 					}
860 					win_print (WWIN(w), w->w.x+x*(1-p), w->w.y+x*p, key);
861 				}
862 			}
863 		}
864 	}
865 
866 	for (x=0; x<5; x++) {
867 		b[x] = border[act_y][act_x*3+x];
868 		b[10-x] = border[act_y+2][act_x*3+x];
869 	}
870 	b[5] = border[act_y+1][act_x*3+4];
871 	b[11] = border[act_y+1][act_x*3];
872 
873 	win_set_forground (COLOR_BLACK_F);
874 	win_box_color (WWIN(w),w->w.x+act_x*3, w->w.y+act_y,
875 				   w->w.x+act_x*3+4, w->w.y+act_y+2, b);
876 }
877 
colorsel_handle_event(WID_COLORSEL * w,WID_EVENT event,int ch)878 static int colorsel_handle_event(WID_COLORSEL *w, WID_EVENT event, int ch)
879 {
880 	int act_x = (w->active & COLOR_BMASK) >> COLOR_BSHIFT;
881 	int act_y = (w->active & COLOR_FMASK) >> COLOR_FSHIFT;
882 	int i, old_act_x = act_x, old_act_y = act_y;
883 
884 	if (event == WID_GET_FOCUS)
885 		return EVENT_HANDLED;
886 	if (event == WID_KEY && w->w.handle_key) {
887 		i = w->w.handle_key((WIDGET *) w, ch);
888 		if (i)
889 			return i;
890 	}
891 	if (ch < 256 && isalpha(ch))
892 		ch = toupper(ch);
893 	switch (ch) {
894 		case KEY_UP:
895 			if (event == WID_KEY && act_y>0)
896 				act_y--;
897 			break;
898 		case KEY_LEFT:
899 			if (event == WID_KEY && act_x>0)
900 				act_x--;
901 			break;
902 		case KEY_DOWN:
903 			if (event == WID_KEY && act_y<COLOR_CNT-1)
904 				act_y++;
905 			break;
906 		case KEY_RIGHT:
907 			if (event == WID_KEY && act_x<COLOR_CNT-1)
908 				act_x++;
909 			break;
910 		case KEY_ENTER:
911 		case '\r':
912 			if (event == WID_KEY)
913 				return handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
914 			break;
915 		case KEY_TAB:
916 			if (event == WID_KEY)
917 				return handle_focus ((WIDGET*)w, FOCUS_NEXT, 0);
918 			break;
919 		default:
920 			if (strchr (w->hkeys, ch)) {
921 				if (ch == w->hkeys[0])
922 					if (act_x>0) act_x--;
923 				if (ch == w->hkeys[1])
924 					if (act_x<COLOR_CNT-1) act_x++;
925 				if (ch == w->hkeys[2])
926 					if (act_y>0) act_y--;
927 				if (ch == w->hkeys[3])
928 					if (act_y<COLOR_CNT-1) act_y++;
929 				w->active = (act_x << COLOR_BSHIFT) + (act_y << COLOR_FSHIFT);
930 				colorsel_paint(w);
931 
932 				i = handle_focus ((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
933 				if (i != FOCUS_ACTIVATE && i != FOCUS_DONT)
934 					return i;
935 
936 				colorsel_paint(w);
937 				return i;
938 			}
939 			return 0;
940 	}
941 	w->active = (act_x << COLOR_BSHIFT) + (act_y << COLOR_FSHIFT);
942 	colorsel_paint (w);
943 	if (w->sel_mode == WID_SEL_BROWSE && (old_act_x != act_x || old_act_y != act_y))
944 		return handle_focus((WIDGET*)w, FOCUS_ACTIVATE, FOCUS_ACTIVATE);
945 
946 	return EVENT_HANDLED;
947 }
948 
colorsel_get_size(WID_COLORSEL * w,int * width,int * height)949 static void colorsel_get_size(WID_COLORSEL *w, int *width, int *height)
950 {
951 	*width = 26;
952 	*height = 10;
953 }
954 
dialog_add(DIALOG * d,WIDGET * w)955 static void dialog_add(DIALOG *d, WIDGET *w)
956 {
957 	d->widget = (WIDGET **) realloc(d->widget, (d->cnt + 1) * sizeof(WIDGET *));
958 	d->widget[d->cnt] = w;
959 	d->cnt++;
960 }
961 
widget_init(WIDGET * w,DIALOG * d,BOOL focus,int spacing)962 static void widget_init(WIDGET *w, DIALOG *d, BOOL focus, int spacing)
963 {
964 	w->x = w->y = w->width = w->height = 1;
965 	w->def_width = w->def_height = -1;
966 	w->spacing = spacing;
967 	w->can_focus = focus;
968 	w->has_focus = 0;
969 	w->d = d;
970 	w->handle_key = w->handle_focus = NULL;
971 	w->w_free = w->w_paint = NULL;
972 	w->w_handle_event = NULL;
973 	w->w_get_size = NULL;
974 	w->data = NULL;
975 }
976 
wid_label_add(DIALOG * d,int spacing,const char * msg)977 WIDGET *wid_label_add(DIALOG *d, int spacing, const char *msg)
978 {
979 	WID_LABEL *w = (WID_LABEL *) malloc(sizeof(WID_LABEL));
980 
981 	widget_init((WIDGET *) w, d, 0, spacing);
982 	w->w.type = TYPE_LABEL;
983 	w->w.w_free = (freeFunc) label_free;
984 	w->w.w_paint = (paintFunc) label_paint;
985 	w->w.w_handle_event = (handleEventFunc) label_handle_event;
986 	w->w.w_get_size = (getSizeFunc) label_get_size;
987 
988 	w->msg = strdup(msg);
989 	dialog_add(d, (WIDGET *) w);
990 	return (WIDGET *) w;
991 }
992 
wid_label_set_label(WID_LABEL * w,const char * label)993 void wid_label_set_label (WID_LABEL *w, const char *label)
994 {
995 	if (w->msg) free (w->msg);
996 	w->msg = strdup (label);
997 }
998 
wid_str_add(DIALOG * d,int spacing,const char * input,int length)999 WIDGET *wid_str_add(DIALOG *d, int spacing, const char *input, int length)
1000 {
1001 	int i;
1002 	WID_STR *w = (WID_STR *) malloc(sizeof(WID_STR));
1003 
1004 	widget_init((WIDGET *) w, d, 1, spacing);
1005 	w->w.type = TYPE_STR;
1006 	w->w.w_free = (freeFunc) str_free;
1007 	w->w.w_paint = (paintFunc) str_paint;
1008 	w->w.w_handle_event = (handleEventFunc) str_handle_event;
1009 	w->w.w_get_size = (getSizeFunc) str_get_size;
1010 
1011 	w->length = length;
1012 	w->w.def_width = STR_WIDTH_MAX;
1013 
1014 	w->input = (char *) malloc(length + 1);
1015 
1016 	i = MIN(strlen(input), length);
1017 	strncpy(w->input, input, i);
1018 	w->input[i] = '\0';
1019 	w->cur_pos = strlen(w->input);
1020 
1021 	dialog_add(d, (WIDGET *) w);
1022 	return (WIDGET *) w;
1023 }
1024 
wid_str_set_input(WID_STR * w,const char * input,int length)1025 void wid_str_set_input (WID_STR *w, const char *input, int length)
1026 {
1027 	if (length>=0) {
1028 		if (w->input) free (w->input);
1029 		if (length) w->input = (char *) malloc(length + 1);
1030 		w->length = length;
1031 	}
1032 	if (w->length == 0) {
1033 		w->input = NULL;
1034 		w->cur_pos = w->start = 0;
1035 	} else {
1036 		int i = MIN (strlen(input), w->length);
1037 		strncpy (w->input, input, i);
1038 		w->input[i] = '\0';
1039 		if (w->cur_pos > strlen(w->input))
1040 			w->cur_pos = strlen(w->input);
1041 
1042 		if (w->cur_pos < w->start)
1043 			w->start = w->cur_pos;
1044 		if (w->cur_pos >= w->start + w->w.width)
1045 			w->start = w->cur_pos - w->w.width + 1;
1046 	}
1047 }
1048 
wid_int_add(DIALOG * d,int spacing,int value,int length)1049 WIDGET *wid_int_add(DIALOG *d, int spacing, int value, int length)
1050 {
1051 	WID_INT *w = (WID_INT *) malloc(sizeof(WID_INT));
1052 
1053 	widget_init((WIDGET *) w, d, 1, spacing);
1054 	w->w.type = TYPE_INT;
1055 	w->w.w_free = (freeFunc) int_free;
1056 	w->w.w_paint = (paintFunc) int_paint;
1057 	w->w.w_handle_event = (handleEventFunc) int_handle_event;
1058 	w->w.w_get_size = (getSizeFunc) int_get_size;
1059 
1060 	w->start = 0;
1061 	w->length = length;
1062 	w->w.def_width = INT_WIDTH_MAX;
1063 
1064 	w->input = (char *) malloc(w->length + 1);
1065 	sprintf(w->input, "%d", value);
1066 	w->cur_pos = strlen(w->input);
1067 
1068 	dialog_add(d, (WIDGET *) w);
1069 	return (WIDGET *) w;
1070 }
1071 
wid_int_set_input(WID_INT * w,int value,int length)1072 void wid_int_set_input (WID_INT *w, int value, int length)
1073 {
1074 	char val[20];
1075 	sprintf(val, "%d", value);
1076 	wid_str_set_input ((WID_STR*)w, val,length);
1077 }
1078 
wid_button_add(DIALOG * d,int spacing,const char * button,int active)1079 WIDGET *wid_button_add(DIALOG *d, int spacing, const char *button, int active)
1080 {
1081 	WID_BUTTON *w = (WID_BUTTON *) malloc(sizeof(WID_BUTTON));
1082 
1083 	widget_init((WIDGET *) w, d, 1, spacing);
1084 	w->w.type = TYPE_BUTTON;
1085 	w->w.w_free = (freeFunc) button_free;
1086 	w->w.w_paint = (paintFunc) button_paint;
1087 	w->w.w_handle_event = (handleEventFunc) button_handle_event;
1088 	w->w.w_get_size = (getSizeFunc) button_get_size;
1089 
1090 	w->button = strdup(button);
1091 	w->active = active;
1092 	dialog_add(d, (WIDGET *) w);
1093 	return (WIDGET *) w;
1094 }
1095 
wid_list_add(DIALOG * d,int spacing,const char ** entries,int cnt)1096 WIDGET *wid_list_add(DIALOG *d, int spacing, const char **entries, int cnt)
1097 {
1098 	WID_LIST *w = (WID_LIST *) malloc(sizeof(WID_LIST));
1099 
1100 	widget_init((WIDGET *) w, d, 1, spacing);
1101 	w->w.type = TYPE_LIST;
1102 
1103 	w->title = NULL;
1104 	w->entries = NULL;
1105 	w->sel_mode = WID_SEL_SINGLE;
1106 	w->cnt = w->cur = w->first = 0;
1107 	w->w.def_width = LIST_WIDTH_DEFAULT;
1108 	w->w.def_height = LIST_HEIGHT_DEFAULT;
1109 	wid_list_set_entries (w,entries,-1,cnt);
1110 
1111 	w->w.w_free = (freeFunc) list_free;
1112 	w->w.w_paint = (paintFunc) list_paint;
1113 	w->w.w_handle_event = (handleEventFunc) list_handle_event;
1114 	w->w.w_get_size = (getSizeFunc) list_get_size;
1115 
1116 	dialog_add(d, (WIDGET *) w);
1117 	return (WIDGET *) w;
1118 }
1119 
wid_list_set_title(WID_LIST * w,const char * title)1120 void wid_list_set_title (WID_LIST *w, const char *title)
1121 {
1122 	if (w->title) free (w->title);
1123 	w->title = strdup (title);
1124 }
1125 
wid_list_set_entries(WID_LIST * w,const char ** entries,int cur,int cnt)1126 void wid_list_set_entries (WID_LIST *w, const char **entries, int cur, int cnt)
1127 {
1128 	int i;
1129 
1130 	if (w->entries) {
1131 		for (i=0; i<w->cnt; i++)
1132 			free (w->entries[i]);
1133 		free (w->entries);
1134 		w->entries = NULL;
1135 	}
1136 	w->cnt = cnt;
1137 	if (cur>=0) {
1138 		w->cur = cur;
1139 		w->first = cur>0 ? cur-1:0;
1140 	}
1141 	if (w->cur >= cnt) w->cur = cnt>0 ? cnt-1:0;
1142 	if (w->first > w->cur) w->first = w->cur>0 ? w->cur-1:0;
1143 
1144 	if (cnt>0) {
1145 		w->entries = (char **) malloc(sizeof(char*) * cnt);
1146 		for (i=0; i<cnt; i++)
1147 			w->entries[i] = strdup(entries[i]);
1148 	}
1149 }
1150 
wid_list_set_active(WID_LIST * w,int cur)1151 void wid_list_set_active (WID_LIST *w, int cur)
1152 {
1153 	if (cur>=0 && cur < w->cnt) {
1154 		w->cur = cur;
1155 
1156 		if (w->cur < w->first)
1157 			w->first = w->cur;
1158 		if (w->cur >= w->first + w->w.height-2)
1159 			w->first = w->cur - w->w.height + 3;
1160 	}
1161 }
1162 
wid_list_set_selection_mode(WID_LIST * w,WID_SEL_MODE mode)1163 void wid_list_set_selection_mode (WID_LIST *w, WID_SEL_MODE mode)
1164 {
1165 	w->sel_mode = mode;
1166 }
1167 
wid_check_add(DIALOG * d,int spacing,const char * button,int active,int selected)1168 WIDGET *wid_check_add(DIALOG *d, int spacing, const char *button, int active, int selected)
1169 {
1170 	WID_CHECK *w = (WID_CHECK *) malloc(sizeof(WID_CHECK));
1171 
1172 	widget_init((WIDGET *) w, d, 1, spacing);
1173 	w->w.type = TYPE_CHECK;
1174 	w->w.w_free = (freeFunc) check_free;
1175 	w->w.w_paint = (paintFunc) check_paint;
1176 	w->w.w_handle_event = (handleEventFunc) check_handle_event;
1177 	w->w.w_get_size = (getSizeFunc) check_get_size;
1178 
1179 	w->button = strdup(button);
1180 	w->active = active;
1181 	w->selected = selected;
1182 	dialog_add(d, (WIDGET *) w);
1183 	return (WIDGET *) w;
1184 }
1185 
wid_check_set_selected(WID_CHECK * w,int selected)1186 void wid_check_set_selected(WID_CHECK *w, int selected)
1187 {
1188 	w->selected = selected;
1189 }
1190 
wid_toggle_add(DIALOG * d,int spacing,const char * button,int active,int selected)1191 WIDGET *wid_toggle_add(DIALOG *d, int spacing, const char *button, int active, int selected)
1192 {
1193 	WID_TOGGLE *w = (WID_TOGGLE *) malloc(sizeof(WID_TOGGLE));
1194 
1195 	widget_init((WIDGET *) w, d, 1, spacing);
1196 	w->w.type = TYPE_TOGGLE;
1197 	w->w.w_free = (freeFunc) toggle_free;
1198 	w->w.w_paint = (paintFunc) toggle_paint;
1199 	w->w.w_handle_event = (handleEventFunc) toggle_handle_event;
1200 	w->w.w_get_size = (getSizeFunc) toggle_get_size;
1201 
1202 	w->button = strdup(button);
1203 	w->active = active;
1204 	w->selected = selected;
1205 	dialog_add(d, (WIDGET *) w);
1206 	return (WIDGET *) w;
1207 }
1208 
wid_toggle_set_selected(WID_TOGGLE * w,int selected)1209 void wid_toggle_set_selected(WID_TOGGLE *w, int selected)
1210 {
1211 	w->selected = selected;
1212 }
1213 
wid_colorsel_add(DIALOG * d,int spacing,const char * hotkeys,int active)1214 WIDGET *wid_colorsel_add(DIALOG *d, int spacing, const char *hotkeys, int active)
1215 {
1216 	WID_COLORSEL *w = (WID_COLORSEL *) malloc(sizeof(WID_COLORSEL));
1217 	int i;
1218 
1219 	widget_init((WIDGET *) w, d, 1, spacing);
1220 	w->w.type = TYPE_COLORSEL;
1221 	w->w.w_free = (freeFunc) colorsel_free;
1222 	w->w.w_paint = (paintFunc) colorsel_paint;
1223 	w->w.w_handle_event = (handleEventFunc) colorsel_handle_event;
1224 	w->w.w_get_size = (getSizeFunc) colorsel_get_size;
1225 
1226 	w->active = active;
1227 	if (hotkeys && *hotkeys) {
1228 		strcpy (w->hkeys, hotkeys);
1229 		w->hkeys[4] = '\0';
1230 		for (i=0; i<strlen(w->hkeys); i++)
1231 			w->hkeys[i] = toupper(w->hkeys[i]);
1232 	} else
1233 		memset (&w->hkeys, 0, 5);
1234 	w->sel_mode = WID_SEL_SINGLE;
1235 	dialog_add(d, (WIDGET *) w);
1236 	return (WIDGET *) w;
1237 }
1238 
wid_colorsel_set_active(WID_COLORSEL * w,int active)1239 void wid_colorsel_set_active(WID_COLORSEL *w, int active)
1240 {
1241 	w->active = active;
1242 }
1243 
wid_set_size(WIDGET * w,int width,int height)1244 void wid_set_size (WIDGET *w, int width, int height)
1245 {
1246 	if (width>=0) w->def_width = width;
1247 	if (height>=0) w->def_height = height;
1248 }
1249 
wid_set_func(WIDGET * w,handleKeyFunc key,handleFocusFunc focus,void * data)1250 void wid_set_func(WIDGET *w, handleKeyFunc key, handleFocusFunc focus,
1251 				  void *data)
1252 {
1253 	w->handle_key = key;
1254 	w->handle_focus = focus;
1255 	w->data = data;
1256 }
1257 
wid_repaint(WIDGET * w)1258 void wid_repaint (WIDGET *w)
1259 {
1260 	if (w->w_paint) w->w_paint (w);
1261 }
1262 
dialog_repaint(MWINDOW * win)1263 BOOL dialog_repaint(MWINDOW *win)
1264 {
1265 	DIALOG *d = (DIALOG *) win->data;
1266 	int i = 0;
1267 
1268 	win_attrset(base_attr(d,ATTR_DLG_FRAME));
1269 	win_clear(win);
1270 	for (i = 0; i < d->cnt; i++)
1271 		d->widget[i]->w_paint(d->widget[i]);
1272 
1273 	return 1;
1274 }
1275 
dialog_close(DIALOG * d)1276 void dialog_close(DIALOG *d)
1277 {
1278 	int i;
1279 
1280 	for (i = 0; i < d->cnt; i++)
1281 		d->widget[i]->w_free(d->widget[i]);
1282 	if (d->cnt)
1283 		free(d->widget);
1284 	win_close(d->win);
1285 	free(d);
1286 }
1287 
dialog_handle_key(MWINDOW * win,int ch)1288 static BOOL dialog_handle_key(MWINDOW *win, int ch)
1289 {
1290 	DIALOG *d = (DIALOG *) win->data;
1291 	int ret, i;
1292 
1293 	/* Handle keys common for all widgets here */
1294 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
1295 	if (ch == KEY_ESC) {
1296 		dialog_close(d);
1297 		return 1;
1298 	}
1299 #endif
1300 
1301 	ret = d->widget[d->active]->w_handle_event(d->widget[d->active], WID_KEY,ch);
1302 	if (!ret) {
1303 		/* KEY not handled -> try the hotkeys */
1304 		for (i = 0; !ret && i < d->cnt; i++) {
1305 			ret = d->widget[i]->w_handle_event(d->widget[i], WID_HOTKEY, ch);
1306 			if (ret == FOCUS_ACTIVATE) {
1307 				d->widget[d->active]->has_focus = 0;
1308 				d->widget[i]->has_focus = 1;
1309 				d->active = i;
1310 				d->widget[d->active]->w_handle_event(d->widget[d->active],
1311 													 WID_GET_FOCUS, ret);
1312 				dialog_repaint(win);
1313 			}
1314 		}
1315 	} else if (ret < EVENT_HANDLED) {
1316 		/* FOCUS_{NEXT|PREV} */
1317 		d->widget[d->active]->has_focus = 0;
1318 		do {
1319 			d->active += ret;
1320 			if (d->active < 0)
1321 				d->active = d->cnt - 1;
1322 			else if (d->active >= d->cnt)
1323 				d->active = 0;
1324 		} while (!d->widget[d->active]->can_focus);
1325 		d->widget[d->active]->has_focus = 1;
1326 		d->widget[d->active]->w_handle_event(d->widget[d->active],
1327 											 WID_GET_FOCUS, ret);
1328 		dialog_repaint(win);
1329 	}
1330 	return !!ret;
1331 }
1332 
1333 /* Return size of column of widgets which starts at widget start */
column_dim(DIALOG * d,int start,int * width,int * height)1334 static void column_dim (DIALOG *d, int start, int *width, int *height)
1335 {
1336 	int i;
1337 
1338 	*width = d->widget[start]->width;
1339 	i = start+1;
1340 	while (i<d->cnt && d->widget[i]->spacing>0) {
1341 		if (d->widget[i]->width > *width)
1342 			*width = d->widget[i]->width;
1343 		i++;
1344 	};
1345 	*height = d->widget[i-1]->y+d->widget[i-1]->height-d->widget[start]->y;
1346 }
1347 
1348 /* Layout the dialog widgets and return the calculated size and position
1349    of the dialog window (which must be still opened).
1350    initial = true: the the focus of the widgets is changed */
dialog_layout(DIALOG * d,int initial,int * w_x,int * w_y,int * w_width,int * w_height)1351 static void dialog_layout(DIALOG *d, int initial,
1352 						  int *w_x, int *w_y, int *w_width, int *w_height)
1353 {
1354 	int m_y, m_width = 0, m_height = 0, i, x, y, width, height;
1355 	int spacing, c_spacing = 1, c_height, c_width;
1356 	BOOL focus = 1;
1357 
1358 	i = 0;
1359 	width = 1;
1360 	height = c_width = c_height = m_height = m_width = 0;
1361 	while (i < d->cnt) {		/* Init all widgets(position and focus) */
1362 		spacing = d->widget[i]->spacing;
1363 		if (i==0 || spacing<0)
1364 			c_spacing = (spacing == 0 ? 1:abs(spacing));
1365 
1366 		x = 999; y = 999;
1367 		d->widget[i]->w_get_size(d->widget[i], &x, &y);
1368 		d->widget[i]->width = x;
1369 		d->widget[i]->height = y;
1370 
1371 		if (spacing>0) {
1372 			c_height += spacing-1;
1373 			d->widget[i]->x = width;
1374 			d->widget[i]->y = m_height+c_height;
1375 			if (x>c_width) c_width = x;
1376 		} else if (spacing==0) {
1377 			if (c_height>height) height = c_height;
1378 			c_height = c_spacing-1;
1379 			width += c_width + 1;
1380 
1381 			d->widget[i]->x = width;
1382 			d->widget[i]->y = m_height+c_height;
1383 
1384 			c_width = x;
1385 		} else {
1386 			width += c_width + 1;
1387 			if (width > m_width) m_width = width;
1388 			if (c_height>height) height = c_height;
1389 			m_height += height;
1390 			c_height = -spacing-1;
1391 			height = 0;
1392 			width = 1;
1393 
1394 			d->widget[i]->x = width;
1395 			d->widget[i]->y = m_height+c_height;
1396 
1397 			c_width = x;
1398 		}
1399 		c_height += y;
1400 
1401 		if (initial) {
1402 			if (d->widget[i]->can_focus) {
1403 				d->widget[i]->has_focus = focus;
1404 				if (focus)
1405 					d->active = i;
1406 				focus = 0;
1407 			} else
1408 				d->widget[i]->has_focus = 0;
1409 		}
1410 		i++;
1411 	}
1412 	width += c_width+1;
1413 	if (width > m_width) m_width = width;
1414 	if (c_height>height) height = c_height;
1415 	m_height += height;
1416 
1417 	width = m_width;
1418 	height = m_height;
1419 	win_get_size_max(&m_y, &m_width, &m_height);
1420 	if (width > m_width-2 || height > m_height-2) {
1421 		/* preferred size of widgets was to big, try to reduce the size */
1422 		int dx = width-m_width+2, dy = height-m_height+2, free_x,
1423 			old_width = width, old_height = height,
1424 			i_start, m_c_height, m_c_height_old, c_height_old, c_width_old, m_x;
1425 
1426 		m_width = m_height = 0;
1427 		i = 0;
1428 		while (i < d->cnt) {		/* reinit all widget positions */
1429 			spacing = abs(d->widget[i]->spacing);
1430 			m_height += (spacing == 0 ? 0:spacing-1);
1431 			width = 1;
1432 
1433 			/* get height of highest column in row */
1434 			x = i;
1435 			do {
1436 				x++;
1437 			} while (x<d->cnt && d->widget[x]->spacing>=0);
1438 			if (x<d->cnt)
1439 				m_c_height_old = d->widget[x]->y+d->widget[x]->spacing - d->widget[i]->y+1;
1440 			else
1441 				m_c_height_old =  old_height - d->widget[i]->y;
1442 
1443 			/* get max x coordinate of last column in row */
1444 			m_x = 0;
1445 			do {
1446 				x--;
1447 				if ((d->widget[x]->x+d->widget[x]->width - 1) > m_x)
1448 					m_x = d->widget[x]->x+d->widget[x]->width - 1;
1449 			} while (x>0 && d->widget[x]->spacing>0);
1450 			/* free space on right side of last column in row */
1451 			free_x = old_width-1-m_x;
1452 			m_c_height = 0;
1453 
1454 			/* for all columns in one row */
1455 			do {
1456 				c_height = c_width = 0;
1457 				i_start = i;
1458 				column_dim (d, i_start, &c_width_old, &c_height_old);
1459 				/* for all widgets in one column */
1460 				do {
1461 					x = d->widget[i]->width - dx + free_x;
1462 					y = d->widget[i]->height - dy + m_c_height_old-c_height_old;
1463 					d->widget[i]->w_get_size(d->widget[i], &x, &y);
1464 
1465 					if (i>0 && d->widget[i]->spacing > 0)
1466 						c_height += d->widget[i]->spacing-1;
1467 					d->widget[i]->x = width;
1468 					d->widget[i]->y = m_height + c_height;
1469 					d->widget[i]->width = x;
1470 					d->widget[i]->height = y;
1471 					if (x>c_width) c_width = x;
1472 					c_height += y;
1473 
1474 					y = c_width_old;
1475 					column_dim (d, i_start, &c_width_old, &c_height_old);
1476 					free_x += y - c_width_old;
1477 
1478 					i++;
1479 				} while ((i < d->cnt) && (d->widget[i]->spacing > 0));
1480 
1481 				width += c_width +1;
1482 				if (c_height > m_c_height)
1483 					m_c_height = c_height;
1484 			} while ((i < d->cnt) && (d->widget[i]->spacing >= 0));
1485 			if (width > m_width)
1486 				m_width = width;
1487 			m_height += m_c_height;
1488 		}
1489 		width = m_width;
1490 		height = m_height;
1491 		win_get_size_max(&m_y, &m_width, &m_height);
1492 	}
1493 	m_width -= 2;
1494 	m_height -= 2;
1495 
1496 	*w_x = (m_width - width) / 2 + 1;
1497 	if (*w_x < 1)
1498 		*w_x = 1;
1499 	*w_y = (m_height - height) / 2 + m_y +1;
1500 	if (*w_y <= m_y)
1501 		*w_y = m_y+1;
1502 	*w_width = (width>m_width ? m_width:width);
1503 	*w_height = (height>m_height ? m_height:height);
1504 }
1505 
dialog_handle_resize(MWINDOW * win,int dx,int dy)1506 static void dialog_handle_resize(MWINDOW *win, int dx, int dy)
1507 {
1508 	DIALOG *d = (DIALOG *) win->data;
1509 	int x,y,width,height;
1510 
1511 	dialog_layout (d,0,&x,&y,&width,&height);
1512 	win->x = x;
1513 	win->y = y;
1514 	win->width = width;
1515 	win->height = height;
1516 }
1517 
dialog_open(DIALOG * d,const char * title)1518 void dialog_open(DIALOG *d, const char *title)
1519 {
1520 	int x,y,width,height;
1521 
1522 	dialog_layout (d,1,&x,&y,&width,&height);
1523 
1524 	if (!title)
1525 		title = "Dialog";
1526 	win_open(x, y, width, height, 1, title, base_attr(d,ATTR_DLG_FRAME));
1527 	win_set_repaint(dialog_repaint);
1528 	win_set_handle_key(dialog_handle_key);
1529 	win_set_resize(0, dialog_handle_resize);
1530 	win_set_data((void *)d);
1531 
1532 	d->win = win_get_window();
1533 	dialog_repaint(d->win);
1534 }
1535 
1536 /* set attribute which is used for DLG_FRAME and DLG_LABEL,
1537    works only before dialog_open() */
dialog_set_attr(DIALOG * d,ATTRS attrs)1538 void dialog_set_attr (DIALOG *d, ATTRS attrs)
1539 {
1540 	d->attrs = attrs;
1541 }
1542 
dialog_new(void)1543 DIALOG *dialog_new(void)
1544 {
1545 	DIALOG *d = (DIALOG *) malloc(sizeof(DIALOG));
1546 
1547 	d->active = 0;
1548 	d->cnt = 0;
1549 	d->attrs = ATTR_NONE;
1550 	d->win = NULL;
1551 	d->widget = NULL;
1552 	return d;
1553 }
1554 
1555 /* ex:set ts=4: */
1556