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

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

unix.superglobalmegacorp.com

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