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