1 /* ---------------------------------------------------------------------- *
2 * dialbox.c
3 * This file is part of lincity.
4 * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
5 * Portions copyright (c) Corey Keasling, 2001.
6 * ---------------------------------------------------------------------- */
7
8 #include "lcconfig.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <stdarg.h> /* XXX: WCK: What does configure need to know? */
13 #include "lcstring.h"
14 #include "screen.h"
15 #include "geometry.h"
16 #include "dialbox.h"
17 #include "mouse.h"
18 #include "lclib.h"
19
20 static Dialog_Box db_entry[MAX_DBOX_ENTRIES];
21
22 static Rect dialog_window; /* Describes position of window on screen */
23 static Rect text_window; /* Describes position of text area on screen */
24
25 static Rect db_rect[MAX_DBOX_ENTRIES]; /* region of each line/button */
26 // static Rect button_rect[MAX_DBOX_ENTRIES]; /* click area for buttons, lines */
27 // static Rect line_rect[MAX_DBOX_ENTRIES]; /* offset from text_window */
28
29 static Mouse_Handle * main_handle;
30 static Mouse_Handle * text_handle;
31
32 static int dbn; /* number of dbox entries */
33 static int bn; /* number of buttons */
34 static int ln; /* number of lines */
35
36 static int db_longest_button; /* total width of all buttons, pixels */
37 static int db_longest_line; /* pixel width of longest line */
38
39 static int bs; /* button spacing */
40 static int bse; /* extra spacing, to be added at beginning and end of line */
41
42 static int color;
43
44 static short db_up = 0;
45 static int db_return_value;
46
47 char * db_screen_buffer; /* hold the screen we overwrite */
48 char db_screen_fresh; /* does the buffer hold information? */
49
50 /* Mouse handling routines: main_handler() and text_handler()
51 main_handler handles the main dialog window: the text area and border.
52 Clicks in the border are useless and ignored; text_handler takes the
53 interesting ones
54 */
55 void
main_handler(int x,int y,int button)56 main_handler(int x, int y, int button)
57 {
58
59 }
60
61 void
text_handler(int x,int y,int button)62 text_handler(int x, int y, int button)
63 {
64 int i;
65 for (i = 0; i < dbn; i++) {
66 if (mouse_in_rect(&db_rect[i], x, y) && db_entry[i].retval)
67 dialog_close(db_entry[i].retval);
68 }
69
70
71 }
72
73 /* Keypress handler: dialog_key_handler()
74 Iterate through possible hotkeys, returning if key matches.
75 */
76
77 void
dialog_key_handler(int key)78 dialog_key_handler (int key)
79 {
80 int i;
81
82 if (key == 0)
83 return;
84
85 /* CR, LF, and space all activate default button, type 2 */
86
87 if (key == 10 || key == 13 || key == 32) {
88 for (i = 0; i < dbn; i++)
89 if (db_entry[i].type == 2) {
90 dialog_close(db_entry[i].retval);
91 return;
92 }
93 } else {
94 for (i = 0; i < dbn; i++) {
95 if (key == db_entry[i].retval) {
96 dialog_close(db_entry[i].retval);
97 return;
98 }
99 }
100 }
101 }
102
103
104 int
dialog_box(int arg_color,int argc,...)105 dialog_box(int arg_color, int argc, ...)
106 {
107 va_list ap;
108 int i;
109 int db_last_button = -1;
110 int key;
111 char * working_str;
112
113 /* Try the locks */
114 if (db_up) {
115 printf("Already have a dialog box on screen!\n");
116 exit(-1); /* GCS: I guess this must be a critical bug. */
117 } else {
118 db_up = 1; /* XXX: Need to reconcile these - don't need both flags */
119 db_flag = 1;
120 }
121
122 bn = 0; ln = 0; dbn = 0;
123 db_longest_button = 0; db_longest_line = 0;
124 bs = 0; bse = 0;
125 color = arg_color;
126 db_screen_fresh = 0;
127
128 va_start(ap, argc);
129
130 /* For each argument pair, get the arguments, determine line or button,
131 calculate width/length, adjust total size accordingly, increment type
132 count. */
133
134 for (i = 0; i < argc; i++) {
135
136 if (dbn >= MAX_DBOX_ENTRIES) {
137 fprintf(stderr,"Too many buttons in dialog_box!\n"
138 "Tweak MAX_DBOX_ENTRIES\n");
139 exit(212);
140 }
141
142 db_entry[dbn].type = (short) va_arg(ap, int);
143 db_entry[dbn].retval = (short) va_arg(ap, int);
144
145 if (db_entry[dbn].type == 0) { /* Text strings: Chop a paragraph into
146 individual lines.*/
147 char * newline;
148 working_str = va_arg(ap, char *);
149 do {
150 newline = (char *)strchr(working_str,'\n');
151 if (newline) {
152 int linelen = newline - working_str;
153 db_entry[dbn].text = (char *)lcalloc(1 + linelen);
154 strncpy(db_entry[dbn].text,working_str,linelen);
155 db_entry[dbn].text[linelen] = '\0';
156 working_str = (newline + 1) != '\0' ? newline + 1 : NULL;
157 } else {
158 db_entry[dbn].text = (char *)lcalloc(1 + strlen(working_str));
159 strncpy(db_entry[dbn].text,working_str,strlen(working_str));
160 db_entry[dbn].text[strlen(working_str)] = '\0';
161 working_str = NULL;
162 }
163
164 db_entry[dbn].type = 0;
165 db_entry[dbn].retval = 0;
166
167 db_rect[dbn].w = (strlen(db_entry[dbn].text) * CHAR_WIDTH);
168 db_rect[dbn].h = CHAR_HEIGHT;
169 if (db_rect[dbn].w > db_longest_line)
170 db_longest_line = db_rect[dbn].w;
171
172 ln++;
173 dbn++;
174 } while ((working_str != NULL) && (strlen(working_str) >= 1));
175 } else {
176 db_entry[dbn].text = va_arg(ap, char *);
177 db_rect[dbn].w = ((strlen(db_entry[dbn].text) * CHAR_WIDTH)
178 + (BUTTON_BORDER * 2));
179 db_rect[dbn].h = (CHAR_HEIGHT + (BUTTON_BORDER * 2));
180
181 db_longest_button += db_rect[dbn].w;
182 bn++;
183 dbn++;
184 }
185 }
186
187 va_end(ap);
188
189 /* figure out how high and wide the box needs to be */
190 text_window.h =
191 ((ln * (CHAR_HEIGHT + DB_V_SPACE)) + BUTTON_HEIGHT + DB_V_SPACE);
192
193 if ((db_longest_button + (bn * BUTTON_MIN_SPACING)) >
194 (db_longest_line + LINE_MIN_SPACING)) {
195 text_window.w = (db_longest_button + (bn * BUTTON_MIN_SPACING));
196 } else {
197 text_window.w = (db_longest_line + LINE_MIN_SPACING);
198 }
199
200 /* Determine button spacing;
201 add some extra in front and back */
202
203 bs = (text_window.w - db_longest_button) / bn;
204 bse = ((text_window.w - db_longest_line) % bn) / 2;
205
206 /* Position the buttons and lines */
207
208 for (i = 0; i < dbn; i++)
209 {
210 if (db_entry[i].type) { /* Buttons */
211 if (db_last_button == -1)
212 db_rect[i].x = ((bs + bse) / 2) - BUTTON_BORDER;
213 else
214 db_rect[i].x = ((db_rect[db_last_button].x
215 + db_rect[db_last_button].w + bs)
216 - BUTTON_BORDER);
217
218 db_rect[i].y = ((ln * (CHAR_HEIGHT + DB_V_SPACE) + DB_V_SPACE)
219 - BUTTON_BORDER);
220
221 db_last_button = i;
222 } else { /* Lines */
223 db_rect[i].x = ((text_window.w - db_rect[i].w) / 2);
224 db_rect[i].y = (i * (CHAR_HEIGHT + DB_V_SPACE));
225 }
226 }
227
228 /* Figure out window size */
229
230 dialog_window.w = (text_window.w + BORDER_SIZE*2);
231 dialog_window.h = (text_window.h + BORDER_SIZE*2);
232
233 main_handle = mouse_register(&scr.client_win,&main_handler);
234 text_handle = mouse_register(&text_window,&text_handler);
235
236 dialog_refresh();
237
238 db_return_value = 0;
239
240 /* Wait for the user to click on it or press an appropriate key */
241 /* Mouse clicks arrive from the mouse handler and set db_return_value */
242
243 while (!db_return_value) {
244 #ifndef LC_X11
245 lc_usleep (1000); /* call_wait_event does this for X11 */
246 #endif
247
248 #ifdef LC_X11
249 call_wait_event ();
250 key = x_key_value;
251 x_key_value = 0;
252 #elif defined (WIN32)
253 HandleMouse ();
254 key = GetKeystroke ();
255 #else
256 mouse_update ();
257 key = vga_getkey ();
258 #endif
259 if (key == 0) continue;
260
261 if (key == 10 || key == 13 || key == ' ') /* default button */
262 for (i = 0; i <= dbn; i++) {
263 if (db_entry[i].type == 2) {
264 dialog_close(db_entry[i].retval);
265 break;
266 }
267 }
268 else
269 for (i = 0; i <= dbn; i++) {
270 if (key == db_entry[i].retval) {
271 dialog_close(key);
272 break;
273 }
274 }
275 }
276 return (db_return_value);
277 }
278
279
280 void
dialog_refresh(void)281 dialog_refresh(void)
282 {
283 int i; /* Line, Button incrementors */
284 if (!db_up)
285 return;
286
287 /* Determine screen position */
288 dialog_window.x = (scr.client_w / 2) - (dialog_window.w / 2);
289 dialog_window.y = (scr.client_h / 2) - (dialog_window.h / 2);
290
291 text_window.x = dialog_window.x + BORDER_SIZE;
292 text_window.y = dialog_window.y + BORDER_SIZE;
293
294 hide_mouse();
295
296 if (screen_refreshing && db_screen_fresh) {
297 free(db_screen_buffer);
298 db_screen_fresh = 0;
299 }
300
301 if (!db_screen_fresh) {
302 db_screen_buffer = (char *)lcalloc(dialog_window.w * dialog_window.h);
303 Fgl_getrect(&dialog_window,db_screen_buffer);
304 db_screen_fresh = 1;
305 };
306
307
308 /* Draw the border, and fill the background */
309 draw_bezel(dialog_window,BORDER_SIZE,color);
310
311 Fgl_fillbox(text_window.x,text_window.y,text_window.w,text_window.h,color);
312
313 #ifdef USE_EXPANDED_FONT
314 gl_setwritemode (WRITEMODE_MASKED | FONT_EXPANDED);
315 #else
316 Fgl_setfontcolors (color, TEXT_FG_COLOUR);
317 #endif
318
319 /* Loop calculating line position, and drawing the line */
320 for (i = 0; i < dbn; i++)
321 {
322
323 if (db_entry[i].type) {
324 Fgl_fillbox(db_rect[i].x + text_window.x,
325 db_rect[i].y + text_window.y,
326 db_rect[i].w,
327 db_rect[i].h,
328 white(0));
329 }
330 Fgl_write(db_rect[i].x + text_window.x + BUTTON_BORDER,
331 db_rect[i].y + text_window.y + BUTTON_BORDER,
332 db_entry[i].text);
333 }
334
335 #ifdef USE_EXPANDED_FONT
336 gl_setwritemode (WRITEMODE_OVERWRITE | FONT_EXPANDED);
337 #else
338 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
339 #endif
340
341 redraw_mouse();
342
343 }
344
345 /* dialog_close: close the mouse handle and remember we closed it;
346 save the results; put the old screen back up and remember that too. */
347
348 void
dialog_close(int return_value)349 dialog_close(int return_value)
350 {
351 int i;
352
353 mouse_unregister(main_handle);
354 mouse_unregister(text_handle);
355 db_up = 0;
356 db_return_value = return_value;
357
358 for (i = 0; i < dbn; i++)
359 if (db_entry[i].type == DB_PARA)
360 free(db_entry[i].text);
361
362 if (db_screen_fresh) {
363 Fgl_putrect(&dialog_window,db_screen_buffer);
364 free(db_screen_buffer);
365 db_screen_fresh = 0;
366 }
367
368 db_flag = 0;
369 }
370
371