Annotation of hatari/src/statusbar.c, revision 1.1.1.9

1.1       root        1: /*
                      2:   Hatari - statusbar.c
                      3: 
1.1.1.8   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:   Code to draw statusbar area, floppy leds etc.
1.1.1.3   root        8: 
1.1       root        9:   Use like this:
                     10:   - Before screen surface is (re-)created Statusbar_SetHeight()
                     11:     has to be called with the new screen height. Add the returned
                     12:     value to screen height (zero means no statusbar).  After this,
                     13:     Statusbar_GetHeight() can be used to retrieve the statusbar size
                     14:   - After screen surface is (re-)created, call Statusbar_Init()
                     15:     to re-initialize / re-draw the statusbar
                     16:   - Call Statusbar_SetFloppyLed() to set floppy drive led ON/OFF,
                     17:     or call Statusbar_EnableHDLed() to enabled HD led for a while
1.1.1.9 ! root       18:   - Whenever screen is redrawn, call Statusbar_Update() to update
        !            19:     statusbar contents and find out whether and what screen area
        !            20:     needs to be updated (outside of screen locking)
        !            21:   - If screen redraws can be partial, Statusbar_OverlayRestore()
1.1       root       22:     needs to be called before locking the screen for drawing and
                     23:     Statusbar_OverlayBackup() needs to be called after screen unlocking,
                     24:     but before calling Statusbar_Update().  These are needed for
1.1.1.9 ! root       25:     hiding the overlay drive led (= restoring the area that was below
        !            26:     them before LED was shown) when drive leds are turned OFF.
1.1       root       27:   - If other information shown by Statusbar (TOS version etc) changes,
                     28:     call Statusbar_UpdateInfo()
                     29: 
                     30:   TODO:
                     31:   - re-calculate colors on each update to make sure they're
                     32:     correct in Falcon & TT 8-bit palette modes?
                     33:   - call Statusbar_AddMessage() from log.c?
                     34: */
1.1.1.3   root       35: const char Statusbar_fileid[] = "Hatari statusbar.c : " __DATE__ " " __TIME__;
1.1       root       36: 
                     37: #include <assert.h>
                     38: #include "main.h"
                     39: #include "configuration.h"
                     40: #include "screenSnapShot.h"
                     41: #include "sdlgui.h"
                     42: #include "statusbar.h"
                     43: #include "tos.h"
1.1.1.5   root       44: #include "screen.h"
1.1       root       45: #include "video.h"
                     46: #include "wavFormat.h"
                     47: #include "ymFormat.h"
1.1.1.4   root       48: #include "avi_record.h"
1.1.1.9 ! root       49: #include "vdi.h"
        !            50: #include "fdc.h"
1.1       root       51: 
                     52: #define DEBUG 0
                     53: #if DEBUG
1.1.1.9 ! root       54: # include <execinfo.h>
1.1.1.7   root       55: # define DEBUGPRINT(x) printf x
1.1       root       56: #else
1.1.1.9 ! root       57: # define DEBUGPRINT(x)
1.1       root       58: #endif
                     59: 
1.1.1.9 ! root       60: /* space needed for FDC information */
        !            61: #define FDC_MSG_MAX_LEN 20
        !            62: 
        !            63: #define STATUSBAR_LINES 2
1.1       root       64: #define MAX_DRIVE_LEDS (DRIVE_LED_HD + 1)
                     65: 
1.1.1.9 ! root       66: /* whole statusbar area, for full updates */
        !            67: static SDL_Rect FullRect;
        !            68: 
1.1       root       69: /* whether drive leds should be ON and their previous shown state */
                     70: static struct {
1.1.1.8   root       71:        drive_led_t state;
                     72:        drive_led_t oldstate;
1.1       root       73:        Uint32 expire;  /* when to disable led, valid only if >0 && state=TRUE */
                     74:        int offset;     /* led x-pos on screen */
                     75: } Led[MAX_DRIVE_LEDS];
                     76: 
1.1.1.8   root       77: 
1.1       root       78: /* drive leds size & y-pos */
                     79: static SDL_Rect LedRect;
                     80: 
                     81: /* overlay led size & pos */
                     82: static SDL_Rect OverlayLedRect;
                     83: 
                     84: /* screen contents left under overlay led */
                     85: static SDL_Surface *OverlayUnderside;
                     86: 
                     87: static enum {
                     88:        OVERLAY_NONE,
                     89:        OVERLAY_DRAWN,
                     90:        OVERLAY_RESTORED
                     91: } bOverlayState;
                     92: 
                     93: static SDL_Rect RecLedRect;
                     94: static bool bOldRecording;
                     95: 
                     96: /* led colors */
1.1.1.8   root       97: static Uint32 LedColor[ MAX_LED_STATE ];
                     98: static Uint32 RecColorOn, RecColorOff;
1.1       root       99: static Uint32 GrayBg, LedColorBg;
                    100: 
1.1.1.9 ! root      101: /* needs to be enough for all messages, but <= MessageRect width / font width */
        !           102: #define MAX_MESSAGE_LEN 52
1.1       root      103: typedef struct msg_item {
                    104:        struct msg_item *next;
                    105:        char msg[MAX_MESSAGE_LEN+1];
                    106:        Uint32 timeout; /* msecs, zero=no timeout */
                    107:        Uint32 expire;  /* when to expire message */
                    108:        bool shown;
                    109: } msg_item_t;
                    110: 
                    111: static msg_item_t DefaultMessage;
                    112: static msg_item_t *MessageList = &DefaultMessage;
                    113: static SDL_Rect MessageRect;
                    114: 
1.1.1.4   root      115: /* rect for both frame skip value and fast forward indicator */
1.1       root      116: static SDL_Rect FrameSkipsRect;
                    117: static int nOldFrameSkips;
1.1.1.4   root      118: static int bOldFastForward;
1.1       root      119: 
1.1.1.9 ! root      120: static SDL_Rect FDCTextRect;
1.1       root      121: 
                    122: /* screen height above statusbar and height of statusbar below screen */
                    123: static int ScreenHeight;
                    124: static int StatusbarHeight;
                    125: 
                    126: 
                    127: /*-----------------------------------------------------------------------*/
                    128: /**
1.1.1.4   root      129:  * Return statusbar height for given width and height
1.1       root      130:  */
1.1.1.4   root      131: int Statusbar_GetHeightForSize(int width, int height)
1.1       root      132: {
1.1.1.9 ! root      133:        int h = 0;
        !           134:        /* Must arrive at same conclusion about font size as SDLGui_SetScreen() */
1.1       root      135:        if (ConfigureParams.Screen.bShowStatusbar) {
1.1.1.9 ! root      136:                /* smaller SDL GUI font height = 8, larger = 16 */
        !           137:                h = 8;
        !           138:                if (width >= 640 && height >= (400-2*h)) {
        !           139:                        h *= 2;
1.1       root      140:                }
1.1.1.9 ! root      141:                h += 1+1;
        !           142:                h *= STATUSBAR_LINES;
1.1       root      143:        }
1.1.1.9 ! root      144:        DEBUGPRINT(("Statusbar_GetHeightForSize(%d, %d) -> %d\n", width, height, h));
        !           145:        return h;
1.1.1.4   root      146: }
                    147: 
                    148: /*-----------------------------------------------------------------------*/
                    149: /**
                    150:  * Set screen height used for statusbar height calculation.
                    151:  *
                    152:  * Return height of statusbar that should be added to the screen
                    153:  * height when screen is (re-)created, or zero if statusbar will
                    154:  * not be shown
                    155:  */
                    156: int Statusbar_SetHeight(int width, int height)
                    157: {
1.1.1.7   root      158: #if DEBUG
                    159:        /* find out from where the set height is called */
                    160:        void *addr[8];
                    161:        int count = backtrace(addr, sizeof(addr)/sizeof(*addr));
                    162:        backtrace_symbols_fd(addr, count, fileno(stderr));
                    163: #endif
1.1.1.4   root      164:        ScreenHeight = height;
                    165:        StatusbarHeight = Statusbar_GetHeightForSize(width, height);
1.1.1.6   root      166:        DEBUGPRINT(("Statusbar_SetHeight(%d, %d) -> %d\n", width, height, StatusbarHeight));
1.1       root      167:        return StatusbarHeight;
                    168: }
                    169: 
                    170: /*-----------------------------------------------------------------------*/
                    171: /**
                    172:  * Return height of statusbar set with Statusbar_SetHeight()
                    173:  */
                    174: int Statusbar_GetHeight(void)
                    175: {
                    176:        return StatusbarHeight;
                    177: }
                    178: 
                    179: 
                    180: /*-----------------------------------------------------------------------*/
                    181: /**
                    182:  * Enable HD drive led, it will be automatically disabled after a while.
                    183:  */
1.1.1.8   root      184: void Statusbar_EnableHDLed(drive_led_t state)
1.1       root      185: {
                    186:        /* leds are shown for 1/2 sec after enabling */
                    187:        Led[DRIVE_LED_HD].expire = SDL_GetTicks() + 1000/2;
1.1.1.8   root      188:        Led[DRIVE_LED_HD].state = state;
1.1       root      189: }
                    190: 
                    191: /*-----------------------------------------------------------------------*/
                    192: /**
                    193:  * Set given floppy drive led state, anything enabling led with this
                    194:  * needs also to take care of disabling it.
                    195:  */
1.1.1.8   root      196: void Statusbar_SetFloppyLed(drive_index_t drive, drive_led_t state)
1.1       root      197: {
                    198:        assert(drive == DRIVE_LED_A || drive == DRIVE_LED_B);
                    199:        Led[drive].state = state;
                    200: }
                    201: 
                    202: 
                    203: /*-----------------------------------------------------------------------*/
                    204: /**
                    205:  * Set overlay led size/pos on given screen to internal Rect
                    206:  * and free previous resources.
                    207:  */
                    208: static void Statusbar_OverlayInit(const SDL_Surface *surf)
                    209: {
                    210:        int h;
                    211:        /* led size/pos needs to be re-calculated in case screen changed */
                    212:        h = surf->h / 50;
                    213:        OverlayLedRect.w = 2*h;
                    214:        OverlayLedRect.h = h;
                    215:        OverlayLedRect.x = surf->w - 5*h/2;
                    216:        OverlayLedRect.y = h/2;
                    217:        /* free previous restore surface if it's incompatible */
                    218:        if (OverlayUnderside &&
                    219:            OverlayUnderside->w == OverlayLedRect.w &&
                    220:            OverlayUnderside->h == OverlayLedRect.h &&
                    221:            OverlayUnderside->format->BitsPerPixel == surf->format->BitsPerPixel) {
                    222:                SDL_FreeSurface(OverlayUnderside);
                    223:                OverlayUnderside = NULL;
                    224:        }
                    225:        bOverlayState = OVERLAY_NONE;
                    226: }
                    227: 
                    228: /*-----------------------------------------------------------------------*/
                    229: /**
                    230:  * (re-)initialize statusbar internal variables for given screen surface
                    231:  * (sizes&colors may need to be re-calculated for the new SDL surface)
                    232:  * and draw the statusbar background.
                    233:  */
                    234: void Statusbar_Init(SDL_Surface *surf)
                    235: {
                    236:        msg_item_t *item;
1.1.1.9 ! root      237:        SDL_Rect ledbox;
        !           238:        int i, fontw, fonth, lineh, xoffset, yoffset;
1.1       root      239:        const char *text[MAX_DRIVE_LEDS] = { "A:", "B:", "HD:" };
1.1.1.9 ! root      240:        char FdcText[FDC_MSG_MAX_LEN];
        !           241:        int FdcTextLen;
1.1       root      242: 
1.1.1.6   root      243:        DEBUGPRINT(("Statusbar_Init()\n"));
1.1       root      244:        assert(surf);
                    245: 
                    246:        /* dark green and light green for leds themselves */
1.1.1.8   root      247:        LedColor[ LED_STATE_OFF ]       = SDL_MapRGB(surf->format, 0x00, 0x40, 0x00);
                    248:        LedColor[ LED_STATE_ON ]        = SDL_MapRGB(surf->format, 0x00, 0xc0, 0x00);
                    249:        LedColor[ LED_STATE_ON_BUSY ]   = SDL_MapRGB(surf->format, 0x00, 0xe0, 0x00);
1.1       root      250:        LedColorBg  = SDL_MapRGB(surf->format, 0x00, 0x00, 0x00);
                    251:        RecColorOff = SDL_MapRGB(surf->format, 0x40, 0x00, 0x00);
                    252:        RecColorOn  = SDL_MapRGB(surf->format, 0xe0, 0x00, 0x00);
                    253:        GrayBg      = SDL_MapRGB(surf->format, 0xc0, 0xc0, 0xc0);
                    254: 
                    255:        /* disable leds */
                    256:        for (i = 0; i < MAX_DRIVE_LEDS; i++) {
1.1.1.8   root      257:                Led[i].state = Led[i].oldstate = LED_STATE_OFF;
1.1       root      258:                Led[i].expire = 0;
                    259:        }
                    260:        Statusbar_OverlayInit(surf);
                    261:        
                    262:        /* disable statusbar if it doesn't fit to video mode */
                    263:        if (surf->h < ScreenHeight + StatusbarHeight) {
                    264:                StatusbarHeight = 0;
                    265:        }
                    266:        if (!StatusbarHeight) {
1.1.1.6   root      267:                DEBUGPRINT(("Doesn't fit <- Statusbar_Init()\n"));
1.1       root      268:                return;
                    269:        }
                    270: 
                    271:        /* prepare fonts */
                    272:        SDLGui_Init();
                    273:        SDLGui_SetScreen(surf);
                    274:        SDLGui_GetFontSize(&fontw, &fonth);
                    275: 
                    276:        /* video mode didn't match, need to recalculate sizes */
1.1.1.9 ! root      277:        lineh = 1+fonth+1;
1.1       root      278:        if (surf->h > ScreenHeight + StatusbarHeight) {
1.1.1.9 ! root      279:                StatusbarHeight = STATUSBAR_LINES*lineh;
1.1       root      280:                /* actually statusbar vertical offset */
                    281:                ScreenHeight = surf->h - StatusbarHeight;
                    282:        } else {
1.1.1.9 ! root      283:                assert(STATUSBAR_LINES*lineh <= StatusbarHeight);
1.1       root      284:        }
                    285: 
                    286:        /* draw statusbar background gray so that text shows */
1.1.1.9 ! root      287:        FullRect.x = 0;
        !           288:        FullRect.y = surf->h - StatusbarHeight;
        !           289:        FullRect.w = surf->w;
        !           290:        FullRect.h = StatusbarHeight;
        !           291:        SDL_FillRect(surf, &FullRect, GrayBg);
        !           292: 
        !           293:        /* intialize messages (first row) */
        !           294:        MessageRect.x = fontw;
        !           295:        MessageRect.y = ScreenHeight + lineh/2 - fonth/2;
        !           296:        MessageRect.w = surf->w - fontw;
        !           297:        MessageRect.h = fonth;
        !           298:        for (item = MessageList; item; item = item->next) {
        !           299:                item->shown = false;
        !           300:        }
1.1       root      301: 
1.1.1.9 ! root      302:        /* indicator leds size (second row) */
1.1.1.4   root      303:        LedRect.w = fonth/2;
1.1       root      304:        LedRect.h = fonth - 4;
1.1.1.9 ! root      305:        LedRect.y = ScreenHeight + lineh + lineh/2 - LedRect.h/2;
1.1.1.4   root      306: 
1.1       root      307:        /* black box for the leds */
                    308:        ledbox = LedRect;
                    309:        ledbox.y -= 1;
                    310:        ledbox.w += 2;
                    311:        ledbox.h += 2;
                    312: 
1.1.1.9 ! root      313:        xoffset = fontw;
        !           314:        yoffset = ScreenHeight + lineh + lineh/2 - fonth/2;
        !           315: 
1.1       root      316:        /* draw led texts and boxes + calculate box offsets */
                    317:        for (i = 0; i < MAX_DRIVE_LEDS; i++) {
1.1.1.9 ! root      318:                SDLGui_Text(xoffset, yoffset, text[i]);
        !           319:                xoffset += strlen(text[i]) * fontw;
        !           320:                xoffset += fontw/2;
1.1       root      321: 
1.1.1.9 ! root      322:                ledbox.x = xoffset - 1;
1.1       root      323:                SDL_FillRect(surf, &ledbox, LedColorBg);
                    324: 
1.1.1.9 ! root      325:                LedRect.x = xoffset;
1.1.1.8   root      326:                SDL_FillRect(surf, &LedRect, LedColor[ LED_STATE_OFF ]);
1.1       root      327: 
1.1.1.9 ! root      328:                Led[i].offset = xoffset;
        !           329:                xoffset += LedRect.w + fontw;
1.1       root      330:        }
                    331: 
1.1.1.9 ! root      332:        /* print FDC's info */
        !           333:        FDCTextRect.x = xoffset;
        !           334:        FDCTextRect.y = yoffset;
        !           335:        FdcTextLen = FDC_Get_Statusbar_Text(FdcText, sizeof(FdcText));
        !           336:        SDLGui_Text(FDCTextRect.x, FDCTextRect.y, FdcText);
        !           337:        FDCTextRect.w = FdcTextLen * fontw + fontw/2;
        !           338:        FDCTextRect.h = fonth;
        !           339:        // xoffset += FDCTextRect.w;
        !           340: 
        !           341:        /* draw frameskip on the right */
        !           342:        FrameSkipsRect.x = surf->w - 15*fontw;
        !           343:        FrameSkipsRect.y = yoffset;
1.1       root      344:        SDLGui_Text(FrameSkipsRect.x, FrameSkipsRect.y, "FS:");
                    345:        FrameSkipsRect.x += 3 * fontw + fontw/2;
1.1.1.4   root      346:        FrameSkipsRect.w = 4 * fontw;
1.1       root      347:        FrameSkipsRect.h = fonth;
1.1.1.4   root      348: 
                    349:        if(ConfigureParams.System.bFastForward) {
                    350:                SDLGui_Text(FrameSkipsRect.x, FrameSkipsRect.y, "0 >>");
                    351:        } else {
                    352:                SDLGui_Text(FrameSkipsRect.x, FrameSkipsRect.y, "0");
                    353:        }
                    354: 
1.1       root      355:        nOldFrameSkips = 0;
1.1.1.4   root      356: 
1.1.1.9 ! root      357:        /* draw recording led box on the right */
1.1       root      358:        RecLedRect = LedRect;
                    359:        RecLedRect.x = surf->w - fontw - RecLedRect.w;
                    360:        ledbox.x = RecLedRect.x - 1;
1.1.1.9 ! root      361:        SDLGui_Text(ledbox.x - 4*fontw - fontw/2, yoffset, "REC:");
1.1       root      362:        SDL_FillRect(surf, &ledbox, LedColorBg);
                    363:        SDL_FillRect(surf, &RecLedRect, RecColorOff);
1.1.1.3   root      364:        bOldRecording = false;
1.1       root      365: 
                    366:        /* and blit statusbar on screen */
1.1.1.9 ! root      367:        SDL_UpdateRects(surf, 1, &FullRect);
1.1.1.6   root      368:        DEBUGPRINT(("Drawn <- Statusbar_Init()\n"));
1.1       root      369: }
                    370: 
                    371: 
                    372: /*-----------------------------------------------------------------------*/
                    373: /**
                    374:  * Qeueue new statusbar message 'msg' to be shown for 'msecs' milliseconds
                    375:  */
                    376: void Statusbar_AddMessage(const char *msg, Uint32 msecs)
                    377: {
                    378:        msg_item_t *item;
                    379: 
                    380:        if (!ConfigureParams.Screen.bShowStatusbar) {
                    381:                /* no sense in queuing messages that aren't shown */
                    382:                return;
                    383:        }
                    384:        item = calloc(1, sizeof(msg_item_t));
                    385:        assert(item);
                    386: 
                    387:        item->next = MessageList;
                    388:        MessageList = item;
                    389: 
                    390:        strncpy(item->msg, msg, MAX_MESSAGE_LEN);
                    391:        item->msg[MAX_MESSAGE_LEN] = '\0';
                    392:        DEBUGPRINT(("Add message: '%s'\n", item->msg));
                    393: 
                    394:        if (msecs) {
                    395:                item->timeout = msecs;
                    396:        } else {
                    397:                /* show items by default for 2.5 secs */
                    398:                item->timeout = 2500;
                    399:        }
1.1.1.3   root      400:        item->shown = false;
1.1       root      401: }
                    402: 
                    403: /*-----------------------------------------------------------------------*/
                    404: /**
                    405:  * Write given 'more' string to 'buffer' and return new end of 'buffer'
                    406:  */
                    407: static char *Statusbar_AddString(char *buffer, const char *more)
                    408: {
                    409:        while(*more) {
                    410:                *buffer++ = *more++;
                    411:        }
                    412:        return buffer;
                    413: }
                    414: 
                    415: /*-----------------------------------------------------------------------*/
                    416: /**
                    417:  * Retrieve/update default statusbar information
                    418:  */
                    419: void Statusbar_UpdateInfo(void)
                    420: {
1.1.1.9 ! root      421:        int i;
1.1       root      422:        char *end = DefaultMessage.msg;
                    423: 
1.1.1.4   root      424:        /* CPU MHz */
                    425:        if (ConfigureParams.System.nCpuFreq > 9) {
                    426:                *end++ = '0' + ConfigureParams.System.nCpuFreq / 10;
                    427:        }
                    428:        *end++ = '0' + ConfigureParams.System.nCpuFreq % 10;
                    429:        end = Statusbar_AddString(end, "MHz/");
                    430: 
                    431:        /* CPU type */
                    432:        if(ConfigureParams.System.nCpuLevel > 0) {
                    433:                *end++ = '0';
                    434:                *end++ = '0' + ConfigureParams.System.nCpuLevel % 10;
                    435:                *end++ = '0';
                    436:                *end++ = '/';
                    437:        }
                    438: 
1.1.1.9 ! root      439:        /* additional WinUAE CPU/FPU info */
        !           440: #if ENABLE_WINUAE_CPU
        !           441:        switch (ConfigureParams.System.n_FPUType) {
        !           442:        case FPU_68881:
        !           443:                end = Statusbar_AddString(end, "68881");
        !           444:                break;
        !           445:        case FPU_68882:
        !           446:                end = Statusbar_AddString(end, "68882");
        !           447:                break;
        !           448:        case FPU_CPU:
        !           449:                end = Statusbar_AddString(end, "040");
        !           450:                break;
        !           451:        default:
        !           452:                *end++ = '-';
        !           453:        }
        !           454:        *end++ = '/';
        !           455:        if (ConfigureParams.System.bMMU) {
        !           456:                end = Statusbar_AddString(end, "MMU/");
        !           457:        }
        !           458: #endif
        !           459: 
1.1       root      460:        /* amount of memory */
                    461:        if (ConfigureParams.Memory.nMemorySize > 9) {
                    462:                *end++ = '1';
                    463:                *end++ = '0' + ConfigureParams.Memory.nMemorySize % 10;
                    464:        } else {
                    465:                if (ConfigureParams.Memory.nMemorySize) {
                    466:                        *end++ = '0' + ConfigureParams.Memory.nMemorySize;
                    467:                } else {
1.1.1.7   root      468:                        end = Statusbar_AddString(end, "0.5");
1.1       root      469:                }
                    470:        }
                    471:        end = Statusbar_AddString(end, "MB ");
1.1.1.4   root      472: 
1.1       root      473:        /* machine type */
                    474:        switch (ConfigureParams.System.nMachineType) {
                    475:        case MACHINE_ST:
                    476:                end = Statusbar_AddString(end, "ST");
                    477:                break;
                    478:        case MACHINE_STE:
                    479:                end = Statusbar_AddString(end, "STE");
                    480:                break;
1.1.1.5   root      481:        case MACHINE_MEGA_STE:
1.1.1.7   root      482:                end = Statusbar_AddString(end, "MegaSTE");
1.1.1.5   root      483:                break;
1.1       root      484:        case MACHINE_TT:
                    485:                end = Statusbar_AddString(end, "TT");
                    486:                break;
                    487:        case MACHINE_FALCON:
                    488:                end = Statusbar_AddString(end, "Falcon");
                    489:                break;
                    490:        default:
                    491:                end = Statusbar_AddString(end, "???");
                    492:        }
                    493: 
                    494:        /* TOS type/version */
1.1.1.9 ! root      495:        end = Statusbar_AddString(end, ", ");
1.1       root      496:        if (bIsEmuTOS) {
1.1.1.9 ! root      497:                end = Statusbar_AddString(end, "EmuTOS");
1.1       root      498:        } else {
1.1.1.9 ! root      499:                end = Statusbar_AddString(end, "TOS v");
1.1       root      500:                *end++ = '0' + ((TosVersion & 0xf00) >> 8);
                    501:                *end++ = '.';
                    502:                *end++ = '0' + ((TosVersion & 0xf0) >> 4);
                    503:                *end++ = '0' + (TosVersion & 0xf);
                    504:        }
1.1.1.9 ! root      505: 
        !           506:        /* monitor type */
        !           507:        end = Statusbar_AddString(end, ", ");
        !           508:        if (bUseVDIRes) {
        !           509:                end = Statusbar_AddString(end, "VDI");
        !           510:        } else {
        !           511:                switch (ConfigureParams.Screen.nMonitorType) {
        !           512:                case MONITOR_TYPE_MONO:
        !           513:                        end = Statusbar_AddString(end, "MONO");
        !           514:                        break;
        !           515:                case MONITOR_TYPE_RGB:
        !           516:                        end = Statusbar_AddString(end, "RGB");
        !           517:                        break;
        !           518:                case MONITOR_TYPE_VGA:
        !           519:                        end = Statusbar_AddString(end, "VGA");
        !           520:                        break;
        !           521:                case MONITOR_TYPE_TV:
        !           522:                        end = Statusbar_AddString(end, "TV");
        !           523:                        break;
        !           524:                default:
        !           525:                        *end++ = '?';
        !           526:                }
        !           527:        }
        !           528: 
        !           529:        /* joystick type */
        !           530:        end = Statusbar_AddString(end, ", ");
        !           531:        for (i = 0; i < JOYSTICK_COUNT; i++) {
        !           532:                switch (ConfigureParams.Joysticks.Joy[i].nJoystickMode) {
        !           533:                case JOYSTICK_DISABLED:
        !           534:                        *end++ = '-';
        !           535:                        break;
        !           536:                case JOYSTICK_REALSTICK:
        !           537:                        *end++ = 'J';
        !           538:                        break;
        !           539:                case JOYSTICK_KEYBOARD:
        !           540:                        *end++ = 'K';
        !           541:                        break;
        !           542:                }
        !           543:        }
1.1       root      544:        *end = '\0';
1.1.1.4   root      545: 
1.1       root      546:        assert(end - DefaultMessage.msg < MAX_MESSAGE_LEN);
                    547:        DEBUGPRINT(("Set default message: '%s'\n", DefaultMessage.msg));
1.1.1.5   root      548:        /* make sure default message gets (re-)drawn when next checked */
1.1.1.3   root      549:        DefaultMessage.shown = false;
1.1       root      550: }
                    551: 
                    552: /*-----------------------------------------------------------------------*/
                    553: /**
                    554:  * Draw 'msg' centered to the message area
                    555:  */
1.1.1.9 ! root      556: static SDL_Rect* Statusbar_DrawMessage(SDL_Surface *surf, const char *msg)
1.1       root      557: {
                    558:        int fontw, fonth, offset;
                    559:        SDL_FillRect(surf, &MessageRect, GrayBg);
                    560:        if (*msg) {
                    561:                SDLGui_GetFontSize(&fontw, &fonth);
                    562:                offset = (MessageRect.w - strlen(msg) * fontw) / 2;
                    563:                SDLGui_Text(MessageRect.x + offset, MessageRect.y, msg);
                    564:        }
                    565:        DEBUGPRINT(("Draw message: '%s'\n", msg));
1.1.1.9 ! root      566:        return &MessageRect;
1.1       root      567: }
                    568: 
                    569: /*-----------------------------------------------------------------------*/
                    570: /**
                    571:  * If message's not shown, show it.  If message's timed out,
                    572:  * remove it and show next one.
1.1.1.9 ! root      573:  * 
        !           574:  * Return updated area, or NULL if nothing drawn
1.1       root      575:  */
1.1.1.9 ! root      576: static SDL_Rect* Statusbar_ShowMessage(SDL_Surface *surf, Uint32 ticks)
1.1       root      577: {
                    578:        msg_item_t *next;
                    579: 
                    580:        if (MessageList->shown) {
                    581:                if (!MessageList->expire) {
1.1.1.5   root      582:                        /* last/default message newer expires */
1.1.1.9 ! root      583:                        return NULL;
1.1       root      584:                }
                    585:                if (MessageList->expire > ticks) {
                    586:                        /* not timed out yet */
1.1.1.9 ! root      587:                        return NULL;
1.1       root      588:                }
                    589:                assert(MessageList->next); /* last message shouldn't end here */
                    590:                next = MessageList->next;
                    591:                free(MessageList);
                    592:                MessageList = next;
                    593:                /* make sure next message gets shown */
1.1.1.3   root      594:                MessageList->shown = false;
1.1       root      595:        }
1.1.1.9 ! root      596:        if (MessageList->shown) {
        !           597:                return NULL;
        !           598:        }
        !           599:        /* not shown yet, show */
        !           600:        MessageList->shown = true;
        !           601:        if (MessageList->timeout && !MessageList->expire) {
        !           602:                MessageList->expire = ticks + MessageList->timeout;
1.1       root      603:        }
1.1.1.9 ! root      604:        return Statusbar_DrawMessage(surf, MessageList->msg);
1.1       root      605: }
                    606: 
                    607: 
                    608: /*-----------------------------------------------------------------------*/
                    609: /**
                    610:  * Save the area that will be left under overlay led
                    611:  */
                    612: void Statusbar_OverlayBackup(SDL_Surface *surf)
                    613: {
1.1.1.3   root      614:        if ((StatusbarHeight && ConfigureParams.Screen.bShowStatusbar)
                    615:            || !ConfigureParams.Screen.bShowDriveLed) {
1.1       root      616:                /* overlay not used with statusbar */
                    617:                return;
                    618:        }
                    619:        assert(surf);
                    620:        if (!OverlayUnderside) {
                    621:                SDL_Surface *bak;
                    622:                SDL_PixelFormat *fmt = surf->format;
                    623:                bak = SDL_CreateRGBSurface(surf->flags,
                    624:                                           OverlayLedRect.w, OverlayLedRect.h,
                    625:                                           fmt->BitsPerPixel,
                    626:                                           fmt->Rmask, fmt->Gmask, fmt->Bmask,
                    627:                                           fmt->Amask);
                    628:                assert(bak);
                    629:                OverlayUnderside = bak;
                    630:        }
                    631:        SDL_BlitSurface(surf, &OverlayLedRect, OverlayUnderside, NULL);
                    632: }
                    633: 
                    634: /*-----------------------------------------------------------------------*/
                    635: /**
                    636:  * Restore the area left under overlay led
1.1.1.9 ! root      637:  * 
        !           638:  * State machine for overlay led handling will return from
        !           639:  * Statusbar_Update() call the area that is restored (if any)
1.1       root      640:  */
                    641: void Statusbar_OverlayRestore(SDL_Surface *surf)
                    642: {
1.1.1.3   root      643:        if ((StatusbarHeight && ConfigureParams.Screen.bShowStatusbar)
                    644:            || !ConfigureParams.Screen.bShowDriveLed) {
1.1       root      645:                /* overlay not used with statusbar */
                    646:                return;
                    647:        }
                    648:        if (bOverlayState == OVERLAY_DRAWN && OverlayUnderside) {
                    649:                assert(surf);
                    650:                SDL_BlitSurface(OverlayUnderside, NULL, surf, &OverlayLedRect);
                    651:                /* this will make the draw function to update this the screen */
                    652:                bOverlayState = OVERLAY_RESTORED;
                    653:        }
                    654: }
                    655: 
                    656: /*-----------------------------------------------------------------------*/
                    657: /**
                    658:  * Draw overlay led
                    659:  */
                    660: static void Statusbar_OverlayDrawLed(SDL_Surface *surf, Uint32 color)
                    661: {
                    662:        SDL_Rect rect;
                    663:        if (bOverlayState == OVERLAY_DRAWN) {
                    664:                /* some led already drawn */
                    665:                return;
                    666:        }
                    667:        bOverlayState = OVERLAY_DRAWN;
                    668: 
                    669:        /* enabled led with border */
                    670:        rect = OverlayLedRect;
                    671:        rect.x += 1;
                    672:        rect.y += 1;
                    673:        rect.w -= 2;
                    674:        rect.h -= 2;
                    675:        SDL_FillRect(surf, &OverlayLedRect, LedColorBg);
                    676:        SDL_FillRect(surf, &rect, color);
                    677: }
                    678: 
                    679: /*-----------------------------------------------------------------------*/
                    680: /**
                    681:  * Draw overlay led onto screen surface if any drives are enabled.
1.1.1.9 ! root      682:  * 
        !           683:  * Return updated area, or NULL if nothing drawn
1.1       root      684:  */
1.1.1.9 ! root      685: static SDL_Rect* Statusbar_OverlayDraw(SDL_Surface *surf)
1.1       root      686: {
                    687:        Uint32 currentticks = SDL_GetTicks();
                    688:        int i;
                    689: 
1.1.1.4   root      690:        if (bRecordingYM || bRecordingWav || bRecordingAvi) {
1.1       root      691:                Statusbar_OverlayDrawLed(surf, RecColorOn);
                    692:        }
                    693:        for (i = 0; i < MAX_DRIVE_LEDS; i++) {
                    694:                if (Led[i].state) {
                    695:                        if (Led[i].expire && Led[i].expire < currentticks) {
1.1.1.8   root      696:                                Led[i].state = LED_STATE_OFF;
1.1       root      697:                                continue;
                    698:                        }
1.1.1.8   root      699:                        Statusbar_OverlayDrawLed(surf, LedColor[ Led[i].state ]);
1.1       root      700:                        break;
                    701:                }
                    702:        }
                    703:        /* possible state transitions:
                    704:         *   NONE -> DRAWN -> RESTORED -> DRAWN -> RESTORED -> NONE
                    705:         * Other than NONE state needs to be updated on screen
                    706:         */
                    707:        switch (bOverlayState) {
                    708:        case OVERLAY_RESTORED:
                    709:                bOverlayState = OVERLAY_NONE;
                    710:        case OVERLAY_DRAWN:
                    711:                DEBUGPRINT(("Overlay LED = %s\n", bOverlayState==OVERLAY_DRAWN?"ON":"OFF"));
1.1.1.9 ! root      712:                return &OverlayLedRect;
1.1       root      713:        case OVERLAY_NONE:
                    714:                break;
                    715:        }
1.1.1.9 ! root      716:        return NULL;
1.1       root      717: }
                    718: 
                    719: 
                    720: /*-----------------------------------------------------------------------*/
                    721: /**
                    722:  * Update statusbar information (leds etc) if/when needed.
                    723:  * 
                    724:  * May not be called when screen is locked (SDL limitation).
1.1.1.9 ! root      725:  * 
        !           726:  * Return updated area, or NULL if nothing is drawn.
1.1       root      727:  */
1.1.1.9 ! root      728: SDL_Rect* Statusbar_Update(SDL_Surface *surf, bool do_update)
1.1       root      729: {
1.1.1.9 ! root      730:        static char FdcOld[FDC_MSG_MAX_LEN] = "";
        !           731:        char FdcNew[FDC_MSG_MAX_LEN];
1.1       root      732:        Uint32 color, currentticks;
1.1.1.9 ! root      733:        static SDL_Rect rect;
        !           734:        SDL_Rect *last_rect;
        !           735:        int i, updates;
1.1       root      736: 
1.1.1.9 ! root      737:        assert(surf);
1.1       root      738:        if (!(StatusbarHeight && ConfigureParams.Screen.bShowStatusbar)) {
1.1.1.9 ! root      739:                last_rect = NULL;
1.1       root      740:                /* not enabled (anymore), show overlay led instead? */
                    741:                if (ConfigureParams.Screen.bShowDriveLed) {
1.1.1.9 ! root      742:                        last_rect = Statusbar_OverlayDraw(surf);
        !           743:                        if (do_update && last_rect) {
        !           744:                                SDL_UpdateRects(surf, 1, last_rect);
        !           745:                                last_rect = NULL;
        !           746:                        }
1.1       root      747:                }
1.1.1.9 ! root      748:                return last_rect;
1.1       root      749:        }
1.1.1.9 ! root      750: 
1.1       root      751:        /* Statusbar_Init() not called before this? */
1.1.1.6   root      752: #if DEBUG
                    753:        if (surf->h != ScreenHeight + StatusbarHeight) {
                    754:                printf("%d != %d + %d\n", surf->h, ScreenHeight, StatusbarHeight);
                    755:        }
                    756: #endif
1.1       root      757:        assert(surf->h == ScreenHeight + StatusbarHeight);
                    758: 
                    759:        currentticks = SDL_GetTicks();
1.1.1.9 ! root      760:        last_rect = Statusbar_ShowMessage(surf, currentticks);
        !           761:        updates = last_rect ? 1 : 0;
        !           762: 
        !           763:        rect = LedRect;
1.1       root      764:        for (i = 0; i < MAX_DRIVE_LEDS; i++) {
                    765:                if (Led[i].expire && Led[i].expire < currentticks) {
1.1.1.8   root      766:                        Led[i].state = LED_STATE_OFF;
1.1       root      767:                }
                    768:                if (Led[i].state == Led[i].oldstate) {
                    769:                        continue;
                    770:                }
                    771:                Led[i].oldstate = Led[i].state;
1.1.1.8   root      772:                color = LedColor[ Led[i].state ];
1.1       root      773:                rect.x = Led[i].offset;
                    774:                SDL_FillRect(surf, &rect, color);
1.1.1.8   root      775:                DEBUGPRINT(("LED[%d] = %d\n", i, Led[i].state));
1.1.1.9 ! root      776:                last_rect = &rect;
        !           777:                updates++;
1.1       root      778:        }
1.1.1.4   root      779: 
1.1.1.9 ! root      780:        FDC_Get_Statusbar_Text(FdcNew, sizeof(FdcNew));
        !           781:        if (strcmp(FdcNew, FdcOld)) {
        !           782:                strcpy(FdcOld, FdcNew);
        !           783:                SDL_FillRect(surf, &FDCTextRect, GrayBg);
        !           784:                SDLGui_Text(FDCTextRect.x, FDCTextRect.y, FdcNew);
        !           785:                last_rect = &FDCTextRect;
        !           786:                updates++;
        !           787:        }
1.1       root      788: 
1.1.1.4   root      789:        if (nOldFrameSkips != nFrameSkips ||
                    790:            bOldFastForward != ConfigureParams.System.bFastForward) {
                    791:                char fscount[5];
                    792:                int end = 2;
                    793: 
1.1.1.9 ! root      794:                nOldFrameSkips = nFrameSkips;
        !           795:                bOldFastForward = ConfigureParams.System.bFastForward;
        !           796: 
1.1.1.3   root      797:                if (nFrameSkips < 10)
                    798:                        fscount[0] = '0' + nFrameSkips;
                    799:                else
                    800:                        fscount[0] = 'X';
1.1.1.4   root      801:                fscount[1] = ' ';
                    802:                if(ConfigureParams.System.bFastForward) {
                    803:                        fscount[2] = '>';
                    804:                        fscount[3] = '>';
                    805:                        end = 4;
                    806:                }
                    807:                fscount[end] = '\0';
                    808: 
1.1       root      809:                SDL_FillRect(surf, &FrameSkipsRect, GrayBg);
                    810:                SDLGui_Text(FrameSkipsRect.x, FrameSkipsRect.y, fscount);
                    811:                DEBUGPRINT(("FS = %s\n", fscount));
1.1.1.9 ! root      812:                last_rect = &FrameSkipsRect;
        !           813:                updates++;
1.1       root      814:        }
                    815: 
1.1.1.4   root      816:        if ((bRecordingYM || bRecordingWav || bRecordingAvi)
1.1       root      817:            != bOldRecording) {
                    818:                bOldRecording = !bOldRecording;
                    819:                if (bOldRecording) {
                    820:                        color = RecColorOn;
                    821:                } else {
                    822:                        color = RecColorOff;
                    823:                }
                    824:                SDL_FillRect(surf, &RecLedRect, color);
                    825:                DEBUGPRINT(("REC = ON\n"));
1.1.1.9 ! root      826:                last_rect = &RecLedRect;
        !           827:                updates++;
        !           828:        }
        !           829: 
        !           830:        if (updates > 1) {
        !           831:                /* multiple items updated -> update whole statusbar */
        !           832:                last_rect = &FullRect;
        !           833:        }
        !           834:        if (do_update && last_rect) {
        !           835:                SDL_UpdateRects(surf, 1, last_rect);
        !           836:                last_rect = NULL;
1.1       root      837:        }
1.1.1.9 ! root      838:        return last_rect;
1.1       root      839: }

unix.superglobalmegacorp.com

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