diff --git a/Changes.txt b/Changes.txt
index eb495b099..ac82c7713 100644
--- a/Changes.txt
+++ b/Changes.txt
@@ -37,7 +37,7 @@
are no longer corrupted/cut off. This includes properly supporting the
2600-daptor II, which is flashable to an AVox-USB converter.
- * Added QuadTari controller support for josticks (TODO: doc, settings etc.)
+ * Added QuadTari controller support for several controllers (TODO: docs)
* Added option to select the audio device.
diff --git a/docs/index.html b/docs/index.html
index 699422419..f466e7413 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -268,24 +268,15 @@
Atari 2600 FPGA project, including cycle-exact audio, analog interference
from mixing of audio channels, as well as stereo sound support; dynamic
sound resampling is also included
-
Emulates the Atari 2600 Joystick Controllers using your computer's keyboard,
+ Emulates the Atari 2600 Joystick, Paddle, Driving, CBS BoosterGrip, Sega Genesis, QuadTari controllers using your computer's keyboard,
joysticks or mouse
- Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard
- Emulates the Atari 2600 Paddle Controllers using your computer's mouse, keyboard
- or joysticks
- Emulates the Atari 2600 Driving Controllers using your computer's keyboard,
- joysticks or mouse
- Emulates the CBS BoosterGrip Controller using your computer's keyboard,
- joysticks or mouse
- Emulates the Sega Genesis Controller using your computer's keyboard,
- joysticks or mouse
- Emulates CX22/CX80 style trackballs and Amiga/Atari Mouse using your
+ Emulates CX22/CX80 style Trackballs, Amiga/Atari Mouse, Mindlink controller and the Light Gun using your
computer's mouse
+ Emulates the Atari 2600 Keyboard controllers using your computer's keyboard
Emulates Spectravideo CompuMate system using your computer's keyboard,
including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to
to the actual keys on your keyboard
- Emulates the Mindlink Controller and the Light Gun using your computer's mouse
- Supports autodetection for most common controller types
+ Supports autodetection for most common controller types
Support for real Atari 2600 controllers using the
Stelladaptor and
2600-daptor/2600-daptor II
diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx
index 86835f54d..644d4e23b 100644
--- a/src/emucore/ControllerDetector.cxx
+++ b/src/emucore/ControllerDetector.cxx
@@ -699,6 +699,11 @@ bool ControllerDetector::isProbablyLightGun(const ByteBuffer& image, size_t size
bool ControllerDetector::isProbablyQuadTari(const ByteBuffer& image, size_t size,
Controller::Jack port)
{
+ uInt8 signatureBoth[] = { 0x1B, 0x1F, 0x0B, 0x0E, 0x1E, 0x0B, 0x1C, 0x13 }; // "QUADTARI"
+
+ if(searchForBytes(image, size, signatureBoth, 8))
+ return true;
+
if(port == Controller::Jack::Left)
{
uInt8 signature[] = { 'Q', 'U', 'A', 'D', 'L' };
@@ -711,8 +716,5 @@ bool ControllerDetector::isProbablyQuadTari(const ByteBuffer& image, size_t size
return searchForBytes(image, size, signature, 5);
}
-
- uInt8 signature[] = { 0x1B, 0x1F, 0x0B, 0x0E, 0x1E, 0x0B, 0x1C, 0x13 };
-
- return searchForBytes(image, size, signature, 8);
+ return false;
}
diff --git a/src/emucore/QuadTari.cxx b/src/emucore/QuadTari.cxx
index afac9294a..9b7b98190 100644
--- a/src/emucore/QuadTari.cxx
+++ b/src/emucore/QuadTari.cxx
@@ -65,17 +65,18 @@ QuadTari::QuadTari(Jack jack, OSystem& osystem, const System& system, const Prop
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr QuadTari::addController(const Controller::Type type, bool second)
{
+ FilesystemNode nvramfile = myOSystem.nvramDir();
+ Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
+ bool devSettings = os.settings().getBool("dev.settings");
+ if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
+ os.frameBuffer().showMessage(msg);
+ };
+
switch(type)
{
case Controller::Type::AtariVox:
{
- FilesystemNode nvramfile = myOSystem.nvramDir();
nvramfile /= "atarivox_eeprom.dat";
- Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
- bool devSettings = os.settings().getBool("dev.settings");
- if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
- os.frameBuffer().showMessage(msg);
- };
return make_unique(myJack, myEvent, mySystem,
myOSystem.settings().getString("avoxport"),
nvramfile, callback); // no alternative mapping here
@@ -85,13 +86,7 @@ unique_ptr QuadTari::addController(const Controller::Type type, bool
case Controller::Type::SaveKey:
{
- FilesystemNode nvramfile = myOSystem.nvramDir();
nvramfile /= "savekey_eeprom.dat";
- Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
- bool devSettings = os.settings().getBool("dev.settings");
- if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
- os.frameBuffer().showMessage(msg);
- };
return make_unique(myJack, myEvent, mySystem,
nvramfile, callback); // no alternative mapping here
}
diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx
index 69e485f93..a603a5a2d 100644
--- a/src/gui/GameInfoDialog.cxx
+++ b/src/gui/GameInfoDialog.cxx
@@ -31,6 +31,7 @@
#include "PopUpWidget.hxx"
#include "Props.hxx"
#include "PropsSet.hxx"
+#include "QuadTariDialog.hxx"
#include "TabWidget.hxx"
#include "TIAConstants.hxx"
#include "Widget.hxx"
@@ -236,10 +237,6 @@ GameInfoDialog::GameInfoDialog(
myLeftPortLabel->getTop()-1,
pwidth, lineHeight, ctrls, "", 0, kLeftCChanged);
wid.push_back(myLeftPort);
-
- myLeftQuadTari = new ButtonWidget(myTab, font, myLeftPort->getRight() + fontWidth * 2, myLeftPort->getTop() - 2,
- "QuadTari" + ELLIPSIS, kLeftQTPressed);
- wid.push_back(myLeftQuadTari);
ypos += lineHeight + VGAP;
myLeftPortDetected = new StaticTextWidget(myTab, ifont, myLeftPort->getLeft(), ypos,
@@ -252,17 +249,17 @@ GameInfoDialog::GameInfoDialog(
pwidth, lineHeight, ctrls, "", 0, kRightCChanged);
wid.push_back(myRightPort);
- myRightQuadTari = new ButtonWidget(myTab, font, myRightPort->getRight() + fontWidth * 2, myRightPort->getTop() - 2,
- "QuadTari" + ELLIPSIS, kRightQTPressed);
- wid.push_back(myRightQuadTari);
+ myQuadTariButton = new ButtonWidget(myTab, font, myRightPort->getRight() + fontWidth * 4, myRightPort->getTop() - 2,
+ "QuadTari" + ELLIPSIS, kQuadTariPressed);
+ wid.push_back(myQuadTariButton);
ypos += lineHeight + VGAP;
myRightPortDetected = new StaticTextWidget(myTab, ifont, myRightPort->getLeft(), ypos,
"Sega Genesis detected");
ypos += ifont.getLineHeight() + VGAP + 4;
- mySwapPorts = new CheckboxWidget(myTab, font, xpos + fontWidth * 2,
- myLeftPortDetected->getTop()-1, "Swap ports");
+ mySwapPorts = new CheckboxWidget(myTab, font, myLeftPort->getRight() + fontWidth * 4,
+ myLeftPort->getTop() + 1, "Swap ports");
wid.push_back(mySwapPorts);
// EEPROM erase button for left/right controller
@@ -601,8 +598,22 @@ void GameInfoDialog::saveProperties()
myGameProperties.set(PropType::Console_RightDiff, myRightDiffGroup->getSelected() ? "B" : "A");
// Controller properties
- myGameProperties.set(PropType::Controller_Left, myLeftPort->getSelectedTag().toString());
- myGameProperties.set(PropType::Controller_Right, myRightPort->getSelectedTag().toString());
+ string controller = myLeftPort->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Left, controller);
+ if(controller != "AUTO" && controller != "QUADTARI")
+ {
+ myGameProperties.set(PropType::Controller_Left1, "");
+ myGameProperties.set(PropType::Controller_Left2, "");
+ }
+
+ controller = myRightPort->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Right, controller);
+ if(controller != "AUTO" && controller != "QUADTARI")
+ {
+ myGameProperties.set(PropType::Controller_Right1, "");
+ myGameProperties.set(PropType::Controller_Right2, "");
+ }
+
myGameProperties.set(PropType::Console_SwapPorts, (mySwapPorts->isEnabled() && mySwapPorts->getState()) ? "YES" : "NO");
myGameProperties.set(PropType::Controller_SwapPaddles, mySwapPaddles->getState() ? "YES" : "NO");
@@ -715,8 +726,12 @@ void GameInfoDialog::updateControllerStates()
if(type == Controller::Type::Unknown)
{
if(instance().hasConsole())
+ {
label = (!swapPorts ? instance().console().leftController().name()
- : instance().console().rightController().name()) + " detected";
+ : instance().console().rightController().name() + " detected");
+ if(BSPF::startsWithIgnoreCase(label, "QUADTARI"))
+ label = "QuadTari detected"; // remove plugged-in controller names
+ }
else if(autoDetect)
label = ControllerDetector::detectName(image, size, type,
!swapPorts ? Controller::Jack::Left : Controller::Jack::Right,
@@ -730,8 +745,12 @@ void GameInfoDialog::updateControllerStates()
if(type == Controller::Type::Unknown)
{
if(instance().hasConsole())
+ {
label = (!swapPorts ? instance().console().rightController().name()
: instance().console().leftController().name()) + " detected";
+ if(BSPF::startsWithIgnoreCase(label, "QUADTARI"))
+ label = "QuadTari detected"; // remove plugged-in controller names
+ }
else if(autoDetect)
label = ControllerDetector::detectName(image, size, type,
!swapPorts ? Controller::Jack::Right : Controller::Jack::Left,
@@ -770,8 +789,10 @@ void GameInfoDialog::updateControllerStates()
myRightPortLabel->setEnabled(enableSelectControl);
myLeftPort->setEnabled(enableSelectControl);
myRightPort->setEnabled(enableSelectControl);
- myLeftQuadTari->setEnabled(BSPF::startsWithIgnoreCase(contrLeft, "QUADTARI"));
- myRightQuadTari->setEnabled(BSPF::startsWithIgnoreCase(contrRight, "QUADTARI"));
+ myQuadTariButton->setEnabled(BSPF::startsWithIgnoreCase(contrLeft, "QUADTARI") ||
+ BSPF::startsWithIgnoreCase(contrRight, "QUADTARI") ||
+ BSPF::startsWithIgnoreCase(myLeftPortDetected->getLabel(), "QUADTARI") ||
+ BSPF::startsWithIgnoreCase(myRightPortDetected->getLabel(), "QUADTARI"));
mySwapPorts->setEnabled(enableSelectControl);
mySwapPaddles->setEnabled(enablePaddles);
@@ -843,7 +864,7 @@ void GameInfoDialog::saveCurrentPropertiesToDisk()
void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
{
- switch (cmd)
+ switch(cmd)
{
case GuiObject::kOKCmd:
saveConfig();
@@ -871,12 +892,22 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
updateControllerStates();
break;
- case kLeftQTPressed:
- break;
+ case kQuadTariPressed:
+ {
+ bool enableLeft =
+ BSPF::startsWithIgnoreCase(myLeftPort->getSelectedTag().toString(), "QUADTARI") ||
+ BSPF::startsWithIgnoreCase(myLeftPortDetected->getLabel(), "QUADTARI");
+ bool enableRight =
+ BSPF::startsWithIgnoreCase(myRightPort->getSelectedTag().toString(), "QUADTARI") ||
+ BSPF::startsWithIgnoreCase(myRightPortDetected->getLabel(), "QUADTARI");
- case kRightQTPressed:
+ if(!myQuadTariDialog)
+ myQuadTariDialog = make_unique
+ (this, _font, _font.getMaxCharWidth() * 37, _font.getFontHeight() * 8,
+ myGameProperties);
+ myQuadTariDialog->show(enableLeft, enableRight);
break;
-
+ }
case kEEButtonPressed:
eraseEEPROM();
break;
diff --git a/src/gui/GameInfoDialog.hxx b/src/gui/GameInfoDialog.hxx
index b1b155f7a..19d1c29e3 100644
--- a/src/gui/GameInfoDialog.hxx
+++ b/src/gui/GameInfoDialog.hxx
@@ -26,6 +26,7 @@ class StaticTextWidget;
class RadioButtonGroup;
class TabWidget;
class SliderWidget;
+class QuadTariDialog;
#include "Dialog.hxx"
#include "Command.hxx"
@@ -87,8 +88,7 @@ class GameInfoDialog : public Dialog, public CommandSender
StaticTextWidget* myLeftPortDetected{nullptr};
PopUpWidget* myRightPort{nullptr};
StaticTextWidget* myRightPortDetected{nullptr};
- ButtonWidget* myLeftQuadTari{nullptr};
- ButtonWidget* myRightQuadTari{nullptr};
+ ButtonWidget* myQuadTariButton{nullptr};
CheckboxWidget* mySwapPorts{nullptr};
CheckboxWidget* mySwapPaddles{nullptr};
StaticTextWidget* myEraseEEPROMLabel{nullptr};
@@ -102,6 +102,9 @@ class GameInfoDialog : public Dialog, public CommandSender
PopUpWidget* myMouseY{nullptr};
SliderWidget* myMouseRange{nullptr};
+ // Allow assigning the four QuadTari controllers
+ unique_ptr myQuadTariDialog;
+
// Cartridge properties
EditTextWidget* myName{nullptr};
EditTextWidget* myMD5{nullptr};
@@ -116,8 +119,7 @@ class GameInfoDialog : public Dialog, public CommandSender
kPPBlendChanged = 'PBch',
kLeftCChanged = 'LCch',
kRightCChanged = 'RCch',
- kLeftQTPressed = 'LQTp',
- kRightQTPressed = 'RQTp',
+ kQuadTariPressed = 'QTpr',
kMCtrlChanged = 'MCch',
kEEButtonPressed = 'EEgb',
kPXCenterChanged = 'Pxch',
diff --git a/src/gui/QuadTariDialog.cxx b/src/gui/QuadTariDialog.cxx
new file mode 100644
index 000000000..dda63853b
--- /dev/null
+++ b/src/gui/QuadTariDialog.cxx
@@ -0,0 +1,200 @@
+//============================================================================
+//
+// 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-2020 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.
+//============================================================================
+
+#include "OSystem.hxx"
+#include "EventHandler.hxx"
+#include "Widget.hxx"
+#include "PopUpWidget.hxx"
+#include "Font.hxx"
+#include "Variant.hxx"
+#include "Props.hxx"
+#include "PropsSet.hxx"
+#include "QuadTariDialog.hxx"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+QuadTariDialog::QuadTariDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h,
+ Properties& properties)
+ : Dialog(boss->instance(), boss->parent(), font, "QuadTari controllers", 0, 0, max_w, max_h),
+ myGameProperties(properties)
+{
+ const int lineHeight = font.getLineHeight(),
+ fontHeight = font.getFontHeight(),
+ fontWidth = font.getMaxCharWidth(),
+ buttonHeight = font.getLineHeight() * 1.25;
+ const int VBORDER = fontHeight / 2;
+ const int HBORDER = fontWidth * 1.25;
+ const int VGAP = fontHeight / 4;
+
+ int xpos, ypos;
+ WidgetArray wid;
+ VariantList ctrls;
+
+ xpos = HBORDER; ypos = VBORDER + _th;
+
+ ctrls.clear();
+ //VarList::push_back(ctrls, "Auto-detect", "AUTO");
+ VarList::push_back(ctrls, "Joystick", "JOYSTICK");
+ //VarList::push_back(ctrls, "Paddles", "PADDLES");
+ //VarList::push_back(ctrls, "Paddles_IAxis", "PADDLES_IAXIS");
+ //VarList::push_back(ctrls, "Paddles_IAxDr", "PADDLES_IAXDR");
+ //VarList::push_back(ctrls, "BoosterGrip", "BOOSTERGRIP");
+ VarList::push_back(ctrls, "Driving", "DRIVING");
+ //VarList::push_back(ctrls, "Keyboard", "KEYBOARD");
+ //VarList::push_back(ctrls, "AmigaMouse", "AMIGAMOUSE");
+ //VarList::push_back(ctrls, "AtariMouse", "ATARIMOUSE");
+ //VarList::push_back(ctrls, "Trakball", "TRAKBALL");
+ VarList::push_back(ctrls, "AtariVox", "ATARIVOX");
+ VarList::push_back(ctrls, "SaveKey", "SAVEKEY");
+ //VarList::push_back(ctrls, "Sega Genesis", "GENESIS");
+ //VarList::push_back(ctrls, "KidVid", "KIDVID");
+ //VarList::push_back(ctrls, "Lightgun", "LIGHTGUN");
+ //VarList::push_back(ctrls, "MindLink", "MINDLINK");
+ //VarList::push_back(ctrls, "QuadTari", "QUADTARI");
+
+ int pwidth = font.getStringWidth("Joystick12"); // looks better overall
+
+ myLeftPortLabel = new StaticTextWidget(this, font, xpos, ypos + 1, "Left port");
+
+ ypos += lineHeight + VGAP * 2;
+ myLeft1Port = new PopUpWidget(this, font, xpos, ypos,
+ pwidth, lineHeight, ctrls, "P1 ");
+ wid.push_back(myLeft1Port);
+
+ ypos += lineHeight + VGAP * 2;
+ myLeft2Port = new PopUpWidget(this, font, xpos, ypos,
+ pwidth, lineHeight, ctrls, "P2 ");
+ wid.push_back(myLeft2Port);
+
+ xpos = _w - HBORDER - myLeft1Port->getWidth(); // aligned right
+ ypos = myLeftPortLabel->getTop() - 1;
+ myRightPortLabel = new StaticTextWidget(this, font, xpos, ypos + 1, "Right port");
+
+ ypos += lineHeight + VGAP * 2;
+ myRight1Port = new PopUpWidget(this, font, xpos, ypos,
+ pwidth, lineHeight, ctrls, "P3 ");
+ wid.push_back(myRight1Port);
+
+ ypos += lineHeight + VGAP * 2;
+ myRight2Port = new PopUpWidget(this, font, xpos, ypos,
+ pwidth, lineHeight, ctrls, "P4 ");
+ wid.push_back(myRight2Port);
+
+ addDefaultsOKCancelBGroup(wid, _font);
+ addBGroupToFocusList(wid);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::show(bool enableLeft, bool enableRight)
+{
+ myLeftPortLabel->setEnabled(enableLeft);
+ myLeft1Port->setEnabled(enableLeft);
+ myLeft2Port->setEnabled(enableLeft);
+ myRightPortLabel->setEnabled(enableRight);
+ myRight1Port->setEnabled(enableRight);
+ myRight2Port->setEnabled(enableRight);
+
+ open();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::loadControllerProperties(const Properties& props)
+{
+ string controller;
+
+ if(myLeftPortLabel->isEnabled())
+ {
+ controller = props.get(PropType::Controller_Left1);
+ myLeft1Port->setSelected(controller, "Joystick");
+ controller = props.get(PropType::Controller_Left2);
+ myLeft2Port->setSelected(controller, "Joystick");
+ }
+
+ if(myRightPortLabel->isEnabled())
+ {
+ controller = props.get(PropType::Controller_Right1);
+ myRight1Port->setSelected(controller, "Joystick");
+ controller = props.get(PropType::Controller_Right2);
+ myRight2Port->setSelected(controller, "Joystick");
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::loadConfig()
+{
+ loadControllerProperties(myGameProperties);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::saveConfig()
+{
+ if(myLeftPortLabel->isEnabled())
+ {
+ string controller = myLeft1Port->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Left1, controller);
+ controller = myLeft2Port->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Left2, controller);
+ }
+ else
+ {
+ myGameProperties.set(PropType::Controller_Left1, "");
+ myGameProperties.set(PropType::Controller_Left2, "");
+ }
+
+ if(myRightPortLabel->isEnabled())
+ {
+ string controller = myRight1Port->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Right1, controller);
+ controller = myRight2Port->getSelectedTag().toString();
+ myGameProperties.set(PropType::Controller_Right2, controller);
+ }
+ else
+ {
+ myGameProperties.set(PropType::Controller_Right1, "");
+ myGameProperties.set(PropType::Controller_Right2, "");
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::setDefaults()
+{
+ // Load the default properties
+ const string& md5 = myGameProperties.get(PropType::Cart_MD5);
+ Properties defaultProperties;
+
+ instance().propSet().getMD5(md5, defaultProperties, true);
+ loadControllerProperties(defaultProperties);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void QuadTariDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
+{
+ switch(cmd)
+ {
+ case GuiObject::kOKCmd:
+ saveConfig();
+ close();
+ break;
+
+ case GuiObject::kDefaultsCmd:
+ setDefaults();
+ break;
+
+ default:
+ Dialog::handleCommand(sender, cmd, data, id);
+ break;
+ }
+}
diff --git a/src/gui/QuadTariDialog.hxx b/src/gui/QuadTariDialog.hxx
new file mode 100644
index 000000000..070a0bd71
--- /dev/null
+++ b/src/gui/QuadTariDialog.hxx
@@ -0,0 +1,69 @@
+//============================================================================
+//
+// 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-2020 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.
+//============================================================================
+
+#ifndef JOYSTICK_DIALOG_HXX
+#define JOYSTICK_DIALOG_HXX
+
+class CommandSender;
+class PopUpWidget;
+
+#include "Dialog.hxx"
+
+/**
+ * Allow assigning controllers to the four QuadTari ports.
+ */
+class QuadTariDialog: public Dialog
+{
+ public:
+ QuadTariDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h,
+ Properties& properties);
+ ~QuadTariDialog() override = default;
+
+ /** Place the dialog onscreen */
+ void show(bool enableLeft, bool enableRight);
+
+ private:
+ void loadConfig() override;
+ void saveConfig() override;
+ void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
+
+ void setDefaults() override;
+
+ void loadControllerProperties(const Properties& props);
+
+ private:
+ StaticTextWidget* myLeftPortLabel{nullptr};
+ PopUpWidget* myLeft1Port{nullptr};
+ PopUpWidget* myLeft2Port{nullptr};
+
+ StaticTextWidget* myRightPortLabel{nullptr};
+ PopUpWidget* myRight1Port{nullptr};
+ PopUpWidget* myRight2Port{nullptr};
+
+ // Game properties for currently loaded ROM
+ Properties& myGameProperties;
+
+ private:
+ // Following constructors and assignment operators not supported
+ QuadTariDialog() = delete;
+ QuadTariDialog(const QuadTariDialog&) = delete;
+ QuadTariDialog(QuadTariDialog&&) = delete;
+ QuadTariDialog& operator=(const QuadTariDialog&) = delete;
+ QuadTariDialog& operator=(QuadTariDialog&&) = delete;
+};
+
+#endif
diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj
index 261ac76b9..f37614cda 100644
--- a/src/windows/Stella.vcxproj
+++ b/src/windows/Stella.vcxproj
@@ -773,6 +773,7 @@
+
@@ -1815,6 +1816,7 @@
+
diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters
index 6be678998..217dfaecf 100644
--- a/src/windows/Stella.vcxproj.filters
+++ b/src/windows/Stella.vcxproj.filters
@@ -1023,6 +1023,9 @@
Source Files\debugger
+
+ Source Files\gui
+
@@ -2102,6 +2105,9 @@
Header Files\debugger
+
+ Header Files\gui
+