From 4b7a2c475ca0db55136a0f8139556d2ca0bdf3e4 Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 28 Sep 2003 21:59:24 +0000 Subject: [PATCH] The first version of a GUI for event remapping is here! Now for the things that aren't finished yet: - Only the most basic functions can be remapped. If you erase the mapping for those that can't yet be remapped, you'll have to delete the 'keymap' line from stellarc and start over. - Core events can only be remapped to other keys on the keyboard. I haven't got the joystick remapping working yet (but it should be easy to do). - The TIA needs to be modified to show 320 pixels horizontally. Right now, I'm using 8 pixel-width fonts on a framebuffer of 160 pixels, so there's not a lot of horizontal real estate. So text will probably overwrite other stuff. This is cosmetic, and WILL be fixed. - Modification of the TIA will break every frontends rendering code. It had to be done sometime ... - I haven't yet added any user feedback mechanism for the user. So when you go into remap mode and are about to remap a key, you won't know it :) I'll be adding arrows (like in XMAME) ... I've added a "Game Information" menu, which shows things like Game name, manufacturer, rarity, type, etc. Basically stuff from the stella.pro file. It has no purpose other than for coolness :) git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@193 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/emucore/EventHandler.cxx | 66 ++-- stella/src/emucore/EventHandler.hxx | 14 +- stella/src/emucore/Settings.cxx | 4 +- stella/src/emucore/StellaEvent.hxx | 8 +- stella/src/emucore/TIA.hxx | 7 +- stella/src/emucore/UserInterface.cxx | 530 ++++++++++++++++----------- stella/src/emucore/UserInterface.hxx | 79 +++- 7 files changed, 434 insertions(+), 274 deletions(-) diff --git a/stella/src/emucore/EventHandler.cxx b/stella/src/emucore/EventHandler.cxx index 73e569550..7e17d6cd6 100644 --- a/stella/src/emucore/EventHandler.cxx +++ b/stella/src/emucore/EventHandler.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: EventHandler.cxx,v 1.13 2003-09-26 22:39:36 stephena Exp $ +// $Id: EventHandler.cxx,v 1.14 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #include @@ -49,9 +49,8 @@ EventHandler::EventHandler(Console* console) myKeyTable[i] = Event::NoType; // Erase the JoyEvent array - for(i = 0; i < StellaEvent::LastJSTICK; ++i) - for(Int32 j = 0; j < StellaEvent::LastJCODE; ++j) - myJoyTable[i][j] = Event::NoType; + for(i = 0; i < StellaEvent::LastJSTICK*StellaEvent::LastJCODE; ++i) + myJoyTable[i] = Event::NoType; // Erase the Message array for(i = 0; i < Event::LastType; ++i) @@ -67,6 +66,9 @@ EventHandler::EventHandler(Console* console) setKeymap(); setJoymap(); + + // Now send the filled event arrays to the GUI for display and remapping +// myConsole->gui(). } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -74,8 +76,6 @@ EventHandler::~EventHandler() { if(myEvent) delete myEvent; - - myEvent = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -110,7 +110,7 @@ void EventHandler::sendJoyEvent(StellaEvent::JoyStick stick, if(myMenuStatus) myConsole->gui().sendJoyEvent(stick, code, state); else - sendEvent(myJoyTable[stick][code], state); + sendEvent(myJoyTable[stick*StellaEvent::LastJCODE + code], state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -202,13 +202,10 @@ void EventHandler::setJoymap() string key; // Fill the joymap table with events - for(Int32 i = 0; i < StellaEvent::LastJSTICK; ++i) + for(Int32 i = 0; i < StellaEvent::LastJSTICK*StellaEvent::LastJCODE; ++i) { - for(Int32 j = 0; j < StellaEvent::LastJCODE; ++j) - { - buf >> key; - myJoyTable[i][j] = (Event::Type) atoi(key.c_str()); - } + buf >> key; + myJoyTable[i] = (Event::Type) atoi(key.c_str()); } } else @@ -234,14 +231,28 @@ string EventHandler::getJoymap() ostringstream buf; // Iterate through the joymap table and create a colon-separated list - for(Int32 i = 0; i < StellaEvent::LastJSTICK; ++i) - for(Int32 j = 0; j < StellaEvent::LastJCODE; ++j) - buf << myJoyTable[i][j] << ":"; + for(Int32 i = 0; i < StellaEvent::LastJSTICK*StellaEvent::LastJCODE; ++i) + buf << myJoyTable[i] << ":"; myJoymapString = buf.str(); return myJoymapString; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandler::getKeymapArray(Event::Type** array, uInt32* sizex) +{ + *array = myKeyTable; + *sizex = StellaEvent::LastKCODE; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandler::getJoymapArray(Event::Type** array, uInt32* sizex, uInt32* sizey) +{ + *array = myJoyTable; + *sizex = StellaEvent::LastJSTICK; + *sizey = StellaEvent::LastJCODE; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setDefaultKeymap() { @@ -313,19 +324,20 @@ void EventHandler::setDefaultKeymap() void EventHandler::setDefaultJoymap() { // Left joystick - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JBUTTON_9 ] = Event::ConsoleSelect; - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JAXIS_UP] = Event::JoystickZeroUp; - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JAXIS_DOWN] = Event::JoystickZeroDown; - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JAXIS_LEFT] = Event::JoystickZeroLeft; - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JAXIS_RIGHT] = Event::JoystickZeroRight; - myJoyTable[StellaEvent::JSTICK_0][StellaEvent::JBUTTON_0] = Event::JoystickZeroFire; + uInt32 i = StellaEvent::JSTICK_0 * StellaEvent::LastJCODE; + myJoyTable[i + StellaEvent::JAXIS_UP] = Event::JoystickZeroUp; + myJoyTable[i + StellaEvent::JAXIS_DOWN] = Event::JoystickZeroDown; + myJoyTable[i + StellaEvent::JAXIS_LEFT] = Event::JoystickZeroLeft; + myJoyTable[i + StellaEvent::JAXIS_RIGHT] = Event::JoystickZeroRight; + myJoyTable[i + StellaEvent::JBUTTON_0] = Event::JoystickZeroFire; // Right joystick - myJoyTable[StellaEvent::JSTICK_1][StellaEvent::JAXIS_UP] = Event::JoystickOneUp; - myJoyTable[StellaEvent::JSTICK_1][StellaEvent::JAXIS_DOWN] = Event::JoystickOneDown; - myJoyTable[StellaEvent::JSTICK_1][StellaEvent::JAXIS_LEFT] = Event::JoystickOneLeft; - myJoyTable[StellaEvent::JSTICK_1][StellaEvent::JAXIS_RIGHT] = Event::JoystickOneRight; - myJoyTable[StellaEvent::JSTICK_1][StellaEvent::JBUTTON_0] = Event::JoystickOneFire; + i = StellaEvent::JSTICK_1 * StellaEvent::LastJCODE; + myJoyTable[i + StellaEvent::JAXIS_UP] = Event::JoystickOneUp; + myJoyTable[i + StellaEvent::JAXIS_DOWN] = Event::JoystickOneDown; + myJoyTable[i + StellaEvent::JAXIS_LEFT] = Event::JoystickOneLeft; + myJoyTable[i + StellaEvent::JAXIS_RIGHT] = Event::JoystickOneRight; + myJoyTable[i + StellaEvent::JBUTTON_0] = Event::JoystickOneFire; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/emucore/EventHandler.hxx b/stella/src/emucore/EventHandler.hxx index c75b8703f..7b0abf82b 100644 --- a/stella/src/emucore/EventHandler.hxx +++ b/stella/src/emucore/EventHandler.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: EventHandler.hxx,v 1.8 2003-09-26 17:35:05 stephena Exp $ +// $Id: EventHandler.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #ifndef EVENTHANDLER_HXX @@ -41,7 +41,7 @@ class MediaSource; mapping can take place. @author Stephen Anthony - @version $Id: EventHandler.hxx,v 1.8 2003-09-26 17:35:05 stephena Exp $ + @version $Id: EventHandler.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $ */ class EventHandler { @@ -98,19 +98,21 @@ class EventHandler void setMediaSource(MediaSource* mediaSource); /** - Get the current keymapping being used + Get the current keymapping being used in string form @return The keymap list in string form */ string getKeymap(); /** - Get the current joymapping being used + Get the current joymapping being used in string form @return The joymap list in string form */ string getJoymap(); + void getKeymapArray(Event::Type** array, uInt32* sizex); + void getJoymapArray(Event::Type** array, uInt32* sizex, uInt32* sizey); private: void setKeymap(); @@ -125,14 +127,12 @@ class EventHandler void loadState(); void takeSnapshot(); - void processMenuEvent(StellaEvent::KeyCode key); - private: // Array of key events Event::Type myKeyTable[StellaEvent::LastKCODE]; // Array of joystick events - Event::Type myJoyTable[StellaEvent::LastJSTICK][StellaEvent::LastJCODE]; + Event::Type myJoyTable[StellaEvent::LastJSTICK*StellaEvent::LastJCODE]; // Array of messages for each Event string ourMessageTable[Event::LastType]; diff --git a/stella/src/emucore/Settings.cxx b/stella/src/emucore/Settings.cxx index 7227354f2..ce607a296 100644 --- a/stella/src/emucore/Settings.cxx +++ b/stella/src/emucore/Settings.cxx @@ -13,10 +13,10 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Settings.cxx,v 1.9 2003-09-25 16:20:34 stephena Exp $ +// $Id: Settings.cxx,v 1.10 2003-09-28 21:59:24 stephena Exp $ //============================================================================ -#include +#include #include #include diff --git a/stella/src/emucore/StellaEvent.hxx b/stella/src/emucore/StellaEvent.hxx index 777006e01..d6f85627f 100644 --- a/stella/src/emucore/StellaEvent.hxx +++ b/stella/src/emucore/StellaEvent.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: StellaEvent.hxx,v 1.4 2003-09-26 00:32:00 stephena Exp $ +// $Id: StellaEvent.hxx,v 1.5 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #ifndef STELLAEVENT_HXX @@ -28,13 +28,17 @@ by the frontends directly. @author Stephen Anthony - @version $Id: StellaEvent.hxx,v 1.4 2003-09-26 00:32:00 stephena Exp $ + @version $Id: StellaEvent.hxx,v 1.5 2003-09-28 21:59:24 stephena Exp $ */ class StellaEvent { public: /** Enumeration of keyboard keycodes + + Note that the order of these codes is related to + UserInterface::ourEventName. If these are ever changed or rearranged, + that array must be updated as well. */ enum KeyCode { diff --git a/stella/src/emucore/TIA.hxx b/stella/src/emucore/TIA.hxx index f4769cb0c..a7b7c37f5 100644 --- a/stella/src/emucore/TIA.hxx +++ b/stella/src/emucore/TIA.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.hxx,v 1.8 2003-09-26 17:35:05 stephena Exp $ +// $Id: TIA.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #ifndef TIA_HXX @@ -43,7 +43,7 @@ class Deserializer; in a bounded queue. @author Bradford W. Mott - @version $Id: TIA.hxx,v 1.8 2003-09-26 17:35:05 stephena Exp $ + @version $Id: TIA.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $ */ class TIA : public Device , public MediaSource { @@ -244,9 +244,6 @@ class TIA : public Device , public MediaSource // Waste cycles until the current scanline is finished void waitHorizontalSync(); - // Draw message to framebuffer - void drawMessageText(); - private: /** A bounded queue class used to hold audio samples after they are diff --git a/stella/src/emucore/UserInterface.cxx b/stella/src/emucore/UserInterface.cxx index 435b58d65..7bb29df3c 100644 --- a/stella/src/emucore/UserInterface.cxx +++ b/stella/src/emucore/UserInterface.cxx @@ -13,25 +13,27 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: UserInterface.cxx,v 1.4 2003-09-26 22:39:36 stephena Exp $ +// $Id: UserInterface.cxx,v 1.5 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #include "bspf.hxx" #include "Console.hxx" #include "Event.hxx" +#include "EventHandler.hxx" +#include "StellaEvent.hxx" #include "Settings.hxx" #include "MediaSrc.hxx" #include "UserInterface.hxx" // Eventually, these may become variables -#define FGCOLOR 10 -#define BGCOLOR 0 -#define FONTWIDTH 8 +#define FGCOLOR 10 // A white color in NTSC and PAL mode +#define BGCOLOR 0 // A black color in NTSC and PAL mode +#define FONTWIDTH 8 // FIXME - TIA framebuffers must be updated for this #define FONTHEIGHT 8 -#define YOFFSET 12 // FONTHEIGHT + 2 pixels on top and bottom -#define XBOXOFFSET 8 // 4 pixels to the left and right of text -#define YBOXOFFSET 8 // 4 pixels to the top and bottom of text +#define LINEOFFSET 10 // FONTHEIGHT + 1 pixel on top and bottom +#define XBOXOFFSET 8 // 4 pixels to the left and right of text +#define YBOXOFFSET 8 // 4 pixels to the top and bottom of text // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UserInterface::UserInterface(Console* console, MediaSource* mediasrc) @@ -40,6 +42,14 @@ UserInterface::UserInterface(Console* console, MediaSource* mediasrc) myCurrentWidget(W_NONE), myRemapEventSelectedFlag(false), mySelectedEvent(Event::NoType), + myMaxLines(0), + myMainMenuIndex(0), + myMainMenuItems(sizeof(ourMainMenu)/sizeof(MainMenuItem)), + myRemapMenuIndex(0), + myRemapMenuLowIndex(0), + myRemapMenuHighIndex(0), + myRemapMenuItems(sizeof(ourRemapMenu)/sizeof(RemapMenuItem)), + myRemapMenuMaxLines(0), myMessageTime(0), myMessageText(""), myInfoMenuWidth(0) @@ -58,30 +68,38 @@ UserInterface::UserInterface(Console* console, MediaSource* mediasrc) } // Fill the properties info array with game information - string info; - info = "NAME: " + myConsole->properties().get("Cartridge.Name"); - ourPropertiesInfo[0] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); + ourPropertiesInfo[0] = myConsole->properties().get("Cartridge.Name"); + if(ourPropertiesInfo[0].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[0].length(); + ourPropertiesInfo[1] = myConsole->properties().get("Cartridge.Manufacturer"); + if(ourPropertiesInfo[1].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[1].length(); + ourPropertiesInfo[2] = myConsole->properties().get("Cartridge.Rarity"); + if(ourPropertiesInfo[2].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[2].length(); + ourPropertiesInfo[3] = myConsole->properties().get("Cartridge.MD5"); + if(ourPropertiesInfo[3].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[3].length(); + ourPropertiesInfo[4] = myConsole->properties().get("Cartridge.Type"); + if(ourPropertiesInfo[4].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[4].length(); + ourPropertiesInfo[5] = myConsole->properties().get("Cartridge.ModelNo"); + if(ourPropertiesInfo[5].length() > myInfoMenuWidth) + myInfoMenuWidth = ourPropertiesInfo[5].length(); - info = "MANUFACTURER: " + myConsole->properties().get("Cartridge.Manufacturer"); - ourPropertiesInfo[1] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); + // Determine the maximum number of items that can be onscreen vertically + myMaxLines = myHeight / LINEOFFSET - 2; - info = "RARITY: " + myConsole->properties().get("Cartridge.Rarity"); - ourPropertiesInfo[2] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); + // Set up the correct bounds for the remap menu + myRemapMenuMaxLines = myRemapMenuItems > myMaxLines ? myMaxLines : myRemapMenuItems; + myRemapMenuLowIndex = 0; + myRemapMenuHighIndex = myRemapMenuMaxLines; - info = "MD5SUM: " + myConsole->properties().get("Cartridge.MD5"); - ourPropertiesInfo[3] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); + // Get the arrays containing key and joystick mappings + myConsole->eventHandler().getKeymapArray(&myKeyTable, &myKeyTableSize); +// myConsole->eventHandler().getJoymapArray(&myJoyTable, &jsize); - info = "MODEL NO: " + myConsole->properties().get("Cartridge.ModelNo"); - ourPropertiesInfo[4] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); - - info = "TYPE: " + myConsole->properties().get("Cartridge.Type"); - ourPropertiesInfo[5] = info; - if(info.length() > myInfoMenuWidth) myInfoMenuWidth = info.length(); + loadRemapMenu(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -93,6 +111,8 @@ UserInterface::~UserInterface(void) void UserInterface::showMainMenu(bool show) { myCurrentWidget = show ? MAIN_MENU : W_NONE; + myRemapEventSelectedFlag = false; + mySelectedEvent = Event::NoType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -118,19 +138,17 @@ void UserInterface::sendKeyEvent(StellaEvent::KeyCode key, Int32 state) if(myRemapEventSelectedFlag) { if(key == StellaEvent::KCODE_ESCAPE) - // associate nothing with the selected event - cerr << "delete binding for " << mySelectedEvent << endl; + deleteBinding(mySelectedEvent); else - // associate this stellaevent with the selected event - cerr << "add binding " << key << " for " << mySelectedEvent << endl; + addKeyBinding(mySelectedEvent, key); myRemapEventSelectedFlag = false; } else if(key == StellaEvent::KCODE_RETURN) { - cerr << "event selected for remapping\n"; mySelectedEvent = currentSelectedEvent(); myRemapEventSelectedFlag = true; +cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "' selected for remapping\n"; } else if(key == StellaEvent::KCODE_UP) moveCursorUp(); @@ -142,7 +160,6 @@ void UserInterface::sendKeyEvent(StellaEvent::KeyCode key, Int32 state) break; // REMAP_MENU case INFO_MENU: - cerr << "key received while in info menu\n"; if(key == StellaEvent::KCODE_ESCAPE) myCurrentWidget = MAIN_MENU; @@ -162,46 +179,85 @@ void UserInterface::sendJoyEvent(StellaEvent::JoyStick stick, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UserInterface::update() { - uInt32 width, height; + // I know this method is hideous :) + uInt32 x, y, width, height, i; + + // A message is a special case of interface element + // It can overwrite even a menu, so we should check for that first + if(myMessageTime > 0) + { + width = myMessageText.length()*FONTWIDTH + FONTWIDTH; + height = LINEOFFSET + FONTHEIGHT; + x = (myWidth >> 1) - (width >> 1); + y = myHeight - height - LINEOFFSET/2; + + // Draw the bounded box and text + drawBoundedBox(x, y, width, height); + drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText); + myMessageTime--; + + return; + } switch(myCurrentWidget) { case W_NONE: - return; // this shouldn't happen -cerr << "W_NONE\n"; + return; break; // NONE case MAIN_MENU: - // draw main menu -cerr << "MAIN_MENU\n"; + width = 16*FONTWIDTH + 2*FONTWIDTH; + height = myMainMenuItems*LINEOFFSET + 2*FONTHEIGHT; + x = (myWidth >> 1) - (width >> 1); + y = (myHeight >> 1) - (height >> 1); + + // Draw the bounded box and text + drawBoundedBox(x, y, width, height); + for(i = 0; i < myMainMenuItems; i++) + drawText(x + XBOXOFFSET, LINEOFFSET*i + y + YBOXOFFSET, ourMainMenu[i].action); + + // FIXME - change the '~' to an arrow on each end of the line + // Now draw the selection arrow around the currently selected item + drawText(x + 2, LINEOFFSET*myMainMenuIndex + y + YBOXOFFSET, "~"); + break; // MAIN_MENU case REMAP_MENU: - // draw remap menu -cerr << "REMAP_MENU\n"; + width = 16*FONTWIDTH + 2*FONTWIDTH; // FIXME - change 16 to maximum in new framebuffer (~ 40) + height = myMaxLines*LINEOFFSET + 2*FONTHEIGHT; + x = (myWidth >> 1) - (width >> 1); + y = (myHeight >> 1) - (height >> 1); + + // Draw the bounded box and text + drawBoundedBox(x, y, width, height); + for(i = myRemapMenuLowIndex; i < myRemapMenuHighIndex; i++) + { + drawText(x + XBOXOFFSET, LINEOFFSET*(i-myRemapMenuLowIndex) + y + YBOXOFFSET, + ourRemapMenu[i].action); + drawText(x + XBOXOFFSET+100, LINEOFFSET*(i-myRemapMenuLowIndex) + y + YBOXOFFSET, + ourRemapMenu[i].key); + } + + // FIXME - change the '~' to an arrow on each end of the line + // Now draw the selection arrow around the currently selected item + drawText(x + 2, LINEOFFSET*(myRemapMenuIndex-myRemapMenuLowIndex) + y + YBOXOFFSET, "~"); + break; // REMAP_MENU case INFO_MENU: - // Calculate the bounds for the box - width = myInfoMenuWidth * FONTWIDTH + XBOXOFFSET; - height = 6 * YOFFSET + YBOXOFFSET; - drawBoundedBox(width, height); - drawText("HELLO", width, height); + width = myInfoMenuWidth*FONTWIDTH + 2*FONTWIDTH; + height = 6*LINEOFFSET + 2*FONTHEIGHT; + x = (myWidth >> 1) - (width >> 1); + y = (myHeight >> 1) - (height >> 1); + + // Draw the bounded box and text + drawBoundedBox(x, y, width, height); + for(i = 0; i < 6; i++) + drawText(x + XBOXOFFSET, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i]); break; // INFO_MENU - case MESSAGE: - if(myMessageTime > 0) - { - drawText(myMessageText, 0, 0); // FIXME - change to draw bounding box and text at correct coords - myMessageTime--; -cerr << "MESSAGE = " << myMessageText << ": " << myMessageTime << endl; - } - - break; // MESSAGE - default: -cerr << "NOT DEFINED\n"; break; } } @@ -209,56 +265,114 @@ cerr << "NOT DEFINED\n"; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UserInterface::Widget UserInterface::currentSelectedWidget() { - return INFO_MENU; // FIXME + if(myMainMenuIndex >= 0 && myMainMenuIndex < myMainMenuItems) + return ourMainMenu[myMainMenuIndex].widget; + else + return W_NONE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type UserInterface::currentSelectedEvent() { - return Event::ConsoleSelect; // FIXME + if(myRemapMenuIndex >= 0 && myRemapMenuIndex < myRemapMenuItems) + return ourRemapMenu[myRemapMenuIndex].event; + else + return Event::NoType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UserInterface::moveCursorUp() { -cerr << "cursor up\n"; + switch(myCurrentWidget) + { + case MAIN_MENU: + if(myMainMenuIndex > 0) + myMainMenuIndex--; + + break; + + case REMAP_MENU: + // Since this menu will have more options than can fit it one screen, + // we have to implement a sliding window + if(myRemapMenuIndex > myRemapMenuLowIndex) + { + myRemapMenuIndex--; +cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "'\n"; + } + else if(myRemapMenuIndex == myRemapMenuLowIndex) + { + if(myRemapMenuLowIndex > 0) + { + myRemapMenuLowIndex--; + myRemapMenuHighIndex--; + myRemapMenuIndex--; +cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "'\n"; + } + } + + break; + + default: // This should never happen + break; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UserInterface::moveCursorDown() { -cerr << "cursor down\n"; + switch(myCurrentWidget) + { + case MAIN_MENU: + if(myMainMenuIndex < myMainMenuItems - 1) + myMainMenuIndex++; + + break; + + case REMAP_MENU: + // Since this menu will have more options than can fit it one screen, + // we have to implement a sliding window + if(myRemapMenuIndex < myRemapMenuHighIndex - 1) + { + myRemapMenuIndex++; +cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "'\n"; + } + else if(myRemapMenuIndex == myRemapMenuHighIndex - 1) + { + if(myRemapMenuHighIndex < myRemapMenuItems) + { + myRemapMenuLowIndex++; + myRemapMenuHighIndex++; + myRemapMenuIndex++; +cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "'\n"; + } + } + + break; + + default: // This should never happen + break; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UserInterface::showMessage(const string& message) { - myCurrentWidget = MESSAGE; - myMessageText = message; - myMessageTime = 120; // FIXME - changes to 2 * framerate - - // Make message uppercase, since there are no lowercase fonts defined - uInt32 length = myMessageText.length(); - for(uInt32 i = 0; i < length; ++i) - myMessageText[i] = toupper(myMessageText[i]); + myMessageTime = 2 * myConsole->settings().getInt("framerate"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void UserInterface::drawBoundedBox(uInt32 width, uInt32 height) +void UserInterface::drawBoundedBox(uInt32 x, uInt32 y, uInt32 width, uInt32 height) { - // Center the box horizontally - uInt32 xBoxOffSet = (myWidth >> 1) - (width >> 1); - uInt32 yBoxOffSet = (myHeight >> 1) - (height >> 1); - uInt8* buffer = myMediaSource->currentFrameBuffer(); - for(uInt32 x = 0; x < width; ++x) - { - for(uInt32 y = 0; y < height; ++y) - { - uInt32 position = ((yBoxOffSet + y) * myWidth) + x + xBoxOffSet; - if((x == 0) || (x == width - 1) || (y == 0) || (y == height - 1)) + for(uInt32 col = 0; col < width; ++col) + { + for(uInt32 row = 0; row < height; ++row) + { + uInt32 position = ((y + row) * myWidth) + col + x; + + if((col == 0) || (col == width - 1) || (row == 0) || (row == height - 1)) buffer[position] = FGCOLOR; else buffer[position] = BGCOLOR; @@ -267,160 +381,140 @@ void UserInterface::drawBoundedBox(uInt32 width, uInt32 height) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void UserInterface::drawText(const string& message, uInt32 xorig, uInt32 yorig) +void UserInterface::drawText(uInt32 xorig, uInt32 yorig, const string& message) { - // First, get access to the framebuffer uInt8* buffer = myMediaSource->currentFrameBuffer(); -/* - // Set up the correct coordinates to draw the surrounding box - uInt32 xBoxOffSet = 2 + myXStart; - uInt32 yBoxOffSet = myHeight - 18; - uInt32 boxToTextXOffSet = 2; - uInt32 boxToTextYOffSet = 4; - - // Set up the correct coordinates to print the message - uInt32 xTextOffSet = xBoxOffSet + boxToTextXOffSet; - uInt32 yTextOffSet = yBoxOffSet + boxToTextYOffSet; - - // Used to indicate the current x/y position of a pixel - uInt32 xPos, yPos; - - // The actual font data for a letter - uInt32 data; - - // The index into the palette to color the current text and background - uInt8 fontColor, backColor; - - // These will probably change in the future ... - fontColor = 10; - backColor = 0; - - // Clip the length if its wider than the screen - uInt8 length = message.length(); - if(((length * 5) + xTextOffSet) >= myWidth) - length = (myWidth - xTextOffSet) / 5; - - // Reset the offsets to center the message - uInt32 boxWidth = (5 * length) + boxToTextXOffSet; - uInt32 boxHeight = 8 + (2 * (yTextOffSet - yBoxOffSet)); - xBoxOffSet = (myWidth >> 1) - (boxWidth >> 1); - xTextOffSet = xBoxOffSet + boxToTextXOffSet; - - // First, draw the surrounding box - for(uInt32 x = 0; x < boxWidth; ++x) - { - for(uInt32 y = 0; y < boxHeight; ++y) - { - uInt32 position = ((yBoxOffSet + y) * myWidth) + x + xBoxOffSet; - - if((x == 0) || (x == boxWidth - 1) || (y == 0) || (y == boxHeight - 1)) - buffer[position] = fontColor; - else - buffer[position] = backColor; - } - }*/ - - // Used to indicate the current x/y position of a pixel - uInt32 xPos, yPos; - - // The actual font data for a letter - uInt32 data; - -uInt32 xTextOffSet = xorig + 4; -uInt32 yTextOffSet = yorig + 4; uInt8 length = message.length(); - // Then, draw the text - for(uInt8 x = 0; x < length; ++x) + for(uInt32 x = 0; x < length; x++) { - char letter = message[x]; - - if((letter >= 'A') && (letter <= 'Z')) - data = ourFontData[(int)letter - 65]; - else if((letter >= '0') && (letter <= '9')) - data = ourFontData[(int)letter - 48 + 26]; - else // unknown character or space + for(uInt32 y = 0; y < FONTHEIGHT; y++) { - xTextOffSet += 4; - continue; - } - - // start scanning the font data from the bottom up - yPos = 7; - - for(uInt8 y = 0; y < 32; ++y) - { - // determine the correct scanline - xPos = y % 4; - if(xPos == 0) - --yPos; - - if((data >> y) & 1) + for(uInt32 z = 0; z < FONTWIDTH; z++) { - uInt32 position = (yPos + yTextOffSet) * myWidth + (4 - xPos) + xTextOffSet; - buffer[position] = FGCOLOR; + char letter = message[x]; + if((ourFontData[(letter << 3) + y] >> z) & 1) + buffer[(y + yorig)*myWidth + (x<<3) + z + xorig] = FGCOLOR; } } - - // move left to the next character - xTextOffSet += 5; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const uInt32 UserInterface::ourFontData[36] = { - 0x699f999, // A - 0xe99e99e, // B - 0x6988896, // C - 0xe99999e, // D - 0xf88e88f, // E - 0xf88e888, // F - 0x698b996, // G - 0x999f999, // H - 0x7222227, // I - 0x72222a4, // J - 0x9accaa9, // K - 0x888888f, // L - 0x9ff9999, // M - 0x9ddbb99, // N - 0x6999996, // O - 0xe99e888, // P - 0x69999b7, // Q - 0xe99ea99, // R - 0x6986196, // S - 0x7222222, // T - 0x9999996, // U - 0x9999966, // V - 0x9999ff9, // W - 0x99fff99, // X - 0x9996244, // Y - 0xf12488f, // Z - 0x69bd996, // 0 - 0x2622227, // 1 - 0x691248f, // 2 - 0x6916196, // 3 - 0xaaaf222, // 4 - 0xf88e11e, // 5 - 0x698e996, // 6 - 0xf112244, // 7 - 0x6996996, // 8 - 0x6997196 // 9 -}; - -/* uInt8* frontbuffer = myMediaSource->currentFrameBuffer(); - uInt8* backbuffer = myMediaSource->previousFrameBuffer(); - - // First, draw the surrounding box - for(uInt32 x = 0; x < 100; ++x) +void UserInterface::loadRemapMenu() +{ + // Fill the remap menu with the current key mappings + for(uInt32 i = 0; i < myRemapMenuItems; ++i) { - for(uInt32 y = 0; y < 100; ++y) + Event::Type event = ourRemapMenu[i].event; + ourRemapMenu[i].key = "None"; + string key = ""; + for(uInt32 j = 0; j < myKeyTableSize; ++j) { - uInt32 position = ((20 + y) * myWidth) + x + 20; + if(myKeyTable[j] == event) + { + if(key == "") + key = key + ourEventName[j]; + else + key = key + ", " + ourEventName[j]; - if((x == 0) || (x == 200 - 1) || (y == 0) || (y == 200 - 1)) - frontbuffer[position] = backbuffer[position] = 10; - else - frontbuffer[position] = backbuffer[position] = 0; + ourRemapMenu[i].key = key; + } } } -*/ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void UserInterface::addKeyBinding(Event::Type event, StellaEvent::KeyCode key) +{ + myKeyTable[key] = event; + + loadRemapMenu(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void UserInterface::deleteBinding(Event::Type event) +{ + for(uInt32 i = 0; i < myKeyTableSize; ++i) + if(myKeyTable[i] == event) + myKeyTable[i] = Event::NoType; + + loadRemapMenu(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const uInt8 UserInterface::ourFontData[2048] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x36,0x7f,0x7f,0x7f,0x3e,0x1c,0x08,0x00,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00,0x1c,0x3e,0x1c,0x7f,0x7f,0x3e,0x1c,0x3e,0x08,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x3e,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xf0,0xe0,0xf0,0xbe,0x33,0x33,0x33,0x1e,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0xfc,0xcc,0xfc,0x0c,0x0c,0x0e,0x0f,0x07,0xfe,0xc6,0xfe,0xc6,0xc6,0xe6,0x67,0x03,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99,0x01,0x07,0x1f,0x7f,0x1f,0x07,0x01,0x00,0x40,0x70,0x7c,0x7f,0x7c,0x70,0x40,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,0xfe,0xdb,0xdb,0xde,0xd8,0xd8,0xd8,0x00,0x7c,0xc6,0x1c,0x36,0x36,0x1c,0x33,0x1e,0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x18,0x30,0x7f,0x30,0x18,0x00,0x00,0x00,0x0c,0x06,0x7f,0x06,0x0c,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x7f,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00,0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00,0x3e,0x63,0x73,0x7b,0x6f,0x67,0x3e,0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00,0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x3f,0x03,0x1f,0x30,0x30,0x33,0x1e,0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06,0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x3f,0x00,0x00,0x3f,0x00,0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00, +0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00,0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x7c,0x00,0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00,0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x1c,0x36,0x63,0x63,0x63,0x36,0x1c,0x00,0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00,0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x1e,0x06,0x06,0x06,0x06,0x06,0x1e,0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00,0x1e,0x18,0x18,0x18,0x18,0x18,0x1e,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, +0x0c,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x07,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00,0x38,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f,0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00,0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00,0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00,0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00,0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x38,0x0c,0x0c,0x07,0x0c,0x0c,0x38,0x00,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x07,0x0c,0x0c,0x38,0x0c,0x0c,0x07,0x00,0x6e,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00, +0x1e,0x33,0x03,0x33,0x1e,0x18,0x30,0x1e,0x00,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x38,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x7e,0xc3,0x3c,0x60,0x7c,0x66,0xfc,0x00,0x33,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x07,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x0c,0x0c,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x00,0x00,0x1e,0x03,0x03,0x1e,0x30,0x1c,0x7e,0xc3,0x3c,0x66,0x7e,0x06,0x3c,0x00,0x33,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x07,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x33,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x3e,0x63,0x1c,0x18,0x18,0x18,0x3c,0x00,0x07,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00,0x0c,0x0c,0x00,0x1e,0x33,0x3f,0x33,0x00,0x38,0x00,0x3f,0x06,0x1e,0x06,0x3f,0x00,0x00,0x00,0xfe,0x30,0xfe,0x33,0xfe,0x00,0x7c,0x36,0x33,0x7f,0x33,0x33,0x73,0x00,0x1e,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x07,0x00,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x07,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x33,0x00,0x33,0x33,0x3e,0x30,0x1f,0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,0x33,0x00,0x33,0x33,0x33,0x33,0x1e,0x00,0x18,0x18,0x7e,0x03,0x03,0x7e,0x18,0x18,0x1c,0x36,0x26,0x0f,0x06,0x67,0x3f,0x00,0x33,0x33,0x1e,0x3f,0x0c,0x3f,0x0c,0x0c,0x1f,0x33,0x33,0x5f,0x63,0xf3,0x63,0xe3,0x70,0xd8,0x18,0x3c,0x18,0x18,0x1b,0x0e, +0x38,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x1c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x38,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x38,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x1f,0x00,0x1f,0x33,0x33,0x33,0x00,0x3f,0x00,0x33,0x37,0x3f,0x3b,0x33,0x00,0x3c,0x36,0x36,0x7c,0x00,0x7e,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00,0x0c,0x00,0x0c,0x06,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x3f,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x30,0x00,0x00,0xc3,0x63,0x33,0x7b,0xcc,0x66,0x33,0xf0,0xc3,0x63,0x33,0xdb,0xec,0xf6,0xf3,0xc0,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xdb,0xee,0xdb,0x77,0xdb,0xee,0xdb,0x77,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0x6f,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x7f,0x6c,0x6c,0x6c,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x7f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6f,0x60,0x7f,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0x7f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18, +0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xef,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xef,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xec,0x6c,0x6c,0x6c,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0xef,0x00,0xef,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfc,0x00,0x00,0x00,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xfc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xff,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, +0x00,0x00,0x6e,0x3b,0x13,0x3b,0x6e,0x00,0x00,0x1e,0x33,0x1f,0x33,0x1f,0x03,0x03,0x00,0x3f,0x33,0x03,0x03,0x03,0x03,0x00,0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00,0x3f,0x33,0x06,0x0c,0x06,0x33,0x3f,0x00,0x00,0x00,0x7e,0x1b,0x1b,0x1b,0x0e,0x00,0x00,0x66,0x66,0x66,0x66,0x3e,0x06,0x03,0x00,0x6e,0x3b,0x18,0x18,0x18,0x18,0x00,0x3f,0x0c,0x1e,0x33,0x33,0x1e,0x0c,0x3f,0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00,0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00,0x38,0x0c,0x18,0x3e,0x33,0x33,0x1e,0x00,0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x60,0x30,0x7e,0xdb,0xdb,0x7e,0x06,0x03,0x1c,0x06,0x03,0x1f,0x03,0x06,0x1c,0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x3f,0x00,0x06,0x0c,0x18,0x0c,0x06,0x00,0x3f,0x00,0x18,0x0c,0x06,0x0c,0x18,0x00,0x3f,0x00,0x70,0xd8,0xd8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x0e,0x0c,0x0c,0x00,0x3f,0x00,0x0c,0x0c,0x00,0x00,0x6e,0x3b,0x00,0x6e,0x3b,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xf0,0x30,0x30,0x30,0x37,0x36,0x3c,0x38,0x1e,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x0e,0x18,0x0c,0x06,0x1e,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +UserInterface::MainMenuItem UserInterface::ourMainMenu[2] = { + { REMAP_MENU, "Key Remapping" }, + { INFO_MENU, "Game Information" } +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +UserInterface::RemapMenuItem UserInterface::ourRemapMenu[23] = { + { Event::ConsoleSelect, "Select", "" }, + { Event::ConsoleReset, "Reset", "" }, + { Event::ConsoleColor, "Color TV", "" }, + { Event::ConsoleBlackWhite, "B/W TV", "" }, + { Event::ConsoleLeftDifficultyB, "P1 Diff. B", "" }, + { Event::ConsoleLeftDifficultyA, "P1 Diff. A", "" }, + { Event::ConsoleRightDifficultyB, "P2 Diff. B", "" }, + { Event::ConsoleRightDifficultyA, "P2 Diff. A", "" }, + { Event::SaveState, "Save State", "" }, + { Event::ChangeState, "Change State", "" }, + { Event::LoadState, "Load State", "" }, + { Event::TakeSnapshot, "Snapshot", "" }, + { Event::Pause, "Pause", "" }, + + { Event::JoystickZeroUp, "P1 Up", "" }, + { Event::JoystickZeroDown, "P1 Down", "" }, + { Event::JoystickZeroLeft, "P1 Left", "" }, + { Event::JoystickZeroRight, "P1 Right", "" }, + { Event::JoystickZeroFire, "P1 Fire", "" }, + + { Event::JoystickOneUp, "P2 Up", "" }, + { Event::JoystickOneDown, "P2 Down", "" }, + { Event::JoystickOneLeft, "P2 Left", "" }, + { Event::JoystickOneRight, "P2 Right", "" }, + { Event::JoystickOneFire, "P2 Fire", "" } + +// { Event::, "" }, +}; + +/** + This array must be initialized in a specific order, matching + there initialization in StellaEvent::KeyCode. + + The other option would be to create an array of structures + (in StellaEvent.hxx) containing event/string pairs. + This would eliminate the use of enumerations and slow down + lookups. So I do it this way instead. + */ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const char* UserInterface::ourEventName[StellaEvent::LastKCODE] = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + + "KP 0", "KP 1", "KP 2", "KP 3", "KP 4", "KP 5", "KP 6", "KP 7", "KP 8", + "KP 9", "KP .", "KP /", "KP *", "KP -", "KP +", "KP ENTER", "KP =", + + "BACKSP", "TAB", "ENTER", "PAUSE", "ESC", ",", ".", "/", ";", "\\", "\"", + "[", "]", "`", + + "CTRL", "ALT", "UP", "DOWN", "LEFT", "RIGHT", "SPACE", + + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" +}; + diff --git a/stella/src/emucore/UserInterface.hxx b/stella/src/emucore/UserInterface.hxx index 21d0fcc20..dc5990747 100644 --- a/stella/src/emucore/UserInterface.hxx +++ b/stella/src/emucore/UserInterface.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: UserInterface.hxx,v 1.4 2003-09-26 22:39:36 stephena Exp $ +// $Id: UserInterface.hxx,v 1.5 2003-09-28 21:59:24 stephena Exp $ //============================================================================ #ifndef USERINTERFACE_HXX @@ -31,7 +31,7 @@ class MediaSource; can be changed. @author Stephen Anthony - @version $Id: UserInterface.hxx,v 1.4 2003-09-26 22:39:36 stephena Exp $ + @version $Id: UserInterface.hxx,v 1.5 2003-09-28 21:59:24 stephena Exp $ */ class UserInterface { @@ -67,9 +67,6 @@ class UserInterface void sendJoyEvent(StellaEvent::JoyStick stick, StellaEvent::JoyCode code, Int32 state); - void sendKeymap(Event::Type table[StellaEvent::LastKCODE]); - void sendJoymap(Event::Type table[StellaEvent::LastJSTICK][StellaEvent::LastJCODE]); - public: void showMainMenu(bool show); void showMessage(const string& message); @@ -77,7 +74,7 @@ class UserInterface private: // Enumeration representing the different types of user interface widgets - enum Widget { W_NONE, MAIN_MENU, REMAP_MENU, INFO_MENU, MESSAGE }; + enum Widget { W_NONE, MAIN_MENU, REMAP_MENU, INFO_MENU }; Widget currentSelectedWidget(); Event::Type currentSelectedEvent(); @@ -85,11 +82,21 @@ class UserInterface void moveCursorUp(); void moveCursorDown(); - // Draw a bounded box centered horizontally - void drawBoundedBox(uInt32 width, uInt32 height); + // Draw a bounded box at the specified coordinates + void drawBoundedBox(uInt32 x, uInt32 y, uInt32 width, uInt32 height); // Draw message text at specified coordinates - void drawText(const string& message, uInt32 x, uInt32 y); + void drawText(uInt32 x, uInt32 y, const string& message); + + // scan the mapping arrays and update the remap menu + void loadRemapMenu(); + + // Add binding between a StellaEvent key and a core event + void addKeyBinding(Event::Type event, StellaEvent::KeyCode key); + + // Remove all bindings for this core event + void deleteBinding(Event::Type event); + private: // The Console for the system @@ -98,11 +105,29 @@ class UserInterface // The Mediasource for the system MediaSource* myMediaSource; + // Structure used for main menu items + struct MainMenuItem + { + Widget widget; + string action; + }; + + // Structure used for remap menu items + struct RemapMenuItem + { + Event::Type event; + string action; + string key; + }; + // Bounds for the window frame uInt32 myXStart, myYStart, myWidth, myHeight; - // Table of bitmapped fonts. Holds A..Z and 0..9. - static const uInt32 ourFontData[36]; + // Table of bitmapped fonts. + static const uInt8 ourFontData[2048]; + + // Table of strings representing the various StellaEvent codes + static const char* ourEventName[StellaEvent::LastKCODE]; // Type of interface item currently slated for redraw Widget myCurrentWidget; @@ -113,17 +138,45 @@ class UserInterface // Indicates the current selected event being remapped Event::Type mySelectedEvent; + // The maximum number of vertical lines of text that can be onscreen + uInt32 myMaxLines; + + // Keep track of current selected main menu item + uInt32 myMainMenuIndex, myMainMenuItems; + + // Keep track of current selected remap menu item + uInt32 myRemapMenuIndex, myRemapMenuLowIndex, myRemapMenuHighIndex; + uInt32 myRemapMenuItems, myRemapMenuMaxLines; + // Message timer Int32 myMessageTime; // Message text string myMessageText; + // The width of the information menu, determined by the longest string + uInt32 myInfoMenuWidth; + // Holds information about the current selected ROM image string ourPropertiesInfo[6]; - // The width of the information menu, determined by the longest string - uInt32 myInfoMenuWidth; + // Holds static strings for the main menu + static MainMenuItem ourMainMenu[2]; + + // Holds static strings for the remap menu + static RemapMenuItem ourRemapMenu[23]; + + // Holds the current key mappings + Event::Type* myKeyTable; + + // Holds the number of items in the keytable array + uInt32 myKeyTableSize; + + // Holds the current joystick mappings + Event::Type* myJoyTable; + + // Holds the number of items in the joytable array + uInt32 myJoyTableSize; }; #endif