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

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

unix.superglobalmegacorp.com

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