Annotation of hatari/src/gui-sdl/sdlgui.c, revision 1.1.1.17

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.