1 
2 #include <stdio.h>
3 #include <stdarg.h>
4 
5 #include "SDL_FrameBuf.h"
6 #include "Mac_FontServ.h"
7 
8 /*  This is a class set for Macintosh-like dialogue boxes. :) */
9 /*  Sorta complex... */
10 
11 /* Defaults for various dialog classes */
12 
13 #define BUTTON_WIDTH	75
14 #define BUTTON_HEIGHT	19
15 
16 #define BOX_WIDTH	170
17 #define BOX_HEIGHT	20
18 
19 #define EXPAND_STEPS	50
20 
21 class Mac_Dialog {
22 
23 public:
24 	Mac_Dialog(int x, int y);
~Mac_Dialog()25 	virtual ~Mac_Dialog() { }
26 
27 	/* Input handling */
SetButtonPress(void (* new_button_callback)(int x,int y,int button,int * doneflag))28 	virtual void SetButtonPress(void (*new_button_callback)
29 				(int x, int y, int button, int *doneflag)) {
30 		button_callback = new_button_callback;
31 	}
HandleButtonPress(int x,int y,int button,int * doneflag)32 	virtual void HandleButtonPress(int x, int y, int button,
33 							int *doneflag) {
34 		if ( button_callback ) {
35 			(*button_callback)(x, y, button, doneflag);
36 		}
37 	}
SetKeyPress(void (* new_key_callback)(SDL_keysym key,int * doneflag))38 	virtual void SetKeyPress(void (*new_key_callback)
39 				(SDL_keysym key, int *doneflag)) {
40 		key_callback = new_key_callback;
41 	}
HandleKeyPress(SDL_keysym key,int * doneflag)42 	virtual void HandleKeyPress(SDL_keysym key, int *doneflag) {
43 		if ( key_callback ) {
44 			(*key_callback)(key, doneflag);
45 		}
46 	}
47 
48 	/* Display handling */
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)49 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
50 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
51 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
52 		X += Xoff;
53 		Y += Yoff;
54 		Screen = screen;
55 	}
Show(void)56 	virtual void Show(void) {
57 	}
58 
EnableText(void)59 	static void EnableText(void) {
60 		if ( text_enabled++ == 0 ) {
61 			SDL_EnableUNICODE(1);
62 		}
63 	}
DisableText(void)64 	static void DisableText(void) {
65 		if ( --text_enabled == 0 ) {
66 			SDL_EnableUNICODE(0);
67 		}
68 	}
69 
70 	/* Error message routine */
Error(void)71 	virtual char *Error(void) {
72 		return(errstr);
73 	}
74 
75 protected:
76 	static int text_enabled;
77 	FrameBuf *Screen;
78 	int  X, Y;
79 	void (*button_callback)(int x, int y, int button, int *doneflag);
80 	void (*key_callback)(SDL_keysym key, int *doneflag);
81 
82 	/* Utility routines for dialogs */
IsSensitive(SDL_Rect * area,int x,int y)83 	int IsSensitive(SDL_Rect *area, int x, int y) {
84 		if ( (y > area->y) && (y < (area->y+area->h)) &&
85 	    	     (x > area->x) && (x < (area->x+area->w)) )
86 			return(1);
87 		return(0);
88 	}
89 
90 	/* Error message */
SetError(char * fmt,...)91 	virtual void SetError(char *fmt, ...) {
92 		va_list ap;
93 
94 		va_start(ap, fmt);
95 		vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
96 		va_end(ap);
97 		errstr = errbuf;
98         }
99 	char *errstr;
100 	char  errbuf[1024];
101 };
102 
103 
104 /* The button callbacks should return 1 if they finish the dialog,
105    or 0 if they do not.
106 */
107 
108 class Mac_Button : public Mac_Dialog {
109 
110 public:
111 	Mac_Button(int x, int y, int width, int height,
112 		char *text, MFont *font, FontServ *fontserv,
113 				int (*callback)(void));
~Mac_Button()114 	virtual ~Mac_Button() {
115 		SDL_FreeSurface(button);
116 	}
117 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)118 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
119 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
120 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
121 		/* Do the normal dialog mapping */
122 		Mac_Dialog::Map(Xoff, Yoff, screen,
123 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
124 
125 		/* Set up the button sensitivity */
126 		sensitive.x = X;
127 		sensitive.y  = Y;
128 		sensitive.w = Width;
129 		sensitive.h = Height;
130 
131 		/* Map the bitmap image */
132 		button->format->palette->colors[0].r = R_bg;
133 		button->format->palette->colors[0].g = G_bg;
134 		button->format->palette->colors[0].b = B_bg;
135 		button->format->palette->colors[1].r = R_fg;
136 		button->format->palette->colors[1].g = G_fg;
137 		button->format->palette->colors[1].b = B_fg;
138 	}
Show(void)139 	virtual void Show(void) {
140 		Screen->QueueBlit(X, Y, button, NOCLIP);
141 	}
142 
HandleButtonPress(int x,int y,int button,int * doneflag)143 	virtual void HandleButtonPress(int x, int y, int button,
144 							int *doneflag) {
145 		if ( IsSensitive(&sensitive, x, y) )
146 			ActivateButton(doneflag);
147 	}
148 
149 protected:
150 	int Width, Height;
151 	SDL_Surface *button;
152 	SDL_Rect sensitive;
153 	int (*Callback)(void);
154 
Bevel_Button(SDL_Surface * image)155 	virtual void Bevel_Button(SDL_Surface *image) {
156 		Uint16 h;
157 		Uint8 *image_bits;
158 
159 		image_bits = (Uint8 *)image->pixels;
160 
161 		/* Bevel upper corners */
162 		memset(image_bits+3, 0x01, image->w-6);
163 		image_bits += image->pitch;
164 		memset(image_bits+1, 0x01, 2);
165 		memset(image_bits+image->w-3, 0x01, 2);
166 		image_bits += image->pitch;
167 		memset(image_bits+1, 0x01, 1);
168 		memset(image_bits+image->w-2, 0x01, 1);
169 		image_bits += image->pitch;
170 
171 		/* Draw sides */
172 		for ( h=3; h<(image->h-3); ++h ) {
173 			image_bits[0] = 0x01;
174 			image_bits[image->w-1] = 0x01;
175 			image_bits += image->pitch;
176 		}
177 
178 		/* Bevel bottom corners */
179 		memset(image_bits+1, 0x01, 1);
180 		memset(image_bits+image->w-2, 0x01, 1);
181 		image_bits += image->pitch;
182 		memset(image_bits+1, 0x01, 2);
183 		memset(image_bits+image->w-3, 0x01, 2);
184 		image_bits += image->pitch;
185 		memset(image_bits+3, 0x01, image->w-6);
186 	}
InvertImage(void)187 	virtual void InvertImage(void) {
188 		int i;
189 		Uint8 *buf;
190 
191 		for ( i=button->h*button->pitch, buf=(Uint8 *)button->pixels;
192 							i > 0; --i, ++buf ) {
193 			*buf = !*buf;
194 		}
195 	}
ActivateButton(int * doneflag)196 	virtual void ActivateButton(int *doneflag) {
197 		/* Flash the button */
198 		InvertImage();
199 		Show();
200 		Screen->Update();
201 		SDL_Delay(50);
202 		InvertImage();
203 		Show();
204 		Screen->Update();
205 		/* Run the callback */
206 		if ( Callback )
207 			*doneflag = (*Callback)();
208 		else
209 			*doneflag = 1;
210 	}
211 };
212 
213 /* The only difference between this button and the Mac_Button is that
214    if <Return> is pressed, this button is activated.
215 */
216 class Mac_DefaultButton : public Mac_Button {
217 
218 public:
219 	Mac_DefaultButton(int x, int y, int width, int height,
220 				char *text, MFont *font, FontServ *fontserv,
221 						int (*callback)(void));
~Mac_DefaultButton()222 	virtual ~Mac_DefaultButton() { }
223 
HandleKeyPress(SDL_keysym key,int * doneflag)224 	virtual void HandleKeyPress(SDL_keysym key, int *doneflag) {
225 		if ( key.sym == SDLK_RETURN )
226 			ActivateButton(doneflag);
227 	}
228 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)229 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
230 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
231 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
232 		Mac_Button::Map(Xoff, Yoff, screen,
233 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
234 		Fg = Screen->MapRGB(R_fg, G_fg, B_fg);
235 	}
Show(void)236 	virtual void Show(void) {
237 		int x, y, maxx, maxy;
238 
239 		/* Show the normal button */
240 		Mac_Button::Show();
241 
242 		/* Show the thick edge */
243 		x = X-4;
244 		maxx = x+4+Width+4-1;
245 		y = Y-4;
246 		maxy = y+4+Height+4-1;
247 
248 		Screen->DrawLine(x+5, y, maxx-5, y, Fg);
249 		Screen->DrawLine(x+3, y+1, maxx-3, y+1, Fg);
250 		Screen->DrawLine(x+2, y+2, maxx-2, y+2, Fg);
251 		Screen->DrawLine(x+1, y+3, x+5, y+3, Fg);
252 		Screen->DrawLine(maxx-5, y+3, maxx-1, y+3, Fg);
253 		Screen->DrawLine(x+1, y+4, x+3, y+4, Fg);
254 		Screen->DrawLine(maxx-3, y+4, maxx-1, y+4, Fg);
255 		Screen->DrawLine(x, y+5, x+3, y+5, Fg);
256 		Screen->DrawLine(maxx-3, y+5, maxx, y+5, Fg);
257 
258 		Screen->DrawLine(x, y+6, x, maxy-6, Fg);
259 		Screen->DrawLine(maxx, y+6, maxx, maxy-6, Fg);
260 		Screen->DrawLine(x+1, y+6, x+1, maxy-6, Fg);
261 		Screen->DrawLine(maxx-1, y+6, maxx-1, maxy-6, Fg);
262 		Screen->DrawLine(x+2, y+6, x+2, maxy-6, Fg);
263 		Screen->DrawLine(maxx-2, y+6, maxx-2, maxy-6, Fg);
264 
265 		Screen->DrawLine(x, maxy-5, x+3, maxy-5, Fg);
266 		Screen->DrawLine(maxx-3, maxy-5, maxx, maxy-5, Fg);
267 		Screen->DrawLine(x+1, maxy-4, x+3, maxy-4, Fg);
268 		Screen->DrawLine(maxx-3, maxy-4, maxx-1, maxy-4, Fg);
269 		Screen->DrawLine(x+1, maxy-3, x+5, maxy-3, Fg);
270 		Screen->DrawLine(maxx-5, maxy-3, maxx-1, maxy-3, Fg);
271 		Screen->DrawLine(x+2, maxy-2, maxx-2, maxy-2, Fg);
272 		Screen->DrawLine(x+3, maxy-1, maxx-3, maxy-1, Fg);
273 		Screen->DrawLine(x+5, maxy, maxx-5, maxy, Fg);
274 	}
275 
276 protected:
277 	Uint32 Fg;		/* The foreground color of the dialog */
278 
279 };
280 
281 /* Class of checkboxes */
282 
283 #define CHECKBOX_SIZE	12
284 
285 class Mac_CheckBox : public Mac_Dialog {
286 
287 public:
288 	Mac_CheckBox(int *toggle, int x, int y, char *text,
289 				MFont *font, FontServ *fontserv);
~Mac_CheckBox()290 	virtual ~Mac_CheckBox() {
291 		if ( label ) {
292 			Fontserv->FreeText(label);
293 		}
294 	}
295 
HandleButtonPress(int x,int y,int button,int * doneflag)296 	virtual void HandleButtonPress(int x, int y, int button,
297 							int *doneflag) {
298 		if ( IsSensitive(&sensitive, x, y) ) {
299 			*checkval = !*checkval;
300 			Check_Box(*checkval);
301 			Screen->Update();
302 		}
303 	}
304 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)305 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
306 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
307 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
308 		/* Do the normal dialog mapping */
309 		Mac_Dialog::Map(Xoff, Yoff, screen,
310 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
311 
312 		/* Set up the checkbox sensitivity */
313 		sensitive.x = X;
314 		sensitive.y = Y;
315 		sensitive.w = CHECKBOX_SIZE;
316 		sensitive.h = CHECKBOX_SIZE;
317 
318 		/* Get the screen colors */
319 		Fg = Screen->MapRGB(R_fg, G_fg, B_fg);
320 		Bg = Screen->MapRGB(R_bg, G_bg, B_bg);
321 
322 		/* Map the checkbox text */
323 		label->format->palette->colors[1].r = R_fg;
324 		label->format->palette->colors[1].g = G_fg;
325 		label->format->palette->colors[1].b = B_fg;
326 	}
Show(void)327 	virtual void Show(void) {
328 		Screen->DrawRect(X, Y, CHECKBOX_SIZE, CHECKBOX_SIZE, Fg);
329 		if ( label ) {
330 			Screen->QueueBlit(X+CHECKBOX_SIZE+4, Y-2, label,NOCLIP);
331 		}
332 		Check_Box(*checkval);
333 	}
334 
335 private:
336 	FontServ *Fontserv;
337 	SDL_Surface *label;
338 	Uint32 Fg, Bg;
339 	int *checkval;
340 	SDL_Rect sensitive;
341 
Check_Box(int checked)342 	void Check_Box(int checked) {
343 		Uint32 color;
344 
345 		if ( checked )
346 			color = Fg;
347 		else
348 			color = Bg;
349 
350 		Screen->DrawLine(X, Y,
351 				X+CHECKBOX_SIZE-1, Y+CHECKBOX_SIZE-1, color);
352 		Screen->DrawLine(X, Y+CHECKBOX_SIZE-1,
353 					X+CHECKBOX_SIZE-1, Y, color);
354 	}
355 };
356 
357 /* Class of radio buttons */
358 
359 class Mac_RadioList : public Mac_Dialog {
360 
361 public:
362 	Mac_RadioList(int *variable, int x, int y,
363 			MFont *font, FontServ *fontserv);
~Mac_RadioList()364 	virtual ~Mac_RadioList() {
365 		struct radio *radio, *old;
366 
367 		for ( radio=radio_list.next; radio; ) {
368 			old = radio;
369 			radio = radio->next;
370 			if ( old->label )
371 				Fontserv->FreeText(old->label);
372 			delete old;
373 		}
374 	}
375 
HandleButtonPress(int x,int y,int button,int * doneflag)376 	virtual void HandleButtonPress(int x, int y, int button,
377 							int *doneflag) {
378 		int n;
379 		struct radio *radio, *oldradio;
380 
381 		oldradio = radio_list.next;
382 		for (n=0, radio=radio_list.next; radio; radio=radio->next, ++n){
383 			if ( n == *radiovar ) {
384 				oldradio = radio;
385 				break;
386 			}
387 		}
388 		for (n=0, radio=radio_list.next; radio; radio=radio->next, ++n){
389 			if ( IsSensitive(&radio->sensitive, x, y) ) {
390 				Spot(oldradio->x, oldradio->y, Bg);
391 				*radiovar = n;
392 				Spot(radio->x, radio->y, Fg);
393 				Screen->Update();
394 			}
395 		}
396 	}
397 
Add_Radio(int x,int y,char * text)398 	virtual void Add_Radio(int x, int y, char *text) {
399 		struct radio *radio;
400 
401 		for ( radio=&radio_list; radio->next; radio=radio->next )
402 			/* Loop to end of radio box list */;
403 /* Which is ANSI C++? */
404 #ifdef linux
405 		radio->next = new struct Mac_RadioList::radio;
406 #else
407 		radio->next = new struct radio;
408 #endif
409 		radio = radio->next;
410 		radio->label = Fontserv->TextImage(text, Font,
411 							STYLE_NORM, 0, 0, 0);
412 		radio->x = x;
413 		radio->y = y;
414 		radio->sensitive.x = x;
415 		radio->sensitive.y = y;
416 		radio->sensitive.w = 20+radio->label->w;
417 		radio->sensitive.h = BOX_HEIGHT;
418 		radio->next = NULL;
419 	}
420 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)421 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
422 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
423 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
424 		struct radio *radio;
425 
426 		/* Do the normal dialog mapping */
427 		Mac_Dialog::Map(Xoff, Yoff, screen,
428 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
429 
430 		/* Get the screen colors */
431 		Fg = Screen->MapRGB(R_fg, G_fg, B_fg);
432 		Bg = Screen->MapRGB(R_bg, G_bg, B_bg);
433 
434 		/* Adjust sensitivity and map the radiobox text */
435 		for ( radio=radio_list.next; radio; radio=radio->next ) {
436 			radio->x += Xoff;
437 			radio->y += Yoff;
438 			radio->sensitive.x += Xoff;
439 			radio->sensitive.y += Yoff;
440 			radio->label->format->palette->colors[1].r = R_fg;
441 			radio->label->format->palette->colors[1].g = G_fg;
442 			radio->label->format->palette->colors[1].b = B_fg;
443 		}
444 	}
Show(void)445 	virtual void Show(void) {
446 		int n;
447 		struct radio *radio;
448 
449 		for (n=0, radio=radio_list.next; radio; radio=radio->next, ++n){
450 			Circle(radio->x, radio->y);
451 			if ( n == *radiovar ) {
452 				Spot(radio->x, radio->y, Fg);
453 			}
454 			if ( radio->label ) {
455 				Screen->QueueBlit(radio->x+21, radio->y+3,
456 							radio->label, NOCLIP);
457 			}
458 		}
459 	}
460 
461 private:
462 	FontServ *Fontserv;
463 	MFont *Font;
464 	Uint32 Fg, Bg;
465 	int *radiovar;
466 	struct radio {
467 		SDL_Surface *label;
468 		int x, y;
469 		SDL_Rect sensitive;
470 		struct radio *next;
471 	} radio_list;
472 
Circle(int x,int y)473 	void Circle(int x, int y) {
474 		x += 5;
475 		y += 5;
476 		Screen->DrawLine(x+4, y, x+7, y, Fg);
477 		Screen->DrawLine(x+2, y+1, x+3, y+1, Fg);
478 		Screen->DrawLine(x+8, y+1, x+9, y+1, Fg);
479 		Screen->DrawLine(x+1, y+2, x+1, y+3, Fg);
480 		Screen->DrawLine(x+10, y+2, x+10, y+3, Fg);
481 		Screen->DrawLine(x, y+4, x, y+7, Fg);
482 		Screen->DrawLine(x+11, y+4, x+11, y+7, Fg);
483 		Screen->DrawLine(x+1, y+8, x+1, y+9, Fg);
484 		Screen->DrawLine(x+10, y+8, x+10, y+9, Fg);
485 		Screen->DrawLine(x+2, y+10, x+3, y+10, Fg);
486 		Screen->DrawLine(x+8, y+10, x+9, y+10, Fg);
487 		Screen->DrawLine(x+4, y+11, x+7, y+11, Fg);
488 	}
Spot(int x,int y,Uint32 color)489 	void Spot(int x, int y, Uint32 color)
490 	{
491 		x += 8;
492 		y += 8;
493 		Screen->DrawLine(x+1, y, x+4, y, color);
494 		++y;
495 		Screen->DrawLine(x, y, x+5, y, color);
496 		++y;
497 		Screen->DrawLine(x, y, x+5, y, color);
498 		++y;
499 		Screen->DrawLine(x, y, x+5, y, color);
500 		++y;
501 		Screen->DrawLine(x, y, x+5, y, color);
502 		++y;
503 		Screen->DrawLine(x+1, y, x+4, y, color);
504 	}
505 };
506 
507 
508 /* Class of text entry boxes */
509 
510 class Mac_TextEntry : public Mac_Dialog {
511 
512 public:
513 	Mac_TextEntry(int x, int y, MFont *font, FontServ *fontserv);
~Mac_TextEntry()514 	virtual ~Mac_TextEntry() {
515 		struct text_entry *entry, *old;
516 
517 		for ( entry=entry_list.next; entry; ) {
518 			old = entry;
519 			entry = entry->next;
520 			if ( old->text )
521 				Fontserv->FreeText(old->text);
522 			delete old;
523 		}
524 		DisableText();
525 	}
526 
HandleButtonPress(int x,int y,int button,int * doneflag)527 	virtual void HandleButtonPress(int x, int y, int button,
528 							int *doneflag) {
529 		struct text_entry *entry;
530 
531 		for ( entry=entry_list.next; entry; entry=entry->next ) {
532 			if ( IsSensitive(&entry->sensitive, x, y) ) {
533 				current->hilite = 0;
534 				Update_Entry(current);
535 				current = entry;
536 				DrawCursor(current);
537 				Screen->Update();
538 			}
539 		}
540 	}
HandleKeyPress(SDL_keysym key,int * doneflag)541 	virtual void HandleKeyPress(SDL_keysym key, int *doneflag) {
542 		int n;
543 
544 		switch (key.sym) {
545 			case SDLK_TAB:
546 				current->hilite = 0;
547 				Update_Entry(current);
548 				if ( current->next )
549 					current=current->next;
550 				else
551 					current=entry_list.next;
552 				current->hilite = 1;
553 				Update_Entry(current);
554 				break;
555 
556 			case SDLK_DELETE:
557 			case SDLK_BACKSPACE:
558 				if ( current->hilite ) {
559 					*current->variable = '\0';
560 					current->hilite = 0;
561 				} else if ( *current->variable ) {
562 					n = strlen(current->variable);
563 					current->variable[n-1] = '\0';
564 				}
565 				Update_Entry(current);
566 				DrawCursor(current);
567 				break;
568 
569 			default:
570 				if ( (current->end+Cwidth) > current->width )
571 					return;
572 				if ( key.unicode ) {
573 					current->hilite = 0;
574 					n = strlen(current->variable);
575 					current->variable[n] = (char)key.unicode;
576 					current->variable[n+1] = '\0';
577 					Update_Entry(current);
578 					DrawCursor(current);
579 				}
580 				break;
581 		}
582 		Screen->Update();
583 	}
584 
Add_Entry(int x,int y,int width,int is_default,char * variable)585 	virtual void Add_Entry(int x, int y, int width, int is_default,
586 							char *variable) {
587 		struct text_entry *entry;
588 
589 		for ( entry=&entry_list; entry->next; entry=entry->next )
590 			/* Loop to end of entry list */;
591 		entry->next = new struct text_entry;
592 		entry = entry->next;
593 
594 		entry->variable = variable;
595 		if ( is_default ) {
596 			current = entry;
597 			entry->hilite = 1;
598 		} else
599 			entry->hilite = 0;
600 		entry->x = x+3;
601 		entry->y = y+3;
602 		entry->width = width*Cwidth;
603 		entry->height = Cheight;
604 		entry->sensitive.x = x;
605 		entry->sensitive.y = y;
606 		entry->sensitive.w = 3+(width*Cwidth)+3;
607 		entry->sensitive.h = 3+Cheight+3;
608 		entry->text = NULL;
609 		entry->next = NULL;
610 	}
611 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)612 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
613 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
614 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
615 		struct text_entry *entry;
616 
617 		/* Do the normal dialog mapping */
618 		Mac_Dialog::Map(Xoff, Yoff, screen,
619 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
620 
621 		/* Get the screen colors */
622 		foreground.r = R_fg;
623 		foreground.g = G_fg;
624 		foreground.b = B_fg;
625 		background.r = R_bg;
626 		background.g = G_bg;
627 		background.b = B_bg;
628 		Fg = Screen->MapRGB(R_fg, G_fg, B_fg);
629 		Bg = Screen->MapRGB(R_bg, G_bg, B_bg);
630 
631 		/* Adjust sensitivity and map the radiobox text */
632 		for ( entry=entry_list.next; entry; entry=entry->next ) {
633 			entry->x += Xoff;
634 			entry->y += Yoff;
635 			entry->sensitive.x += Xoff;
636 			entry->sensitive.y += Yoff;
637 		}
638 	}
Show(void)639 	virtual void Show(void) {
640 		struct text_entry *entry;
641 
642 		for ( entry=entry_list.next; entry; entry=entry->next ) {
643 			Screen->DrawRect(entry->x-3, entry->y-3,
644 					3+entry->width+3, 3+Cheight+3, Fg);
645 			Update_Entry(entry);
646 		}
647 	}
648 
649 private:
650 	FontServ *Fontserv;
651 	MFont *Font;
652 	Uint32 Fg, Bg;
653 	int Cwidth, Cheight;
654 	SDL_Color foreground;
655 	SDL_Color background;
656 
657 	struct text_entry {
658 		SDL_Surface *text;
659 		char *variable;
660 		SDL_Rect sensitive;
661 		int  x, y;
662 		int  width, height;
663 		int  end;
664 		int  hilite;
665 		struct text_entry *next;
666 	} entry_list, *current;
667 
668 
Update_Entry(struct text_entry * entry)669 	void Update_Entry(struct text_entry *entry) {
670 		Uint32 clear;
671 
672 		/* Create the new entry text */
673 		if ( entry->text ) {
674 			Fontserv->FreeText(entry->text);
675 		}
676 		if ( entry->hilite ) {
677 			clear = Fg;
678 			entry->text = Fontserv->TextImage(entry->variable,
679 				Font, STYLE_NORM, background, foreground);
680 		} else {
681 			clear = Bg;
682 			entry->text = Fontserv->TextImage(entry->variable,
683 				Font, STYLE_NORM, foreground, background);
684 		}
685 		Screen->FillRect(entry->x, entry->y,
686 					entry->width, entry->height, clear);
687 		if ( entry->text ) {
688 			entry->end = entry->text->w;
689 			Screen->QueueBlit(entry->x, entry->y, entry->text, NOCLIP);
690 		} else {
691 			entry->end = 0;
692 		}
693 	}
DrawCursor(struct text_entry * entry)694 	void DrawCursor(struct text_entry *entry) {
695 		Screen->DrawLine(entry->x+entry->end, entry->y,
696 			entry->x+entry->end, entry->y+entry->height-1, Fg);
697 	}
698 };
699 
700 
701 /* Class of numeric entry boxes */
702 
703 class Mac_NumericEntry : public Mac_Dialog {
704 
705 public:
706 	Mac_NumericEntry(int x, int y, MFont *font, FontServ *fontserv);
~Mac_NumericEntry()707 	virtual ~Mac_NumericEntry() {
708 		struct numeric_entry *entry, *old;
709 
710 		for ( entry=entry_list.next; entry; ) {
711 			old = entry;
712 			entry = entry->next;
713 			if ( old->text )
714 				Fontserv->FreeText(old->text);
715 			delete old;
716 		}
717 	}
718 
HandleButtonPress(int x,int y,int button,int * doneflag)719 	virtual void HandleButtonPress(int x, int y, int button,
720 							int *doneflag) {
721 		struct numeric_entry *entry;
722 
723 		for ( entry=entry_list.next; entry; entry=entry->next ) {
724 			if ( IsSensitive(&entry->sensitive, x, y) ) {
725 				current->hilite = 0;
726 				Update_Entry(current);
727 				current = entry;
728 				DrawCursor(current);
729 				Screen->Update();
730 			}
731 		}
732 	}
HandleKeyPress(SDL_keysym key,int * doneflag)733 	virtual void HandleKeyPress(SDL_keysym key, int *doneflag) {
734 		int n;
735 
736 		switch (key.sym) {
737 			case SDLK_TAB:
738 				current->hilite = 0;
739 				Update_Entry(current);
740 				if ( current->next )
741 					current=current->next;
742 				else
743 					current=entry_list.next;
744 				current->hilite = 1;
745 				Update_Entry(current);
746 				break;
747 
748 			case SDLK_DELETE:
749 			case SDLK_BACKSPACE:
750 				if ( current->hilite ) {
751 					*current->variable = 0;
752 					current->hilite = 0;
753 				} else
754 					*current->variable /= 10;
755 				Update_Entry(current);
756 				DrawCursor(current);
757 				break;
758 
759 			case SDLK_0:
760 			case SDLK_1:
761 			case SDLK_2:
762 			case SDLK_3:
763 			case SDLK_4:
764 			case SDLK_5:
765 			case SDLK_6:
766 			case SDLK_7:
767 			case SDLK_8:
768 			case SDLK_9:
769 				n = (key.sym-SDLK_0);
770 				if ( (current->end+Cwidth) > current->width )
771 					return;
772 				if ( current->hilite ) {
773 					*current->variable = n;
774 					current->hilite = 0;
775 				} else {
776 					*current->variable *= 10;
777 					*current->variable += n;
778 				}
779 				Update_Entry(current);
780 				DrawCursor(current);
781 				break;
782 
783 			default:
784 				break;
785 		}
786 		Screen->Update();
787 	}
788 
Add_Entry(int x,int y,int width,int is_default,int * variable)789 	virtual void Add_Entry(int x, int y, int width, int is_default,
790 							int *variable) {
791 		struct numeric_entry *entry;
792 
793 		for ( entry=&entry_list; entry->next; entry=entry->next )
794 			/* Loop to end of numeric entry list */;
795 		entry->next = new struct numeric_entry;
796 		entry = entry->next;
797 
798 		entry->variable = variable;
799 		if ( is_default ) {
800 			current = entry;
801 			entry->hilite = 1;
802 		} else
803 			entry->hilite = 0;
804 		entry->x = x+3;
805 		entry->y = y+3;
806 		entry->width = width*Cwidth;
807 		entry->height = Cheight;
808 		entry->sensitive.x = x;
809 		entry->sensitive.y = y;
810 		entry->sensitive.w = 3+(width*Cwidth)+3;
811 		entry->sensitive.h = 3+Cheight+3;
812 		entry->text = NULL;
813 		entry->next = NULL;
814 	}
815 
Map(int Xoff,int Yoff,FrameBuf * screen,Uint8 R_bg,Uint8 G_bg,Uint8 B_bg,Uint8 R_fg,Uint8 G_fg,Uint8 B_fg)816 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
817 				Uint8 R_bg, Uint8 G_bg, Uint8 B_bg,
818 				Uint8 R_fg, Uint8 G_fg, Uint8 B_fg) {
819 		struct numeric_entry *entry;
820 
821 		/* Do the normal dialog mapping */
822 		Mac_Dialog::Map(Xoff, Yoff, screen,
823 				R_bg, G_bg, B_bg, R_fg, G_fg, B_fg);
824 
825 		/* Get the screen colors */
826 		foreground.r = R_fg;
827 		foreground.g = G_fg;
828 		foreground.b = B_fg;
829 		background.r = R_bg;
830 		background.g = G_bg;
831 		background.b = B_bg;
832 		Fg = Screen->MapRGB(R_fg, G_fg, B_fg);
833 		Bg = Screen->MapRGB(R_bg, G_bg, B_bg);
834 
835 		/* Adjust sensitivity and map the radiobox text */
836 		for ( entry=entry_list.next; entry; entry=entry->next ) {
837 			entry->x += Xoff;
838 			entry->y += Yoff;
839 			entry->sensitive.x += Xoff;
840 			entry->sensitive.y += Yoff;
841 		}
842 	}
Show(void)843 	virtual void Show(void) {
844 		struct numeric_entry *entry;
845 
846 		for ( entry=entry_list.next; entry; entry=entry->next ) {
847 			Screen->DrawRect(entry->x-3, entry->y-3,
848 					3+entry->width+3, 3+Cheight+3, Fg);
849 			Update_Entry(entry);
850 		}
851 	}
852 
853 private:
854 	FontServ *Fontserv;
855 	MFont *Font;
856 	Uint32 Fg, Bg;
857 	int Cwidth, Cheight;
858 	SDL_Color foreground;
859 	SDL_Color background;
860 
861 	struct numeric_entry {
862 		SDL_Surface *text;
863 		int *variable;
864 		SDL_Rect sensitive;
865 		int  x, y;
866 		int  width, height;
867 		int  end;
868 		int  hilite;
869 		struct numeric_entry *next;
870 	} entry_list, *current;
871 
872 
Update_Entry(struct numeric_entry * entry)873 	void Update_Entry(struct numeric_entry *entry) {
874 		char buf[128];
875 		Uint32 clear;
876 
877 		/* Create the new entry text */
878 		if ( entry->text ) {
879 			Fontserv->FreeText(entry->text);
880 		}
881 		snprintf(buf, sizeof(buf), "%d", *entry->variable);
882 
883 		if ( entry->hilite ) {
884 			clear = Fg;
885 			entry->text = Fontserv->TextImage(buf,
886 				Font, STYLE_NORM, background, foreground);
887 		} else {
888 			clear = Bg;
889 			entry->text = Fontserv->TextImage(buf,
890 				Font, STYLE_NORM, foreground, background);
891 		}
892 		entry->end = entry->text->w;
893 		Screen->FillRect(entry->x, entry->y,
894 					entry->width, entry->height, clear);
895 		Screen->QueueBlit(entry->x, entry->y, entry->text, NOCLIP);
896 	}
DrawCursor(struct numeric_entry * entry)897 	void DrawCursor(struct numeric_entry *entry) {
898 		Screen->DrawLine(entry->x+entry->end, entry->y,
899 			entry->x+entry->end, entry->y+entry->height-1, Fg);
900 	}
901 };
902 
903 
904 /* Finally, the macintosh-like dialog class */
905 
906 class Maclike_Dialog {
907 
908 public:
909 	Maclike_Dialog(int x, int y, int width, int height, FrameBuf *screen);
910 	~Maclike_Dialog();
911 
912 	void Add_Rectangle(int x, int y, int w, int h, Uint32 color);
913 	void Add_Image(SDL_Surface *image, int x, int y);
914 	void Add_Dialog(Mac_Dialog *dialog);
915 
916 	void Run(int expand_steps = 1);
917 
918 private:
919 	FrameBuf *Screen;
920 	int X, Y;
921 	int Width, Height;
922 
923 	struct rect_elem {
924 		Sint16 x, y;
925 		Uint16 w, h;
926 		Uint32 color;
927 		struct rect_elem *next;
928 	} rect_list;
929 	struct image_elem {
930 		SDL_Surface *image;
931 		int x, y;
932 		struct image_elem *next;
933 	} image_list;
934 	struct dialog_elem {
935 		Mac_Dialog *dialog;
936 		struct dialog_elem *next;
937 	} dialog_list;
938 };
939