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