diff --git a/Changes.txt b/Changes.txt index 2e7e3141c..b0ac84891 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,9 +22,15 @@ * Fixed major bug with joysticks, where mapping was being lost on reset, the app would crash when plugging/unplugging certain sticks, etc. + * Added dialog which shows the joystick database, and the ability to + remove (currently unplugged) joysticks from this database. + + * Added preliminary support for 'WD' (Wickstead Design) bankswitching + scheme. + * The minimum supported version for the OSX port is now OSX 10.7. Because of this, the 32-bit version is also discontinued, as 10.7 - is 64-bit Intel only. + supports 64-bit Intel only apps. * The debugger 'reset' command now does a complete system reset, instead of simply setting the PC to the reset vector address. diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 44598bb18..332144343 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -1251,6 +1251,22 @@ void EventHandler::setComboMap() saveComboMapping(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +VariantList EventHandler::joystickDatabase() const +{ + VariantList db; + for(const auto& i: myJoyHandler->database()) + VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1); + + return db; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandler::removeJoystickFromDatabase(const string& name) +{ + myJoyHandler->remove(name); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key) { diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 661f20cd0..2a5c55dd2 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -235,7 +235,7 @@ class EventHandler string keyAtIndex(int idx, EventMode mode) const; /** - Bind a key to an event/action and regenerate the mapping array(s) + Bind a key to an event/action and regenerate the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @@ -245,7 +245,7 @@ class EventHandler /** Bind a joystick axis direction to an event/action and regenerate - the mapping array(s) + the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @@ -262,7 +262,7 @@ class EventHandler /** Bind a joystick button to an event/action and regenerate the - mapping array(s) + mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @@ -277,7 +277,7 @@ class EventHandler /** Bind a joystick hat direction to an event/action and regenerate - the mapping array(s) + the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @@ -293,7 +293,7 @@ class EventHandler bool updateMenus = true); /** - Erase the specified mapping + Erase the specified mapping. @param event The event for which we erase all mappings @param mode The mode where this event is active @@ -301,7 +301,7 @@ class EventHandler void eraseMapping(Event::Type event, EventMode mode); /** - Resets the event mappings to default values + Resets the event mappings to default values. @param event The event which to (re)set (Event::NoType resets all) @param mode The mode for which the defaults are set @@ -315,12 +315,24 @@ class EventHandler /** Joystick emulates 'impossible' directions (ie, left & right - at the same time) + at the same time). @param allow Whether or not to allow impossible directions */ void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; } + /** + Return a list of all joysticks currently in the internal database + (first part of variant) and its internal ID (second part of variant). + */ + VariantList joystickDatabase() const; + + /** + Remove the joystick identified by 'name' from the joystick database, + only if it is not currently active. + */ + void removeJoystickFromDatabase(const string& name); + protected: // Global OSystem object OSystem& myOSystem; @@ -424,27 +436,7 @@ class EventHandler class JoystickHandler { - using StickList = map; - public: - JoystickHandler(OSystem& system); - ~JoystickHandler(); - - bool add(StellaJoystick* stick); - bool remove(int id); - void mapStelladaptors(const string& saport); - void setDefaultMapping(Event::Type type, EventMode mode); - void eraseMapping(Event::Type event, EventMode mode); - void saveMapping(); - - const StellaJoystick* joy(int id) const { - const auto& i = mySticks.find(id); - return i != mySticks.cend() ? i->second : nullptr; - } - const StickList& sticks() const { return mySticks; } - private: - OSystem& myOSystem; - struct StickInfo { StickInfo(const string& map = EmptyString, StellaJoystick* stick = nullptr) @@ -458,8 +450,34 @@ class EventHandler return os; } }; + + public: + using StickDatabase = map; + using StickList = map; + + JoystickHandler(OSystem& system); + ~JoystickHandler(); + + bool add(StellaJoystick* stick); + bool remove(int id); + bool remove(const string& name); + void mapStelladaptors(const string& saport); + void setDefaultMapping(Event::Type type, EventMode mode); + void eraseMapping(Event::Type event, EventMode mode); + void saveMapping(); + + const StellaJoystick* joy(int id) const { + const auto& i = mySticks.find(id); + return i != mySticks.cend() ? i->second : nullptr; + } + const StickDatabase& database() const { return myDatabase; } + const StickList& sticks() const { return mySticks; } + + private: + OSystem& myOSystem; + // Contains all joysticks that Stella knows about, indexed by name - map myDatabase; + StickDatabase myDatabase; // Contains only joysticks that are currently available, indexed by id StickList mySticks; diff --git a/src/emucore/EventJoyHandler.cxx b/src/emucore/EventJoyHandler.cxx index 48085a52a..a03799bae 100644 --- a/src/emucore/EventJoyHandler.cxx +++ b/src/emucore/EventJoyHandler.cxx @@ -393,6 +393,18 @@ bool EventHandler::JoystickHandler::remove(int id) return false; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool EventHandler::JoystickHandler::remove(const string& name) +{ + auto it = myDatabase.find(name); + if(it != myDatabase.end() && it->second.joy == nullptr) + { + myDatabase.erase(it); + return true; + } + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::mapStelladaptors(const string& saport) { diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index e3c8df49d..5e5e4def3 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -202,6 +202,12 @@ void InputDialog::addDevicePortTab(const GUI::Font& font) myHideCursor->clearFlags(WIDGET_ENABLED); #endif + // Show joystick database + xpos += 20; ypos += lineHeight + 8; + myJoyDlgButton = new ButtonWidget(myTab, font, xpos, ypos, + font.getStringWidth("Show Joystick Database") + 20, font.getLineHeight() + 4, + "Show Joystick Database", kDBButtonPressed); + // Add items for virtual device ports addToFocusList(wid, myTab, tabID); } @@ -412,6 +418,13 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, myMPaddleLabel->setValue(myMPaddleSpeed->getValue()); break; + case kDBButtonPressed: + if(!myJoyDialog) + myJoyDialog = make_ptr + (this, instance().frameBuffer().font(), _w-60, _h-60); + myJoyDialog->show(); + break; + default: Dialog::handleCommand(sender, cmd, data, 0); } diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index b78e84ee9..4f8d9dead 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -31,6 +31,7 @@ class SliderWidget; class StaticTextWidget; #include "Dialog.hxx" +#include "JoystickDialog.hxx" #include "bspf.hxx" class InputDialog : public Dialog @@ -58,7 +59,8 @@ class InputDialog : public Dialog enum { kDeadzoneChanged = 'DZch', kDPSpeedChanged = 'PDch', - kMPSpeedChanged = 'PMch' + kMPSpeedChanged = 'PMch', + kDBButtonPressed = 'DBbp' }; TabWidget* myTab; @@ -80,6 +82,11 @@ class InputDialog : public Dialog CheckboxWidget* myAllowAll4; CheckboxWidget* myGrabMouse; CheckboxWidget* myHideCursor; + + ButtonWidget* myJoyDlgButton; + + // Show the list of joysticks that the eventhandler knows about + unique_ptr myJoyDialog; }; #endif diff --git a/src/gui/JoystickDialog.cxx b/src/gui/JoystickDialog.cxx new file mode 100644 index 000000000..5dc45cfb1 --- /dev/null +++ b/src/gui/JoystickDialog.cxx @@ -0,0 +1,128 @@ +//============================================================================ +// +// 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-2014 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 "OSystem.hxx" +#include "Widget.hxx" +#include "EditTextWidget.hxx" +#include "StringListWidget.hxx" +#include "Variant.hxx" + +#include "JoystickDialog.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoystickDialog::JoystickDialog(GuiObject* boss, const GUI::Font& font, + int max_w, int max_h) + : Dialog(boss->instance(), boss->parent(), 0, 0, max_w, max_h) +{ + int xpos, ypos; + WidgetArray wid; + + int buttonWidth = font.getStringWidth("Close") + 20, + buttonHeight = font.getLineHeight() + 4; + + // Joystick list + xpos = 10; ypos = 10; + int w = _w - 2 * xpos; + int h = _h - buttonHeight - ypos - 20; + myJoyList = new StringListWidget(this, font, xpos, ypos, w, h); + wid.push_back(myJoyList); + + // Joystick ID + ypos = _h - buttonHeight - 10; + StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos, + font.getStringWidth("Joystick ID: "), font.getFontHeight(), + "Joystick ID: ", kTextAlignLeft); + xpos += t->getWidth() + 4; + myJoyText = new EditTextWidget(this, font, xpos, ypos-2, + font.getStringWidth("Unplugged")+8, font.getLineHeight(), ""); + myJoyText->setEditable(false); + + // Add buttons at bottom + xpos = _w - buttonWidth - 10; + myCloseBtn = new ButtonWidget(this, font, xpos, ypos, + buttonWidth, buttonHeight, "Close", kCloseCmd); + addOKWidget(myCloseBtn); addCancelWidget(myCloseBtn); + + buttonWidth = font.getStringWidth("Remove") + 20; + xpos -= buttonWidth + 5; + myRemoveBtn = new ButtonWidget(this, font, xpos, ypos, + buttonWidth, buttonHeight, "Remove", kRemoveCmd); + myRemoveBtn->clearFlags(WIDGET_ENABLED); + + // Now we can finally add the widgets to the focus list + wid.push_back(myRemoveBtn); + wid.push_back(myCloseBtn); + addToFocusList(wid); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoystickDialog::~JoystickDialog() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoystickDialog::loadConfig() +{ + myJoyIDs.clear(); + + StringList sticks; + for(const auto& i: instance().eventHandler().joystickDatabase()) + { + sticks.push_back(i.first); + myJoyIDs.push_back(i.second.toInt()); + } + myJoyList->setList(sticks); + if(sticks.size() > 0) + myJoyList->setSelected(0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoystickDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) +{ + switch(cmd) + { + case kOKCmd: + close(); + break; + + case kRemoveCmd: + instance().eventHandler().removeJoystickFromDatabase(myJoyList->getSelectedString()); + loadConfig(); + break; + + case ListWidget::kSelectionChangedCmd: + if(myJoyIDs[data] >= 0) + { + myRemoveBtn->setEnabled(false); + ostringstream buf; + buf << "J" << myJoyIDs[data]; + myJoyText->setText(buf.str()); + } + else + { + myRemoveBtn->setEnabled(true); + myJoyText->setText("Unplugged"); + } + break; + + default: + Dialog::handleCommand(sender, cmd, data, id); + break; + } +} diff --git a/src/gui/JoystickDialog.hxx b/src/gui/JoystickDialog.hxx new file mode 100644 index 000000000..26286771f --- /dev/null +++ b/src/gui/JoystickDialog.hxx @@ -0,0 +1,62 @@ +//============================================================================ +// +// 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-2014 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 JOYSTICK_DIALOG_HXX +#define JOYSTICK_DIALOG_HXX + +class GuiObject; +class ButtonWidget; +class EditTextWidgetWidget; +class StringListWidget; + +#include "Dialog.hxx" +#include "Command.hxx" +#include "DialogContainer.hxx" + +/** + * Show a listing of joysticks currently stored in the eventhandler database, + * and allow to remove those that aren't currently being used. + */ +class JoystickDialog : public Dialog +{ + public: + JoystickDialog(GuiObject* boss, const GUI::Font& font, + int max_w, int max_h); + virtual ~JoystickDialog(); + + /** Place the dialog onscreen and center it */ + void show() { open(); } + + private: + void loadConfig(); + void handleCommand(CommandSender* sender, int cmd, int data, int id); + + private: + StringListWidget* myJoyList; + EditTextWidget* myJoyText; + + ButtonWidget* myRemoveBtn; + ButtonWidget* myCloseBtn; + + IntArray myJoyIDs; + + enum { kRemoveCmd = 'JDrm' }; +}; + +#endif diff --git a/src/gui/module.mk b/src/gui/module.mk index a940b856d..6b836eac0 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -23,6 +23,7 @@ MODULE_OBJS := \ src/gui/HelpDialog.o \ src/gui/InputDialog.o \ src/gui/InputTextDialog.o \ + src/gui/JoystickDialog.o \ src/gui/Launcher.o \ src/gui/LauncherDialog.o \ src/gui/LauncherFilterDialog.o \