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