|
|
1.1 root 1: /*
2: Hatari - sdlgui.c
3:
1.1.1.13 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: A tiny graphical user interface for Hatari.
8: */
1.1.1.8 root 9: const char SDLGui_fileid[] = "Hatari sdlgui.c : " __DATE__ " " __TIME__;
1.1 root 10:
11: #include <SDL.h>
12: #include <ctype.h>
13: #include <string.h>
1.1.1.14 root 14: #include <stdlib.h>
1.1.1.15! root 15: #include <assert.h>
1.1 root 16:
17: #include "main.h"
1.1.1.14 root 18: #include "screen.h"
1.1 root 19: #include "sdlgui.h"
1.1.1.14 root 20: #include "str.h"
1.1 root 21:
22: #include "font5x8.h"
23: #include "font10x16.h"
24:
1.1.1.15! root 25: #define DEBUG_INFO 0
! 26: #if DEBUG_INFO
! 27: # define Dprintf(a) printf a
! 28: #else
! 29: # define Dprintf(a)
! 30: #endif
! 31:
1.1.1.14 root 32: #if WITH_SDL2
33: #define SDL_SRCCOLORKEY SDL_TRUE
34: #define SDLKey SDL_Keycode
35: #endif
1.1 root 36:
1.1.1.2 root 37: static SDL_Surface *pSdlGuiScrn; /* Pointer to the actual main SDL screen surface */
1.1 root 38: static SDL_Surface *pSmallFontGfx = NULL; /* The small font graphics */
39: static SDL_Surface *pBigFontGfx = NULL; /* The big font graphics */
1.1.1.2 root 40: static SDL_Surface *pFontGfx = NULL; /* The actual font graphics */
1.1.1.15! root 41: static int current_object = SDLGUI_NOTFOUND;/* Current selected object */
1.1 root 42:
1.1.1.14 root 43: static struct {
44: Uint32 darkbar, midbar, lightbar;
45: Uint32 darkgrey, midgrey, lightgrey;
46: Uint32 focus, cursor, underline, editfield;
47: } colors;
48:
1.1.1.11 root 49: int sdlgui_fontwidth; /* Width of the actual font */
50: int sdlgui_fontheight; /* Height of the actual font */
51:
1.1.1.14 root 52: #define UNDERLINE_INDICATOR '_'
53:
54:
1.1 root 55: /*-----------------------------------------------------------------------*/
1.1.1.9 root 56: /**
57: * Load an 1 plane XBM into a 8 planes SDL_Surface.
58: */
1.1.1.4 root 59: static SDL_Surface *SDLGui_LoadXBM(int w, int h, const Uint8 *pXbmBits)
1.1 root 60: {
1.1.1.5 root 61: SDL_Surface *bitmap;
62: Uint8 *dstbits;
63: const Uint8 *srcbits;
64: int x, y, srcpitch;
65: int mask;
66:
67: srcbits = pXbmBits;
68:
69: /* Allocate the bitmap */
70: bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
71: if (bitmap == NULL)
72: {
73: fprintf(stderr, "Failed to allocate bitmap: %s", SDL_GetError());
74: return NULL;
75: }
76:
77: srcpitch = ((w + 7) / 8);
78: dstbits = (Uint8 *)bitmap->pixels;
79: mask = 1;
80:
81: /* Copy the pixels */
82: for (y = 0 ; y < h ; y++)
83: {
84: for (x = 0 ; x < w ; x++)
85: {
86: dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
87: mask <<= 1;
88: mask |= (mask >> 8);
89: mask &= 0xFF;
90: }
91: dstbits += bitmap->pitch;
92: srcbits += srcpitch;
93: }
1.1 root 94:
1.1.1.5 root 95: return bitmap;
1.1 root 96: }
97:
98:
99: /*-----------------------------------------------------------------------*/
1.1.1.9 root 100: /**
101: * Initialize the GUI.
102: */
1.1 root 103: int SDLGui_Init(void)
104: {
1.1.1.14 root 105: SDL_Color blackWhiteColors[2] = {{255, 255, 255, 255}, {0, 0, 0, 255}};
1.1 root 106:
1.1.1.6 root 107: if (pSmallFontGfx && pBigFontGfx)
108: {
109: /* already initialized */
110: return 0;
111: }
112:
1.1.1.5 root 113: /* Initialize the font graphics: */
114: pSmallFontGfx = SDLGui_LoadXBM(font5x8_width, font5x8_height, font5x8_bits);
115: pBigFontGfx = SDLGui_LoadXBM(font10x16_width, font10x16_height, font10x16_bits);
116: if (pSmallFontGfx == NULL || pBigFontGfx == NULL)
117: {
118: fprintf(stderr, "Error: Can not init font graphics!\n");
119: return -1;
120: }
121:
122: /* Set color palette of the font graphics: */
123: SDL_SetColors(pSmallFontGfx, blackWhiteColors, 0, 2);
124: SDL_SetColors(pBigFontGfx, blackWhiteColors, 0, 2);
125:
126: /* Set font color 0 as transparent: */
127: SDL_SetColorKey(pSmallFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
128: SDL_SetColorKey(pBigFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
1.1 root 129:
1.1.1.5 root 130: return 0;
1.1 root 131: }
132:
133:
134: /*-----------------------------------------------------------------------*/
1.1.1.9 root 135: /**
136: * Uninitialize the GUI.
137: */
1.1 root 138: int SDLGui_UnInit(void)
139: {
1.1.1.5 root 140: if (pSmallFontGfx)
141: {
142: SDL_FreeSurface(pSmallFontGfx);
143: pSmallFontGfx = NULL;
144: }
145:
146: if (pBigFontGfx)
147: {
148: SDL_FreeSurface(pBigFontGfx);
149: pBigFontGfx = NULL;
150: }
1.1 root 151:
1.1.1.5 root 152: return 0;
1.1 root 153: }
154:
155:
156: /*-----------------------------------------------------------------------*/
1.1.1.9 root 157: /**
158: * Inform the SDL-GUI about the actual SDL_Surface screen pointer and
159: * prepare the font to suit the actual resolution.
160: */
1.1.1.2 root 161: int SDLGui_SetScreen(SDL_Surface *pScrn)
1.1 root 162: {
1.1.1.5 root 163: pSdlGuiScrn = pScrn;
1.1.1.2 root 164:
1.1.1.5 root 165: /* Decide which font to use - small or big one: */
166: if (pSdlGuiScrn->w >= 640 && pSdlGuiScrn->h >= 400 && pBigFontGfx != NULL)
167: {
168: pFontGfx = pBigFontGfx;
169: }
170: else
171: {
172: pFontGfx = pSmallFontGfx;
173: }
174:
175: if (pFontGfx == NULL)
176: {
1.1.1.13 root 177: fprintf(stderr, "Error: A problem with the font occurred!\n");
1.1.1.5 root 178: return -1;
179: }
180:
181: /* Get the font width and height: */
1.1.1.10 root 182: sdlgui_fontwidth = pFontGfx->w/16;
183: sdlgui_fontheight = pFontGfx->h/16;
1.1 root 184:
1.1.1.14 root 185: /* scrollbar */
186: colors.darkbar = SDL_MapRGB(pSdlGuiScrn->format, 64, 64, 64);
187: colors.midbar = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
188: colors.lightbar = SDL_MapRGB(pSdlGuiScrn->format,196,196,196);
189: /* buttons, midgray is also normal bg color */
190: colors.darkgrey = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
191: colors.midgrey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
192: colors.lightgrey = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
193: /* others */
194: colors.focus = SDL_MapRGB(pSdlGuiScrn->format,212,212,212);
195: colors.cursor = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
196: if (sdlgui_fontheight < 16)
197: colors.underline = SDL_MapRGB(pSdlGuiScrn->format,255,0,255);
198: else
199: colors.underline = SDL_MapRGB(pSdlGuiScrn->format,0,0,0);
200: colors.editfield = SDL_MapRGB(pSdlGuiScrn->format,160,160,160);
201:
1.1.1.5 root 202: return 0;
1.1 root 203: }
204:
1.1.1.6 root 205: /*-----------------------------------------------------------------------*/
1.1.1.9 root 206: /**
207: * Return character size for current font in given arguments.
208: */
1.1.1.6 root 209: void SDLGui_GetFontSize(int *width, int *height)
210: {
1.1.1.10 root 211: *width = sdlgui_fontwidth;
212: *height = sdlgui_fontheight;
1.1.1.6 root 213: }
1.1 root 214:
215: /*-----------------------------------------------------------------------*/
1.1.1.9 root 216: /**
217: * Center a dialog so that it appears in the middle of the screen.
218: * Note: We only store the coordinates in the root box of the dialog,
219: * all other objects in the dialog are positioned relatively to this one.
220: */
1.1 root 221: void SDLGui_CenterDlg(SGOBJ *dlg)
222: {
1.1.1.10 root 223: dlg[0].x = (pSdlGuiScrn->w/sdlgui_fontwidth-dlg[0].w)/2;
224: dlg[0].y = (pSdlGuiScrn->h/sdlgui_fontheight-dlg[0].h)/2;
1.1 root 225: }
226:
1.1.1.14 root 227: /*-----------------------------------------------------------------------*/
228: /**
229: * Return text length which ignores underlining.
230: */
231: static int SDLGui_TextLen(const char *str)
232: {
233: int len;
234: for (len = 0; *str; str++)
235: {
236: if (*str != UNDERLINE_INDICATOR)
237: len++;
238: }
239: return len;
240: }
1.1 root 241:
242: /*-----------------------------------------------------------------------*/
1.1.1.9 root 243: /**
1.1.1.14 root 244: * Draw a text string (internal version).
1.1.1.9 root 245: */
1.1.1.14 root 246: static void SDLGui_TextInt(int x, int y, const char *txt, bool underline)
1.1 root 247: {
1.1.1.14 root 248: int i, offset;
1.1.1.13 root 249: unsigned char c;
1.1.1.5 root 250: SDL_Rect sr, dr;
251:
1.1.1.14 root 252: /* underline offset needs to go outside the box for smaller font */
253: if (sdlgui_fontheight < 16)
254: offset = sdlgui_fontheight - 1;
255: else
256: offset = sdlgui_fontheight - 2;
257:
258: i = 0;
259: while (txt[i])
1.1.1.5 root 260: {
1.1.1.14 root 261: dr.x=x;
262: dr.y=y;
263: dr.w=sdlgui_fontwidth;
264: dr.h=sdlgui_fontheight;
265:
266: c = txt[i++];
267: if (c == UNDERLINE_INDICATOR && underline)
268: {
269: dr.h = 1;
270: dr.y += offset;
271: SDL_FillRect(pSdlGuiScrn, &dr, colors.underline);
272: continue;
273: }
274: /* for now, assume (only) Linux file paths are UTF-8 */
275: #if !(defined(WIN32) || defined(USE_LOCALE_CHARSET))
1.1.1.15! root 276: /* Quick and dirty conversion for latin1 characters only... */
1.1.1.14 root 277: if ((c & 0xc0) == 0xc0)
278: {
279: c = c << 6;
280: c |= (txt[i++]) & 0x7f;
281: }
282: else if (c >= 0x80)
283: {
284: printf("Unsupported character '%c' (0x%x)\n", c, c);
285: }
286: #endif
287: x += sdlgui_fontwidth;
288:
1.1.1.10 root 289: sr.x=sdlgui_fontwidth*(c%16);
290: sr.y=sdlgui_fontheight*(c/16);
291: sr.w=sdlgui_fontwidth;
292: sr.h=sdlgui_fontheight;
1.1.1.5 root 293: SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
294: }
1.1 root 295: }
296:
1.1.1.14 root 297: /*-----------------------------------------------------------------------*/
298: /**
299: * Draw a text string (generic).
300: */
301: void SDLGui_Text(int x, int y, const char *txt)
302: {
303: SDLGui_TextInt(x, y, txt, false);
304: }
1.1 root 305:
306: /*-----------------------------------------------------------------------*/
1.1.1.9 root 307: /**
308: * Draw a dialog text object.
309: */
1.1.1.2 root 310: static void SDLGui_DrawText(const SGOBJ *tdlg, int objnum)
1.1 root 311: {
1.1.1.5 root 312: int x, y;
1.1.1.10 root 313: x = (tdlg[0].x+tdlg[objnum].x)*sdlgui_fontwidth;
314: y = (tdlg[0].y+tdlg[objnum].y)*sdlgui_fontheight;
1.1.1.14 root 315:
316: if (tdlg[objnum].flags & SG_EXIT)
317: {
318: SDL_Rect rect;
319: /* Draw background: */
320: rect.x = x;
321: rect.y = y;
322: rect.w = tdlg[objnum].w * sdlgui_fontwidth;
323: rect.h = tdlg[objnum].h * sdlgui_fontheight;
324: if (tdlg[objnum].state & SG_FOCUSED)
325: SDL_FillRect(pSdlGuiScrn, &rect, colors.focus);
326: else
327: SDL_FillRect(pSdlGuiScrn, &rect, colors.midgrey);
328: }
329:
1.1.1.5 root 330: SDLGui_Text(x, y, tdlg[objnum].txt);
1.1 root 331: }
332:
333:
334: /*-----------------------------------------------------------------------*/
1.1.1.9 root 335: /**
336: * Draw a edit field object.
337: */
1.1.1.2 root 338: static void SDLGui_DrawEditField(const SGOBJ *edlg, int objnum)
1.1 root 339: {
1.1.1.5 root 340: int x, y;
341: SDL_Rect rect;
1.1 root 342:
1.1.1.10 root 343: x = (edlg[0].x+edlg[objnum].x)*sdlgui_fontwidth;
344: y = (edlg[0].y+edlg[objnum].y)*sdlgui_fontheight;
1.1.1.5 root 345: SDLGui_Text(x, y, edlg[objnum].txt);
346:
347: rect.x = x;
1.1.1.10 root 348: rect.y = y + edlg[objnum].h * sdlgui_fontheight;
349: rect.w = edlg[objnum].w * sdlgui_fontwidth;
1.1.1.5 root 350: rect.h = 1;
1.1.1.14 root 351: SDL_FillRect(pSdlGuiScrn, &rect, colors.editfield);
1.1 root 352: }
353:
354:
355: /*-----------------------------------------------------------------------*/
1.1.1.9 root 356: /**
357: * Draw a dialog box object.
358: */
1.1.1.2 root 359: static void SDLGui_DrawBox(const SGOBJ *bdlg, int objnum)
1.1 root 360: {
1.1.1.5 root 361: SDL_Rect rect;
362: int x, y, w, h, offset;
1.1.1.14 root 363: Uint32 color, upleftc, downrightc;
364:
365: if (bdlg[objnum].state & SG_FOCUSED)
366: color = colors.focus;
367: else
368: color = colors.midgrey;
1.1.1.5 root 369:
1.1.1.10 root 370: x = bdlg[objnum].x*sdlgui_fontwidth;
371: y = bdlg[objnum].y*sdlgui_fontheight;
1.1.1.5 root 372: if (objnum > 0) /* Since the root object is a box, too, */
373: {
374: /* we have to look for it now here and only */
1.1.1.10 root 375: x += bdlg[0].x*sdlgui_fontwidth; /* add its absolute coordinates if we need to */
376: y += bdlg[0].y*sdlgui_fontheight;
1.1.1.5 root 377: }
1.1.1.10 root 378: w = bdlg[objnum].w*sdlgui_fontwidth;
379: h = bdlg[objnum].h*sdlgui_fontheight;
1.1.1.5 root 380:
381: if (bdlg[objnum].state & SG_SELECTED)
382: {
1.1.1.14 root 383: upleftc = colors.darkgrey;
384: downrightc = colors.lightgrey;
1.1.1.5 root 385: }
386: else
387: {
1.1.1.14 root 388: upleftc = colors.lightgrey;
389: downrightc = colors.darkgrey;
1.1.1.5 root 390: }
391:
392: /* The root box should be bigger than the screen, so we disable the offset there: */
393: if (objnum != 0)
394: offset = 1;
395: else
396: offset = 0;
397:
398: /* Draw background: */
399: rect.x = x;
400: rect.y = y;
401: rect.w = w;
402: rect.h = h;
1.1.1.14 root 403: SDL_FillRect(pSdlGuiScrn, &rect, color);
1.1.1.5 root 404:
405: /* Draw upper border: */
406: rect.x = x;
407: rect.y = y - offset;
408: rect.w = w;
409: rect.h = 1;
410: SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
411:
412: /* Draw left border: */
413: rect.x = x - offset;
414: rect.y = y;
415: rect.w = 1;
416: rect.h = h;
417: SDL_FillRect(pSdlGuiScrn, &rect, upleftc);
418:
419: /* Draw bottom border: */
420: rect.x = x;
421: rect.y = y + h - 1 + offset;
422: rect.w = w;
423: rect.h = 1;
424: SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
425:
426: /* Draw right border: */
427: rect.x = x + w - 1 + offset;
428: rect.y = y;
429: rect.w = 1;
430: rect.h = h;
431: SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
1.1 root 432: }
433:
434:
435: /*-----------------------------------------------------------------------*/
1.1.1.9 root 436: /**
437: * Draw a normal button.
438: */
1.1.1.2 root 439: static void SDLGui_DrawButton(const SGOBJ *bdlg, int objnum)
1.1 root 440: {
1.1.1.5 root 441: int x,y;
1.1 root 442:
1.1.1.5 root 443: SDLGui_DrawBox(bdlg, objnum);
1.1 root 444:
1.1.1.14 root 445: x = (bdlg[0].x + bdlg[objnum].x + (bdlg[objnum].w-SDLGui_TextLen(bdlg[objnum].txt))/2) * sdlgui_fontwidth;
1.1.1.10 root 446: y = (bdlg[0].y + bdlg[objnum].y + (bdlg[objnum].h-1)/2) * sdlgui_fontheight;
1.1 root 447:
1.1.1.5 root 448: if (bdlg[objnum].state & SG_SELECTED)
449: {
450: x+=1;
451: y+=1;
452: }
1.1.1.14 root 453: SDLGui_TextInt(x, y, bdlg[objnum].txt, true);
1.1 root 454: }
455:
1.1.1.14 root 456: /*-----------------------------------------------------------------------*/
457: /**
458: * If object is focused, draw a focused background to it
459: */
460: static void SDLGui_DrawFocusBg(const SGOBJ *obj, int x, int y)
461: {
462: SDL_Rect rect;
463: Uint32 color;
464:
465: if (obj->state & SG_WASFOCUSED)
466: color = colors.midgrey;
467: else if (obj->state & SG_FOCUSED)
468: color = colors.focus;
469: else
470: return;
471:
472: rect.x = x;
473: rect.y = y;
474: rect.w = obj->w * sdlgui_fontwidth;
475: rect.h = obj->h * sdlgui_fontheight;
476:
477: SDL_FillRect(pSdlGuiScrn, &rect, color);
478: }
1.1 root 479:
480: /*-----------------------------------------------------------------------*/
1.1.1.9 root 481: /**
482: * Draw a dialog radio button object.
483: */
1.1.1.2 root 484: static void SDLGui_DrawRadioButton(const SGOBJ *rdlg, int objnum)
1.1 root 485: {
1.1.1.5 root 486: char str[80];
487: int x, y;
1.1 root 488:
1.1.1.10 root 489: x = (rdlg[0].x + rdlg[objnum].x) * sdlgui_fontwidth;
490: y = (rdlg[0].y + rdlg[objnum].y) * sdlgui_fontheight;
1.1.1.14 root 491: SDLGui_DrawFocusBg(&(rdlg[objnum]), x, y);
1.1 root 492:
1.1.1.5 root 493: if (rdlg[objnum].state & SG_SELECTED)
494: str[0]=SGRADIOBUTTON_SELECTED;
495: else
496: str[0]=SGRADIOBUTTON_NORMAL;
497: str[1]=' ';
498: strcpy(&str[2], rdlg[objnum].txt);
1.1 root 499:
1.1.1.14 root 500: SDLGui_TextInt(x, y, str, true);
1.1 root 501: }
502:
503:
504: /*-----------------------------------------------------------------------*/
1.1.1.9 root 505: /**
506: * Draw a dialog check box object.
507: */
1.1.1.2 root 508: static void SDLGui_DrawCheckBox(const SGOBJ *cdlg, int objnum)
1.1 root 509: {
1.1.1.5 root 510: char str[80];
511: int x, y;
1.1 root 512:
1.1.1.10 root 513: x = (cdlg[0].x + cdlg[objnum].x) * sdlgui_fontwidth;
514: y = (cdlg[0].y + cdlg[objnum].y) * sdlgui_fontheight;
1.1.1.14 root 515: SDLGui_DrawFocusBg(&(cdlg[objnum]), x, y);
1.1 root 516:
1.1.1.5 root 517: if ( cdlg[objnum].state&SG_SELECTED )
518: str[0]=SGCHECKBOX_SELECTED;
519: else
520: str[0]=SGCHECKBOX_NORMAL;
521: str[1]=' ';
522: strcpy(&str[2], cdlg[objnum].txt);
1.1 root 523:
1.1.1.14 root 524: SDLGui_TextInt(x, y, str, true);
1.1 root 525: }
526:
527:
528: /*-----------------------------------------------------------------------*/
1.1.1.9 root 529: /**
1.1.1.10 root 530: * Draw a scrollbar button.
531: */
532: static void SDLGui_DrawScrollbar(const SGOBJ *bdlg, int objnum)
533: {
534: SDL_Rect rect;
535: int x, y, w, h;
536:
537: x = bdlg[objnum].x * sdlgui_fontwidth;
538: y = bdlg[objnum].y * sdlgui_fontheight + bdlg[objnum].h;
539:
540: x += bdlg[0].x*sdlgui_fontwidth; /* add mainbox absolute coordinates */
541: y += bdlg[0].y*sdlgui_fontheight; /* add mainbox absolute coordinates */
542:
543: w = 1 * sdlgui_fontwidth;
544: h = bdlg[objnum].w;
545:
546: /* Draw background: */
547: rect.x = x;
548: rect.y = y;
549: rect.w = w;
550: rect.h = h;
1.1.1.14 root 551: SDL_FillRect(pSdlGuiScrn, &rect, colors.midbar);
1.1.1.10 root 552:
553: /* Draw upper border: */
554: rect.x = x;
555: rect.y = y;
556: rect.w = w;
557: rect.h = 1;
1.1.1.14 root 558: SDL_FillRect(pSdlGuiScrn, &rect, colors.lightbar);
1.1.1.10 root 559:
560: /* Draw bottom border: */
561: rect.x = x;
562: rect.y = y + h - 1;
563: rect.w = w;
564: rect.h = 1;
1.1.1.14 root 565: SDL_FillRect(pSdlGuiScrn, &rect, colors.darkbar);
1.1.1.10 root 566: }
567:
568: /*-----------------------------------------------------------------------*/
569: /**
1.1.1.9 root 570: * Draw a dialog popup button object.
571: */
1.1.1.2 root 572: static void SDLGui_DrawPopupButton(const SGOBJ *pdlg, int objnum)
1.1 root 573: {
1.1.1.10 root 574: int x, y, w;
1.1.1.5 root 575: const char *downstr = "\x02";
1.1 root 576:
1.1.1.5 root 577: SDLGui_DrawBox(pdlg, objnum);
1.1 root 578:
1.1.1.10 root 579: x = (pdlg[0].x + pdlg[objnum].x) * sdlgui_fontwidth;
580: y = (pdlg[0].y + pdlg[objnum].y) * sdlgui_fontheight;
581: w = pdlg[objnum].w * sdlgui_fontwidth;
1.1 root 582:
1.1.1.14 root 583: SDLGui_TextInt(x, y, pdlg[objnum].txt, true);
1.1.1.10 root 584: SDLGui_Text(x+w-sdlgui_fontwidth, y, downstr);
1.1 root 585: }
586:
587:
588: /*-----------------------------------------------------------------------*/
1.1.1.9 root 589: /**
590: * Let the user insert text into an edit field object.
591: * NOTE: The dlg[objnum].txt must point to an an array that is big enough
592: * for dlg[objnum].w characters!
593: */
1.1 root 594: static void SDLGui_EditField(SGOBJ *dlg, int objnum)
595: {
1.1.1.5 root 596: size_t cursorPos; /* Position of the cursor in the edit field */
597: int blinkState = 0; /* Used for cursor blinking */
1.1.1.8 root 598: int bStopEditing = false; /* true if user wants to exit the edit field */
1.1.1.5 root 599: char *txt; /* Shortcut for dlg[objnum].txt */
600: SDL_Rect rect;
601: SDL_Event event;
1.1.1.14 root 602: #if !WITH_SDL2
1.1.1.5 root 603: int nOldUnicodeMode;
1.1.1.14 root 604: #endif
1.1.1.5 root 605:
1.1.1.10 root 606: rect.x = (dlg[0].x + dlg[objnum].x) * sdlgui_fontwidth;
607: rect.y = (dlg[0].y + dlg[objnum].y) * sdlgui_fontheight;
608: rect.w = (dlg[objnum].w + 1) * sdlgui_fontwidth - 1;
609: rect.h = dlg[objnum].h * sdlgui_fontheight;
1.1.1.5 root 610:
1.1.1.14 root 611: #if WITH_SDL2
612: SDL_SetTextInputRect(&rect);
613: SDL_StartTextInput();
614: #else
615: /* Enable unicode translation to get shifted etc chars with SDL_PollEvent */
616: nOldUnicodeMode = SDL_EnableUNICODE(true);
617: #endif
618:
1.1.1.5 root 619: txt = dlg[objnum].txt;
620: cursorPos = strlen(txt);
621:
622: do
623: {
624: /* Look for events */
625: if (SDL_PollEvent(&event) == 0)
626: {
627: /* No event: Wait some time for cursor blinking */
628: SDL_Delay(250);
629: blinkState ^= 1;
630: }
631: else
632: {
633: /* Handle events */
634: do
635: {
636: switch (event.type)
637: {
638: case SDL_QUIT: /* User wants to quit */
1.1.1.8 root 639: bQuitProgram = true;
640: bStopEditing = true;
1.1.1.5 root 641: break;
642: case SDL_MOUSEBUTTONDOWN: /* Mouse pressed -> stop editing */
1.1.1.8 root 643: bStopEditing = true;
1.1.1.5 root 644: break;
1.1.1.14 root 645: #if WITH_SDL2
646: case SDL_TEXTINPUT:
647: if (strlen(txt) < (size_t)dlg[objnum].w)
648: {
649: memmove(&txt[cursorPos+1], &txt[cursorPos],
650: strlen(&txt[cursorPos])+1);
651: txt[cursorPos] = event.text.text[0];
652: cursorPos += 1;
653: }
654: break;
655: #endif
1.1.1.5 root 656: case SDL_KEYDOWN: /* Key pressed */
657: switch (event.key.keysym.sym)
658: {
659: case SDLK_RETURN:
660: case SDLK_KP_ENTER:
1.1.1.8 root 661: bStopEditing = true;
1.1.1.5 root 662: break;
663: case SDLK_LEFT:
664: if (cursorPos > 0)
665: cursorPos -= 1;
666: break;
667: case SDLK_RIGHT:
668: if (cursorPos < strlen(txt))
669: cursorPos += 1;
670: break;
671: case SDLK_BACKSPACE:
672: if (cursorPos > 0)
673: {
674: memmove(&txt[cursorPos-1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
675: cursorPos -= 1;
676: }
677: break;
678: case SDLK_DELETE:
679: if (cursorPos < strlen(txt))
680: memmove(&txt[cursorPos], &txt[cursorPos+1], strlen(&txt[cursorPos+1])+1);
681: break;
682: default:
1.1.1.14 root 683: #if !WITH_SDL2
1.1.1.5 root 684: /* If it is a "good" key then insert it into the text field */
685: if (event.key.keysym.unicode >= 32 && event.key.keysym.unicode < 128
686: && event.key.keysym.unicode != PATHSEP)
687: {
688: if (strlen(txt) < (size_t)dlg[objnum].w)
689: {
690: memmove(&txt[cursorPos+1], &txt[cursorPos], strlen(&txt[cursorPos])+1);
691: txt[cursorPos] = event.key.keysym.unicode;
692: cursorPos += 1;
693: }
694: }
1.1.1.14 root 695: #endif
1.1.1.5 root 696: break;
697: }
698: break;
699: }
700: }
701: while (SDL_PollEvent(&event));
702:
703: blinkState = 1;
704: }
705:
706: /* Redraw the text field: */
1.1.1.14 root 707: SDL_FillRect(pSdlGuiScrn, &rect, colors.midgrey); /* Draw background */
1.1.1.5 root 708: /* Draw the cursor: */
709: if (blinkState && !bStopEditing)
710: {
711: SDL_Rect cursorrect;
1.1.1.10 root 712: cursorrect.x = rect.x + cursorPos * sdlgui_fontwidth;
1.1.1.5 root 713: cursorrect.y = rect.y;
1.1.1.10 root 714: cursorrect.w = sdlgui_fontwidth;
1.1.1.5 root 715: cursorrect.h = rect.h;
1.1.1.14 root 716: SDL_FillRect(pSdlGuiScrn, &cursorrect, colors.cursor);
1.1.1.5 root 717: }
718: SDLGui_Text(rect.x, rect.y, dlg[objnum].txt); /* Draw text */
719: SDL_UpdateRects(pSdlGuiScrn, 1, &rect);
720: }
721: while (!bStopEditing);
722:
1.1.1.14 root 723: #if WITH_SDL2
724: SDL_StopTextInput();
725: #else
1.1.1.5 root 726: SDL_EnableUNICODE(nOldUnicodeMode);
1.1.1.14 root 727: #endif
1.1 root 728: }
729:
730:
731: /*-----------------------------------------------------------------------*/
1.1.1.9 root 732: /**
1.1.1.14 root 733: * Draw single object based on its type
734: */
735: static void SDLGui_DrawObj(const SGOBJ *dlg, int i)
736: {
737: switch (dlg[i].type)
738: {
739: case SGBOX:
740: SDLGui_DrawBox(dlg, i);
741: break;
742: case SGTEXT:
743: SDLGui_DrawText(dlg, i);
744: break;
745: case SGEDITFIELD:
746: SDLGui_DrawEditField(dlg, i);
747: break;
748: case SGBUTTON:
749: SDLGui_DrawButton(dlg, i);
750: break;
751: case SGRADIOBUT:
752: SDLGui_DrawRadioButton(dlg, i);
753: break;
754: case SGCHECKBOX:
755: SDLGui_DrawCheckBox(dlg, i);
756: break;
757: case SGPOPUP:
758: SDLGui_DrawPopupButton(dlg, i);
759: break;
760: case SGSCROLLBAR:
761: SDLGui_DrawScrollbar(dlg, i);
762: break;
763: }
764: }
765:
766: /*-----------------------------------------------------------------------*/
767: /**
1.1.1.9 root 768: * Draw a whole dialog.
769: */
1.1.1.3 root 770: void SDLGui_DrawDialog(const SGOBJ *dlg)
1.1 root 771: {
1.1.1.5 root 772: int i;
1.1.1.10 root 773:
1.1.1.15! root 774: for (i = 0; dlg[i].type != SGSTOP; i++)
1.1.1.5 root 775: {
1.1.1.14 root 776: SDLGui_DrawObj(dlg, i);
1.1.1.5 root 777: }
778: SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
1.1 root 779: }
780:
781:
782: /*-----------------------------------------------------------------------*/
1.1.1.9 root 783: /**
784: * Search an object at a certain position.
1.1.1.15! root 785: * If found, return its index, otherwise SDLGUI_NOTFOUND.
1.1.1.9 root 786: */
1.1.1.2 root 787: static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
1.1 root 788: {
1.1.1.5 root 789: int len, i;
1.1.1.15! root 790: int ob = SDLGUI_NOTFOUND;
1.1.1.5 root 791: int xpos, ypos;
792:
793: len = 0;
1.1.1.15! root 794: while (dlg[len].type != SGSTOP)
! 795: len++;
! 796:
1.1.1.10 root 797: xpos = fx / sdlgui_fontwidth;
798: ypos = fy / sdlgui_fontheight;
1.1.1.15! root 799:
! 800: /* Now search for the object.
! 801: * Searching is done from end to start,
! 802: * as later objects cover earlier ones
! 803: */
1.1.1.5 root 804: for (i = len; i >= 0; i--)
805: {
1.1.1.10 root 806: /* clicked on a scrollbar ? */
807: if (dlg[i].type == SGSCROLLBAR) {
808: if (xpos >= dlg[0].x+dlg[i].x && xpos < dlg[0].x+dlg[i].x+1) {
809: ypos = dlg[i].y * sdlgui_fontheight + dlg[i].h + dlg[0].y * sdlgui_fontheight;
810: if (fy >= ypos && fy < ypos + dlg[i].w) {
811: ob = i;
812: break;
813: }
814: }
815: }
816: /* clicked on another object ? */
817: else if (xpos >= dlg[0].x+dlg[i].x && ypos >= dlg[0].y+dlg[i].y
1.1.1.5 root 818: && xpos < dlg[0].x+dlg[i].x+dlg[i].w && ypos < dlg[0].y+dlg[i].y+dlg[i].h)
819: {
820: ob = i;
821: break;
822: }
823: }
824:
825: return ob;
826: }
827:
828:
829: /*-----------------------------------------------------------------------*/
1.1.1.9 root 830: /**
1.1.1.14 root 831: * Search an object with a special flag (e.g. SG_DEFAULT or SG_CANCEL).
1.1.1.15! root 832: * If found, return its index, otherwise SDLGUI_NOTFOUND.
1.1.1.9 root 833: */
1.1.1.14 root 834: static int SDLGui_SearchFlags(const SGOBJ *dlg, int flag)
1.1.1.5 root 835: {
836: int i = 0;
837:
1.1.1.15! root 838: while (dlg[i].type != SGSTOP)
1.1.1.5 root 839: {
840: if (dlg[i].flags & flag)
841: return i;
842: i++;
843: }
1.1.1.15! root 844: return SDLGUI_NOTFOUND;
1.1.1.14 root 845: }
1.1 root 846:
1.1.1.14 root 847: /*-----------------------------------------------------------------------*/
848: /**
849: * Search an object with a special state (e.g. SG_FOCUSED).
1.1.1.15! root 850: * If found, return its index, otherwise SDLGUI_NOTFOUND.
1.1.1.14 root 851: */
852: static int SDLGui_SearchState(const SGOBJ *dlg, int state)
853: {
854: int i = 0;
855:
1.1.1.15! root 856: while (dlg[i].type != SGSTOP)
1.1.1.14 root 857: {
858: if (dlg[i].state & state)
859: return i;
860: i++;
861: }
1.1.1.15! root 862: return SDLGUI_NOTFOUND;
! 863: }
! 864:
! 865: /*-----------------------------------------------------------------------*/
! 866: /**
! 867: * Print dialog object flags & state for debug purposes.
! 868: */
! 869: static void SDLGui_DebugPrintDialog(const SGOBJ *dlg)
! 870: {
! 871: #if DEBUG_INFO
! 872: int i;
! 873: printf("obj: flags |Â state\n");
! 874: for (i = 0; dlg[i].type != SGSTOP; i++)
! 875: printf("%3d: 0x%02x |Â 0x%02x\n", i, dlg[i].flags, dlg[i].state);
! 876: #endif
1.1 root 877: }
878:
1.1.1.14 root 879: /*-----------------------------------------------------------------------*/
880: /**
881: * For given dialog object type, returns whether it could have shortcut key
882: */
883: static bool SDLGui_CanHaveShortcut(int kind)
884: {
885: if (kind == SGBUTTON || kind == SGRADIOBUT || kind == SGCHECKBOX)
886: return true;
887: return false;
888: }
889:
890: /*-----------------------------------------------------------------------*/
891: /**
892: * Check & set dialog item shortcut values based on their text strings.
893: * Asserts if dialog has same shortcut defined multiple times.
894: */
895: static void SDLGui_SetShortcuts(SGOBJ *dlg)
896: {
897: unsigned chr, used[256];
898: const char *str;
899: unsigned int i;
900:
901: memset(used, 0, sizeof(used));
1.1.1.15! root 902: for (i = 0; dlg[i].type != SGSTOP; i++)
1.1.1.14 root 903: {
904: if (!SDLGui_CanHaveShortcut(dlg[i].type))
905: continue;
906: if (!(str = dlg[i].txt))
907: continue;
908: while(*str)
909: {
910: if (*str++ == UNDERLINE_INDICATOR)
911: {
912: /* TODO: conversion */
913: chr = toupper(*str);
914: dlg[i].shortcut = chr;
915: if (used[chr])
916: {
917: fprintf(stderr, "ERROR: Duplicate Hatari SDL GUI shortcut in '%s'!\n", dlg[i].txt);
918: exit(1);
919: }
920: used[chr] = 1;
921: }
922: }
923: }
924: }
925:
926: /*-----------------------------------------------------------------------*/
927: /**
928: * Unfocus given button
929: */
930: static void SDLGui_RemoveFocus(SGOBJ *dlg, int old)
931: {
1.1.1.15! root 932: if (old == SDLGUI_NOTFOUND)
1.1.1.14 root 933: return;
934: dlg[old].state &= ~SG_FOCUSED;
935: dlg[old].state |= SG_WASFOCUSED;
936: SDLGui_DrawObj(dlg, old);
937: dlg[old].state ^= SG_WASFOCUSED;
938: }
939:
940: /*-----------------------------------------------------------------------*/
941: /**
1.1.1.15! root 942: * Search next button to focus, and focus it.
! 943: * If found, return its index, otherwise given starting index.
1.1.1.14 root 944: */
945: static int SDLGui_FocusNext(SGOBJ *dlg, int i, int inc)
946: {
947: int old = i;
1.1.1.15! root 948: if (i == SDLGUI_NOTFOUND)
1.1.1.14 root 949: return i;
950:
951: for (;;)
952: {
953: i += inc;
954:
955: /* wrap */
1.1.1.15! root 956: if (dlg[i].type == SGSTOP)
1.1.1.14 root 957: {
1.1.1.15! root 958: assert(inc > 0);
1.1.1.14 root 959: i = 0;
960: }
961: else if (i == 0)
962: {
1.1.1.15! root 963: assert(inc < 0);
! 964: while (dlg[i].type != SGSTOP)
1.1.1.14 root 965: i++;
966: i--;
967: }
968: /* change focus for items that can have shortcuts
969: * and for items in Fsel lists
970: */
971: if (SDLGui_CanHaveShortcut(dlg[i].type) || (dlg[i].flags & SG_EXIT) != 0)
972: {
973: dlg[i].state |= SG_FOCUSED;
974: SDLGui_DrawObj(dlg, i);
975: SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
976: return i;
977: }
978: /* wrapped around without even initial one matching */
979: if (i == old)
980: return 0;
981: }
982: return old;
983: }
984:
985:
986: /*-----------------------------------------------------------------------*/
987: /**
1.1.1.15! root 988: * Handle button selection, either with mouse or keyboard.
! 989: * If handled, return its index, otherwise SDLGUI_NOTFOUND.
1.1.1.14 root 990: */
991: static int SDLGui_HandleSelection(SGOBJ *dlg, int obj, int oldbutton)
992: {
993: SDL_Rect rct;
1.1.1.15! root 994: int i, retbutton = SDLGUI_NOTFOUND;
1.1.1.14 root 995:
996: switch (dlg[obj].type)
997: {
998: case SGBUTTON:
999: if (oldbutton==obj)
1000: retbutton=obj;
1001: break;
1002: case SGSCROLLBAR:
1003: dlg[obj].state &= ~SG_MOUSEDOWN;
1004:
1005: if (oldbutton==obj)
1006: retbutton=obj;
1007: break;
1008: case SGEDITFIELD:
1009: SDLGui_EditField(dlg, obj);
1010: break;
1011: case SGRADIOBUT:
1012: for (i = obj-1; i > 0 && dlg[i].type == SGRADIOBUT; i--)
1013: {
1014: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1015: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
1016: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
1017: rct.w = sdlgui_fontwidth;
1018: rct.h = sdlgui_fontheight;
1019: SDL_FillRect(pSdlGuiScrn, &rct, colors.midgrey); /* Clear old */
1020: SDLGui_DrawRadioButton(dlg, i);
1021: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1022: }
1023: for (i = obj+1; dlg[i].type == SGRADIOBUT; i++)
1024: {
1025: dlg[i].state &= ~SG_SELECTED; /* Deselect all radio buttons in this group */
1026: rct.x = (dlg[0].x+dlg[i].x)*sdlgui_fontwidth;
1027: rct.y = (dlg[0].y+dlg[i].y)*sdlgui_fontheight;
1028: rct.w = sdlgui_fontwidth;
1029: rct.h = sdlgui_fontheight;
1030: SDL_FillRect(pSdlGuiScrn, &rct, colors.midgrey); /* Clear old */
1031: SDLGui_DrawRadioButton(dlg, i);
1032: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1033: }
1034: dlg[obj].state |= SG_SELECTED; /* Select this radio button */
1035: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
1036: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
1037: rct.w = sdlgui_fontwidth;
1038: rct.h = sdlgui_fontheight;
1039: SDL_FillRect(pSdlGuiScrn, &rct, colors.midgrey); /* Clear old */
1040: SDLGui_DrawRadioButton(dlg, obj);
1041: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1042: break;
1043: case SGCHECKBOX:
1044: dlg[obj].state ^= SG_SELECTED;
1045: rct.x = (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth;
1046: rct.y = (dlg[0].y+dlg[obj].y)*sdlgui_fontheight;
1047: rct.w = sdlgui_fontwidth;
1048: rct.h = sdlgui_fontheight;
1049: SDL_FillRect(pSdlGuiScrn, &rct, colors.midgrey); /* Clear old */
1050: SDLGui_DrawCheckBox(dlg, obj);
1051: SDL_UpdateRects(pSdlGuiScrn, 1, &rct);
1052: break;
1053: case SGPOPUP:
1054: dlg[obj].state |= SG_SELECTED;
1055: SDLGui_DrawPopupButton(dlg, obj);
1056: SDL_UpdateRect(pSdlGuiScrn,
1057: (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2,
1058: (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
1059: dlg[obj].w*sdlgui_fontwidth+4,
1060: dlg[obj].h*sdlgui_fontheight+4);
1061: retbutton=obj;
1062: break;
1063: }
1064:
1.1.1.15! root 1065: if (retbutton == SDLGUI_NOTFOUND && (dlg[obj].flags & SG_EXIT) != 0)
1.1.1.14 root 1066: {
1067: retbutton = obj;
1068: }
1069:
1070: return retbutton;
1071: }
1072:
1073:
1074: /*-----------------------------------------------------------------------*/
1075: /**
1.1.1.15! root 1076: * If object with given shortcut is found, handle that.
! 1077: * If handled, return its index, otherwise SDLGUI_NOTFOUND.
1.1.1.14 root 1078: */
1079: static int SDLGui_HandleShortcut(SGOBJ *dlg, int key)
1080: {
1081: int i = 0;
1.1.1.15! root 1082: while (dlg[i].type != SGSTOP)
1.1.1.14 root 1083: {
1084: if (dlg[i].shortcut == key)
1085: return SDLGui_HandleSelection(dlg, i, i);
1086: i++;
1087: }
1.1.1.15! root 1088: return SDLGUI_NOTFOUND;
! 1089: }
! 1090:
! 1091: /**
! 1092: * Scale mouse coordinates in case we've got a re-sized SDL2 window
! 1093: */
! 1094: static void SDLGui_ScaleMouseButtonCoordinates(SDL_MouseButtonEvent *bev)
! 1095: {
! 1096: #if WITH_SDL2
! 1097: int win_width, win_height;
! 1098:
! 1099: if (bInFullScreen)
! 1100: return;
! 1101:
! 1102: SDL_GetWindowSize(sdlWindow, &win_width, &win_height);
! 1103: bev->x = bev->x * pSdlGuiScrn->w / win_width;
! 1104: bev->y = bev->y * pSdlGuiScrn->h / win_height;
! 1105: #endif
1.1.1.14 root 1106: }
1.1 root 1107:
1108: /*-----------------------------------------------------------------------*/
1.1.1.9 root 1109: /**
1.1.1.15! root 1110: * Show and process a dialog. Returns either:
! 1111: * - index of the GUI item that was invoked
! 1112: * - SDLGUI_UNKNOWNEVENT if an unsupported event occurred
! 1113: * (will be stored in parameter pEventOut)
! 1114: * - SDLGUI_QUIT if user wants to close Hatari
! 1115: * - SDLGUI_ERROR if unable to show dialog
! 1116: * GUI item indeces are positive, other return values are negative
1.1.1.9 root 1117: */
1.1.1.14 root 1118: int SDLGui_DoDialog(SGOBJ *dlg, SDL_Event *pEventOut, bool KeepCurrentObject)
1.1 root 1119: {
1.1.1.15! root 1120: int oldbutton = SDLGUI_NOTFOUND;
! 1121: int retbutton = SDLGUI_NOTFOUND;
! 1122: int i, j, b, value, obj;
1.1.1.14 root 1123: SDLKey key;
1124: int focused;
1.1.1.5 root 1125: SDL_Event sdlEvent;
1126: SDL_Surface *pBgSurface;
1127: SDL_Rect dlgrect, bgrect;
1.1.1.14 root 1128: SDL_Joystick *joy = NULL;
1129: #if !WITH_SDL2
1130: int nOldUnicodeMode;
1131: #endif
1132:
1133: /* In the case of dialog using a scrollbar, we must keep the previous */
1134: /* value of current_object, as the same dialog is displayed in a loop */
1135: /* to handle scrolling. For other dialogs, we need to reset current_object */
1136: /* (ie no object selected at start when displaying the dialog) */
1137: if ( !KeepCurrentObject )
1138: current_object = 0;
1.1.1.5 root 1139:
1.1.1.10 root 1140: if (pSdlGuiScrn->h / sdlgui_fontheight < dlg[0].h)
1.1.1.5 root 1141: {
1142: fprintf(stderr, "Screen size too small for dialog!\n");
1143: return SDLGUI_ERROR;
1144: }
1145:
1.1.1.10 root 1146: dlgrect.x = dlg[0].x * sdlgui_fontwidth;
1147: dlgrect.y = dlg[0].y * sdlgui_fontheight;
1148: dlgrect.w = dlg[0].w * sdlgui_fontwidth;
1149: dlgrect.h = dlg[0].h * sdlgui_fontheight;
1.1.1.5 root 1150:
1151: bgrect.x = bgrect.y = 0;
1152: bgrect.w = dlgrect.w;
1153: bgrect.h = dlgrect.h;
1154:
1155: /* Save background */
1156: pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
1157: pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
1158: if (pSdlGuiScrn->format->palette != NULL)
1159: {
1160: SDL_SetColors(pBgSurface, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
1161: }
1162:
1163: if (pBgSurface != NULL)
1164: {
1165: SDL_BlitSurface(pSdlGuiScrn, &dlgrect, pBgSurface, &bgrect);
1166: }
1167: else
1168: {
1169: fprintf(stderr, "SDLGUI_DoDialog: CreateRGBSurface failed: %s\n", SDL_GetError());
1170: }
1.1.1.15! root 1171: SDLGui_DebugPrintDialog(dlg);
1.1.1.5 root 1172:
1.1.1.14 root 1173: /* focus default button if nothing else is focused */
1174: focused = SDLGui_SearchState(dlg, SG_FOCUSED);
1.1.1.15! root 1175: if (focused == SDLGUI_NOTFOUND)
1.1.1.14 root 1176: {
1.1.1.15! root 1177: int defbutton = SDLGui_SearchFlags(dlg, SG_DEFAULT);
! 1178: if (defbutton != SDLGUI_NOTFOUND)
1.1.1.14 root 1179: {
1.1.1.15! root 1180: dlg[defbutton].state |= SG_FOCUSED;
! 1181: focused = defbutton;
1.1.1.14 root 1182: }
1183: }
1.1.1.15! root 1184: Dprintf(("focused: %d\n", focused));
1.1.1.14 root 1185: SDLGui_SetShortcuts(dlg);
1186:
1.1.1.5 root 1187: /* (Re-)draw the dialog */
1188: SDLGui_DrawDialog(dlg);
1189:
1190: /* Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here */
1191: SDL_PumpEvents();
1192: b = SDL_GetMouseState(&i, &j);
1.1.1.10 root 1193:
1194: /* If current object is the scrollbar, and mouse is still down, we can scroll it */
1195: /* also if the mouse pointer has left the scrollbar */
1.1.1.15! root 1196: if (current_object != SDLGUI_NOTFOUND && dlg[current_object].type == SGSCROLLBAR) {
! 1197: obj = current_object;
! 1198: retbutton = obj;
! 1199: oldbutton = obj;
! 1200: if (b & SDL_BUTTON(1))
! 1201: {
1.1.1.10 root 1202: dlg[obj].state |= SG_MOUSEDOWN;
1203: }
1.1.1.15! root 1204: else
! 1205: {
1.1.1.10 root 1206: current_object = 0;
1.1.1.14 root 1207: dlg[obj].state &= ~SG_MOUSEDOWN;
1.1.1.5 root 1208: }
1209: }
1.1.1.10 root 1210: else {
1211: obj = SDLGui_FindObj(dlg, i, j);
1212: current_object = obj;
1.1.1.15! root 1213: if (obj != SDLGUI_NOTFOUND && (dlg[obj].flags&SG_TOUCHEXIT) )
1.1.1.10 root 1214: {
1215: oldbutton = obj;
1216: if (b & SDL_BUTTON(1))
1217: {
1218: dlg[obj].state |= SG_SELECTED;
1219: retbutton = obj;
1220: }
1221: }
1222: }
1223:
1.1.1.14 root 1224: if (SDL_NumJoysticks() > 0)
1225: joy = SDL_JoystickOpen(0);
1226:
1227: #if !WITH_SDL2
1228: /* Enable unicode translation to get shifted etc chars with SDL_PollEvent */
1229: nOldUnicodeMode = SDL_EnableUNICODE(true);
1230: #endif
1.1.1.15! root 1231: Dprintf(("ENTER - obj: %d, old: %d, ret: %d\n", obj, oldbutton, retbutton));
1.1.1.5 root 1232:
1233: /* The main loop */
1.1.1.15! root 1234: while (retbutton == SDLGUI_NOTFOUND && !bQuitProgram)
1.1.1.5 root 1235: {
1236: if (SDL_WaitEvent(&sdlEvent) == 1) /* Wait for events */
1.1.1.10 root 1237:
1.1.1.5 root 1238: switch (sdlEvent.type)
1239: {
1240: case SDL_QUIT:
1241: retbutton = SDLGUI_QUIT;
1242: break;
1243:
1244: case SDL_MOUSEBUTTONDOWN:
1245: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
1246: {
1247: /* Not left mouse button -> unsupported event */
1248: if (pEventOut)
1249: retbutton = SDLGUI_UNKNOWNEVENT;
1250: break;
1251: }
1252: /* It was the left button: Find the object under the mouse cursor */
1.1.1.15! root 1253: SDLGui_ScaleMouseButtonCoordinates(&sdlEvent.button);
1.1.1.5 root 1254: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
1.1.1.15! root 1255: if (obj != SDLGUI_NOTFOUND)
1.1.1.5 root 1256: {
1257: if (dlg[obj].type==SGBUTTON)
1258: {
1259: dlg[obj].state |= SG_SELECTED;
1260: SDLGui_DrawButton(dlg, obj);
1.1.1.10 root 1261: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[obj].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[obj].y)*sdlgui_fontheight-2,
1262: dlg[obj].w*sdlgui_fontwidth+4, dlg[obj].h*sdlgui_fontheight+4);
1263: oldbutton=obj;
1264: }
1265: if (dlg[obj].type==SGSCROLLBAR)
1266: {
1267: dlg[obj].state |= SG_MOUSEDOWN;
1.1.1.5 root 1268: oldbutton=obj;
1269: }
1270: if ( dlg[obj].flags&SG_TOUCHEXIT )
1271: {
1272: dlg[obj].state |= SG_SELECTED;
1273: retbutton = obj;
1274: }
1275: }
1276: break;
1277:
1278: case SDL_MOUSEBUTTONUP:
1279: if (sdlEvent.button.button != SDL_BUTTON_LEFT)
1280: {
1281: /* Not left mouse button -> unsupported event */
1282: if (pEventOut)
1283: retbutton = SDLGUI_UNKNOWNEVENT;
1284: break;
1285: }
1286: /* It was the left button: Find the object under the mouse cursor */
1.1.1.15! root 1287: SDLGui_ScaleMouseButtonCoordinates(&sdlEvent.button);
1.1.1.5 root 1288: obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
1.1.1.15! root 1289: if (obj != SDLGUI_NOTFOUND)
1.1.1.5 root 1290: {
1.1.1.14 root 1291: retbutton = SDLGui_HandleSelection(dlg, obj, oldbutton);
1.1.1.5 root 1292: }
1.1.1.15! root 1293: if (oldbutton != SDLGUI_NOTFOUND && dlg[oldbutton].type == SGBUTTON)
1.1.1.5 root 1294: {
1295: dlg[oldbutton].state &= ~SG_SELECTED;
1296: SDLGui_DrawButton(dlg, oldbutton);
1.1.1.10 root 1297: SDL_UpdateRect(pSdlGuiScrn, (dlg[0].x+dlg[oldbutton].x)*sdlgui_fontwidth-2, (dlg[0].y+dlg[oldbutton].y)*sdlgui_fontheight-2,
1298: dlg[oldbutton].w*sdlgui_fontwidth+4, dlg[oldbutton].h*sdlgui_fontheight+4);
1.1.1.15! root 1299: oldbutton = SDLGUI_NOTFOUND;
1.1.1.5 root 1300: }
1.1.1.14 root 1301: break;
1302:
1303: case SDL_JOYAXISMOTION:
1304: value = sdlEvent.jaxis.value;
1305: if (value < -3200 || value > 3200)
1.1.1.5 root 1306: {
1.1.1.14 root 1307: if(sdlEvent.jaxis.axis == 0)
1308: {
1309: /* Left-right movement */
1310: if (value < 0)
1311: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_LEFT);
1312: else
1313: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_RIGHT);
1314: }
1315: else if(sdlEvent.jaxis.axis == 1)
1316: {
1317: /* Up-Down movement */
1318: if (value < 0)
1319: {
1320: SDLGui_RemoveFocus(dlg, focused);
1321: focused = SDLGui_FocusNext(dlg, focused, -1);
1322: }
1323: else
1324: {
1325: SDLGui_RemoveFocus(dlg, focused);
1326: focused = SDLGui_FocusNext(dlg, focused, +1);
1327: }
1328: }
1.1.1.5 root 1329: }
1330: break;
1331:
1.1.1.14 root 1332: case SDL_JOYBUTTONDOWN:
1333: retbutton = SDLGui_HandleSelection(dlg, focused, focused);
1334: break;
1335:
1.1.1.6 root 1336: case SDL_JOYBALLMOTION:
1337: case SDL_JOYHATMOTION:
1.1.1.5 root 1338: case SDL_MOUSEMOTION:
1339: break;
1340:
1341: case SDL_KEYDOWN: /* Key pressed */
1.1.1.14 root 1342: key = sdlEvent.key.keysym.sym;
1343: /* keyboard shortcuts are with modifiers */
1344: if (sdlEvent.key.keysym.mod & KMOD_LALT
1345: || sdlEvent.key.keysym.mod & KMOD_RALT)
1.1.1.5 root 1346: {
1.1.1.14 root 1347: if (key == SDLK_LEFT)
1348: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_LEFT);
1349: else if (key == SDLK_RIGHT)
1350: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_RIGHT);
1351: else if (key == SDLK_UP)
1352: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_UP);
1353: else if (key == SDLK_DOWN)
1354: retbutton = SDLGui_HandleShortcut(dlg, SG_SHORTCUT_DOWN);
1355: else
1356: {
1357: #if !WITH_SDL2
1358: /* unicode member is needed to handle shifted etc special chars */
1359: key = sdlEvent.key.keysym.unicode;
1360: #endif
1361: if (key >= 33 && key <= 126)
1362: retbutton = SDLGui_HandleShortcut(dlg, toupper(key));
1363: }
1364: if (!retbutton && pEventOut)
1365: retbutton = SDLGUI_UNKNOWNEVENT;
1366: break;
1.1.1.5 root 1367: }
1.1.1.14 root 1368: switch (key)
1.1.1.5 root 1369: {
1.1.1.14 root 1370: case SDLK_UP:
1371: case SDLK_LEFT:
1372: SDLGui_RemoveFocus(dlg, focused);
1373: focused = SDLGui_FocusNext(dlg, focused, -1);
1374: break;
1375: case SDLK_TAB:
1376: case SDLK_DOWN:
1377: case SDLK_RIGHT:
1378: SDLGui_RemoveFocus(dlg, focused);
1379: focused = SDLGui_FocusNext(dlg, focused, +1);
1380: break;
1381: case SDLK_HOME:
1382: SDLGui_RemoveFocus(dlg, focused);
1383: focused = SDLGui_FocusNext(dlg, 1, +1);
1384: break;
1385: case SDLK_END:
1386: SDLGui_RemoveFocus(dlg, focused);
1387: focused = SDLGui_FocusNext(dlg, 1, -1);
1388: break;
1389: case SDLK_SPACE:
1390: case SDLK_RETURN:
1391: case SDLK_KP_ENTER:
1392: retbutton = SDLGui_HandleSelection(dlg, focused, focused);
1393: break;
1394: case SDLK_ESCAPE:
1395: retbutton = SDLGui_SearchFlags(dlg, SG_CANCEL);
1396: break;
1397: default:
1398: if (pEventOut)
1399: retbutton = SDLGUI_UNKNOWNEVENT;
1400: break;
1.1.1.5 root 1401: }
1402: break;
1403:
1.1.1.15! root 1404: #if WITH_SDL2
! 1405: case SDL_WINDOWEVENT:
! 1406: if (sdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
! 1407: {
! 1408: SDL_UpdateRect(pSdlGuiScrn, 0, 0, 0, 0);
! 1409: }
! 1410: break;
! 1411: #endif
! 1412:
1.1.1.5 root 1413: default:
1414: if (pEventOut)
1415: retbutton = SDLGUI_UNKNOWNEVENT;
1416: break;
1417: }
1418: }
1419:
1420: /* Restore background */
1421: if (pBgSurface)
1422: {
1423: SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn, &dlgrect);
1424: SDL_FreeSurface(pBgSurface);
1425: }
1426:
1427: /* Copy event data of unsupported events if caller wants to have it */
1428: if (retbutton == SDLGUI_UNKNOWNEVENT && pEventOut)
1429: memcpy(pEventOut, &sdlEvent, sizeof(SDL_Event));
1.1.1.2 root 1430:
1.1.1.5 root 1431: if (retbutton == SDLGUI_QUIT)
1.1.1.8 root 1432: bQuitProgram = true;
1.1 root 1433:
1.1.1.14 root 1434: #if !WITH_SDL2
1435: SDL_EnableUNICODE(nOldUnicodeMode);
1436: #endif
1437: if (joy)
1438: SDL_JoystickClose(joy);
1439:
1.1.1.15! root 1440: Dprintf(("EXIT - ret: %d, current: %d\n", retbutton, current_object));
1.1.1.5 root 1441: return retbutton;
1.1 root 1442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.