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

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

unix.superglobalmegacorp.com

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