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

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

unix.superglobalmegacorp.com

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