|
|
1.1 root 1: /*
2: Hatari - sdlgui.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: A tiny graphical user interface for Hatari.
8: */
9: const char SDLGui_fileid[] = "Previous sdlgui.c : " __DATE__ " " __TIME__;
10:
11: #include <SDL.h>
12: #include <ctype.h>
13: #include <string.h>
14:
15: #include "main.h"
16: #include "sdlgui.h"
17:
18: #include "font5x8.h"
19: #include "font10x16.h"
20:
21:
22: static SDL_Surface *pSdlGuiScrn; /* Pointer to the actual main SDL screen surface */
23: static SDL_Surface *pSmallFontGfx = NULL; /* The small font graphics */
24: static SDL_Surface *pBigFontGfx = NULL; /* The big font graphics */
25: static SDL_Surface *pFontGfx = NULL; /* The actual font graphics */
1.1.1.2 ! root 26: static int current_object = 0; /* Current selected object */
1.1 root 27:
28:
29: /*-----------------------------------------------------------------------*/
30: /**
31: * Load an 1 plane XBM into a 8 planes SDL_Surface.
32: */
33: static SDL_Surface *SDLGui_LoadXBM(int w, int h, const Uint8 *pXbmBits)
34: {
35: SDL_Surface *bitmap;
36: Uint8 *dstbits;
37: const Uint8 *srcbits;
38: int x, y, srcpitch;
39: int mask;
40:
41: srcbits = pXbmBits;
42:
43: /* Allocate the bitmap */
44: bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
45: if (bitmap == NULL)
46: {
47: fprintf(stderr, "Failed to allocate bitmap: %s", SDL_GetError());
48: return NULL;
49: }
50:
51: srcpitch = ((w + 7) / 8);
52: dstbits = (Uint8 *)bitmap->pixels;
53: mask = 1;
54:
55: /* Copy the pixels */
56: for (y = 0 ; y < h ; y++)
57: {
58: for (x = 0 ; x < w ; x++)
59: {
60: dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
61: mask <<= 1;
62: mask |= (mask >> 8);
63: mask &= 0xFF;
64: }
65: dstbits += bitmap->pitch;
66: srcbits += srcpitch;
67: }
68:
69: return bitmap;
70: }
71:
72:
73: /*-----------------------------------------------------------------------*/
74: /**
75: * Initialize the GUI.
76: */
77: int SDLGui_Init(void)
78: {
79: SDL_Color blackWhiteColors[2] = {{255, 255, 255, 0}, {0, 0, 0, 0}};
80:
81: if (pSmallFontGfx && pBigFontGfx)
82: {
83: /* already initialized */
84: return 0;
85: }
86:
87: /* Initialize the font graphics: */
88: pSmallFontGfx = SDLGui_LoadXBM(font5x8_width, font5x8_height, font5x8_bits);
89: pBigFontGfx = SDLGui_LoadXBM(font10x16_width, font10x16_height, font10x16_bits);
90: if (pSmallFontGfx == NULL || pBigFontGfx == NULL)
91: {
92: fprintf(stderr, "Error: Can not init font graphics!\n");
93: return -1;
94: }
95:
96: /* Set color palette of the font graphics: */
97: SDL_SetColors(pSmallFontGfx, blackWhiteColors, 0, 2);
98: SDL_SetColors(pBigFontGfx, blackWhiteColors, 0, 2);
99:
100: /* Set font color 0 as transparent: */
101: SDL_SetColorKey(pSmallFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
102: SDL_SetColorKey(pBigFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
103:
104: return 0;
105: }
106:
107:
108: /*-----------------------------------------------------------------------*/
109: /**
110: * Uninitialize the GUI.
111: */
112: int SDLGui_UnInit(void)
113: {
114: if (pSmallFontGfx)
115: {
116: SDL_FreeSurface(pSmallFontGfx);
117: pSmallFontGfx = NULL;
118: }
119:
120: if (pBigFontGfx)
121: {
122: SDL_FreeSurface(pBigFontGfx);
123: pBigFontGfx = NULL;
124: }
125:
126: return 0;
127: }
128:
129:
130: /*-----------------------------------------------------------------------*/
131: /**
132: * Inform the SDL-GUI about the actual SDL_Surface screen pointer and
133: * prepare the font to suit the actual resolution.
134: */
135: int SDLGui_SetScreen(SDL_Surface *pScrn)
136: {
137: pSdlGuiScrn = pScrn;
138:
139: /* Decide which font to use - small or big one: */
140: if (pSdlGuiScrn->w >= 640 && pSdlGuiScrn->h >= 400 && pBigFontGfx != NULL)
141: {
142: pFontGfx = pBigFontGfx;
143: }
144: else
145: {
146: pFontGfx = pSmallFontGfx;
147: }
148:
149: if (pFontGfx == NULL)
150: {
151: fprintf(stderr, "Error: A problem with the font occured!\n");
152: return -1;
153: }
154:
155: /* Get the font width and height: */
1.1.1.2 ! root 156: sdlgui_fontwidth = pFontGfx->w/16;
! 157: sdlgui_fontheight = pFontGfx->h/16;
1.1 root 158:
159: return 0;
160: }
161:
162: /*-----------------------------------------------------------------------*/
163: /**
164: * Return character size for current font in given arguments.
165: */
166: void SDLGui_GetFontSize(int *width, int *height)
167: {
1.1.1.2 ! root 168: *width = sdlgui_fontwidth;
! 169: *height = sdlgui_fontheight;
1.1 root 170: }
171:
172: /*-----------------------------------------------------------------------*/
173: /**
174: * Center a dialog so that it appears in the middle of the screen.
175: * Note: We only store the coordinates in the root box of the dialog,
176: * all other objects in the dialog are positioned relatively to this one.
177: */
178: void SDLGui_CenterDlg(SGOBJ *dlg)
179: {
1.1.1.2 ! root 180: dlg[0].x = (pSdlGuiScrn->w/sdlgui_fontwidth-dlg[0].w)/2;
! 181: dlg[0].y = (pSdlGuiScrn->h/sdlgui_fontheight-dlg[0].h)/2;
1.1 root 182: }
183:
184:
185: /*-----------------------------------------------------------------------*/
186: /**
187: * Draw a text string.
188: */
189: void SDLGui_Text(int x, int y, const char *txt)
190: {
191: int i;
192: char c;
193: SDL_Rect sr, dr;
194:
195: for (i=0; txt[i]!=0; i++)
196: {
197: c = txt[i];
1.1.1.2 ! root 198: sr.x=sdlgui_fontwidth*(c%16);
! 199: sr.y=sdlgui_fontheight*(c/16);
! 200: sr.w=sdlgui_fontwidth;
! 201: sr.h=sdlgui_fontheight;
! 202: dr.x=x+i*sdlgui_fontwidth;
! 203: dr.y=y;
! 204: dr.w=sdlgui_fontwidth;
! 205: dr.h=sdlgui_fontheight;
1.1 root 206: SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
207: }
208: }
209:
210:
211: /*-----------------------------------------------------------------------*/
212: /**
213: * Draw a dialog text object.
214: */
215: static void SDLGui_DrawText(const SGOBJ *tdlg, int objnum)
216: {
217: int x, y;
1.1.1.2 ! root 218: x = (tdlg[0].x+tdlg[objnum].x)*sdlgui_fontwidth;
! 219: y = (tdlg[0].y+tdlg[objnum].y)*sdlgui_fontheight;
1.1 root 220: SDLGui_Text(x, y, tdlg[objnum].txt);
221: }
222:
223:
224: /*-----------------------------------------------------------------------*/
225: /**
226: * Draw a edit field object.
227: */
228: static void SDLGui_DrawEditField(const SGOBJ *edlg, int objnum)
229: {
230: int x, y;
231: SDL_Rect rect;
232:
1.1.1.2 ! root 233: x = (edlg[0].x+edlg[objnum].x)*sdlgui_fontwidth;
! 234: y = (edlg[0].y+edlg[objnum].y)*sdlgui_fontheight;
1.1 root 235: SDLGui_Text(x, y, edlg[objnum].txt);
236:
237: rect.x = x;
1.1.1.2 ! root 238: rect.y = y + edlg[objnum].h * sdlgui_fontheight;
! 239: rect.w = edlg[objnum].w * sdlgui_fontwidth;
1.1 root 240: rect.h = 1;
241: SDL_FillRect(pSdlGuiScrn, &rect, SDL_MapRGB(pSdlGuiScrn->format,160,160,160));
242: }
243:
244:
245: /*-----------------------------------------------------------------------*/
246: /**
247: * Draw a dialog box object.
248: */
249: static void SDLGui_DrawBox(const SGOBJ *bdlg, int objnum)
250: {
251: SDL_Rect rect;
252: int x, y, w, h, offset;
253: Uint32 grey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
254: Uint32 upleftc, downrightc;
255:
1.1.1.2 ! root 256: x = bdlg[objnum].x*sdlgui_fontwidth;
! 257: y = bdlg[objnum].y*sdlgui_fontheight;
! 258: if (objnum > 0) /* Since the root object is a box, too, */
! 259: {
! 260: /* we have to look for it now here and only */
! 261: x += bdlg[0].x*sdlgui_fontwidth; /* add its absolute coordinates if we need to */
! 262: y += bdlg[0].y*sdlgui_fontheight;
! 263: }
! 264: w = bdlg[objnum].w*sdlgui_fontwidth;
! 265: h = bdlg[objnum].h*sdlgui_fontheight;
1.1 root 266:
267: if (bdlg[objnum].state & SG_SELECTED)
268: {
269: upleftc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
270: downrightc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
271: }
272: else
273: {
274: upleftc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
275: downrightc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
276: }
277:
278: /* The root box should be bigger than the screen, so we disable the offset there: */
279: if (objnum != 0)
280: offset = 1;
281: else
282: offset = 0;
283:
284: /* Draw background: */
285: rect.x = x;
286: rect.y = y;
287: rect.w = w;
288: rect.h = h;
289: SDL_FillRect(pSdlGuiScrn, &rect, grey);
290:
291: /* Draw upper border: */
292: rect.x = x;
293: rect.y = y - offset;
294: rect.w = w;
295: rect.h = 1;
296: SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
297:
298: /* Draw left border: */
299: rect.x = x - offset;
300: rect.y = y;
301: rect.w = 1;
302: rect.h = h;
303: SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
304:
305: /* Draw bottom border: */
306: rect.x = x;
307: rect.y = y + h - 1 + offset;
308: rect.w = w;
309: rect.h = 1;
310: SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
311:
312: /* Draw right border: */
313: rect.x = x + w - 1 + offset;
314: rect.y = y;
315: rect.w = 1;
316: rect.h = h;
317: SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
318: }
319:
320:
321: /*-----------------------------------------------------------------------*/
322: /**
323: * Draw a normal button.
324: */
325: static void SDLGui_DrawButton(const SGOBJ *bdlg, int objnum)
326: {
327: int x,y;
328:
329: SDLGui_DrawBox(bdlg, objnum);
330:
1.1.1.2 ! root 331: x = (bdlg[0].x + bdlg[objnum].x + (bdlg[objnum].w-strlen(bdlg[objnum].txt))/2) * sdlgui_fontwidth;
! 332: y = (bdlg[0].y + bdlg[objnum].y + (bdlg[objnum].h-1)/2) * sdlgui_fontheight;
1.1 root 333:
334: if (bdlg[objnum].state & SG_SELECTED)
335: {
336: x+=1;
337: y+=1;
338: }
339: SDLGui_Text(x, y, bdlg[objnum].txt);
340: }
341:
342:
343: /*-----------------------------------------------------------------------*/
344: /**
345: * Draw a dialog radio button object.
346: */
347: static void SDLGui_DrawRadioButton(const SGOBJ *rdlg, int objnum)
348: {
349: char str[80];
350: int x, y;
351:
1.1.1.2 ! root 352: x = (rdlg[0].x + rdlg[objnum].x) * sdlgui_fontwidth;
! 353: y = (rdlg[0].y + rdlg[objnum].y) * sdlgui_fontheight;
1.1 root 354:
355: if (rdlg[objnum].state & SG_SELECTED)
356: str[0]=SGRADIOBUTTON_SELECTED;
357: else
358: str[0]=SGRADIOBUTTON_NORMAL;
359: str[1]=' ';
360: strcpy(&str[2], rdlg[objnum].txt);
361:
362: SDLGui_Text(x, y, str);
363: }
364:
365:
366: /*-----------------------------------------------------------------------*/
367: /**
368: * Draw a dialog check box object.
369: */
370: static void SDLGui_DrawCheckBox(const SGOBJ *cdlg, int objnum)
371: {
372: char str[80];
373: int x, y;
374:
1.1.1.2 ! root 375: x = (cdlg[0].x + cdlg[objnum].x) * sdlgui_fontwidth;
! 376: y = (cdlg[0].y + cdlg[objnum].y) * sdlgui_fontheight;
1.1 root 377:
378: if ( cdlg[objnum].state&SG_SELECTED )
379: str[0]=SGCHECKBOX_SELECTED;
380: else
381: str[0]=SGCHECKBOX_NORMAL;
382: str[1]=' ';
383: strcpy(&str[2], cdlg[objnum].txt);
384:
385: SDLGui_Text(x, y, str);
386: }
387:
388:
389: /*-----------------------------------------------------------------------*/
390: /**
1.1.1.2 ! root 391: * Draw a scrollbar button.
! 392: */
! 393: static void SDLGui_DrawScrollbar(const SGOBJ *bdlg, int objnum)
! 394: {
! 395: SDL_Rect rect;
! 396: int x, y, w, h;
! 397: Uint32 grey0 = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
! 398: Uint32 grey1 = SDL_MapRGB(pSdlGuiScrn->format,196,196,196);
! 399: Uint32 grey2 = SDL_MapRGB(pSdlGuiScrn->format, 64, 64, 64);
! 400:
! 401: x = bdlg[objnum].x * sdlgui_fontwidth;
! 402: y = bdlg[objnum].y * sdlgui_fontheight + bdlg[objnum].h;
! 403:
! 404: x += bdlg[0].x*sdlgui_fontwidth; /* add mainbox absolute coordinates */
! 405: y += bdlg[0].y*sdlgui_fontheight; /* add mainbox absolute coordinates */
! 406:
! 407: w = 1 * sdlgui_fontwidth;
! 408: h = bdlg[objnum].w;
! 409:
! 410: /* Draw background: */
! 411: rect.x = x;
! 412: rect.y = y;
! 413: rect.w = w;
! 414: rect.h = h;
! 415: SDL_FillRect(pSdlGuiScrn, &rect, grey0);
! 416:
! 417: /* Draw upper border: */
! 418: rect.x = x;
! 419: rect.y = y;
! 420: rect.w = w;
! 421: rect.h = 1;
! 422: SDL_FillRect(pSdlGuiScrn, &rect, grey1);
! 423:
! 424: /* Draw bottom border: */
! 425: rect.x = x;
! 426: rect.y = y + h - 1;
! 427: rect.w = w;
! 428: rect.h = 1;
! 429: SDL_FillRect(pSdlGuiScrn, &rect, grey2);
! 430:
! 431: }
! 432:
! 433: /*-----------------------------------------------------------------------*/
! 434: /**
1.1 root 435: * Draw a dialog popup button object.
436: */
437: static void SDLGui_DrawPopupButton(const SGOBJ *pdlg, int objnum)
438: {
1.1.1.2 ! root 439: int x, y, w;
1.1 root 440: const char *downstr = "\x02";
441:
442: SDLGui_DrawBox(pdlg, objnum);
443:
1.1.1.2 ! root 444: x = (pdlg[0].x + pdlg[objnum].x) * sdlgui_fontwidth;
! 445: y = (pdlg[0].y + pdlg[objnum].y) * sdlgui_fontheight;
! 446: w = pdlg[objnum].w * sdlgui_fontwidth;
! 447:
! 448: SDLGui_Text(x, y, pdlg[objnum].txt);
! 449: SDLGui_Text(x+w-sdlgui_fontwidth, y, downstr);
1.1 root 450: }
451:
452:
453: /*-----------------------------------------------------------------------*/
454: /**
455: * Let the user insert text into an edit field object.
456: * NOTE: The dlg[objnum].txt must point to an an array that is big enough
457: * for dlg[objnum].w characters!
458: */
459: static void SDLGui_EditField(SGOBJ *dlg, int objnum)
460: {
461: size_t cursorPos; /* Position of the cursor in the edit field */
462: int blinkState = 0; /* Used for cursor blinking */
463: int bStopEditing = false; /* true if user wants to exit the edit field */
464: char *txt; /* Shortcut for dlg[objnum].txt */
465: SDL_Rect rect;
466: Uint32 grey, cursorCol;
467: SDL_Event event;
468: int nOldUnicodeMode;
469:
470: /* Enable unicode translation to get proper characters with SDL_PollEvent */
471: nOldUnicodeMode = SDL_EnableUNICODE(true);
472:
473: grey = SDL_MapRGB(pSdlGuiScrn->format, 192, 192, 192);
474: cursorCol = SDL_MapRGB(pSdlGuiScrn->format, 128, 128, 128);
475:
1.1.1.2 ! root 476: rect.x = (dlg[0].x + dlg[objnum].x) * sdlgui_fontwidth;
! 477: rect.y = (dlg[0].y + dlg[objnum].y) * sdlgui_fontheight;
! 478: rect.w = (dlg[objnum].w + 1) * sdlgui_fontwidth - 1;
! 479: rect.h = dlg[objnum].h * sdlgui_fontheight;
1.1 root 480:
481: txt = dlg[objnum].txt;
482: cursorPos = strlen(txt);
483:
484: do
485: {
486: /* Look for events */
487: if (SDL_PollEvent(&event) == 0)
488: {
489: /* No event: Wait some time for cursor blinking */
490: SDL_Delay(250);
491: blinkState ^= 1;
492: }
493: else
494: {
495: /* Handle events */
496: do
497: {
498: switch (event.type)
499: {
500: case SDL_QUIT: /* User wants to quit */
501: bQuitProgram = true;
502: bStopEditing = true;
503: break;
504: case SDL_MOUSEBUTTONDOWN: /* Mouse pressed -> stop editing */
505: bStopEditing = true;
506: break;
507: case SDL_KEYDOWN: /* Key pressed */
508: switch (event.key.keysym.sym)
509: {
510: case SDLK_RETURN:
511: case SDLK_KP_ENTER:
512: bStopEditing = true;
513: break;
514: case SDLK_LEFT:
515: if (cursorPos > 0)
516: cursorPos -= 1;
517: break;
518: case SDLK_RIGHT:
519: if (cursorPos < strlen(txt))
520: cursorPos += 1;
521: break;
522: case SDLK_BACKSPACE:
523: if (cursorPos > 0)
524: {
525: memmove(&txt[cursorPos-1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
526: cursorPos -= 1;
527: }
528: break;
529: case SDLK_DELETE:
530: if (cursorPos < strlen(txt))
531: memmove(&txt[cursorPos], &txt[cursorPos+1], strlen(&txt[cursorPos+1])+1);
532: break;
533: default:
534: /* If it is a "good" key then insert it into the text field */
535: if (event.key.keysym.unicode >= 32 && event.key.keysym.unicode < 128
536: && event.key.keysym.unicode != PATHSEP)
537: {
538: if (strlen(txt) < (size_t)dlg[objnum].w)
539: {
540: memmove(&txt[cursorPos+1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
541: txt[cursorPos] = event.key.keysym.unicode;
542: cursorPos += 1;
543: }
544: }
545: break;
546: }
547: break;
548: }
549: }
550: while (SDL_PollEvent(&event));
551:
552: blinkState = 1;
553: }
554:
555: /* Redraw the text field: */
556: SDL_FillRect(pSdlGuiScrn, &rect, grey); /* Draw background */
557: /* Draw the cursor: */
558: if (blinkState && !bStopEditing)
559: {
560: SDL_Rect cursorrect;
1.1.1.2 ! root 561: cursorrect.x = rect.x + cursorPos * sdlgui_fontwidth;
1.1 root 562: cursorrect.y = rect.y;
1.1.1.2 ! root 563: cursorrect.w = sdlgui_fontwidth;
1.1 root 564: cursorrect.h = rect.h;
565: SDL_FillRect(pSdlGuiScrn, &cursorrect, cursorCol);
566: }
567: SDLGui_Text(rect.x, rect.y, dlg[objnum].txt); /* Draw text */
568: SDL_UpdateRects(pSdlGuiScrn, 1, &rect);
569: }
570: while (!bStopEditing);
571:
572: SDL_EnableUNICODE(nOldUnicodeMode);
573: }
574:
575:
576: /*-----------------------------------------------------------------------*/
577: /**
578: * Draw a whole dialog.
579: */
580: void SDLGui_DrawDialog(const SGOBJ *dlg)
581: {
582: int i;
583: for (i = 0; dlg[i].type != -1; i++)
584: {
585: switch (dlg[i].type)
586: {
587: case SGBOX:
588: SDLGui_DrawBox(dlg, i);
589: break;
590: case SGTEXT:
591: SDLGui_DrawText(dlg, i);
592: break;
593: case SGEDITFIELD:
594: SDLGui_DrawEditField(dlg, i);
595: break;
596: case SGBUTTON:
597: SDLGui_DrawButton(dlg, i);
598: break;
599: case SGRADIOBUT:
600: SDLGui_DrawRadioButton(dlg, i);
601: break;
602: case SGCHECKBOX:
603: SDLGui_DrawCheckBox(dlg, i);
604: break;
605: case SGPOPUP:
606: SDLGui_DrawPopupButton(dlg, i);
607: break;
1.1.1.2 ! root 608: case SGSCROLLBAR:
! 609: SDLGui_DrawScrollbar(dlg, i);
! 610: break;
1.1 root 611: }
612: }
613: SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
614: }
615:
616:
617: /*-----------------------------------------------------------------------*/
618: /**
619: * Search an object at a certain position.
620: */
621: static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
622: {
623: int len, i;
624: int ob = -1;
625: int xpos, ypos;
626:
627: len = 0;
628: while (dlg[len].type != -1) len++;
629:
1.1.1.2 ! root 630: xpos = fx / sdlgui_fontwidth;
! 631: ypos = fy / sdlgui_fontheight;
1.1 root 632: /* Now search for the object: */
633: for (i = len; i >= 0; i--)
634: {
1.1.1.2 ! root 635: /* clicked on a scrollbar ? */
! 636: if (dlg[i].type == SGSCROLLBAR) {
! 637: if (xpos >= dlg[0].x+dlg[i].x && xpos < dlg[0].x+dlg[i].x+1) {
! 638: ypos = dlg[i].y * sdlgui_fontheight + dlg[i].h + dlg[0].y * sdlgui_fontheight;
! 639: if (fy >= ypos && fy < ypos + dlg[i].w) {
! 640: ob = i;
! 641: break;
! 642: }
! 643: }
! 644: }
! 645: /* clicked on another object ? */
! 646: else if (xpos >= dlg[0].x+dlg[i].x && ypos >= dlg[0].y+dlg[i].y
! 647: && xpos < dlg[0].x+dlg[i].x+dlg[i].w && ypos < dlg[0].y+dlg[i].y+dlg[i].h)
1.1 root 648: {
649: ob = i;
650: break;
651: }
652: }
653:
654: return ob;
655: }
656:
657:
658: /*-----------------------------------------------------------------------*/
659: /**
660: * Search a button with a special flag (e.g. SG_DEFAULT or SG_CANCEL).
661: */
662: static int SDLGui_SearchFlaggedButton(const SGOBJ *dlg, int flag)
663: {
664: int i = 0;
665:
666: while (dlg[i].type != -1)
667: {
668: if (dlg[i].flags & flag)
669: return i;
670: i++;
671: }
672:
673: return 0;
674: }
675:
676:
677: /*-----------------------------------------------------------------------*/
678: /**
679: * Show and process a dialog. Returns the button number that has been
680: * pressed or SDLGUI_UNKNOWNEVENT if an unsupported event occured (will be
681: * stored in parameter pEventOut).
682: */
683: int SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut)
684: {
685: int obj=0;
686: int oldbutton=0;
687: int retbutton=0;
688: int i, j, b;
689: SDL_Event sdlEvent;
690: SDL_Rect rct;
691: Uint32 grey;
692: SDL_Surface *pBgSurface;
693: SDL_Rect dlgrect, bgrect;
694:
1.1.1.2 ! root 695: if (pSdlGuiScrn->h / sdlgui_fontheight < dlg[0].h)
1.1 root 696: {
697: fprintf(stderr, "Screen size too small for dialog!\n");
698: return SDLGUI_ERROR;
699: }
700:
701: grey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
702:
1.1.1.2 ! root 703: dlgrect.x = dlg[0].x * sdlgui_fontwidth;
! 704: dlgrect.y = dlg[0].y * sdlgui_fontheight;
! 705: dlgrect.w = dlg[0].w * sdlgui_fontwidth;
! 706: dlgrect.h = dlg[0].h * sdlgui_fontheight;
1.1 root 707:
708: bgrect.x = bgrect.y = 0;
709: bgrect.w = dlgrect.w;
710: bgrect.h = dlgrect.h;
711:
712: /* Save background */
713: pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
714: pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
715: if (pSdlGuiScrn->format->palette != NULL)
716: {
717: SDL_SetColors(pBgSurface, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
718: }
719:
720: if (pBgSurface != NULL)
721: {
722: SDL_BlitSurface(pSdlGuiScrn, &dlgrect, pBgSurface, &bgrect);
723: }
724: else
725: {
726: fprintf(stderr, "SDLGUI_DoDialog: CreateRGBSurface failed: %s\n", SDL_GetError());
727: }
728:
729: /* (Re-)draw the dialog */
730: SDLGui_DrawDialog(dlg);
731:
732: /* Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here */
733: SDL_PumpEvents();
734: b = SDL_GetMouseState(&i, &j);
1.1.1.2 ! root 735:
! 736: /* If current object is the scrollbar, and mouse is still down, we can scroll it */
! 737: /* also if the mouse pointer has left the scrollbar */
! 738: if (dlg[current_object].type == SGSCROLLBAR) {
! 739: if (b & SDL_BUTTON(1)) {
! 740: obj = current_object;
! 741: dlg[obj].state |= SG_MOUSEDOWN;
! 742: oldbutton = obj;
! 743: retbutton = obj;
! 744: }
! 745: else {
! 746: obj = current_object;
! 747: current_object = 0;
! 748: dlg[obj].state &= SG_MOUSEUP;
1.1 root 749: retbutton = obj;
1.1.1.2 ! root 750: oldbutton = obj;
1.1 root 751: }
752: }
1.1.1.2 ! root 753: else {
! 754: obj = SDLGui_FindObj(dlg, i, j);
! 755: current_object = obj;
! 756: if (obj > 0 && (dlg[obj].flags&SG_TOUCHEXIT) )
! 757: {
! 758: oldbutton = obj;
! 759: if (b & SDL_BUTTON(1))
! 760: {
! 761: dlg[obj].state |= SG_SELECTED;
! 762: retbutton = obj;
! 763: }
! 764: }
! 765: }
1.1 root 766:
1.1.1.2 ! root 767:
1.1 root 768: /* The main loop */
769: while (retbutton == 0 && !bQuitProgram)
770: {
771: if (SDL_WaitEvent(&sdlEvent) == 1) /* Wait for events */
1.1.1.2 ! root 772:
1.1 root 773: switch (sdlEvent.type)
774: {
775: case SDL_QUIT:
776: retbutton = SDLGUI_QUIT;
777: break;
778:
779: case SDL_MOUSEBUTTONDOWN:
780: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
781: {
782: /* Not left mouse button -> unsupported event */
783: if (pEventOut)
784: retbutton = SDLGUI_UNKNOWNEVENT;
785: break;
786: }
787: /* It was the left button: Find the object under the mouse cursor */
788: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
789: if (obj>0)
790: {
791: if (dlg[obj].type==SGBUTTON)
792: {
793: dlg[obj].state |= SG_SELECTED;
794: SDLGui_DrawButton(dlg, obj);
1.1.1.2 ! root 795: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
! 796: dlg[obj].w*sdlgui_fontwidth+4, dlg[obj].h*sdlgui_fontheight+4);
! 797: oldbutton=obj;
! 798: }
! 799: if (dlg[obj].type==SGSCROLLBAR)
! 800: {
! 801: dlg[obj].state |= SG_MOUSEDOWN;
1.1 root 802: oldbutton=obj;
803: }
804: if ( dlg[obj].flags&SG_TOUCHEXIT )
805: {
806: dlg[obj].state |= SG_SELECTED;
807: retbutton = obj;
808: }
809: }
810: break;
811:
812: case SDL_MOUSEBUTTONUP:
813: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
814: {
815: /* Not left mouse button -> unsupported event */
816: if (pEventOut)
817: retbutton = SDLGUI_UNKNOWNEVENT;
818: break;
819: }
820: /* It was the left button: Find the object under the mouse cursor */
821: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
822: if (obj>0)
823: {
824: switch (dlg[obj].type)
825: {
826: case SGBUTTON:
827: if (oldbutton==obj)
828: retbutton=obj;
829: break;
1.1.1.2 ! root 830: case SGSCROLLBAR:
! 831: dlg[obj].state &= SG_MOUSEUP;
! 832:
! 833: if (oldbutton==obj)
! 834: retbutton=obj;
! 835: break;
! 836: case SGEDITFIELD:
1.1 root 837: SDLGui_EditField(dlg, obj);
838: break;
839: case SGRADIOBUT:
840: for (i = obj-1; i > 0 && dlg[i].type == SGRADIOBUT; i--)
841: {
842: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1.1.1.2 ! root 843: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
! 844: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
! 845: rct.w = sdlgui_fontwidth;
! 846: rct.h = sdlgui_fontheight;
1.1 root 847: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
848: SDLGui_DrawRadioButton(dlg, i);
849: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
850: }
851: for (i = obj+1; dlg[i].type == SGRADIOBUT; i++)
852: {
853: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1.1.1.2 ! root 854: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
! 855: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
! 856: rct.w = sdlgui_fontwidth;
! 857: rct.h = sdlgui_fontheight;
1.1 root 858: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
859: SDLGui_DrawRadioButton(dlg, i);
860: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
861: }
862: dlg[obj].state |= SG_SELECTED; /* Select this radio button */
1.1.1.2 ! root 863: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
! 864: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
! 865: rct.w = sdlgui_fontwidth;
! 866: rct.h = sdlgui_fontheight;
1.1 root 867: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
868: SDLGui_DrawRadioButton(dlg, obj);
869: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
870: break;
871: case SGCHECKBOX:
872: dlg[obj].state ^= SG_SELECTED;
1.1.1.2 ! root 873: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
! 874: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
! 875: rct.w = sdlgui_fontwidth;
! 876: rct.h = sdlgui_fontheight;
1.1 root 877: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
878: SDLGui_DrawCheckBox(dlg, obj);
879: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
880: break;
881: case SGPOPUP:
882: dlg[obj].state |= SG_SELECTED;
883: SDLGui_DrawPopupButton(dlg, obj);
1.1.1.2 ! root 884: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
! 885: dlg[obj].w*sdlgui_fontwidth+4, dlg[obj].h*sdlgui_fontheight+4);
1.1 root 886: retbutton=obj;
887: break;
888: }
889: }
1.1.1.2 ! root 890: if (oldbutton > 0 && dlg[oldbutton].type == SGBUTTON)
1.1 root 891: {
892: dlg[oldbutton].state &= ~SG_SELECTED;
893: SDLGui_DrawButton(dlg, oldbutton);
1.1.1.2 ! root 894: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[oldbutton].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[oldbutton].y)*sdlgui_fontheight-2,
! 895: dlg[oldbutton].w*sdlgui_fontwidth+4, dlg[oldbutton].h*sdlgui_fontheight+4);
1.1 root 896: oldbutton = 0;
897: }
898: if (obj >= 0 && (dlg[obj].flags&SG_EXIT))
899: {
900: retbutton = obj;
901: }
902: break;
903:
904: case SDL_JOYAXISMOTION:
905: case SDL_JOYBALLMOTION:
906: case SDL_JOYHATMOTION:
907: case SDL_MOUSEMOTION:
908: break;
909:
910: case SDL_KEYDOWN: /* Key pressed */
911: if (sdlEvent.key.keysym.sym == SDLK_RETURN
912: || sdlEvent.key.keysym.sym == SDLK_KP_ENTER)
913: {
914: retbutton = SDLGui_SearchFlaggedButton(dlg, SG_DEFAULT);
915: }
916: else if (sdlEvent.key.keysym.sym == SDLK_ESCAPE)
917: {
918: retbutton = SDLGui_SearchFlaggedButton(dlg, SG_CANCEL);
919: }
920: else if (pEventOut)
921: {
922: retbutton = SDLGUI_UNKNOWNEVENT;
923: }
924: break;
925:
926: default:
927: if (pEventOut)
928: retbutton = SDLGUI_UNKNOWNEVENT;
929: break;
930: }
931: }
932:
933: /* Restore background */
934: if (pBgSurface)
935: {
936: SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn, &dlgrect);
937: SDL_FreeSurface(pBgSurface);
938: }
939:
940: /* Copy event data of unsupported events if caller wants to have it */
941: if (retbutton == SDLGUI_UNKNOWNEVENT && pEventOut)
942: memcpy(pEventOut, &sdlEvent, sizeof(SDL_Event));
943:
944: if (retbutton == SDLGUI_QUIT)
945: bQuitProgram = true;
946:
947: return retbutton;
948: }
949:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.