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