|
|
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: {
1.1.1.4 ! root 79: SDL_Color blackWhiteColors[2] = {{255, 255, 255, 255}, {0, 0, 0, 255}};
1.1 root 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: */
1.1.1.4 ! root 97: SDL_SetPaletteColors(pSmallFontGfx->format->palette, blackWhiteColors, 0, 2);
! 98: SDL_SetPaletteColors(pBigFontGfx->format->palette, blackWhiteColors, 0, 2);
1.1 root 99:
100: /* Set font color 0 as transparent: */
1.1.1.4 ! root 101: SDL_SetColorKey(pSmallFontGfx, (SDL_TRUE|SDL_RLEACCEL), 0);
! 102: SDL_SetColorKey(pBigFontGfx, (SDL_TRUE|SDL_RLEACCEL), 0);
1.1 root 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;
1.1.1.4 ! root 138:
1.1 root 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: }
1.1.1.4 ! root 154:
1.1 root 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;
1.1.1.4 ! root 253: Uint32 grey = SDL_MapRGB(pSdlGuiScrn->format,181,183,170);
1.1 root 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: {
1.1.1.4 ! root 269: upleftc = SDL_MapRGB(pSdlGuiScrn->format,147,145,170);
1.1 root 270: downrightc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
271: }
272: else
273: {
274: upleftc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
1.1.1.4 ! root 275: downrightc = SDL_MapRGB(pSdlGuiScrn->format,147,145,170);
1.1 root 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;
1.1.1.4 ! root 397: Uint32 grey0 = SDL_MapRGB(pSdlGuiScrn->format,147,145,170);
! 398: Uint32 grey1 = SDL_MapRGB(pSdlGuiScrn->format,181,183,170);
! 399: Uint32 grey2 = SDL_MapRGB(pSdlGuiScrn->format, 73, 72, 85);
1.1.1.2 root 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:
1.1.1.4 ! root 469: /* Enable text input to get unicode characters with SDL_TEXTINPUT event */
! 470: SDL_SetTextInputRect(&rect);
! 471: SDL_StartTextInput();
1.1 root 472:
1.1.1.4 ! root 473: grey = SDL_MapRGB(pSdlGuiScrn->format, 181, 183, 170);
! 474: cursorCol = SDL_MapRGB(pSdlGuiScrn->format, 147, 145, 170);
1.1 root 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: {
1.1.1.4 ! root 500: case SDL_WINDOWEVENT:
! 501: if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
! 502: bQuitProgram = true;
! 503: bStopEditing = true;
! 504: }
! 505: break;
1.1 root 506: case SDL_QUIT: /* User wants to quit */
507: bQuitProgram = true;
508: bStopEditing = true;
509: break;
510: case SDL_MOUSEBUTTONDOWN: /* Mouse pressed -> stop editing */
511: bStopEditing = true;
512: break;
513: case SDL_KEYDOWN: /* Key pressed */
514: switch (event.key.keysym.sym)
515: {
516: case SDLK_RETURN:
517: case SDLK_KP_ENTER:
518: bStopEditing = true;
519: break;
520: case SDLK_LEFT:
521: if (cursorPos > 0)
522: cursorPos -= 1;
523: break;
524: case SDLK_RIGHT:
525: if (cursorPos < strlen(txt))
526: cursorPos += 1;
527: break;
528: case SDLK_BACKSPACE:
529: if (cursorPos > 0)
530: {
531: memmove(&txt[cursorPos-1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
532: cursorPos -= 1;
533: }
534: break;
535: case SDLK_DELETE:
536: if (cursorPos < strlen(txt))
537: memmove(&txt[cursorPos], &txt[cursorPos+1], strlen(&txt[cursorPos+1])+1);
538: break;
539: default:
1.1.1.4 ! root 540: /* Get other keys from SDL_TEXTINPUT event */
! 541: break;
! 542: }
! 543: break;
! 544: case SDL_TEXTINPUT:
! 545: if (strlen(txt) < (size_t)dlg[objnum].w)
! 546: {
! 547: memmove(&txt[cursorPos+1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
! 548: txt[cursorPos] = event.text.text[0];
! 549: cursorPos += 1;
! 550: }
1.1 root 551: break;
552: }
553: break;
554: }
555: while (SDL_PollEvent(&event));
556:
557: blinkState = 1;
558: }
559:
560: /* Redraw the text field: */
561: SDL_FillRect(pSdlGuiScrn, &rect, grey); /* Draw background */
562: /* Draw the cursor: */
563: if (blinkState && !bStopEditing)
564: {
565: SDL_Rect cursorrect;
1.1.1.2 root 566: cursorrect.x = rect.x + cursorPos * sdlgui_fontwidth;
1.1 root 567: cursorrect.y = rect.y;
1.1.1.2 root 568: cursorrect.w = sdlgui_fontwidth;
1.1 root 569: cursorrect.h = rect.h;
570: SDL_FillRect(pSdlGuiScrn, &cursorrect, cursorCol);
571: }
572: SDLGui_Text(rect.x, rect.y, dlg[objnum].txt); /* Draw text */
573: SDL_UpdateRects(pSdlGuiScrn, 1, &rect);
574: }
575: while (!bStopEditing);
576:
1.1.1.4 ! root 577: SDL_StopTextInput();
1.1 root 578: }
579:
580:
581: /*-----------------------------------------------------------------------*/
582: /**
583: * Draw a whole dialog.
584: */
585: void SDLGui_DrawDialog(const SGOBJ *dlg)
586: {
587: int i;
588: for (i = 0; dlg[i].type != -1; i++)
589: {
590: switch (dlg[i].type)
591: {
592: case SGBOX:
593: SDLGui_DrawBox(dlg, i);
594: break;
595: case SGTEXT:
596: SDLGui_DrawText(dlg, i);
597: break;
598: case SGEDITFIELD:
599: SDLGui_DrawEditField(dlg, i);
600: break;
601: case SGBUTTON:
602: SDLGui_DrawButton(dlg, i);
603: break;
604: case SGRADIOBUT:
605: SDLGui_DrawRadioButton(dlg, i);
606: break;
607: case SGCHECKBOX:
608: SDLGui_DrawCheckBox(dlg, i);
609: break;
610: case SGPOPUP:
611: SDLGui_DrawPopupButton(dlg, i);
612: break;
1.1.1.2 root 613: case SGSCROLLBAR:
614: SDLGui_DrawScrollbar(dlg, i);
615: break;
1.1 root 616: }
617: }
618: SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
619: }
620:
621:
622: /*-----------------------------------------------------------------------*/
623: /**
624: * Search an object at a certain position.
625: */
626: static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
627: {
628: int len, i;
629: int ob = -1;
630: int xpos, ypos;
631:
632: len = 0;
633: while (dlg[len].type != -1) len++;
634:
1.1.1.2 root 635: xpos = fx / sdlgui_fontwidth;
636: ypos = fy / sdlgui_fontheight;
1.1 root 637: /* Now search for the object: */
638: for (i = len; i >= 0; i--)
639: {
1.1.1.2 root 640: /* clicked on a scrollbar ? */
641: if (dlg[i].type == SGSCROLLBAR) {
642: if (xpos >= dlg[0].x+dlg[i].x && xpos < dlg[0].x+dlg[i].x+1) {
643: ypos = dlg[i].y * sdlgui_fontheight + dlg[i].h + dlg[0].y * sdlgui_fontheight;
644: if (fy >= ypos && fy < ypos + dlg[i].w) {
645: ob = i;
646: break;
647: }
648: }
649: }
650: /* clicked on another object ? */
651: else if (xpos >= dlg[0].x+dlg[i].x && ypos >= dlg[0].y+dlg[i].y
652: && xpos < dlg[0].x+dlg[i].x+dlg[i].w && ypos < dlg[0].y+dlg[i].y+dlg[i].h)
1.1 root 653: {
654: ob = i;
655: break;
656: }
657: }
658:
659: return ob;
660: }
661:
662:
663: /*-----------------------------------------------------------------------*/
664: /**
665: * Search a button with a special flag (e.g. SG_DEFAULT or SG_CANCEL).
666: */
667: static int SDLGui_SearchFlaggedButton(const SGOBJ *dlg, int flag)
668: {
669: int i = 0;
670:
671: while (dlg[i].type != -1)
672: {
673: if (dlg[i].flags & flag)
674: return i;
675: i++;
676: }
677:
678: return 0;
679: }
680:
681:
682: /*-----------------------------------------------------------------------*/
683: /**
684: * Show and process a dialog. Returns the button number that has been
685: * pressed or SDLGUI_UNKNOWNEVENT if an unsupported event occured (will be
686: * stored in parameter pEventOut).
687: */
688: int SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut)
689: {
690: int obj=0;
691: int oldbutton=0;
692: int retbutton=0;
693: int i, j, b;
694: SDL_Event sdlEvent;
695: SDL_Rect rct;
696: Uint32 grey;
697: SDL_Surface *pBgSurface;
698: SDL_Rect dlgrect, bgrect;
699:
1.1.1.2 root 700: if (pSdlGuiScrn->h / sdlgui_fontheight < dlg[0].h)
1.1 root 701: {
702: fprintf(stderr, "Screen size too small for dialog!\n");
703: return SDLGUI_ERROR;
704: }
705:
1.1.1.4 ! root 706: grey = SDL_MapRGB(pSdlGuiScrn->format,181,183,170);
1.1 root 707:
1.1.1.2 root 708: dlgrect.x = dlg[0].x * sdlgui_fontwidth;
709: dlgrect.y = dlg[0].y * sdlgui_fontheight;
710: dlgrect.w = dlg[0].w * sdlgui_fontwidth;
711: dlgrect.h = dlg[0].h * sdlgui_fontheight;
1.1 root 712:
713: bgrect.x = bgrect.y = 0;
714: bgrect.w = dlgrect.w;
715: bgrect.h = dlgrect.h;
716:
717: /* Save background */
718: pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
719: pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
720: if (pSdlGuiScrn->format->palette != NULL)
721: {
1.1.1.4 ! root 722: SDL_SetPaletteColors(pBgSurface->format->palette, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
1.1 root 723: }
724:
725: if (pBgSurface != NULL)
726: {
727: SDL_BlitSurface(pSdlGuiScrn, &dlgrect, pBgSurface, &bgrect);
728: }
729: else
730: {
731: fprintf(stderr, "SDLGUI_DoDialog: CreateRGBSurface failed: %s\n", SDL_GetError());
732: }
733:
734: /* (Re-)draw the dialog */
735: SDLGui_DrawDialog(dlg);
736:
737: /* Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here */
738: SDL_PumpEvents();
739: b = SDL_GetMouseState(&i, &j);
1.1.1.2 root 740:
741: /* If current object is the scrollbar, and mouse is still down, we can scroll it */
742: /* also if the mouse pointer has left the scrollbar */
743: if (dlg[current_object].type == SGSCROLLBAR) {
744: if (b & SDL_BUTTON(1)) {
745: obj = current_object;
746: dlg[obj].state |= SG_MOUSEDOWN;
747: oldbutton = obj;
748: retbutton = obj;
749: }
750: else {
751: obj = current_object;
752: current_object = 0;
753: dlg[obj].state &= SG_MOUSEUP;
1.1 root 754: retbutton = obj;
1.1.1.2 root 755: oldbutton = obj;
1.1 root 756: }
757: }
1.1.1.2 root 758: else {
759: obj = SDLGui_FindObj(dlg, i, j);
760: current_object = obj;
761: if (obj > 0 && (dlg[obj].flags&SG_TOUCHEXIT) )
762: {
763: oldbutton = obj;
764: if (b & SDL_BUTTON(1))
765: {
766: dlg[obj].state |= SG_SELECTED;
767: retbutton = obj;
768: }
769: }
770: }
1.1 root 771:
1.1.1.2 root 772:
1.1 root 773: /* The main loop */
774: while (retbutton == 0 && !bQuitProgram)
775: {
776: if (SDL_WaitEvent(&sdlEvent) == 1) /* Wait for events */
1.1.1.2 root 777:
1.1 root 778: switch (sdlEvent.type)
779: {
780: case SDL_QUIT:
781: retbutton = SDLGUI_QUIT;
782: break;
783:
784: case SDL_MOUSEBUTTONDOWN:
785: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
786: {
787: /* Not left mouse button -> unsupported event */
788: if (pEventOut)
789: retbutton = SDLGUI_UNKNOWNEVENT;
790: break;
791: }
792: /* It was the left button: Find the object under the mouse cursor */
793: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
794: if (obj>0)
795: {
796: if (dlg[obj].type==SGBUTTON)
797: {
798: dlg[obj].state |= SG_SELECTED;
799: SDLGui_DrawButton(dlg, obj);
1.1.1.2 root 800: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
801: dlg[obj].w*sdlgui_fontwidth+4, dlg[obj].h*sdlgui_fontheight+4);
802: oldbutton=obj;
803: }
804: if (dlg[obj].type==SGSCROLLBAR)
805: {
806: dlg[obj].state |= SG_MOUSEDOWN;
1.1 root 807: oldbutton=obj;
808: }
809: if ( dlg[obj].flags&SG_TOUCHEXIT )
810: {
811: dlg[obj].state |= SG_SELECTED;
812: retbutton = obj;
813: }
814: }
815: break;
816:
817: case SDL_MOUSEBUTTONUP:
818: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
819: {
820: /* Not left mouse button -> unsupported event */
821: if (pEventOut)
822: retbutton = SDLGUI_UNKNOWNEVENT;
823: break;
824: }
825: /* It was the left button: Find the object under the mouse cursor */
826: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
827: if (obj>0)
828: {
829: switch (dlg[obj].type)
830: {
831: case SGBUTTON:
832: if (oldbutton==obj)
833: retbutton=obj;
834: break;
1.1.1.2 root 835: case SGSCROLLBAR:
836: dlg[obj].state &= SG_MOUSEUP;
837:
838: if (oldbutton==obj)
839: retbutton=obj;
840: break;
841: case SGEDITFIELD:
1.1 root 842: SDLGui_EditField(dlg, obj);
843: break;
844: case SGRADIOBUT:
845: for (i = obj-1; i > 0 && dlg[i].type == SGRADIOBUT; i--)
846: {
847: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1.1.1.2 root 848: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
849: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
850: rct.w = sdlgui_fontwidth;
851: rct.h = sdlgui_fontheight;
1.1 root 852: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
853: SDLGui_DrawRadioButton(dlg, i);
854: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
855: }
856: for (i = obj+1; dlg[i].type == SGRADIOBUT; i++)
857: {
858: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1.1.1.2 root 859: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
860: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
861: rct.w = sdlgui_fontwidth;
862: rct.h = sdlgui_fontheight;
1.1 root 863: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
864: SDLGui_DrawRadioButton(dlg, i);
865: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
866: }
867: dlg[obj].state |= SG_SELECTED; /* Select this radio button */
1.1.1.2 root 868: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
869: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
870: rct.w = sdlgui_fontwidth;
871: rct.h = sdlgui_fontheight;
1.1 root 872: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
873: SDLGui_DrawRadioButton(dlg, obj);
874: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1.1.1.3 root 875: retbutton = obj; // added by andreas_g
1.1 root 876: break;
877: case SGCHECKBOX:
878: dlg[obj].state ^= SG_SELECTED;
1.1.1.2 root 879: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
880: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
881: rct.w = sdlgui_fontwidth;
882: rct.h = sdlgui_fontheight;
1.1 root 883: SDL_FillRect(pSdlGuiScrn, &rct, grey); /* Clear old */
884: SDLGui_DrawCheckBox(dlg, obj);
885: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1.1.1.3 root 886: retbutton = obj; // added by andreas_g
1.1 root 887: break;
888: case SGPOPUP:
889: dlg[obj].state |= SG_SELECTED;
890: SDLGui_DrawPopupButton(dlg, obj);
1.1.1.2 root 891: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
892: dlg[obj].w*sdlgui_fontwidth+4, dlg[obj].h*sdlgui_fontheight+4);
1.1 root 893: retbutton=obj;
894: break;
895: }
896: }
1.1.1.2 root 897: if (oldbutton > 0 && dlg[oldbutton].type == SGBUTTON)
1.1 root 898: {
899: dlg[oldbutton].state &= ~SG_SELECTED;
900: SDLGui_DrawButton(dlg, oldbutton);
1.1.1.2 root 901: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[oldbutton].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[oldbutton].y)*sdlgui_fontheight-2,
902: dlg[oldbutton].w*sdlgui_fontwidth+4, dlg[oldbutton].h*sdlgui_fontheight+4);
1.1 root 903: oldbutton = 0;
904: }
905: if (obj >= 0 && (dlg[obj].flags&SG_EXIT))
906: {
907: retbutton = obj;
908: }
909: break;
910:
911: case SDL_JOYAXISMOTION:
912: case SDL_JOYBALLMOTION:
913: case SDL_JOYHATMOTION:
914: case SDL_MOUSEMOTION:
915: break;
916:
917: case SDL_KEYDOWN: /* Key pressed */
918: if (sdlEvent.key.keysym.sym == SDLK_RETURN
919: || sdlEvent.key.keysym.sym == SDLK_KP_ENTER)
920: {
921: retbutton = SDLGui_SearchFlaggedButton(dlg, SG_DEFAULT);
922: }
923: else if (sdlEvent.key.keysym.sym == SDLK_ESCAPE)
924: {
925: retbutton = SDLGui_SearchFlaggedButton(dlg, SG_CANCEL);
926: }
927: else if (pEventOut)
928: {
929: retbutton = SDLGUI_UNKNOWNEVENT;
930: }
931: break;
932:
933: default:
934: if (pEventOut)
935: retbutton = SDLGUI_UNKNOWNEVENT;
936: break;
937: }
938: }
939:
940: /* Restore background */
941: if (pBgSurface)
942: {
943: SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn, &dlgrect);
944: SDL_FreeSurface(pBgSurface);
945: }
946:
947: /* Copy event data of unsupported events if caller wants to have it */
948: if (retbutton == SDLGUI_UNKNOWNEVENT && pEventOut)
949: memcpy(pEventOut, &sdlEvent, sizeof(SDL_Event));
950:
951: if (retbutton == SDLGUI_QUIT)
952: bQuitProgram = true;
953:
954: return retbutton;
955: }
956:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.