|
|
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 = ▭
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 = ▭
! 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 = ▭
! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.