1 /*
2  * sdlgui.cpp - a GEM like graphical user interface
3  *
4  * Copyright (c) 2001 Thomas Huth - taken from his hatari project
5  * Copyright (c) 2002-2007 Petr Stehlik of ARAnyM dev team (see AUTHORS)
6  *
7  * This file is part of the ARAnyM project which builds a new and powerful
8  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
9  *
10  * ARAnyM is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * ARAnyM is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with ARAnyM; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #include "sysdeps.h"
26 #include "sdlgui.h"
27 #include "file.h"
28 #include "tools.h"
29 #include "host_surface.h"
30 #include "hostscreen.h"
31 #include "host.h"
32 #include "main.h"
33 #include "maptab.h"
34 #ifdef OS_darwin
35 #include <CoreFoundation/CoreFoundation.h>
36 #endif
37 
38 #include <cstdlib>
39 #include <stack>
40 
41 #include "font.h"
42 #include "fontsmall.h"
43 #include "dialog.h"
44 #include "dlgMain.h"
45 #include "dlgAlert.h"
46 
47 #define DEBUG 0
48 #include "debug.h"
49 
50 #define sdlscrn		gui_surf
51 
52 static SDL_Surface *fontgfx=NULL;
53 static SDL_Surface *fontgfxsmall=NULL;
54 /* layout of the converted surface */
55 #define FONTCOLS 128
56 #define FONTROWS ((FONTCHARS + FONTCOLS - 1) / FONTCOLS)
57 
58 static std::stack<Dialog *> dlgStack;
59 
60 /* gui surface */
61 static HostSurface *gui_hsurf = NULL;
62 static SDL_Surface *gui_surf = NULL;
63 static int gui_x = 0, gui_y = 0; /* gui position */
64 
65 /* current dialog to draw */
66 static Dialog *gui_dlg = NULL;
67 
68 static SDL_Color gui_palette[4] = {
69 	{0,0,0,255},
70 	{128,128,128,255},
71 	{192,192,192, 255},
72 	{255, 255, 255, 255}
73 };
74 
75 enum {
76 	blackc = 0,
77 	darkgreyc,
78 	greyc,
79 	whitec
80 };
81 
82 /* the glyph to display for undefined characters */
83 #define REPLACEMENT_GLYPH 0x6ff
84 
85 // Stores current dialog coordinates
86 static SDL_Rect DialogRect = {0, 0, 0, 0};
87 
88 #if 0
89 // Used by SDLGui_Get[First|Next]BackgroundRect()
90 static SDL_Rect BackgroundRect = {0, 0, 0, 0};
91 static int BackgroundRectCounter;
92 enum
93 {
94   SG_BCKGND_RECT_BEGIN,
95   SG_BCKGND_RECT_TOP,
96   SG_BCKGND_RECT_LEFT,
97   SG_BCKGND_RECT_RIGHT,
98   SG_BCKGND_RECT_BOTTOM,
99   SG_BCKGND_RECT_END
100 };
101 #endif
102 
103 /* Special characters: */
104 /*
105  * These are used for radio & checkboxes.
106  * Each graphic is composed of two characters,
107  * which are encoded as 0x600-0x0607 so they
108  * don't conflict with any other character.
109  */
110 static char const SGCHECKBOX_RADIO_NORMAL[4] = { '\330', '\200', '\330', '\201' };
111 static char const SGCHECKBOX_RADIO_SELECTED[4] = { '\330', '\202', '\330', '\203' };
112 static char const SGCHECKBOX_NORMAL[4] = { '\330', '\204', '\330', '\205' };
113 static char const SGCHECKBOX_SELECTED[4] = { '\330', '\206', '\330', '\207' };
114 
115 /*-----------------------------------------------------------------------*/
116 /*
117   Load an 1 plane XBM into a 8 planes SDL_Surface.
118 */
SDLGui_LoadXBM(const Uint8 * srcbits,int width,int height,int form_width)119 static SDL_Surface *SDLGui_LoadXBM(const Uint8 *srcbits, int width, int height, int form_width)
120 {
121 	SDL_Surface *bitmap;
122 	Uint8 *dstbits;
123 	int ascii;
124 
125 	/* Allocate the bitmap */
126 	bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, FONTCOLS * width, FONTROWS * height, 8, 0, 0, 0, 0);
127 	if ( bitmap == NULL )
128 	{
129 		panicbug("Couldn't allocate bitmap: %s", SDL_GetError());
130 		return(NULL);
131 	}
132 
133 	dstbits = (Uint8 *)bitmap->pixels;
134 
135 	/* Copy the pixels */
136 	for (ascii = 0; ascii < FONTCHARS; ascii++)
137 	{
138 		int y0 = ascii / FONTCOLS;
139 		int x0 = ascii % FONTCOLS;
140 		int x, y;
141 
142 		for (y = 0; y < height; y++)
143 		{
144 			for (x = 0; x < width; x++)
145 			{
146 				int off = ascii * width + x;
147 				int bit = off & 7;
148 				dstbits[(y0 * height + y) * bitmap->pitch + x0 * width + x] =
149 					(srcbits[(off >> 3) + y * form_width] & (0x80 >> bit)) ? 1 : 0;
150 			}
151 		}
152 	}
153 
154 	return bitmap;
155 }
156 
157 /*-----------------------------------------------------------------------*/
158 /*
159   Initialize the GUI.
160 */
SDLGui_Init()161 bool SDLGui_Init()
162 {
163 	// Load the font graphics
164 	char font_filename[256];
165 	unsigned char font_data_buffer[FONTHEIGHT * FORM_WIDTH];
166 	getConfFilename("font", font_filename, sizeof(font_filename));
167 	FILE *f = fopen(font_filename, "rb");
168 	const unsigned char *font_data = NULL;
169 	if (f != NULL) {
170 		if (fread(font_data_buffer, 1, sizeof(font_data_buffer), f) == sizeof(font_data_buffer)) {
171 			font_data = font_data_buffer;
172 		}
173 		fclose(f);
174 	}
175 	// If font can't be loaded use the internal one
176 	if (font_data == NULL) {
177 		font_data = font_bits;
178 	}
179 
180 	fontgfx = SDLGui_LoadXBM(font_data, FONTWIDTH, FONTHEIGHT, FORM_WIDTH);
181 	if (fontgfx == NULL)
182 	{
183 		panicbug("Could not create font data");
184 		panicbug("ARAnyM GUI will not be available");
185 		return false;
186 	}
187 	fontgfxsmall = SDLGui_LoadXBM(fontsmall_bits, FONTSMALLWIDTH, FONTSMALLHEIGHT, FORMSMALL_WIDTH);
188 
189 	gui_hsurf = host->video->createSurface(76*8+16,25*16+16,8);
190 	if (!gui_hsurf) {
191 		panicbug("Could not create surface for GUI");
192 		panicbug("ARAnyM GUI will not be available");
193 		return false;
194 	}
195 
196 	gui_surf = gui_hsurf->getSdlSurface();
197 
198 	gui_hsurf->setPalette(gui_palette, 0, 4);
199 
200 //	gui_hsurf->setParam(HostSurface::SURF_ALPHA, bx_options.opengl.gui_alpha);
201 //	gui_hsurf->setParam(HostSurface::SURF_USE_ALPHA, 1);
202 
203 	/* Set font color 0 as transparent */
204 	SDL_SetColorKey(fontgfx, SDL_SRCCOLORKEY, 0);
205 	if (fontgfxsmall)
206 		SDL_SetColorKey(fontgfxsmall, SDL_SRCCOLORKEY, 0);
207 
208 #if 0 /* for testing */
209 #if SDL_VERSION_ATLEAST(2, 0, 0)
210 	SDL_SetPaletteColors(fontgfx->format->palette, &gui_palette[whitec], 0, 1);
211 	SDL_SetPaletteColors(fontgfx->format->palette, &gui_palette[blackc], 1, 1);
212 #else
213 	SDL_SetColors(fontgfx, &gui_palette[whitec], 0, 1);
214 	SDL_SetColors(fontgfx, &gui_palette[blackc], 1, 1);
215 #endif
216 
217 	SDL_SaveBMP(fontgfx, "aranym-font.bmp");
218 #endif
219 
220 	return true;
221 }
222 
223 
224 /*-----------------------------------------------------------------------*/
225 /*
226   Uninitialize the GUI.
227 */
SDLGui_UnInit()228 int SDLGui_UnInit()
229 {
230 	if (gui_hsurf) {
231 		host->video->destroySurface(gui_hsurf);
232 		gui_hsurf = NULL;
233 	}
234 
235 	if (fontgfx)
236 	{
237 		SDL_FreeSurface(fontgfx);
238 		fontgfx = NULL;
239 	}
240 
241 	if (fontgfxsmall)
242 	{
243 		SDL_FreeSurface(fontgfxsmall);
244 		fontgfxsmall = NULL;
245 	}
246 
247 	return 0;
248 }
249 
250 
251 /*-----------------------------------------------------------------------*/
252 /*
253   Compute real coordinates for a given object.
254   Note: centers dialog on screen.
255 */
SDLGui_ObjCoord(SGOBJ * dlg,int objnum,SDL_Rect * rect)256 static void SDLGui_ObjCoord(SGOBJ *dlg, int objnum, SDL_Rect *rect)
257 {
258   rect->x = dlg[objnum].x * FONTWIDTH;
259   rect->y = dlg[objnum].y * FONTHEIGHT;
260   if (dlg[objnum].flags & SG_SMALLTEXT)
261   {
262     rect->w = dlg[objnum].w * FONTSMALLWIDTH;
263     rect->h = dlg[objnum].h * FONTSMALLHEIGHT;
264     rect->y += 3;
265   } else
266   {
267     rect->w = dlg[objnum].w * FONTWIDTH;
268     rect->h = dlg[objnum].h * FONTHEIGHT;
269   }
270   rect->x += (sdlscrn->w - (dlg[0].w * FONTWIDTH)) / 2;
271   rect->y += (sdlscrn->h - (dlg[0].h * FONTHEIGHT)) / 2;
272 }
273 
274 
275 /*-----------------------------------------------------------------------*/
276 /*
277   Compute real coordinates for a given object.
278   This one takes borders into account and give coordinates as seen by user
279 */
SDLGui_ObjFullCoord(SGOBJ * dlg,int objnum,SDL_Rect * coord)280 void SDLGui_ObjFullCoord(SGOBJ *dlg, int objnum, SDL_Rect *coord)
281 {
282   SDLGui_ObjCoord(dlg, objnum, coord);
283 
284   switch (dlg[objnum].type)
285   {
286     case SGBOX:
287     case SGBUTTON:
288       {
289         // Take border into account
290         int border_size;
291 
292         if (dlg[objnum].flags & SG_SELECTABLE)
293         {
294           if (dlg[objnum].flags & SG_DEFAULT)
295             border_size = 4;
296           else
297             border_size = 3;
298         }
299         else
300         {
301           if (dlg[objnum].flags & SG_BACKGROUND)
302             border_size = 6;
303           else
304             border_size = 5;
305         }
306 
307         coord->x -= border_size;
308         coord->y -= border_size;
309         coord->w += (border_size * 2);
310         coord->h += (border_size * 2);
311       }
312       break;
313     case SGEDITFIELD:
314       // Allow one more pixel to the right for cursor
315       coord->w += 1;
316       // There is a line below
317       coord->h += 1;
318       break;
319   }
320 }
321 
322 
323 /*-----------------------------------------------------------------------*/
324 /*
325   Refresh display at given coordinates.
326   Unlike SDL_UpdateRect() this function can eat coords that goes beyond screen
327   boundaries.
328   "rect" will be modified to represent the area actually refreshed.
329 */
SDLGui_UpdateRect(SDL_Rect * rect)330 void SDLGui_UpdateRect(SDL_Rect *rect)
331 {
332   if (rect->x < 0)
333   {
334     rect->w += rect->x;
335     rect->x = 0;
336   }
337   if ((rect->x + rect->w) > sdlscrn->w)
338     rect->w = (sdlscrn->w - rect->x);
339 
340   if (rect->y < 0)
341   {
342     rect->h += rect->y;
343     rect->y = 0;
344   }
345   if ((rect->y + rect->h) > sdlscrn->h)
346     rect->h = (sdlscrn->h - rect->y);
347 
348   if ((rect->w > 0) && (rect->h > 0))
349   {
350 #if SDL_VERSION_ATLEAST(2, 0, 0)
351     host->video->refreshScreenFromSurface(sdlscrn);
352 #else
353     SDL_UpdateRects(sdlscrn, 1, rect);
354 #endif
355   } else
356   {
357     rect->x = 0;
358     rect->y = 0;
359     rect->w = 0;
360     rect->h = 0;
361   }
362 }
363 
364 
365 /*-----------------------------------------------------------------------*/
366 /*
367   Maps an SDL_Color to the screen format.
368 */
SDLGui_MapColor(int color)369 Uint32 SDLGui_MapColor(int color)
370 {
371   return SDL_MapRGB(sdlscrn->format,
372   	gui_palette[color].r, gui_palette[color].g, gui_palette[color].b);
373 }
374 
375 
376 /*-----------------------------------------------------------------------*/
377 /*
378   Refresh display to reflect an object change.
379 */
SDLGui_RefreshObj(SGOBJ * dlg,int objnum)380 void SDLGui_RefreshObj(SGOBJ *dlg, int objnum)
381 {
382   SDL_Rect coord;
383 
384   SDLGui_ObjFullCoord(dlg, objnum, &coord);
385 
386   SDLGui_UpdateRect(&coord);
387 }
388 
389 
host_to_atari(const char * src)390 static unsigned short *host_to_atari(const char *src)
391 {
392 #ifdef OS_darwin
393 	/* MacOSX uses decomposed strings, normalize them first */
394 	CFMutableStringRef theString = CFStringCreateMutable(NULL, 0);
395 	CFStringAppendCString(theString, src, kCFStringEncodingUTF8);
396 	CFStringNormalize(theString, kCFStringNormalizationFormC);
397 	UniChar ch;
398 	CFIndex idx;
399 	CFIndex len = CFStringGetLength(theString);
400 	unsigned short *dst, *res;
401 	size_t count = strlen(src);
402 
403 	res = (unsigned short *)malloc((count + 1) * sizeof(*res));
404 	dst = res;
405 	idx = 0;
406 	while (idx < len )
407 	{
408 		ch = CFStringGetCharacterAtIndex(theString, idx);
409 		if (ch >= FONTCHARS || (ch >= 0x80 && ch < 0xa0))
410 		{
411 			ch = REPLACEMENT_GLYPH;
412 		} else if (ch >= FONTCHARS)
413 		{
414 			ch = utf16_to_atari[ch];
415 			if (ch >= FONTCHARS)
416 				ch = REPLACEMENT_GLYPH;
417 		}
418 		*dst++ = ch;
419 		idx++;
420 	}
421 	*dst = '\0';
422 	CFRelease(theString);
423 #else
424 	unsigned short ch;
425 	size_t bytes;
426 	unsigned short *dst, *res;
427 	size_t count = strlen(src);
428 
429 	res = (unsigned short *)malloc((count + 1) * sizeof(*res));
430 	dst = res;
431 
432 	while (*src)
433 	{
434 		ch = (unsigned char) *src;
435 		if (ch < 0x80)
436 		{
437 			bytes = 1;
438 		} else if ((ch & 0xe0) == 0xc0)
439 		{
440 			ch = ((ch & 0x1f) << 6) | (src[1] & 0x3f);
441 			bytes = 2;
442 		} else
443 		{
444 			ch = ((((ch & 0x0f) << 6) | (src[1] & 0x3f)) << 6) | (src[2] & 0x3f);
445 			bytes = 3;
446 		}
447 		if (ch >= FONTCHARS || (ch >= 0x80 && ch < 0xa0))
448 		{
449 			ch = REPLACEMENT_GLYPH;
450 		} else if (ch >= 0x100)
451 		{
452 			ch = utf16_to_atari[ch];
453 			if (ch >= FONTCHARS)
454 				ch = REPLACEMENT_GLYPH;
455 		}
456 		*dst++ = ch;
457 		src += bytes;
458 	}
459 	*dst = '\0';
460 #endif
461 	return res;
462 }
463 
464 /*-----------------------------------------------------------------------*/
465 /*
466   Draw a text string.
467 */
SDLGui_Text(int x,int y,const char * txt,int col)468 void SDLGui_Text(int x, int y, const char *txt, int col)
469 {
470   int i;
471   unsigned short c;
472   SDL_Rect sr, dr;
473   unsigned short *conv;
474 
475 #if SDL_VERSION_ATLEAST(2, 0, 0)
476   SDL_SetPaletteColors(fontgfx->format->palette, &gui_palette[col], 1, 1);
477 #else
478   SDL_SetColors(fontgfx, &gui_palette[col], 1, 1);
479 #endif
480 
481   conv = host_to_atari(txt);
482   for (i = 0; conv[i] != 0; i++)
483   {
484     c = conv[i];
485     sr.x = FONTWIDTH * (c % FONTCOLS);
486     sr.y = FONTHEIGHT * (c / FONTCOLS);
487     sr.w = FONTWIDTH;
488     sr.h = FONTHEIGHT;
489 
490     dr.x = x + (FONTWIDTH * i);
491     dr.y = y;
492     dr.w = FONTWIDTH;
493     dr.h = FONTHEIGHT;
494 
495     SDL_BlitSurface(fontgfx, &sr, sdlscrn, &dr);
496   }
497   free(conv);
498 }
499 
500 /*-----------------------------------------------------------------------*/
501 /*
502   Draw a text string, using the smaller font.
503 */
SDLGui_TextSmall(int x,int y,const char * txt,int col)504 void SDLGui_TextSmall(int x, int y, const char *txt, int col)
505 {
506   int i;
507   unsigned short c;
508   SDL_Rect sr, dr;
509   unsigned short *conv;
510 
511   if (fontgfxsmall == NULL)
512   {
513     SDLGui_Text(x, y, txt, col);
514     return;
515   }
516 #if SDL_VERSION_ATLEAST(2, 0, 0)
517   SDL_SetPaletteColors(fontgfxsmall->format->palette, &gui_palette[col], 1, 1);
518 #else
519   SDL_SetColors(fontgfxsmall, &gui_palette[col], 1, 1);
520 #endif
521 
522   conv = host_to_atari(txt);
523   for (i = 0; conv[i] != 0; i++)
524   {
525     c = conv[i];
526     sr.x = FONTSMALLWIDTH * (c % FONTCOLS);
527     sr.y = FONTSMALLHEIGHT * (c / FONTCOLS);
528     sr.w = FONTSMALLWIDTH;
529     sr.h = FONTSMALLHEIGHT;
530 
531     dr.x = x + (FONTSMALLWIDTH * i);
532     dr.y = y;
533     dr.w = FONTSMALLWIDTH;
534     dr.h = FONTSMALLHEIGHT;
535 
536     SDL_BlitSurface(fontgfxsmall, &sr, sdlscrn, &dr);
537   }
538   free(conv);
539 }
540 
541 /*-----------------------------------------------------------------------*/
542 /*
543  * return the number of characters that are displayed
544  */
SDLGui_TextLen(const char * txt)545 int SDLGui_TextLen(const char *txt)
546 {
547   unsigned short *conv;
548   int i;
549 
550   conv = host_to_atari(txt);
551   for (i = 0; conv[i] != 0; i++)
552     ;
553   free(conv);
554   return i;
555 }
556 
557 /*-----------------------------------------------------------------------*/
558 /*
559  * return the number of up to a given character index
560  */
SDLGui_ByteLen(const char * txt,int pos)561 int SDLGui_ByteLen(const char *txt, int pos)
562 {
563 	size_t bytes;
564 	const char *src = txt;
565 	unsigned char ch;
566 
567 	while (pos > 0 && *src)
568 	{
569 		ch = *src;
570 		if (ch < 0x80)
571 		{
572 			bytes = 1;
573 		} else if ((ch & 0xe0) == 0xc0 && src[1])
574 		{
575 			bytes = 2;
576 		} else if (src[1] && src[2])
577 		{
578 			bytes = 3;
579 		} else
580 		{
581 			bytes = 1;
582 		}
583 		src += bytes;
584 		pos--;
585 	}
586 
587 	return (int)(src - txt);
588 }
589 
590 /*-----------------------------------------------------------------------*/
591 /*
592   Draw a dialog text object.
593 */
SDLGui_DrawText(SGOBJ * tdlg,int objnum)594 void SDLGui_DrawText(SGOBJ *tdlg, int objnum)
595 {
596   SDL_Rect coord;
597   int textc, backgroundc;
598 
599   if (tdlg[objnum].state & SG_SELECTED)
600   {
601     textc       = whitec;
602     backgroundc = darkgreyc;
603   }
604   else if (tdlg[objnum].state & SG_DISABLED)
605   {
606     textc       = darkgreyc;
607     backgroundc = greyc;
608   }
609   else
610   {
611     textc       = blackc;
612     backgroundc = greyc;
613   }
614 
615   SDLGui_ObjCoord(tdlg, objnum, &coord);
616   SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(backgroundc));
617   SDLGui_Text(coord.x, coord.y, tdlg[objnum].txt, textc);
618 }
619 
620 
621 /*-----------------------------------------------------------------------*/
622 /*
623   Draw a dialog text object.
624 */
SDLGui_DrawTextSmall(SGOBJ * tdlg,int objnum)625 void SDLGui_DrawTextSmall(SGOBJ *tdlg, int objnum)
626 {
627   SDL_Rect coord;
628   int textc, backgroundc;
629 
630   if (tdlg[objnum].state & SG_SELECTED)
631   {
632     textc       = whitec;
633     backgroundc = darkgreyc;
634   }
635   else if (tdlg[objnum].state & SG_DISABLED)
636   {
637     textc       = darkgreyc;
638     backgroundc = greyc;
639   }
640   else
641   {
642     textc       = blackc;
643     backgroundc = greyc;
644   }
645 
646   SDLGui_ObjCoord(tdlg, objnum, &coord);
647   SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(backgroundc));
648   SDLGui_TextSmall(coord.x, coord.y, tdlg[objnum].txt, textc);
649 }
650 
651 
652 /*-----------------------------------------------------------------------*/
653 /*
654   Draw an edit field object.
655 */
SDLGui_DrawEditField(SGOBJ * edlg,int objnum)656 void SDLGui_DrawEditField(SGOBJ *edlg, int objnum)
657 {
658   SDL_Rect coord;
659   int textc;
660 
661   if (edlg[objnum].state & SG_DISABLED)
662     textc = darkgreyc;
663   else
664     textc = blackc;
665 
666   SDLGui_ObjCoord(edlg, objnum, &coord);
667   coord.w += 1;
668   SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(greyc));
669   SDLGui_Text(coord.x, coord.y, edlg[objnum].txt, textc);
670 
671   // Draw a line below.
672   coord.y = coord.y + coord.h;
673   coord.h = 1;
674   SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(darkgreyc));
675 }
676 
677 
678 /*-----------------------------------------------------------------------*/
679 /*
680   Draw or erase cursor.
681 */
SDLGui_DrawCursor(SGOBJ * dlg,cursor_state * cursor)682 void SDLGui_DrawCursor(SGOBJ *dlg, cursor_state *cursor)
683 {
684   if (cursor->object != -1)
685   {
686     SDL_Rect coord;
687     int cursorc;
688 
689     SDLGui_DrawEditField(dlg, cursor->object);
690 
691     if (cursor->blink_state)
692       cursorc = blackc;
693     else
694       cursorc = greyc;
695 
696     SDLGui_ObjCoord(dlg, cursor->object, &coord);
697     coord.x += (cursor->position * FONTWIDTH);
698     coord.w = 1;
699     SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(cursorc));
700 
701     SDLGui_RefreshObj(dlg, cursor->object);
702   }
703 }
704 
705 
706 /*-----------------------------------------------------------------------*/
707 /*
708   Draw a 3D effect around a given rectangle.
709   Rectangle is updated to the full size of the new object.
710 */
SDLGui_Draw3DAround(SDL_Rect * coord,int upleftc,int downrightc,int cornerc,int width)711 void SDLGui_Draw3DAround(SDL_Rect *coord, int upleftc, int downrightc, int cornerc, int width)
712 {
713   SDL_Rect rect;
714   int i;
715   Uint32 upleftcol    = SDLGui_MapColor(upleftc);
716   Uint32 downrightcol = SDLGui_MapColor(downrightc);
717   Uint32 cornercol    = SDLGui_MapColor(cornerc);
718 
719   for ( i = 1 ; i <= width ; i++)
720   {
721     rect.x = coord->x - i;
722     rect.y = coord->y - i;
723     rect.w = coord->w + (i * 2) - 1;
724     rect.h = 1;
725     SDL_FillRect(sdlscrn, &rect, upleftcol);
726 
727     rect.x = coord->x - i;
728     rect.y = coord->y - i;
729     rect.w = 1;
730     rect.h = coord->h + (i * 2) - 1;
731     SDL_FillRect(sdlscrn, &rect, upleftcol);
732 
733     rect.x = coord->x - i + 1;
734     rect.y = coord->y + coord->h - 1 + i;
735     rect.w = coord->w + (i * 2) - 1;
736     rect.h = 1;
737     SDL_FillRect(sdlscrn, &rect, downrightcol);
738 
739     rect.x = coord->x + coord->w - 1 + i;
740     rect.y = coord->y - i + 1;
741     rect.w = 1;
742     rect.h = coord->h + (i * 2) - 1;
743     SDL_FillRect(sdlscrn, &rect, downrightcol);
744 
745     rect.x = coord->x + coord->w + i - 1;
746     rect.y = coord->y - i;
747     rect.w = 1;
748     rect.h = 1;
749     SDL_FillRect(sdlscrn, &rect, cornercol);
750 
751     rect.x = coord->x - i;
752     rect.y = coord->y + coord->h + i - 1;
753     rect.w = 1;
754     rect.h = 1;
755     SDL_FillRect(sdlscrn, &rect, cornercol);
756   }
757 
758   coord->x -= width;
759   coord->y -= width;
760   coord->w += (width * 2);
761   coord->h += (width * 2);
762 }
763 
764 
765 /*-----------------------------------------------------------------------*/
766 /*
767   Draw a colored box around a given rectangle.
768   Rectangle is updated to the full size of the new object.
769 */
SDLGui_DrawBoxAround(SDL_Rect * coord,int color,int width)770 void SDLGui_DrawBoxAround(SDL_Rect *coord, int color, int width)
771 {
772   SDL_Rect rect;
773   Uint32 col = SDLGui_MapColor(color);
774 
775   rect.x = coord->x - width;
776   rect.y = coord->y - width;
777   rect.w = coord->w + (width * 2);
778   rect.h = width;
779   SDL_FillRect(sdlscrn, &rect, col);
780 
781   rect.x = coord->x - width;
782   rect.y = coord->y - width;
783   rect.w = width;
784   rect.h = coord->h + (width * 2);
785   SDL_FillRect(sdlscrn, &rect, col);
786 
787   rect.x = coord->x + coord->w;
788   rect.y = coord->y - width;
789   rect.w = width;
790   rect.h = coord->h + (width * 2);
791   SDL_FillRect(sdlscrn, &rect, col);
792 
793   rect.x = coord->x - width;
794   rect.y = coord->y + coord->h;
795   rect.w = coord->w + (width * 2);
796   rect.h = width;
797   SDL_FillRect(sdlscrn, &rect, col);
798 
799   coord->x -= width;
800   coord->y -= width;
801   coord->w += (width * 2);
802   coord->h += (width * 2);
803 }
804 
805 
806 /*-----------------------------------------------------------------------*/
807 /*
808   Draw a 3D box with given attributes.
809 */
SDLGui_Draw3DBox(SDL_Rect * coord,int backgroundc,int inboxc,int upleftc,int downrightc,int outboxc,int widthbackground,int widthinbox,int width3D1,int width3D2,int widthoutbox)810 void SDLGui_Draw3DBox(SDL_Rect *coord,
811                       int backgroundc,
812                       int inboxc,
813                       int upleftc,
814                       int downrightc,
815                       int outboxc,
816                       int widthbackground,
817                       int widthinbox,
818                       int width3D1,
819                       int width3D2,
820                       int widthoutbox)
821 {
822   SDL_Rect rect;
823 
824   // Draw background
825   rect.x = coord->x - widthbackground;
826   rect.y = coord->y - widthbackground*2;
827   rect.w = coord->w + (widthbackground * 2);
828   rect.h = coord->h + (widthbackground*2 * 2);
829   SDL_FillRect(sdlscrn, &rect, SDLGui_MapColor(backgroundc));
830 
831   // Update coords
832   coord->x -= widthbackground;
833   coord->y -= widthbackground*5/2;
834   coord->w += (widthbackground * 2);
835   coord->h += (widthbackground*5/2 * 2);
836 
837   if (widthinbox > 0)
838     SDLGui_DrawBoxAround(coord, inboxc, widthinbox);
839 
840   if (width3D1 > 0)
841     SDLGui_Draw3DAround(coord, upleftc, downrightc, backgroundc, width3D1);
842 
843   if (width3D2 > 0)
844     SDLGui_Draw3DAround(coord, downrightc, upleftc, backgroundc, width3D2);
845 
846   if (widthoutbox > 0)
847     SDLGui_DrawBoxAround(coord, outboxc, widthoutbox);
848 }
849 
850 
851 /*-----------------------------------------------------------------------*/
852 /*
853   Draw a dialog box object.
854 */
SDLGui_DrawBox(SGOBJ * bdlg,int objnum)855 void SDLGui_DrawBox(SGOBJ *bdlg, int objnum)
856 {
857   SDL_Rect coord;
858   int my_blackc, upleftc, downrightc;
859 
860   SDLGui_ObjCoord(bdlg, objnum, &coord);
861 
862   // Modify box drawing according to object state
863   if (bdlg[objnum].state & SG_DISABLED)
864     my_blackc = darkgreyc;
865   else
866     my_blackc = blackc;
867 
868   if (bdlg[objnum].state & SG_SELECTED)
869   {
870     upleftc    = darkgreyc;
871     downrightc = whitec;
872   }
873   else
874   {
875     upleftc    = whitec;
876     downrightc = darkgreyc;
877   }
878 
879   // Draw box according to object flags
880   switch (bdlg[objnum].flags & (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND))
881   {
882     case (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND):
883     case (SG_SELECTABLE | SG_DEFAULT):
884       SDLGui_Draw3DBox(&coord,
885                        greyc, 0, upleftc, downrightc, my_blackc,
886                        1, 0, 1, 0, 2);
887       break;
888     case (SG_SELECTABLE | SG_BACKGROUND):
889     case SG_SELECTABLE:
890       SDLGui_Draw3DBox(&coord,
891                        greyc, 0, upleftc, downrightc, my_blackc,
892                        1, 0, 1, 0, 1);
893       break;
894     case (SG_DEFAULT | SG_BACKGROUND):
895     case SG_BACKGROUND:
896       SDLGui_Draw3DBox(&coord,
897                        greyc, my_blackc, upleftc, downrightc, darkgreyc,
898                        0, 2, 3, 0, 1);
899       break;
900     case SG_DEFAULT:
901     case 0:
902       SDLGui_Draw3DBox(&coord,
903                        greyc, 0, upleftc, downrightc, 0,
904                        3, 0, 1, 1, 0);
905       break;
906   }
907 }
908 
909 
910 /*-----------------------------------------------------------------------*/
911 /*
912   Draw a normal button.
913 */
SDLGui_DrawButton(SGOBJ * bdlg,int objnum)914 void SDLGui_DrawButton(SGOBJ *bdlg, int objnum)
915 {
916   SDL_Rect coord;
917   int x, y;
918   int textc;
919 
920   SDLGui_ObjCoord(bdlg, objnum, &coord);
921 
922   x = coord.x + ((coord.w - (SDLGui_TextLen(bdlg[objnum].txt) * FONTWIDTH)) / 2);
923   y = coord.y + ((coord.h - FONTHEIGHT) / 2);
924 
925   if (bdlg[objnum].state & SG_SELECTED)
926   {
927     x += 1;
928     y += 1;
929   }
930 
931   if (bdlg[objnum].state & SG_DISABLED)
932     textc = darkgreyc;
933   else
934     textc = blackc;
935 
936   SDLGui_DrawBox(bdlg, objnum);
937   SDLGui_Text(x, y, bdlg[objnum].txt, textc);
938 }
939 
940 
941 /*-----------------------------------------------------------------------*/
942 /*
943   Draw a normal button.
944 */
SDLGui_DrawButtonSmall(SGOBJ * bdlg,int objnum)945 void SDLGui_DrawButtonSmall(SGOBJ *bdlg, int objnum)
946 {
947   SDL_Rect coord;
948   int x, y;
949   int textc;
950 
951   SDLGui_ObjCoord(bdlg, objnum, &coord);
952 
953   x = coord.x + ((coord.w - (SDLGui_TextLen(bdlg[objnum].txt) * FONTSMALLWIDTH)) / 2);
954   y = coord.y + ((coord.h - FONTSMALLHEIGHT) / 2);
955 
956   if (bdlg[objnum].state & SG_SELECTED)
957   {
958     x += 1;
959     y += 1;
960   }
961 
962   if (bdlg[objnum].state & SG_DISABLED)
963     textc = darkgreyc;
964   else
965     textc = blackc;
966 
967   SDLGui_DrawBox(bdlg, objnum);
968   SDLGui_TextSmall(x, y, bdlg[objnum].txt, textc);
969 }
970 
971 
972 /*-----------------------------------------------------------------------*/
973 /*
974   Draw a dialog check box object state.
975 */
SDLGui_DrawCheckBoxState(SGOBJ * cdlg,int objnum)976 void SDLGui_DrawCheckBoxState(SGOBJ *cdlg, int objnum)
977 {
978   Uint32 grey = SDLGui_MapColor(greyc);
979   SDL_Rect coord;
980   char str[5];
981   int textc;
982 
983   SDLGui_ObjCoord(cdlg, objnum, &coord);
984 
985   if (cdlg[objnum].flags & SG_RADIO)
986   {
987     if (cdlg[objnum].state & SG_SELECTED) {
988       str[0]=SGCHECKBOX_RADIO_SELECTED[0];
989       str[1]=SGCHECKBOX_RADIO_SELECTED[1];
990       str[2]=SGCHECKBOX_RADIO_SELECTED[2];
991       str[3]=SGCHECKBOX_RADIO_SELECTED[3];
992     }
993     else {
994       str[0]=SGCHECKBOX_RADIO_NORMAL[0];
995       str[1]=SGCHECKBOX_RADIO_NORMAL[1];
996       str[2]=SGCHECKBOX_RADIO_NORMAL[2];
997       str[3]=SGCHECKBOX_RADIO_NORMAL[3];
998     }
999   }
1000   else
1001   {
1002     if (cdlg[objnum].state & SG_SELECTED) {
1003       str[0]=SGCHECKBOX_SELECTED[0];
1004       str[1]=SGCHECKBOX_SELECTED[1];
1005       str[2]=SGCHECKBOX_SELECTED[2];
1006       str[3]=SGCHECKBOX_SELECTED[3];
1007     }
1008     else {
1009       str[0]=SGCHECKBOX_NORMAL[0];
1010       str[1]=SGCHECKBOX_NORMAL[1];
1011       str[2]=SGCHECKBOX_NORMAL[2];
1012       str[3]=SGCHECKBOX_NORMAL[3];
1013     }
1014   }
1015   str[4]='\0';
1016 
1017   if (cdlg[objnum].state & SG_DISABLED)
1018     textc = darkgreyc;
1019   else
1020     textc = blackc;
1021 
1022   coord.w = FONTWIDTH*2;
1023   coord.h = FONTHEIGHT;
1024 
1025   if (cdlg[objnum].flags & SG_BUTTON_RIGHT)
1026     coord.x += ((SDLGui_TextLen(cdlg[objnum].txt) + 1) * FONTWIDTH);
1027 
1028   SDL_FillRect(sdlscrn, &coord, grey);
1029   SDLGui_Text(coord.x, coord.y, str, textc);
1030 }
1031 
1032 
1033 /*-----------------------------------------------------------------------*/
1034 /*
1035   Draw a dialog check box object.
1036 */
SDLGui_DrawCheckBox(SGOBJ * cdlg,int objnum)1037 void SDLGui_DrawCheckBox(SGOBJ *cdlg, int objnum)
1038 {
1039   SDL_Rect coord;
1040   int textc;
1041 
1042   SDLGui_ObjCoord(cdlg, objnum, &coord);
1043 
1044   if (!(cdlg[objnum].flags&SG_BUTTON_RIGHT))
1045     coord.x += (FONTWIDTH * 3); // 2 chars for the box plus 1 space
1046 
1047   if (cdlg[objnum].state & SG_DISABLED)
1048     textc = darkgreyc;
1049   else
1050     textc = blackc;
1051 
1052   SDLGui_Text(coord.x, coord.y, cdlg[objnum].txt, textc);
1053   SDLGui_DrawCheckBoxState(cdlg, objnum);
1054 }
1055 
1056 
1057 /*-----------------------------------------------------------------------*/
1058 /*
1059   Draw a dialog popup button object.
1060 */
SDLGui_DrawPopupButton(SGOBJ * pdlg,int objnum)1061 void SDLGui_DrawPopupButton(SGOBJ *pdlg, int objnum)
1062 {
1063   SDL_Rect coord;
1064   static char const downstr[2] = { SGARROWDOWN, 0 };
1065   int textc;
1066 
1067   if (pdlg[objnum].state & SG_DISABLED)
1068     textc = darkgreyc;
1069   else
1070     textc = blackc;
1071 
1072   SDLGui_DrawBox(pdlg, objnum);
1073 
1074   SDLGui_ObjCoord(pdlg, objnum, &coord);
1075 
1076   SDLGui_Text(coord.x, coord.y, pdlg[objnum].txt, textc);
1077   SDLGui_Text(coord.x+coord.w-FONTWIDTH, coord.y, downstr, textc);
1078 }
1079 
1080 
1081 /*-----------------------------------------------------------------------*/
1082 /*
1083   Draw an object.
1084 */
SDLGui_DrawObject(SGOBJ * dlg,int objnum)1085 void SDLGui_DrawObject(SGOBJ *dlg, int objnum)
1086 {
1087   switch (dlg[objnum].type)
1088   {
1089     case SGBOX:
1090       SDLGui_DrawBox(dlg, objnum);
1091       break;
1092     case SGTEXT:
1093       if (dlg[objnum].flags & SG_SMALLTEXT)
1094         SDLGui_DrawTextSmall(dlg, objnum);
1095       else
1096         SDLGui_DrawText(dlg, objnum);
1097       break;
1098     case SGEDITFIELD:
1099       SDLGui_DrawEditField(dlg, objnum);
1100       break;
1101     case SGBUTTON:
1102       if (dlg[objnum].flags & SG_SMALLTEXT)
1103         SDLGui_DrawButtonSmall(dlg, objnum);
1104       else
1105         SDLGui_DrawButton(dlg, objnum);
1106       break;
1107     case SGCHECKBOX:
1108     case SGRADIOBUT:
1109       SDLGui_DrawCheckBox(dlg, objnum);
1110       break;
1111     case SGPOPUP:
1112       SDLGui_DrawPopupButton(dlg, objnum);
1113       break;
1114   }
1115 }
1116 
1117 
1118 /*-----------------------------------------------------------------------*/
1119 /*
1120   Draw a whole dialog.
1121 */
SDLGui_DrawDialog(SGOBJ * dlg)1122 void SDLGui_DrawDialog(SGOBJ *dlg)
1123 {
1124   int i;
1125 
1126   // Store dialog coordinates
1127   SDLGui_ObjFullCoord(dlg, 0, &DialogRect);
1128 
1129   for (i = 0 ; dlg[i].type != -1 ; i++)
1130   {
1131     if (dlg[i].state & SG_HIDDEN) continue;
1132     SDLGui_DrawObject(dlg, i);
1133   }
1134   SDLGui_RefreshObj(dlg, 0);
1135 }
1136 
SDLGui_setGuiPos(int guix,int guiy)1137 void SDLGui_setGuiPos(int guix, int guiy)
1138 {
1139 	gui_x = guix;
1140 	gui_y = guiy;
1141 }
1142 
SDLGui_getSurface(void)1143 HostSurface *SDLGui_getSurface(void)
1144 {
1145 	if (gui_dlg) {
1146 		/* Process a TOUCHEXIT object ? */
1147 		if (gui_dlg->isTouchExitPressed()) {
1148 			/*int retval =*/ gui_dlg->processDialog();
1149 		}
1150 
1151 		/* Blink cursor ? */
1152 		cursor_state *cursor = gui_dlg->getCursor();
1153 		Uint32 cur_ticks = SDL_GetTicks();
1154 		if (cur_ticks-cursor->blink_counter >= 500) {
1155 			cursor->blink_counter = cur_ticks;
1156 			cursor->blink_state = !cursor->blink_state;
1157 		}
1158 
1159 		/* Redraw updated dialog */
1160 		SDLGui_DrawDialog(gui_dlg->getDialog());
1161 		SDLGui_DrawCursor(gui_dlg->getDialog(), cursor);
1162 	}
1163 
1164 	if (gui_hsurf) {
1165 		gui_hsurf->setDirtyRect(0,0,
1166 			gui_hsurf->getWidth(),gui_hsurf->getHeight());
1167 	}
1168 
1169 	return gui_hsurf;
1170 }
1171 
1172 /*-----------------------------------------------------------------------*/
1173 /*
1174   Search default object in a dialog.
1175 */
SDLGui_FindDefaultObj(SGOBJ * dlg)1176 int SDLGui_FindDefaultObj(SGOBJ *dlg)
1177 {
1178   int i = 0;
1179 
1180   while (dlg[i].type != -1)
1181   {
1182     if (dlg[i].flags & SG_DEFAULT)
1183       return i;
1184     i++;
1185   }
1186 
1187   return -1;
1188 }
1189 
1190 
1191 /*-----------------------------------------------------------------------*/
1192 /*
1193   Search an object at given coordinates.
1194 */
SDLGui_FindObj(SGOBJ * dlg,int fx,int fy)1195 int SDLGui_FindObj(SGOBJ *dlg, int fx, int fy)
1196 {
1197   SDL_Rect coord;
1198   int end, i;
1199   int ob = -1;
1200 
1201   // Search end object in dialog
1202   i = 0;
1203   while (dlg[i++].type != -1) ;
1204   end = i;
1205 
1206   // Now check each object
1207   for (i = end-1 ; i >= 0 ; i--)
1208   {
1209     SDLGui_ObjFullCoord(dlg, i, &coord);
1210 
1211     if(fx >= coord.x &&
1212        fy >= coord.y &&
1213        fx < (coord.x + coord.w) &&
1214        fy < (coord.y + coord.h))
1215     {
1216       if (dlg[i].state & (SG_HIDDEN | SG_DISABLED)) continue;
1217       ob = i;
1218       break;
1219     }
1220   }
1221 
1222   return ob;
1223 }
1224 
1225 
1226 /*-----------------------------------------------------------------------*/
1227 /*
1228   A radio object has been selected. Let's deselect any other in his group.
1229 */
SDLGui_SelectRadioObject(SGOBJ * dlg,int clicked_obj)1230 void SDLGui_SelectRadioObject(SGOBJ *dlg, int clicked_obj)
1231 {
1232   int obj;
1233 
1234   // Find first radio object in this group
1235   obj = clicked_obj;
1236   while (dlg[--obj].flags & SG_RADIO) ;
1237 
1238   // Update state
1239   while (dlg[++obj].flags & SG_RADIO)
1240   {
1241     // This code scan every object in the group. This allows to solve cases
1242     // where multiple objects were selected in the group by clicking one.
1243     if (obj != clicked_obj)
1244     {
1245 		// Deselect this radio button
1246 		SDLGui_DeselectAndRedraw(dlg, obj);
1247     }
1248   }
1249 }
1250 
1251 
1252 /*-----------------------------------------------------------------------*/
1253 /*
1254   Update clicked object state depending on given mouse coordinates.
1255   Returns true if the mouse is over the object, false otherwise.
1256 */
SDLGui_UpdateObjState(SGOBJ * dlg,int clicked_obj,int original_state,int x,int y)1257 bool SDLGui_UpdateObjState(SGOBJ *dlg, int clicked_obj, int original_state,
1258                            int x, int y)
1259 {
1260   int obj;
1261 
1262   obj = SDLGui_FindObj(dlg, x, y);
1263 
1264   // Special case : user clicked on an already selected radio object
1265   // do not modify its state.
1266   // We handle it here because it allows to exit if the object is SG_EXIT or
1267   // SG_TOUCHEXIT without any additional test.
1268   if ((dlg[clicked_obj].flags & SG_RADIO) && (original_state & SG_SELECTED))
1269     return (obj == clicked_obj);
1270 
1271   if (((obj != clicked_obj) &&
1272        (dlg[clicked_obj].state != original_state)) ||
1273       ((obj == clicked_obj) &&
1274        (dlg[clicked_obj].state == original_state)))
1275   {
1276     if (dlg[clicked_obj].flags & SG_SELECTABLE)
1277     {
1278       dlg[clicked_obj].state ^= SG_SELECTED;
1279       SDLGui_DrawObject(dlg, clicked_obj);
1280       SDLGui_RefreshObj(dlg, clicked_obj);
1281     }
1282   }
1283 
1284   return (obj == clicked_obj);
1285 }
1286 
SDLGui_DeselectAndRedraw(SGOBJ * dlg,int obj)1287 void SDLGui_DeselectAndRedraw(SGOBJ *dlg, int obj)
1288 {
1289     if (dlg[obj].flags & SG_SELECTABLE)
1290     {
1291 		dlg[obj].state &= ~SG_SELECTED;
1292 		SDLGui_DrawObject(dlg, obj);
1293 		SDLGui_RefreshObj(dlg, obj);
1294     }
1295 }
1296 
1297 /*-----------------------------------------------------------------------*/
1298 /*
1299   Search edit field in a dialog.
1300 */
SDLGui_FindEditField(SGOBJ * dlg,int objnum,int mode)1301 int SDLGui_FindEditField(SGOBJ *dlg, int objnum, int mode)
1302 {
1303   int i, j;
1304 
1305   switch (mode)
1306   {
1307     case SG_FIRST_EDITFIELD:
1308       i = 0;
1309       while (dlg[i].type != -1)
1310       {
1311         if ((dlg[i].type == SGEDITFIELD) &&
1312             ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
1313           return i;
1314         i++;
1315       }
1316       break;
1317 
1318     case SG_PREVIOUS_EDITFIELD:
1319       i = objnum - 1;
1320       while (i >= 0)
1321       {
1322         if ((dlg[i].type == SGEDITFIELD) &&
1323             ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
1324           return i;
1325         i--;
1326       }
1327       break;
1328 
1329     case SG_NEXT_EDITFIELD:
1330       i = objnum + 1;
1331       while (dlg[i].type != -1)
1332       {
1333         if ((dlg[i].type == SGEDITFIELD) &&
1334             ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
1335           return i;
1336         i++;
1337       }
1338       break;
1339 
1340     case SG_LAST_EDITFIELD:
1341       i = objnum + 1;
1342       j = -1;
1343       while (dlg[i].type != -1)
1344       {
1345         if ((dlg[i].type == SGEDITFIELD) &&
1346             ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
1347           j = i;
1348         i++;
1349       }
1350       if (j != -1)
1351         return j;
1352       break;
1353   }
1354 
1355   return objnum;
1356 }
1357 
1358 
1359 /*-----------------------------------------------------------------------*/
1360 /*
1361   Move cursor to another edit field.
1362 */
SDLGui_MoveCursor(SGOBJ * dlg,cursor_state * cursor,int mode)1363 void SDLGui_MoveCursor(SGOBJ *dlg, cursor_state *cursor, int mode)
1364 {
1365   int new_object;
1366 
1367   new_object = SDLGui_FindEditField(dlg, cursor->object, mode);
1368 
1369   if (new_object != cursor->object)
1370   {
1371     /* Erase old cursor */
1372     cursor->blink_state = false;
1373     SDLGui_DrawCursor(dlg, cursor);
1374 
1375     cursor->object = new_object;
1376     cursor->position = SDLGui_TextLen(dlg[new_object].txt);
1377   }
1378   else
1379   {
1380     /* We stay in the same field */
1381     /* Move cursor to begin or end of text depending on mode */
1382     switch (mode)
1383     {
1384       case SG_FIRST_EDITFIELD:
1385       case SG_PREVIOUS_EDITFIELD:
1386         cursor->position = 0;
1387         break;
1388 
1389       case SG_NEXT_EDITFIELD:
1390       case SG_LAST_EDITFIELD:
1391         cursor->position = SDLGui_TextLen(dlg[new_object].txt);
1392         break;
1393     }
1394   }
1395 }
1396 
1397 /* Deselect all buttons */
SDLGui_DeselectButtons(SGOBJ * dlg)1398 void SDLGui_DeselectButtons(SGOBJ *dlg)
1399 {
1400 	int i = 0;
1401 	while (dlg[i].type != -1) {
1402 		if (dlg[i].type == SGBUTTON) {
1403 			dlg[i].state &= ~SG_SELECTED;
1404 		}
1405 		++i;
1406 	}
1407 }
1408 
1409 /*-----------------------------------------------------------------------*/
1410 /*
1411   Handle mouse clicks on edit fields.
1412 */
SDLGui_ClickEditField(SGOBJ * dlg,cursor_state * cursor,int clicked_obj,int x)1413 void SDLGui_ClickEditField(SGOBJ *dlg, cursor_state *cursor, int clicked_obj, int x)
1414 {
1415   SDL_Rect coord;
1416   int i, j;
1417 
1418   /* Erase old cursor */
1419   cursor->blink_state = false;
1420   SDLGui_DrawCursor(dlg, cursor);
1421 
1422   SDLGui_ObjFullCoord(dlg, clicked_obj, &coord);
1423   i = (x - coord.x + (FONTWIDTH / 2)) / FONTWIDTH;
1424   j = SDLGui_TextLen(dlg[clicked_obj].txt);
1425 
1426   cursor->object = clicked_obj;
1427   cursor->position = MIN(i, j);
1428   cursor->blink_state = true;
1429   cursor->blink_counter = 0;
1430   SDLGui_DrawCursor(dlg, cursor);
1431 }
1432 
1433 #if 0
1434 
1435 /*-----------------------------------------------------------------------*/
1436 /*
1437   Used to update screen while GUI is opened. Return a list of rectangles that
1438   covers the screen without overlaping the current dialog.
1439 */
1440 SDL_Rect *SDLGui_GetFirstBackgroundRect(void)
1441 {
1442   // Reset counter...
1443   BackgroundRectCounter = SG_BCKGND_RECT_BEGIN;
1444   // And returns first rectangle
1445   return SDLGui_GetNextBackgroundRect();
1446 }
1447 
1448 
1449 /*-----------------------------------------------------------------------*/
1450 /*
1451   Returns next rectangle to be redrawn to update screen or NULL if we reached
1452   the end of the list.
1453   This code is "flying dialog" ready :)
1454   It will need some updating if we implement popup buttons handled by sdlgui,
1455   as the popup could be higher than the root box...
1456   I used some recursivity here to simplify the code.
1457 */
1458 SDL_Rect *SDLGui_GetNextBackgroundRect(void)
1459 {
1460   SDL_Rect *return_rect = NULL;
1461 
1462   switch (BackgroundRectCounter)
1463   {
1464     case SG_BCKGND_RECT_END:
1465       // Nothing to do : return_rect is already initialized to NULL.
1466       break;
1467 
1468     case SG_BCKGND_RECT_BEGIN:
1469       if (DialogRect.w == 0)
1470       {
1471         // The dialog is not drawn yet...
1472         // Let's redraw the full screen.
1473       	BackgroundRect.x = 0;
1474       	BackgroundRect.y = 0;
1475       	BackgroundRect.w = sdlscrn->w;
1476       	BackgroundRect.h = sdlscrn->h;
1477         return_rect = &BackgroundRect;
1478         // We reached the end of the list.
1479         BackgroundRectCounter = SG_BCKGND_RECT_END;
1480       }
1481       else
1482       {
1483         BackgroundRectCounter = SG_BCKGND_RECT_TOP;
1484         return_rect = SDLGui_GetNextBackgroundRect();
1485       }
1486       break;
1487 
1488     case SG_BCKGND_RECT_TOP:
1489       BackgroundRectCounter = SG_BCKGND_RECT_LEFT;
1490       if (DialogRect.y > 0)
1491       {
1492       	BackgroundRect.x = 0;
1493       	BackgroundRect.y = 0;
1494       	BackgroundRect.w = sdlscrn->w;
1495       	BackgroundRect.h = DialogRect.y;
1496         return_rect = &BackgroundRect;
1497       }
1498       else
1499         return_rect = SDLGui_GetNextBackgroundRect();
1500       break;
1501 
1502     case SG_BCKGND_RECT_LEFT:
1503       BackgroundRectCounter = SG_BCKGND_RECT_RIGHT;
1504       if (DialogRect.x > 0)
1505       {
1506         BackgroundRect.x = 0;
1507         BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
1508         BackgroundRect.w = DialogRect.x;
1509         BackgroundRect.h =
1510           ((DialogRect.y + DialogRect.h) < (int)sdlscrn->h) ?
1511           (DialogRect.h + DialogRect.y - BackgroundRect.y) :
1512           (sdlscrn->h - DialogRect.y);
1513         return_rect = &BackgroundRect;
1514       }
1515       else
1516         return_rect = SDLGui_GetNextBackgroundRect();
1517       break;
1518 
1519     case SG_BCKGND_RECT_RIGHT:
1520       BackgroundRectCounter = SG_BCKGND_RECT_BOTTOM;
1521       if ((DialogRect.x + DialogRect.w) < (int)sdlscrn->w)
1522       {
1523         BackgroundRect.x = DialogRect.x + DialogRect.w;
1524         BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
1525         BackgroundRect.w = sdlscrn->w - (DialogRect.x + DialogRect.w);
1526         BackgroundRect.h =
1527           ((DialogRect.y + DialogRect.h) < (int)sdlscrn->w) ?
1528           (DialogRect.h + DialogRect.y - BackgroundRect.y) :
1529           (sdlscrn->h - DialogRect.y);
1530         return_rect = &BackgroundRect;
1531       }
1532       else
1533         return_rect = SDLGui_GetNextBackgroundRect();
1534       break;
1535 
1536     case SG_BCKGND_RECT_BOTTOM:
1537       BackgroundRectCounter = SG_BCKGND_RECT_END;
1538       if ((DialogRect.y + DialogRect.h) < (int)sdlscrn->h)
1539       {
1540         // Bottom
1541         BackgroundRect.x = 0;
1542         BackgroundRect.y = DialogRect.y + DialogRect.h;
1543         BackgroundRect.w = sdlscrn->w;
1544         BackgroundRect.h = sdlscrn->h - (DialogRect.y + DialogRect.h);
1545         return_rect = &BackgroundRect;
1546       }
1547       else
1548         return_rect = SDLGui_GetNextBackgroundRect();
1549       break;
1550   }
1551 
1552   return return_rect;
1553 }
1554 
1555 #endif
1556 
1557 /* Process event for a dialog */
SDLGui_DoEvent(const SDL_Event & event)1558 int SDLGui_DoEvent(const SDL_Event &event)
1559 {
1560 	int retval = Dialog::GUI_CONTINUE;
1561 	int num_dialogs=1;	/* Number of processDialog to call */
1562 
1563 	if (gui_dlg) {
1564 		gui_dlg->idle();
1565 
1566 		switch(event.type) {
1567 			case SDL_KEYDOWN:
1568 				gui_dlg->keyPress(event);
1569 				break;
1570 			case SDL_MOUSEBUTTONDOWN:
1571 			case SDL_MOUSEBUTTONUP:
1572 				gui_dlg->mouseClick(event, gui_x, gui_y);
1573 				break;
1574 			case SDL_QUIT:
1575 				return Dialog::GUI_CLOSE;
1576 			case SDL_MOUSEMOTION:
1577 				return Dialog::GUI_CONTINUE;
1578 		}
1579 
1580 		while (num_dialogs-->0) {
1581 			retval = gui_dlg->processDialog();
1582 
1583 			if (retval != Dialog::GUI_CONTINUE) {
1584 				Dialog *prev_dlg = NULL;
1585 				Dialog *curr_dlg = dlgStack.top();
1586 				dlgStack.pop();
1587 				if (!dlgStack.empty()) {
1588 					prev_dlg = dlgStack.top();
1589 
1590 					/* Process result of called dialog */
1591 					prev_dlg->processResult();
1592 
1593 					/* Continue displaying GUI with previous dialog */
1594 					retval = Dialog::GUI_CONTINUE;
1595 				}
1596 
1597 				/* Close current dialog */
1598 				delete curr_dlg;
1599 
1600 				/* Set dialog to previous one */
1601 				if (gui_dlg == curr_dlg)
1602 					gui_dlg = prev_dlg;
1603 				if (gui_dlg) {
1604 					gui_dlg->init();
1605 					++num_dialogs; /* Need to process result in the caller dialog */
1606 				}
1607 			}
1608 		}
1609 	}
1610 
1611 	return retval;
1612 }
1613 
1614 /* Open a dialog */
SDLGui_Open(Dialog * new_dlg)1615 void SDLGui_Open(Dialog *new_dlg)
1616 {
1617 	if (new_dlg==NULL) {
1618 		/* Open main as default */
1619 		new_dlg = DlgMainOpen();
1620 		if (startupAlert)
1621 		{
1622 			dlgStack.push(new_dlg);
1623 			new_dlg = DlgAlertOpen(startupAlert, ALERT_OK);
1624 			free(startupAlert);
1625 			startupAlert = NULL;
1626 		}
1627 	}
1628 
1629 	dlgStack.push(new_dlg);
1630 
1631 	gui_dlg = dlgStack.top();
1632 	gui_dlg->init();
1633 	gui_dlg->idle();
1634 }
1635 
SDLGui_Close(void)1636 void SDLGui_Close(void)
1637 {
1638 	/* Empty the dialog stack */
1639 	while (!dlgStack.empty()) {
1640 		Dialog *dlg = dlgStack.top();
1641 		delete dlg;
1642 		dlgStack.pop();
1643 	}
1644 
1645 	gui_dlg = NULL;
1646 }
1647 
SDLGui_isClosed(void)1648 bool SDLGui_isClosed(void)
1649 {
1650 	return (gui_dlg == NULL);
1651 }
1652