4 // Graphical User Interface support
20 using namespace std; // For STL stuff
22 // Private function prototypes
24 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap);
25 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 opacity, const char * text, ...);
26 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...);
32 // Local global variables
39 0x03E0,0x0000,0x0000,0x0000,0x0000,0x0000, // +
40 0x0300,0x03E0,0x0000,0x0000,0x0000,0x0000, // @+
41 0x0300,0x03E0,0x03E0,0x0000,0x0000,0x0000, // @++
42 0x0300,0x0300,0x03E0,0x03E0,0x0000,0x0000, // @@++
43 0x0300,0x0300,0x03E0,0x03E0,0x03E0,0x0000, // @@+++
44 0x0300,0x0300,0x0300,0x03E0,0x03E0,0x03E0, // @@@+++
45 0x0300,0x0300,0x0300,0x0000,0x0000,0x0000, // @@@
46 0x0300,0x0000,0x0000,0x0000,0x0000,0x0000 // @
48 0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0000, // +
49 0xE318,0xFFFF,0x0000,0x0000,0x0000,0x0000, // @+
50 0xE318,0xFFFF,0xFFFF,0x0000,0x0000,0x0000, // @++
51 0xE318,0xE318,0xFFFF,0xFFFF,0x0000,0x0000, // @@++
52 0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF,0x0000, // @@+++
53 0xE318,0xE318,0xE318,0xFFFF,0xFFFF,0xFFFF, // @@@+++
54 0xE318,0xE318,0xE318,0x0000,0x0000,0x0000, // @@@
55 0xE318,0x0000,0x0000,0x0000,0x0000,0x0000 // @
58 // 1 111 00 11 100 1 1100 -> F39C
59 // 1 100 00 10 000 1 0000 -> C210
60 // 1 110 00 11 000 1 1000 -> E318
61 // 0 000 00 11 111 0 0000 -> 03E0
62 // 0 000 00 11 000 0 0000 -> 0300
67 0x0000,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x4B5E,0x0000, // +++++
68 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
69 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
70 0x4B5E,0x0000,0x0000,0xFFFF,0x0000,0x0000,0x0217, // + @ .
71 0x4B5E,0x0000,0xFFFF,0x0000,0xFFFF,0x0000,0x0217, // + @ @ .
72 0x4B5E,0xFFFF,0x0000,0x0000,0x0000,0xFFFF,0x0217, // +@ @.
73 0x0000,0x0217,0x0217,0x0217,0x0217,0x0217,0x0000 // .....
76 char separator[] = "--------------------------------------------------------";
85 Element(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0)
86 { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
87 virtual void HandleKey(SDLKey key) = 0;
88 virtual void HandleMouseMove(uint32 x, uint32 y) = 0;
89 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) = 0;
90 virtual void Draw(uint32, uint32) = 0;
91 //Needed? virtual ~Element() = 0;
92 //We're not allocating anything in the base class, so the answer would be NO.
93 bool Inside(uint32 x, uint32 y);
95 static void SetScreenAndPitch(int16 * s, uint32 p) { screenBuffer = s, pitch = p; }
100 // Class variables...
101 static int16 * screenBuffer;
105 int16 * Element::screenBuffer = NULL;
106 uint32 Element::pitch = 0;
108 bool Element::Inside(uint32 x, uint32 y)
110 return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
111 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
114 class Button: public Element
117 Button(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
118 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
119 bgColor(0x03E0), pic(NULL) {}
120 Button(uint32 x, uint32 y, uint32 w, uint32 h, uint16 * p): Element(x, y, w, h),
121 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
122 bgColor(0x03E0), pic(p) {}
123 Button(uint32 x, uint32 y, uint32 w, uint32 h, string s): Element(x, y, w, h),
124 activated(false), clicked(false), inside(false), fgColor(0xFFFF),
125 bgColor(0x03E0), pic(NULL), text(s) {}
126 virtual void HandleKey(SDLKey key) {}
127 virtual void HandleMouseMove(uint32 x, uint32 y);
128 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
129 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
130 bool ButtonClicked(void) { return activated; }
133 bool activated, clicked, inside;
134 uint16 fgColor, bgColor;
139 void Button::HandleMouseMove(uint32 x, uint32 y)
141 inside = Inside(x, y);
144 void Button::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
151 if (clicked && !mouseDown)
152 clicked = false, activated = true;
155 clicked = activated = false;
158 void Button::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
160 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
162 for(uint32 y=0; y<extents.h; y++)
164 for(uint32 x=0; x<extents.w; x++)
166 // Doesn't clip in y axis! !!! FIX !!!
167 if (extents.x + x < pitch)
168 screenBuffer[addr + x + (y * pitch)]
169 = (clicked && inside ? fgColor : (inside ? 0x43F0 : bgColor));
173 //WriteLog("Button::Draw [%08X]\n", this);
176 //WriteLog("--> Button: About to draw pic [%08X].\n", pic);
177 DrawTransparentBitmap(screenBuffer, extents.x + offsetX, extents.y + offsetY, pic);
180 if (text.length() > 0)
182 //WriteLog("--> Button: About to draw string [%s].\n", text.c_str());
183 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
187 class Window: public Element
190 Window(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
191 /*clicked(false), inside(false),*/ fgColor(0x4FF0), bgColor(0xFE10),
192 close(w - 8, 1, 7, 7, closeBox) { list.push_back(&close); }
193 virtual void HandleKey(SDLKey key) {}
194 virtual void HandleMouseMove(uint32 x, uint32 y);
195 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
196 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
197 void AddElement(Element * e);
198 bool WindowActive(void) { return !close.ButtonClicked(); }
201 // bool clicked, inside;
202 uint16 fgColor, bgColor;
204 //We have to use a list of Element *pointers* because we can't make a list that will hold
205 //all the different object types in the same list...
206 vector<Element *> list;
209 void Window::HandleMouseMove(uint32 x, uint32 y)
211 // Handle the items this window contains...
212 for(uint32 i=0; i<list.size(); i++)
213 // Make coords relative to upper right corner of this window...
214 list[i]->HandleMouseMove(x - extents.x, y - extents.y);
217 void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
219 // Handle the items this window contains...
220 for(uint32 i=0; i<list.size(); i++)
221 // Make coords relative to upper right corner of this window...
222 list[i]->HandleMouseButton(x - extents.x, y - extents.y, mouseDown);
225 void Window::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
227 uint32 addr = (extents.x + offsetX) + ((extents.y + offsetY) * pitch);
229 for(uint32 y=0; y<extents.h; y++)
231 for(uint32 x=0; x<extents.w; x++)
233 // Doesn't clip in y axis! !!! FIX !!!
234 if (extents.x + x < pitch)
235 screenBuffer[addr + x + (y * pitch)] = bgColor;
239 // Handle the items this window contains...
240 for(uint32 i=0; i<list.size(); i++)
241 list[i]->Draw(extents.x, extents.y);
244 void Window::AddElement(Element * e)
249 class Text: public Element
252 Text(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 0): Element(x, y, w, h),
253 fgColor(0x4FF0), bgColor(0xFE10) {}
254 Text(uint32 x, uint32 y, string s): Element(x, y, 0, 0),
255 fgColor(0x4FF0), bgColor(0xFE10), text(s) {}
256 virtual void HandleKey(SDLKey key) {}
257 virtual void HandleMouseMove(uint32 x, uint32 y) {}
258 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
259 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
262 uint16 fgColor, bgColor;
266 void Text::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
268 if (text.length() > 0)
269 DrawString(screenBuffer, extents.x + offsetX, extents.y + offsetY, false, "%s", text.c_str());
275 void (* action)(void);
278 NameAction(string n, void (* a)(void) = NULL, bool w = false): name(n), action(a),
285 MenuItems(): charLength(0) {}
286 bool Inside(uint32 x, uint32 y)
287 { return (x >= (uint32)extents.x && x < (uint32)(extents.x + extents.w)
288 && y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false); }
291 vector<NameAction> item;
296 class Menu: public Element
299 Menu(uint32 x = 0, uint32 y = 0, uint32 w = 0, uint32 h = 8,
300 uint16 fgc = 0x1CFF, uint16 bgc = 0x000F, uint16 fgch = 0x421F,
301 uint16 bgch = 0x1CFF): Element(x, y, w, h), clicked(false), inside(0),
302 insidePopup(0), fgColor(fgc), bgColor(bgc), fgColorHL(fgch), bgColorHL(bgch),
303 menuChosen(-1), menuItemChosen(-1) {}
304 // { extents.x = x, extents.y = y, extents.w = w, extents.h = h; }
305 virtual void HandleKey(SDLKey key);
306 virtual void HandleMouseMove(uint32 x, uint32 y);
307 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown);
308 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0);
309 void Add(MenuItems mi);
310 //This is wrong. !!! FIX !!!
311 bool ItemChosen(void) { return (clicked && insidePopup); }
312 //This is bad... !!! FIX !!!
313 NameAction & GetItem(void)
314 // { if (ItemChosen()) return itemList[menuChosen].item[menuItemChosen]; return NULL; }
315 { return itemList[menuChosen].item[menuItemChosen]; }
319 uint32 inside, insidePopup;
320 uint16 fgColor, bgColor, fgColorHL, bgColorHL;
321 int menuChosen, menuItemChosen;
324 vector<MenuItems> itemList;
327 void Menu::HandleKey(SDLKey Key)
331 void Menu::HandleMouseMove(uint32 x, uint32 y)
333 inside = insidePopup = 0;
337 // Find out *where* we are inside the menu bar
338 uint32 xpos = extents.x;
340 for(uint32 i=0; i<itemList.size(); i++)
342 uint32 width = (itemList[i].title.length() + 2) * 8;
344 if (x >= xpos && x < xpos + width)
355 if (!Inside(x, y) && !clicked)
360 if (itemList[menuChosen].Inside(x, y) && clicked)
362 insidePopup = ((y - itemList[menuChosen].extents.y) / 8) + 1;
363 menuItemChosen = insidePopup - 1;
367 void Menu::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
376 menuChosen = -1; // clicked is already false...!
379 else // clicked == true
381 if (insidePopup && !mouseDown) // I.e., mouse-button-up
383 if (itemList[menuChosen].item[menuItemChosen].action != NULL)
385 itemList[menuChosen].item[menuItemChosen].action();
387 clicked = false, menuChosen = menuItemChosen = -1;
390 while (SDL_PollEvent(&event)); // Flush the event queue...
391 event.type = SDL_MOUSEMOTION;
393 SDL_GetMouseState(&mx, &my);
394 event.motion.x = mx, event.motion.y = my;
395 SDL_PushEvent(&event); // & update mouse position...!
399 if (!inside && !insidePopup && mouseDown)
400 clicked = false, menuChosen = menuItemChosen = -1;
404 void Menu::Draw(uint32 offsetX/*= 0*/, uint32 offsetY/*= 0*/)
406 uint32 xpos = extents.x + offsetX;
408 for(uint32 i=0; i<itemList.size(); i++)
410 uint16 color1 = fgColor, color2 = bgColor;
411 if (inside == (i + 1) || (menuChosen != -1 && (uint32)menuChosen == i))
412 color1 = fgColorHL, color2 = bgColorHL;
414 DrawStringOpaque(screenBuffer, xpos, extents.y + offsetY, color1, color2,
415 " %s ", itemList[i].title.c_str());
416 xpos += (itemList[i].title.length() + 2) * 8;
419 // Draw sub menu (but only if active)
422 uint32 ypos = extents.y + 9;
424 for(uint32 i=0; i<itemList[menuChosen].item.size(); i++)
426 uint16 color1 = fgColor, color2 = bgColor;
428 if (insidePopup == i + 1)
429 color1 = fgColorHL, color2 = bgColorHL, menuItemChosen = i;
431 if (itemList[menuChosen].item[i].name.length() > 0)
432 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
433 color1, color2, " %-*.*s ", itemList[menuChosen].charLength,
434 itemList[menuChosen].charLength, itemList[menuChosen].item[i].name.c_str());
436 DrawStringOpaque(screenBuffer, itemList[menuChosen].extents.x, ypos,
437 fgColor, bgColor, "%.*s", itemList[menuChosen].charLength + 2, separator);
444 void Menu::Add(MenuItems mi)
446 for(uint32 i=0; i<mi.item.size(); i++)
447 if (mi.item[i].name.length() > mi.charLength)
448 mi.charLength = mi.item[i].name.length();
450 // Set extents here as well...
451 mi.extents.x = extents.x + extents.w, mi.extents.y = extents.y + 9;
452 mi.extents.w = (mi.charLength + 2) * 8, mi.extents.h = mi.item.size() * 8;
454 itemList.push_back(mi);
455 extents.w += (mi.title.length() + 2) * 8;
458 //Do we even *need* this?
459 class RootWindow: public Window
462 RootWindow(Menu * m, Window * w = NULL): menu(m), window(w) {}
463 //Do we even need to care about this crap?
464 // { extents.x = extents.y = 0, extents.w = 320, extents.h = 240; }
465 virtual void HandleKey(SDLKey key) {}
466 virtual void HandleMouseMove(uint32 x, uint32 y) {}
467 virtual void HandleMouseButton(uint32 x, uint32 y, bool mouseDown) {}
468 virtual void Draw(uint32 offsetX = 0, uint32 offsetY = 0) {}
473 int16 * rootImage[1280 * 240 * 2];
479 // GUI stuff--it's not crunchy, it's GUI! ;-)
484 SDL_ShowCursor(SDL_DISABLE);
485 SDL_GetMouseState(&mouseX, &mouseY);
493 // Draw text at the given x/y coordinates. Can invert text as well.
495 void DrawString(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
501 vsprintf(string, text, arg);
504 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
505 uint32 length = strlen(string), address = x + (y * pitch);
507 for(uint32 i=0; i<length; i++)
509 uint32 fontAddr = (uint32)string[i] * 64;
511 for(uint32 yy=0; yy<8; yy++)
513 for(uint32 xx=0; xx<8; xx++)
515 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
516 *(screen + address + xx + (yy * pitch)) = 0xFE00;
526 // Draw text at the given x/y coordinates, using FG/BG colors.
528 void DrawStringOpaque(int16 * screen, uint32 x, uint32 y, uint16 color1, uint16 color2, const char * text, ...)
534 vsprintf(string, text, arg);
537 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
538 uint32 length = strlen(string), address = x + (y * pitch);
540 for(uint32 i=0; i<length; i++)
542 uint32 fontAddr = (uint32)string[i] * 64;
544 for(uint32 yy=0; yy<8; yy++)
546 for(uint32 xx=0; xx<8; xx++)
548 *(screen + address + xx + (yy * pitch)) = (font1[fontAddr] ? color1 : color2);
558 // Draw text at the given x/y coordinates. Can invert text as well.
560 void DrawStringTrans(int16 * screen, uint32 x, uint32 y, uint16 color, uint8 trans, const char * text, ...)
566 vsprintf(string, text, arg);
569 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
570 uint32 length = strlen(string), address = x + (y * pitch);
572 for(uint32 i=0; i<length; i++)
574 uint32 fontAddr = (uint32)string[i] * 64;
576 for(uint32 yy=0; yy<8; yy++)
578 for(uint32 xx=0; xx<8; xx++)
582 uint16 existingColor = *(screen + address + xx + (yy * pitch));
584 uint8 eRed = (existingColor >> 10) & 0x1F,
585 eGreen = (existingColor >> 5) & 0x1F,
586 eBlue = existingColor & 0x1F,
587 //This could be done ahead of time, instead of on each pixel...
588 nRed = (color >> 10) & 0x1F,
589 nGreen = (color >> 5) & 0x1F,
590 nBlue = color & 0x1F;
592 //This could be sped up by using a table of 5 + 5 + 5 bits (32 levels transparency -> 32768 entries)
593 //Here we've modified it to have 33 levels of transparency (could have any # we want!)
594 //because dividing by 32 is faster than dividing by 31!
595 uint8 invTrans = 32 - trans;
596 uint16 bRed = (eRed * trans + nRed * invTrans) / 32;
597 uint16 bGreen = (eGreen * trans + nGreen * invTrans) / 32;
598 uint16 bBlue = (eBlue * trans + nBlue * invTrans) / 32;
600 uint16 blendedColor = (bRed << 10) | (bGreen << 5) | bBlue;
602 *(screen + address + xx + (yy * pitch)) = blendedColor;
618 extern int16 * backbuffer;
622 // Set up the GUI classes...
623 Element::SetScreenAndPitch(backbuffer, GetSDLScreenPitch() / 2);
625 Button closeButton(45, 90, 16, 16);
626 Window someWindow(15, 16, 60, 60);
627 Button button1(50, 15, 9, 9), button2(10, 10, 8, 8), button3(25, 48, 32, 8, " Ok ");
628 someWindow.AddElement(&button1);
629 someWindow.AddElement(&button2);
630 someWindow.AddElement(&button3);
632 Menu mainMenu;//(0, 160);
635 mi.item.push_back(NameAction("Load...", LoadROM));
636 mi.item.push_back(NameAction("Reset"));
637 mi.item.push_back(NameAction("Run", RunEmu));
638 mi.item.push_back(NameAction(""));
639 mi.item.push_back(NameAction("Quit", Quit));
641 mi.title = "Settings";
643 mi.item.push_back(NameAction("Video..."));
644 mi.item.push_back(NameAction("Audio..."));
645 mi.item.push_back(NameAction("Misc..."));
647 mi.title = "Options";
649 mi.item.push_back(NameAction("About..."));
652 bool showMouse = true;
654 //This is crappy!!! !!! FIX !!!
659 while (SDL_PollEvent(&event))
661 if (event.type == SDL_ACTIVEEVENT)
663 if (event.active.state == SDL_APPMOUSEFOCUS)
664 showMouse = (event.active.gain ? true : false);
666 if (event.type == SDL_KEYDOWN)
668 closeButton.HandleKey(event.key.keysym.sym);
669 if (someWindow.WindowActive())
670 someWindow.HandleKey(event.key.keysym.sym);
671 mainMenu.HandleKey(event.key.keysym.sym);
673 else if (event.type == SDL_MOUSEMOTION)
675 mouseX = event.motion.x, mouseY = event.motion.y;
678 mouseX /= 2, mouseY /= 2;
680 closeButton.HandleMouseMove(mouseX, mouseY);
681 if (someWindow.WindowActive())
682 someWindow.HandleMouseMove(mouseX, mouseY);
683 mainMenu.HandleMouseMove(mouseX, mouseY);
685 else if (event.type == SDL_MOUSEBUTTONDOWN)
687 uint32 mx = event.button.x, my = event.button.y;
692 closeButton.HandleMouseButton(mx, my, true);
693 if (someWindow.WindowActive())
694 someWindow.HandleMouseButton(mx, my, true);
695 mainMenu.HandleMouseButton(mx, my, true);
697 else if (event.type == SDL_MOUSEBUTTONUP)
699 uint32 mx = event.button.x, my = event.button.y;
704 closeButton.HandleMouseButton(mx, my, false);
705 if (someWindow.WindowActive())
706 someWindow.HandleMouseButton(mx, my, false);
707 mainMenu.HandleMouseButton(mx, my, false);
711 // The way we do things here is kinda stupid (redrawing the screen every frame), but
712 // it's simple. Perhaps there may be a reason down the road to be more selective with
713 // our clearing, but for now, this will suffice.
714 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
717 if (someWindow.WindowActive())
722 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
732 // GUI "action" functions
740 //This is crappy... !!! FIX !!!
741 extern int16 * backbuffer;
742 extern bool finished;
744 uint32 nFrame = 0, nFrameskip = 0;
745 uint32 totalFrames = 0;
747 bool showMessage = true;
748 uint32 showMsgFrames = 60;
749 uint8 transparency = 0;
753 // Set up new backbuffer with new pixels and data
754 JaguarExecute(backbuffer, true);
756 //WriteLog("Frame #%u...\n", totalFrames);
757 //extern bool doDSPDis;
758 //if (totalFrames == 373)
761 // Some QnD GUI stuff here...
764 extern uint32 gpu_pc, dsp_pc;
765 DrawString(backbuffer, 8, 8, false, "GPU PC: %08X", gpu_pc);
766 DrawString(backbuffer, 8, 16, false, "DSP PC: %08X", dsp_pc);
771 DrawStringTrans(backbuffer, 8, 24*8, 0xFF0F, transparency, "Running...");
773 if (showMsgFrames == 0)
777 if (transparency == 33)
785 if (nFrame == nFrameskip)
799 WriteLog("GUI: Quitting due to user request.\n");
806 extern int16 * backbuffer;
808 uint16 * bgSave = (uint16 *)malloc(tom_getVideoModeWidth() * 240 * 2);
809 memcpy(bgSave, backbuffer, tom_getVideoModeWidth() * 240 * 2);
814 while (SDL_PollEvent(&event))
816 if (event.type == SDL_KEYDOWN)
818 if (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_RETURN)
821 else if (event.type == SDL_MOUSEMOTION)
823 mouseX = event.motion.x, mouseY = event.motion.y;
825 mouseX /= 2, mouseY /= 2;
827 else if (event.type == SDL_MOUSEBUTTONDOWN)
829 uint32 mx = event.button.x, my = event.button.y;
837 memcpy(backbuffer, bgSave, tom_getVideoModeWidth() * 240 * 2);
839 DrawStringOpaque(backbuffer, 64, 64, 0x1CFF, 0x000F, " ");
840 DrawStringOpaque(backbuffer, 64, 72, 0x1CFF, 0x000F, " Virtual Jaguar by JLH & crew ");
841 DrawStringOpaque(backbuffer, 64, 80, 0x1CFF, 0x000F, " ");
843 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
854 // Uses zero as transparent color
856 void DrawTransparentBitmap(int16 * screen, uint32 x, uint32 y, uint16 * bitmap)
858 uint16 width = bitmap[0], height = bitmap[1];
861 uint32 pitch = GetSDLScreenPitch() / 2; // Returns pitch in bytes but we need words...
862 uint32 address = x + (y * pitch);
864 for(int yy=0; yy<height; yy++)
866 for(int xx=0; xx<width; xx++)
868 if (*bitmap && x + xx < pitch) // NOTE: Still doesn't clip the Y val...
869 *(screen + address + xx + (yy * pitch)) = *bitmap;
876 // Very very crude GUI file selector
878 bool UserSelectFile(char * path, char * filename)
883 extern int16 * backbuffer;
884 vector<string> fileList;
886 // Read in the candidate files from the directory pointed to by "path"
888 DIR * dp = opendir(path);
891 while ((de = readdir(dp)) != NULL)
893 char * ext = strrchr(de->d_name, '.');
896 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
897 fileList.push_back(string(de->d_name));
902 if (fileList.size() == 0) // Any files found?
903 return false; // Nope. Bail!
905 // Main GUI selection loop
907 uint32 cursor = 0, startFile = 0;
909 if (fileList.size() > 1) // Only go GUI if more than one possibility!
911 sort(fileList.begin(), fileList.end());
914 uint32 limit = (fileList.size() > 30 ? 30 : fileList.size());
917 // Ensure that the GUI is drawn before any user input...
918 event.type = SDL_USEREVENT;
919 SDL_PushEvent(&event);
923 while (SDL_PollEvent(&event))
925 if (event.type == SDL_KEYDOWN)
927 SDLKey key = event.key.keysym.sym;
929 if (key == SDLK_DOWN)
931 if (cursor != limit - 1) // Cursor is within its window
933 else // Otherwise, scroll the window...
935 if (cursor + startFile != fileList.size() - 1)
949 if (key == SDLK_PAGEDOWN)
951 if (cursor != limit - 1)
956 if (startFile > fileList.size() - limit)
957 startFile = fileList.size() - limit;
960 if (key == SDLK_PAGEUP)
966 if (startFile < limit)
972 if (key == SDLK_RETURN)
974 if (key == SDLK_ESCAPE)
976 WriteLog("GUI: Aborting VJ by user request.\n");
977 return false; // Bail out!
979 if (key >= SDLK_a && key <= SDLK_z)
981 // Advance cursor to filename with first letter pressed...
982 uint8 which = (key - SDLK_a) + 65; // Convert key to A-Z char
984 for(uint32 i=0; i<fileList.size(); i++)
986 if ((fileList[i][0] & 0xDF) == which)
988 cursor = i - startFile;
989 if (i > startFile + limit - 1)
990 startFile = i - limit + 1,
1000 else if (event.type == SDL_MOUSEMOTION)
1002 mouseX = event.motion.x, mouseY = event.motion.y;
1004 mouseX /= 2, mouseY /= 2;
1006 else if (event.type == SDL_MOUSEBUTTONDOWN)
1008 uint32 mx = event.button.x, my = event.button.y;
1015 // memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
1016 memset(backbuffer, 0x11, tom_getVideoModeWidth() * 240 * 2);
1018 for(uint32 i=0; i<limit; i++)
1020 // Clip our strings to guarantee that they fit on the screen...
1021 // (and strip off the extension too)
1022 string s(fileList[startFile + i], 0, fileList[startFile + i].length() - 4);
1023 if (s.length() > 38)
1025 DrawString(backbuffer, 0, i*8, (cursor == i ? true : false), " %s ", s.c_str());
1028 DrawTransparentBitmap(backbuffer, mouseX, mouseY, mousePic);
1035 strcpy(filename, path);
1037 if (strlen(path) > 0)
1038 if (path[strlen(path) - 1] != '/')
1039 strcat(filename, "/");
1041 strcat(filename, fileList[startFile + cursor].c_str());