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