diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 19f9dd6ed..df1246034 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -618,14 +618,61 @@ void EventHandler::poll(uInt64 time) } case SDL_MOUSEMOTION: - handleMouseMotionEvent(event); + // Determine which mode we're in, then send the event to the appropriate place + if(myState == S_EMULATE) + { + if(myMouseEnabled) + { + int x = event.motion.xrel, y = event.motion.yrel; + myEvent->set(Event::MouseAxisXValue, x); + myEvent->set(Event::MouseAxisYValue, y); + } + } + else if(myOverlay) + { + int x = event.motion.x, y = event.motion.y; + myOverlay->handleMouseMotionEvent(x, y, 0); + } break; // SDL_MOUSEMOTION case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONDOWN: { uInt8 state = event.button.type == SDL_MOUSEBUTTONDOWN ? 1 : 0; - handleMouseButtonEvent(event, state); + + // Determine which mode we're in, then send the event to the appropriate place + if(myState == S_EMULATE) + { + if(myMouseEnabled) + myEvent->set(Event::MouseButtonValue, state); + } + else if(myOverlay) + { + // Take window zooming into account + Int32 x = event.button.x, y = event.button.y; + + switch(event.button.button) + { + case SDL_BUTTON_LEFT: + myOverlay->handleMouseButtonEvent( + state ? EVENT_LBUTTONDOWN : EVENT_LBUTTONUP, x, y, state); + break; + case SDL_BUTTON_RIGHT: + myOverlay->handleMouseButtonEvent( + state ? EVENT_RBUTTONDOWN : EVENT_RBUTTONUP, x, y, state); + break; + case SDL_BUTTON_WHEELDOWN: + if(state) + myOverlay->handleMouseButtonEvent(EVENT_WHEELDOWN, x, y, 1); + break; + case SDL_BUTTON_WHEELUP: + if(state) + myOverlay->handleMouseButtonEvent(EVENT_WHEELUP, x, y, 1); + break; + default: + break; + } + } break; // SDL_MOUSEBUTTONUP, SDL_MOUSEBUTTONDOWN } @@ -663,8 +710,17 @@ void EventHandler::poll(uInt64 time) // Filter out buttons handled by OSystem if(!myOSystem->joyButtonHandled(button)) - handleJoyEvent(stick, button, state); + { + // Handle buttons which switch eventhandler state + if(state && eventStateChange(myJoyTable[stick][button][kEmulationMode])) + return; + // Determine which mode we're in, then send the event to the appropriate place + if(myState == S_EMULATE) + handleEvent(myJoyTable[stick][button][kEmulationMode], state); + else if(myOverlay != NULL) + myOverlay->handleJoyEvent(stick, button, state); + } break; // Regular button case JT_STELLADAPTOR_LEFT: @@ -696,7 +752,46 @@ void EventHandler::poll(uInt64 time) { case JT_REGULAR: if(myState == S_EMULATE) - handleJoyAxisEvent(stick, axis, value); + { + // Every axis event has two associated values, negative and positive + Event::Type eventAxisNeg = myJoyAxisTable[stick][axis][0][kEmulationMode]; + Event::Type eventAxisPos = myJoyAxisTable[stick][axis][1][kEmulationMode]; + + // Check for analog events, which are handled differently + // We'll pass them off as Stelladaptor events, and let the controllers + // handle it + switch((int)eventAxisNeg) + { + case Event::PaddleZeroAnalog: + myEvent->set(Event::SALeftAxis0Value, value); + break; + case Event::PaddleOneAnalog: + myEvent->set(Event::SALeftAxis1Value, value); + break; + case Event::PaddleTwoAnalog: + myEvent->set(Event::SARightAxis0Value, value); + break; + case Event::PaddleThreeAnalog: + myEvent->set(Event::SARightAxis1Value, value); + break; + default: + { + // Otherwise, we know the event is digital + if(value > Joystick::deadzone()) + handleEvent(eventAxisPos, 1); + else if(value < -Joystick::deadzone()) + handleEvent(eventAxisNeg, 1); + else + { + // Turn off both events, since we don't know exactly which one + // was previously activated. + handleEvent(eventAxisNeg, 0); + handleEvent(eventAxisPos, 0); + } + break; + } + } + } else if(myOverlay != NULL) { // First, clamp the values to simulate digital input @@ -745,7 +840,7 @@ void EventHandler::poll(uInt64 time) break; // Preprocess all hat events, converting to Stella JoyHat type - // Generate two equivalent hat events representing combined direction + // Generate multiple equivalent hat events representing combined direction // when we get a diagonal hat event if(value == SDL_HAT_CENTERED) handleJoyHatEvent(stick, hat, EVENT_HATCENTER); @@ -808,123 +903,6 @@ void EventHandler::poll(uInt64 time) myEvent->set(Event::MouseAxisYValue, 0); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EventHandler::handleMouseMotionEvent(SDL_Event& event) -{ - // Determine which mode we're in, then send the event to the appropriate place - if(myState == S_EMULATE) - { - if(myMouseEnabled) - { - int x = event.motion.xrel, y = event.motion.yrel; - myEvent->set(Event::MouseAxisXValue, x); - myEvent->set(Event::MouseAxisYValue, y); - } - } - else if(myOverlay) - { - int x = event.motion.x, y = event.motion.y; - myOverlay->handleMouseMotionEvent(x, y, 0); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EventHandler::handleMouseButtonEvent(SDL_Event& event, int state) -{ - // Determine which mode we're in, then send the event to the appropriate place - if(myState == S_EMULATE) - { - if(myMouseEnabled) - myEvent->set(Event::MouseButtonValue, state); - } - else if(myOverlay) - { - // Take window zooming into account - Int32 x = event.button.x, y = event.button.y; - MouseButton button; - - switch(event.button.button) - { - case SDL_BUTTON_LEFT: - button = state ? EVENT_LBUTTONDOWN : EVENT_LBUTTONUP; - break; - case SDL_BUTTON_RIGHT: - button = state ? EVENT_RBUTTONDOWN : EVENT_RBUTTONUP; - break; - case SDL_BUTTON_WHEELDOWN: - if(state) button = EVENT_WHEELDOWN; - else return; - break; - case SDL_BUTTON_WHEELUP: - if(state) button = EVENT_WHEELUP; - else return; - break; - default: - return; - } - myOverlay->handleMouseButtonEvent(button, x, y, state); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EventHandler::handleJoyEvent(int stick, int button, int state) -{ -#ifdef JOYSTICK_SUPPORT - if(state && eventStateChange(myJoyTable[stick][button][kEmulationMode])) - return; - - // Determine which mode we're in, then send the event to the appropriate place - if(myState == S_EMULATE) - handleEvent(myJoyTable[stick][button][kEmulationMode], state); - else if(myOverlay != NULL) - myOverlay->handleJoyEvent(stick, button, state); -#endif -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EventHandler::handleJoyAxisEvent(int stick, int axis, int value) -{ -#ifdef JOYSTICK_SUPPORT - // Every axis event has two associated values, negative and positive - Event::Type eventAxisNeg = myJoyAxisTable[stick][axis][0][kEmulationMode]; - Event::Type eventAxisPos = myJoyAxisTable[stick][axis][1][kEmulationMode]; - - // Check for analog events, which are handled differently - // We'll pass them off as Stelladaptor events, and let the controllers - // handle it - switch((int)eventAxisNeg) - { - case Event::PaddleZeroAnalog: - myEvent->set(Event::SALeftAxis0Value, value); - break; - case Event::PaddleOneAnalog: - myEvent->set(Event::SALeftAxis1Value, value); - break; - case Event::PaddleTwoAnalog: - myEvent->set(Event::SARightAxis0Value, value); - break; - case Event::PaddleThreeAnalog: - myEvent->set(Event::SARightAxis1Value, value); - break; - default: - { - // Otherwise, we know the event is digital - int deadzone = Joystick::deadzone(); - if(value > -deadzone && value < deadzone) - { - // Turn off both events, since we don't know exactly which one - // was previously activated. - handleEvent(eventAxisNeg, 0); - handleEvent(eventAxisPos, 0); - } - else - handleEvent(value < 0 ? eventAxisNeg : eventAxisPos, 1); - break; - } - } -#endif -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleJoyHatEvent(int stick, int hat, JoyHat value) { @@ -1163,7 +1141,7 @@ void EventHandler::setActionMappings(EventMode mode) if(myJoyTable[stick][button][mode] == event) { buf.str(""); - buf << "J" << stick << " B" << button; + buf << "J" << stick << "/B" << button; if(key == "") key = key + buf.str(); else @@ -1181,16 +1159,16 @@ void EventHandler::setActionMappings(EventMode mode) if(myJoyAxisTable[stick][axis][dir][mode] == event) { buf.str(""); - buf << "J" << stick << " axis " << axis; + buf << "J" << stick << "/A" << axis; if(eventIsAnalog(event)) { dir = 2; // Immediately exit the inner loop after this iteration - buf << " abs"; + buf << "/+|-"; } else if(dir == 0) - buf << " neg"; + buf << "/-"; else - buf << " pos"; + buf << "/+"; if(key == "") key = key + buf.str(); @@ -1210,13 +1188,13 @@ void EventHandler::setActionMappings(EventMode mode) if(myJoyHatTable[stick][hat][dir][mode] == event) { buf.str(""); - buf << "J" << stick << " hat " << hat; + buf << "J" << stick << "/H" << hat; switch(dir) { - case EVENT_HATUP: buf << " up"; break; - case EVENT_HATDOWN: buf << " down"; break; - case EVENT_HATLEFT: buf << " left"; break; - case EVENT_HATRIGHT: buf << " right"; break; + case EVENT_HATUP: buf << "/up"; break; + case EVENT_HATDOWN: buf << "/down"; break; + case EVENT_HATLEFT: buf << "/left"; break; + case EVENT_HATRIGHT: buf << "/right"; break; } if(key == "") key = key + buf.str(); diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 2d7e2c33c..c6d8d0c51 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -325,38 +325,6 @@ class EventHandler void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; } private: - /** - Send a mouse motion event to the handler. - - @param event The mouse motion event generated by SDL - */ - void handleMouseMotionEvent(SDL_Event& event); - - /** - Send a mouse button event to the handler. - - @param event The mouse button event generated by SDL - */ - void handleMouseButtonEvent(SDL_Event& event, int state); - - /** - Send a joystick button event to the handler - - @param stick The joystick number - @param button The joystick button - @param state The state of the button (pressed or released) - */ - void handleJoyEvent(int stick, int button, int state); - - /** - Send a joystick axis event to the handler - - @param stick The joystick number - @param axis The joystick axis - @param value The value on the given axis - */ - void handleJoyAxisEvent(int stick, int axis, int value); - /** Send a joystick hat event to the handler diff --git a/src/gui/InputTextDialog.hxx b/src/gui/InputTextDialog.hxx index 01f19db76..9b588f3e0 100644 --- a/src/gui/InputTextDialog.hxx +++ b/src/gui/InputTextDialog.hxx @@ -30,8 +30,6 @@ class EditTextWidget; #include "Dialog.hxx" #include "Command.hxx" -typedef Common::Array InputWidget; - class InputTextDialog : public Dialog, public CommandSender { public: @@ -60,6 +58,8 @@ class InputTextDialog : public Dialog, public CommandSender virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: + typedef Common::Array InputWidget; + InputWidget myInput; StaticTextWidget* myTitle; diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 15a65a9e9..1beccfbe8 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -35,6 +35,7 @@ #include "OptionsDialog.hxx" #include "GlobalPropsDialog.hxx" #include "LauncherFilterDialog.hxx" +#include "MessageBox.hxx" #include "OSystem.hxx" #include "Props.hxx" #include "PropsSet.hxx" @@ -61,6 +62,7 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent, myMenu(NULL), myGlobalProps(NULL), myFilters(NULL), + myFirstRunMsg(NULL), myRomDir(NULL), mySelectedItem(0) { @@ -237,11 +239,19 @@ void LauncherDialog::loadConfig() // time running Stella; in this case, we should prompt the user if(romdir == "") { - if(!myRomDir) - myRomDir = new BrowserDialog(this, instance().font(), _w, _h); - - myRomDir->show("First startup -> Select ROM directory:", romdir, - FilesystemNode::kListDirectoriesOnly, kStartupRomDirChosenCmd); + if(!myFirstRunMsg) + { + StringList msg; + msg.push_back("This seems to be your first time running Stella."); + msg.push_back("Before you can start a game, you need to"); + msg.push_back("specify where your ROMs are located."); + msg.push_back(""); + msg.push_back("Click 'OK' to select a default ROM directory,"); + msg.push_back("or 'Cancel' to browse the filesystem manually."); + myFirstRunMsg = new MessageBox(this, instance().font(), msg, + kFirstRunMsgChosenCmd); + } + myFirstRunMsg->show(); } // Assume that if the list is empty, this is the first time that loadConfig() @@ -565,6 +575,15 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, instance().eventHandler().quit(); break; + case kFirstRunMsgChosenCmd: + // Show a file browser, starting from the users' home directory + if(!myRomDir) + myRomDir = new BrowserDialog(this, instance().font(), _w, _h); + + myRomDir->show("Select ROM directory:", "~", + FilesystemNode::kListDirectoriesOnly, kStartupRomDirChosenCmd); + break; + case kStartupRomDirChosenCmd: { FilesystemNode dir(myRomDir->getResult()); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index bdb35eb08..a20366abf 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -34,6 +34,7 @@ class BrowserDialog; class OptionsDialog; class GlobalPropsDialog; class LauncherFilterDialog; +class MessageBox; class OSystem; class Properties; class EditTextWidget; @@ -97,13 +98,15 @@ class LauncherDialog : public Dialog EditTextWidget* myPattern; GameList* myGameList; - OptionsDialog* myOptions; - RomInfoWidget* myRomInfoWidget; + OptionsDialog* myOptions; + RomInfoWidget* myRomInfoWidget; ContextMenu* myMenu; GlobalPropsDialog* myGlobalProps; LauncherFilterDialog* myFilters; - BrowserDialog* myRomDir; + + MessageBox* myFirstRunMsg; + BrowserDialog* myRomDir; int mySelectedItem; int myRomInfoSize; @@ -119,6 +122,7 @@ class LauncherDialog : public Dialog kOptionsCmd = 'OPTI', kQuitCmd = 'QUIT', + kFirstRunMsgChosenCmd = 'frmc', kStartupRomDirChosenCmd = 'rmsc' }; }; diff --git a/src/gui/MessageBox.cxx b/src/gui/MessageBox.cxx new file mode 100644 index 000000000..4fc7c91b3 --- /dev/null +++ b/src/gui/MessageBox.cxx @@ -0,0 +1,83 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#include "Dialog.hxx" +#include "OSystem.hxx" +#include "Version.hxx" +#include "Widget.hxx" + +#include "MessageBox.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +MessageBox::MessageBox(GuiObject* boss, const GUI::Font& font, + const StringList& text, int cmd) + : Dialog(&boss->instance(), &boss->parent(), 0, 0, 16, 16), + CommandSender(boss), + myCmd(cmd) +{ + const int lineHeight = font.getLineHeight(), + fontWidth = font.getMaxCharWidth(), + fontHeight = font.getFontHeight(); + int xpos, ypos; + WidgetArray wid; + + // Set real dimensions + _w = 50 * fontWidth + 8; + _h = (text.size() + 2) * lineHeight + 20; + + xpos = 10; ypos = 10; + for(uInt32 i = 0; i < text.size(); ++i) + { + new StaticTextWidget(this, font, xpos, ypos, _w - 20, + fontHeight, text[i], kTextAlignLeft); + ypos += fontHeight; + } + + addOKCancelBGroup(wid, font); + + addToFocusList(wid); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +MessageBox::~MessageBox() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void MessageBox::handleCommand(CommandSender* sender, int cmd, int data, int id) +{ + switch(cmd) + { + case kOKCmd: + { + close(); + + // Send a signal to the calling class that 'OK' has been selected + // Since we aren't derived from a widget, we don't have a 'data' or 'id' + if(myCmd) + sendCommand(myCmd, 0, 0); + + break; + } + + default: + Dialog::handleCommand(sender, cmd, data, id); + break; + } +} diff --git a/src/gui/MessageBox.hxx b/src/gui/MessageBox.hxx new file mode 100644 index 000000000..2b13b2f35 --- /dev/null +++ b/src/gui/MessageBox.hxx @@ -0,0 +1,52 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#ifndef MESSAGE_BOX_HXX +#define MESSAGE_BOX_HXX + +class GuiObject; +class StaticTextWidget; + +#include "Dialog.hxx" +#include "Command.hxx" +#include "DialogContainer.hxx" + +/** + * Show a simple message box containing the given text, with buttons + * prompting the user to accept or reject. If the user selects 'OK', + * the value of 'cmd' is returned. + */ +class MessageBox : public Dialog, public CommandSender +{ + public: + MessageBox(GuiObject* boss, const GUI::Font& font, const StringList& text, + int cmd = 0); + virtual ~MessageBox(); + + /** Place the input dialog onscreen and center it */ + void show() { parent().addDialog(this); } + + private: + virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); + + private: + int myCmd; +}; + +#endif diff --git a/src/gui/module.mk b/src/gui/module.mk index bb3bb6f42..9f3461150 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -25,6 +25,7 @@ MODULE_OBJS := \ src/gui/LauncherFilterDialog.o \ src/gui/ListWidget.o \ src/gui/Menu.o \ + src/gui/MessageBox.o \ src/gui/OptionsDialog.o \ src/gui/PopUpWidget.o \ src/gui/ProgressDialog.o \