1 
2 /* This is a set of C functions wrapping C++ classes for popup text output */
3 
4 #include <stdarg.h>
5 #include <string.h>
6 #include <math.h>
7 
8 #include "GUI.h"
9 #include "GUI_widgets.h"
10 #include "GUI_loadimage.h"
11 #include "GUI_output.h"
12 
13 /************************************************************************/
14 /* C functions for GUI output window support                            */
15 /*                                                                      */
16 /************************************************************************/
17 
OK_ButtonProc(void * statusp)18 static GUI_status OK_ButtonProc(void *statusp)
19 {
20 	*((int *)statusp) = 1;
21 	return(GUI_QUIT);
22 }
Cancel_ButtonProc(void * statusp)23 static GUI_status Cancel_ButtonProc(void *statusp)
24 {
25 	*((int *)statusp) = 0;
26 	return(GUI_QUIT);
27 }
28 
29 extern "C" {
30 
31 /* The (really C++) structure holding information for popup text output */
32 struct GUI_Output {
33 	int visible;
34 	SDL_Surface *screen;
35 	GUI_TermWin *window;
36 	GUI_Area *frame_inner;
37 	GUI_Area *frame_outer;
38 	SDL_Surface *behind;
39 };
40 
41 /* Function to create a hidden output window 'width' by 'height' characters.
42    The 'font' argument should either be a pointer to a 16x16 character font
43    image (with an extra pixel row under each row of characters), or NULL to
44    use a default internal 8x8-pixel font.
45  */
GUI_CreateOutput(SDL_Surface * screen,int width,int height,SDL_Surface * font)46 GUI_Output *GUI_CreateOutput(SDL_Surface *screen,
47 				int width, int height, SDL_Surface *font)
48 {
49 	GUI_Output *output;
50 	int w, h, x, y;
51 
52 	/* Create a new output window */
53 	output = new GUI_Output;
54 	output->visible = 0;
55 	output->screen = screen;
56 	if ( font == NULL ) {
57 		font = GUI_DefaultFont();
58 	}
59 
60 	/* Allocate the text window */
61 	w = width * (font->w/16);
62 	h = height * ((font->h/16)-1);
63 	x = (screen->w - w)/2;
64 	y = (screen->h - h)/2;
65 	output->window = new GUI_TermWin(x, y, w, h, font);
66 
67 	/* Allocate the frame areas */
68 	w += 2; h += 2;
69 	x -= 1; y -= 1;
70 	output->frame_inner = new GUI_Area(x, y, w, h, 255, 255, 255);
71 	w += 2; h += 2;
72 	x -= 1; y -= 1;
73 	output->frame_outer = new GUI_Area(x, y, w, h, 0, 0, 0);
74 
75 	/* Allocate a save buffer for the area behind it */
76 	output->behind = SDL_AllocSurface(SDL_SWSURFACE, w, h,
77 				screen->format->BitsPerPixel,
78 				screen->format->Rmask,
79 				screen->format->Gmask,
80 				screen->format->Bmask, 0);
81 
82 	/* Return the output window */
83 	return(output);
84 }
85 
86 /* Add output to an output window.  If the window is visible, the output
87    will appear immediately.  Note that the output windows are not overlays,
88    and any normal SDL drawing will overwrite the output window display.
89    If output causes the window to scroll, previous text will be lost.
90 */
GUI_AddOutput(GUI_Output * output,const char * fmt,...)91 void GUI_AddOutput(GUI_Output *output, const char *fmt, ...)
92 {
93 	va_list ap;
94 	char text[4096];
95 
96 	/* Get the text string */
97 	va_start(ap, fmt);
98 	vsprintf(text, fmt, ap);	/* CAUTION: possible buffer overflow */
99 	va_end(ap);
100 
101 	/* Add it to the window */
102 	output->window->AddText(text, strlen(text));
103 }
104 
105 /* Clear the contents of an output window */
GUI_ClearOutput(GUI_Output * output)106 void GUI_ClearOutput(GUI_Output *output)
107 {
108 	output->window->Clear();
109 }
110 
111 /* Show an output window, saving the area behind the window, and wait for
112    keyboard or mouse press input if 'wait' is non-zero.
113  */
GUI_ShowOutput(GUI_Output * output,int wait)114 void GUI_ShowOutput(GUI_Output *output, int wait)
115 {
116 	/* Display the text output window */
117 	output->frame_outer->SetDisplay(output->screen);
118 	output->frame_inner->SetDisplay(output->screen);
119 	output->window->SetDisplay(output->screen);
120 	if ( output->behind ) {
121 		SDL_Rect src;
122 
123 		src.x = output->frame_outer->X();
124 		src.y = output->frame_outer->Y();
125 		src.w = output->frame_outer->W();
126 		src.h = output->frame_outer->H();
127 		SDL_BlitSurface(output->screen, &src, output->behind, NULL);
128 	}
129 	output->frame_outer->Display();
130 	output->frame_inner->Display();
131 	output->window->Display();
132 	SDL_UpdateRect(output->screen, 0, 0, 0, 0);
133 	output->visible = 1;
134 
135 	/* Pump the event queue, waiting for key and mouse press events */
136 	if ( wait ) {
137 		SDL_Event event;
138 
139 		while ( ! SDL_PeepEvents(&event, 1, SDL_GETEVENT,
140 				(SDL_KEYDOWNMASK|SDL_MOUSEBUTTONDOWNMASK)) ) {
141 			SDL_Delay(20);
142 			SDL_PumpEvents();
143 		}
144 	}
145 }
146 
147 /* Hide an output window, restoring the previous contents of the display */
GUI_HideOutput(GUI_Output * output)148 void GUI_HideOutput(GUI_Output *output)
149 {
150 	if ( output->behind ) {
151 		SDL_Rect dst;
152 
153 		dst.x = output->frame_outer->X();
154 		dst.y = output->frame_outer->Y();
155 		dst.w = output->frame_outer->W();
156 		dst.h = output->frame_outer->H();
157 		SDL_BlitSurface(output->behind, NULL, output->screen, &dst);
158 		SDL_UpdateRects(output->screen, 1, &dst);
159 	}
160 	output->visible = 0;
161 }
162 
163 /* Delete an output window */
GUI_DeleteOutput(GUI_Output * output)164 void GUI_DeleteOutput(GUI_Output *output)
165 {
166 	if ( output ) {
167 		if ( output->visible ) {
168 			GUI_HideOutput(output);
169 		}
170 		if ( output->window ) {
171 			delete output->window;
172 			output->window = NULL;
173 		}
174 		if ( output->behind ) {
175 			SDL_FreeSurface(output->behind);
176 			output->behind = NULL;
177 		}
178 		delete output;
179 	}
180 }
181 
182 
183 /************************************************************************/
184 /* Simple C message-box functions for quick popup output                */
185 /*                                                                      */
186 /************************************************************************/
187 
188 #include "okay_img.h"
189 #include "cancel_img.h"
190 
191 
192 /* Create a popup message box of the given style, and wait for user input.
193    If 'title' is NULL, then no title-text will be used.
194 
195    Returns the index of the button pressed, which is style dependent:
196 */
GUI_MessageBox(SDL_Surface * screen,const char * title,const char * text,Uint32 style)197 int GUI_MessageBox(SDL_Surface *screen,
198 			const char *title, const char *text, Uint32 style)
199 {
200 	int status;
201 	const int gui_w = 320, gui_h = 200;
202 	GUI *gui;
203 	GUI_Widget *widget;
204 	GUI_TermWin *textout;
205 	GUI_Button *button;
206 	int w, h, x, y;
207 	unsigned int i;
208 	SDL_Surface *font;
209 	SDL_Surface *images[2];
210 	SDL_Surface *background;
211 	SDL_Rect srcrect;
212 	SDL_Rect dstrect;
213 
214 	/* Initialize status */
215 	status = -1;
216 
217 	/* Create the GUI holder */
218 	gui = new GUI(screen);
219 	font = GUI_DefaultFont();
220 
221 	/* Create the GUI elements */
222 	w = gui_w;
223 	h = gui_h;
224 	x = (screen->w - w)/2;
225 	y = (screen->h - h)/2;
226 
227 	/* Save the message box background to a private surface */
228 	srcrect.x = x;
229 	srcrect.y = y;
230 	srcrect.w = w;
231 	srcrect.h = h;
232 	dstrect = srcrect;
233 	background = SDL_AllocSurface(SDL_SWSURFACE, w, h,
234 				screen->format->BitsPerPixel,
235 				screen->format->Rmask,
236 				screen->format->Gmask,
237 				screen->format->Bmask, 0);
238 	SDL_BlitSurface(screen, &srcrect, background, NULL);
239 
240 	/* Adjust for the height of buttons */
241 	if ( style != GUI_MBNONE ) {
242 		h -= 1+32+1;
243 	}
244 
245 	/* Create the title, if any */
246 	if ( title ) {
247 		char titletext[1024];
248 		int title_x, title_y;
249 		int title_w, title_h;
250 
251 		/* Set up the title coordinates */
252 		title_x = x;
253 		title_y = x;
254 		title_w = w;
255 		title_h = ((font->h/16)-1) + 4;
256 		y += title_h;
257 		h -= title_h;
258 
259 		/* Add the outer frame */
260 		widget = new GUI_Area(title_x, title_y, title_w, title_h,
261 							0, 0, 0);
262 		gui->AddWidget(widget);
263 
264 		/* Add the inner frame */
265 		title_x += 1; title_y += 1;
266 		title_h -= 1; title_w -= 2;
267 		widget = new GUI_Area(title_x, title_y, title_w, title_h,
268 							255, 255, 255);
269 		gui->AddWidget(widget);
270 
271 		/* Add the centered title text */
272 		title_x += 1; title_y += 1;
273 		title_h -= 2; title_w -= 2;
274 		textout = new GUI_TermWin(title_x, title_y, title_w, title_h,
275 							font);
276 		for ( i=0; i<((title_w/(font->w/16))-strlen(title))/2; ++i ) {
277 			titletext[i] = ' ';
278 		}
279 		titletext[i] = '\0';
280 		strcat(titletext, title);
281 		textout->AddText(titletext, strlen(titletext));
282 		gui->AddWidget(textout);
283 	}
284 
285 	/* Create outer frame */
286 	widget = new GUI_Area(x, y, w, h, 0, 0, 0);
287 	gui->AddWidget(widget);
288 
289 	/* Create inner frame */
290 	x += 1; y += 1;
291 	w -= 2; h -= 2;
292 	widget = new GUI_Area(x, y, w, h, 255, 255, 255);
293 	gui->AddWidget(widget);
294 
295 	/* Create text output area */
296 	x += 1; y += 1;
297 	h -= 2; w -= 2;
298 	textout = new GUI_TermWin(x, y, w, h, font);
299 	textout->AddText(text, strlen(text));
300 	gui->AddWidget(textout);
301 
302 	/* Create any buttons */
303 	y += h+2;
304 	for ( i=0; i<2; ++i ) {
305 		images[i] = NULL;
306 	}
307 	if ( style == GUI_MBNONE ) {
308 		y += 1;
309 	} else {
310 		/* Create button frame */
311 		x = (screen->w - gui_w)/2;
312 		w = gui_w;
313 		h = 1+32+1;
314 		widget = new GUI_Area(x, y, w, h, 0, 0, 0);
315 		gui->AddWidget(widget);
316 		x += 1; y += 1;
317 		w -= 2; h -= 2;
318 		widget = new GUI_Area(x, y, w, h, 0xAA, 0xAA, 0xAA);
319 		gui->AddWidget(widget);
320 	}
321 	switch (style) {
322 		case GUI_MBNONE:	/* Create a single large button */
323 			x = (screen->w - gui_w)/2;
324 			y = (screen->h - gui_h)/2;
325 			button = new GUI_Button(NULL, x, y, gui_w, gui_h);
326 			gui->AddWidget(button);
327 			break;
328 		case GUI_MBOK:	/* Create a single "OK" button */
329 			images[0] = GUI_LoadImage(okay_w, okay_h, okay_pal,
330 								okay_data);
331 			x = (screen->w - images[0]->w)/2;
332 			button = new GUI_Button(&status, x, y,images[0],NULL,
333 							OK_ButtonProc);
334 			gui->AddWidget(button);
335 			break;
336 		case GUI_MBOKCANCEL: /* Create "OK" and "Cancel" buttons */
337 			images[0] = GUI_LoadImage(cancel_w, cancel_h,
338 						cancel_pal, cancel_data);
339 			x = (screen->w - gui_w)/2 + 1;
340 			button = new GUI_Button(&status, x, y,images[0],NULL,
341 							Cancel_ButtonProc);
342 			gui->AddWidget(button);
343 			images[1] = GUI_LoadImage(okay_w, okay_h, okay_pal,
344 								okay_data);
345 			x = screen->w - ((screen->w - gui_w)/2 + 1) -
346 							images[0]->w;
347 			button = new GUI_Button(&status, x, y,images[1],NULL,
348 							OK_ButtonProc);
349 			gui->AddWidget(button);
350 			break;
351 	}
352 
353 	/* Run the GUI */
354 	gui->Run();
355 
356 	/* Clean up, restore background, and return the status */
357 	delete gui;
358 	for ( i=0; i<2; ++i ) {
359 		if ( images[i] ) {
360 			SDL_FreeSurface(images[i]);
361 		}
362 	}
363 	SDL_BlitSurface(background, NULL, screen, &dstrect);
364 	SDL_UpdateRects(screen, 1, &dstrect);
365 	return(status);
366 }
367 
368 }; /* Extern C */
369