]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/gui/controllertab.cpp
Fix for RISC SUBC opcode, more tweaks to controller config.
[virtualjaguar] / src / gui / controllertab.cpp
index a5b5328de18c4813909a2bbecbd0f55ddd993744..bc8274f3dd3ccd588693eb4bf8c362978357052f 100644 (file)
 #include "gamepad.h"
 #include "joystick.h"
 #include "keygrabber.h"
+#include "profile.h"
 
 
 ControllerTab::ControllerTab(QWidget * parent/*= 0*/): QWidget(parent),
-       label(new QLabel(tr("Controller:"))),
-       profileList(new QComboBox(this)),
+       label1(new QLabel(tr("Host Device:"))),
+       label2(new QLabel(tr("Map Name:"))),
+       label3(new QLabel(tr("Maps to:"))),
+       deviceList(new QComboBox(this)),
+       mapNameList(new QComboBox(this)),
+       mapToList(new QComboBox(this)),
+       addMapName(new QPushButton(tr("+"))),
+       deleteMapName(new QPushButton(tr("-"))),
        redefineAll(new QPushButton(tr("Define All Inputs"))),
        controllerWidget(new ControllerWidget(this))
 {
        QVBoxLayout * layout = new QVBoxLayout;
        QHBoxLayout * top = new QHBoxLayout;
+       QVBoxLayout * left = new QVBoxLayout;
+       QVBoxLayout * right = new QVBoxLayout;
+       QHBoxLayout * middle = new QHBoxLayout;
+       top->addLayout(left, 0);
+       top->addLayout(right, 1);
        layout->addLayout(top);
-       top->addWidget(label);
-       top->addWidget(profileList, 0, Qt::AlignLeft);
+       left->addWidget(label1, 0, Qt::AlignRight);
+       left->addWidget(label2, 0, Qt::AlignRight);
+       left->addWidget(label3, 0, Qt::AlignRight);
+       right->addWidget(deviceList);
+
+       right->addLayout(middle);
+       middle->addWidget(mapNameList, 1);
+       middle->addWidget(addMapName, 0);
+       middle->addWidget(deleteMapName, 0);
+
+       right->addWidget(mapToList);
        layout->addWidget(controllerWidget);
        layout->addWidget(redefineAll, 0, Qt::AlignHCenter);
        setLayout(layout);
@@ -40,15 +61,65 @@ ControllerTab::ControllerTab(QWidget * parent/*= 0*/): QWidget(parent),
        setFixedWidth(sizeHint().width());
 
        connect(redefineAll, SIGNAL(clicked()), this, SLOT(DefineAllKeys()));
-       connect(profileList, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeProfile(int)));
+       connect(deviceList, SIGNAL(activaed(int)), this, SLOT(ChangeDevice(int)));
+       connect(mapNameList, SIGNAL(activated(int)), this, SLOT(ChangeMapName(int)));
+       connect(addMapName, SIGNAL(clicked()), this, SLOT(AddMapName()));
+       connect(deleteMapName, SIGNAL(clicked()), this, SLOT(DeleteMapName()));
+       connect(controllerWidget, SIGNAL(KeyDefined(int, uint32_t)), this, SLOT(UpdateProfileKeys(int, uint32_t)));
+       connect(mapToList, SIGNAL(activated(int)), this, SLOT(UpdateProfileConnections(int)));
 
-       // Set up the profile combobox (Keyboard is the default, and always
+       // Set up the device combobox (Keyboard is the default, and always
        // present)
-       profileList->addItem(tr("Keyboard"));
+       deviceList->addItem(tr("Keyboard"), 0);
 
        for(int i=0; i<Gamepad::numJoysticks; i++)
-               profileList->addItem(Gamepad::GetJoystickName(i));
+       {
+               int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
+               deviceList->addItem(Gamepad::GetJoystickName(i), deviceNum);
+       }
+
+       // Set up "Map To" combobox
+       mapToList->addItem(tr("None"), 0);
+       mapToList->addItem(tr("Controller #1"), CONTROLLER1);
+       mapToList->addItem(tr("Controller #2"), CONTROLLER2);
+       mapToList->addItem(tr("Either one that's free"), CONTROLLER1 | CONTROLLER2);
 }
+/*
+So now we come to implementation. When changing devices, could have a helper function
+in profile.cpp that fills the mapNameList combobox with the appropriate names/profile
+numbers.
+
+There needs to be some way of getting data from the ControllerWidget and the current
+profile.
+
+Gamepad will have to have some way of knowing which profile is mapped to which
+Jaguar controllers and filtering out everything else.
+
+Will have to have some intelligent handling of profiles when first run, to see first
+what is connected and second, to assign profiles to Jaguar controllers. In this
+case, keyboard is the lowest priority--if a controller is plugged in and assigned to
+the same Jaguar controller as a keyboard, the controller is used. Not sure what to
+do in the case of multiple controllers plugged in and assigned to the same Jaguar
+controller.
+
+Also, need a way to load/save profiles.
+
+Meaning of checkboxes: None checked == profile not used.
+1 checked == prefer connection to Jaguar controller X.
+2 checked == no preference, use any available.
+
+Single mapping cannot be deleted ("-" will be disabled). Can always add, up to the max
+limit of profiles (MAX_PROFILES).
+
+------------------------------
+
+Now the main window passes in/removes the last edited profile #. From here, when starting
+up, we need to pull that number from the profile store and populate all our boxes.
+
+-------------------------------
+
+Need to do AutoConnectProfiles from here, and detect any conflicts
+*/
 
 
 ControllerTab::~ControllerTab()
@@ -56,6 +127,36 @@ ControllerTab::~ControllerTab()
 }
 
 
+void ControllerTab::SetupLastUsedProfile(void)
+{
+       int deviceNumIndex = deviceList->findData(profile[profileNum].device);
+       int mapNumIndex = mapNameList->findText(profile[profileNum].mapName);
+
+       if (deviceNumIndex == -1 || mapNumIndex == -1)
+       {
+               // We're doing the default, so set it up...
+//             mapToList->setCurrentIndex(mapToList->findData(profile[0].preferredController));
+//printf("ControllerTab::SetupLastUsedProfile: [FAILED] profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[0].preferredController);
+//             return;
+               deviceNumIndex = 0;
+               mapNumIndex = 0;
+               profileNum = 0;
+       }
+
+       deviceList->setCurrentIndex(deviceNumIndex);
+       mapNameList->setCurrentIndex(mapNumIndex);
+//no more: #warning "!!! bug in here where it doesn't save your preferred controller !!!"
+
+       int controllerIndex = mapToList->findData(profile[profileNum].preferredController);
+       mapToList->setCurrentIndex(controllerIndex);
+//printf("ControllerTab::SetupLastUsedProfile: profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[profileNum].preferredController);
+
+       // We have to do this manually, since it's no longer done automagically...
+       ChangeDevice(deviceNumIndex);
+       ChangeMapName(mapNumIndex);
+}
+
+
 void ControllerTab::DefineAllKeys(void)
 {
 //     char jagButtonName[21][10] = { "Up", "Down", "Left", "Right",
@@ -66,7 +167,6 @@ void ControllerTab::DefineAllKeys(void)
 
        for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
        {
-//             keyGrab.SetText(jagButtonName[orderToDefine[i]]);
                keyGrab.SetKeyText(orderToDefine[i]);
                keyGrab.exec();
                int key = keyGrab.key;
@@ -77,16 +177,113 @@ void ControllerTab::DefineAllKeys(void)
                // Otherwise, populate the appropriate spot in the settings & update screen...
                controllerWidget->keys[orderToDefine[i]] = key;
                controllerWidget->update();
+               profile[profileNum].map[orderToDefine[i]] = key;
        }
 }
 
 
-void ControllerTab::ChangeProfile(int profile)
+void ControllerTab::UpdateProfileKeys(int mapPosition, uint32_t key)
+{
+       profile[profileNum].map[mapPosition] = key;
+}
+
+
+void ControllerTab::UpdateProfileConnections(int selection)
+{
+//     profile[profileNum].preferredController = (controller1->isChecked() ? CONTROLLER1 : 0) | (controller2->isChecked() ? CONTROLLER2 : 0);
+       profile[profileNum].preferredController = mapToList->itemData(selection).toInt();
+//printf("Setting profile #%i 'Maps To' to %i...\n", profileNum, mapToList->itemData(selection).toInt());
+}
+
+
+void ControllerTab::ChangeDevice(int selection)
+{
+//printf("ControllerTab::ChangeDevice\n");
+       int deviceNum = deviceList->itemData(selection).toInt();
+       mapNameList->clear();
+       int numberOfMappings = FindMappingsForDevice(deviceNum, mapNameList);
+       deleteMapName->setDisabled(numberOfMappings == 1 ? true : false);
+//printf("Found %i mappings for device #%u...\n", numberOfMappings, deviceNum);
+}
+
+
+void ControllerTab::ChangeMapName(int selection)
 {
-printf("You selected profile: %s\n", (profile == 0 ? "Keyboard" : Gamepad::GetJoystickName(profile - 1)));
+//printf("ControllerTab::ChangeMapName\n");
+       profileNum = mapNameList->itemData(selection).toInt();
+//printf("You selected mapping: %s (profile #%u)\n", (mapNameList->itemText(selection)).toAscii().data(), profileNum);
+
+       for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
+               controllerWidget->keys[i] = profile[profileNum].map[i];
+
+       controllerWidget->update();
+//     controller1->setChecked(profile[profileNum].preferredController & CONTROLLER1);
+//     controller2->setChecked(profile[profileNum].preferredController & CONTROLLER2);
+       mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredController));
 }
 
+
+void ControllerTab::AddMapName(void)
+{
+       int freeProfile = GetFreeProfile();
+
+       if (freeProfile == -1)
+       {
+               // Oh crap, we're out of room! Alert the media!
+               // (Really, tho, we should pop this up *before* asking for user input.
+               // Which we now do!)
 #if 0
+               QMessageBox msg;
+               msg.setText(QString(tr("Can't create any more profiles!")));
+               msg.setIcon(QMessageBox::Warning);
+               msg.exec();
+#else
+               QMessageBox::warning(this, tr("Houston, we have a problem..."), tr("Can't create any more profiles!"));
+#endif
+
+               return;
+       }
+
+       QString text = QInputDialog::getText(this, tr("Add Map Name"), tr("Map name:"), QLineEdit::Normal);
+
+       if (text.isEmpty())
+               return;
+
+       // Add mapping...
+       profileNum = freeProfile;
+       profile[profileNum].device = deviceList->itemData(deviceList->currentIndex()).toInt();
+       strncpy(profile[profileNum].mapName, text.toAscii().data(), 31);
+       profile[profileNum].mapName[31] = 0;
+       profile[profileNum].preferredController = CONTROLLER1;
+
+       for(int i=BUTTON_FIRST; i<BUTTON_LAST; i++)
+               profile[profileNum].map[i] = '*';
+
+       mapNameList->addItem(text, profileNum);
+       mapNameList->setCurrentIndex(mapNameList->count() - 1);
+}
+
+
+void ControllerTab::DeleteMapName(void)
+{
+//printf("Delete current mapping (TODO)...\n");
+
+       // hmm, don't need to check this... Because presumably, it's already been checked for.
+//     if (mapNameList->count() == 1) ;
+
+       QMessageBox::StandardButton retVal = QMessageBox::question(this, tr("Remove Mapping"), tr("Are you sure you want to remove this mapping?"), QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
+
+       if (retVal == QMessageBox::No)
+               return;
+
+       int index = mapNameList->currentIndex();
+       int profileToRemove = profileNum;
+       mapNameList->removeItem(index);
+       DeleteProfile(profileToRemove);
+}
+
+
+/*
 The profiles need the following:
 
  - The name of the controller
@@ -129,5 +326,32 @@ data structure.
 When a new controller is plugged in with no profiles attached, it defaults to
 a set keyboard layout which the user can change. So every new controller will
 always have at least one profile.
-#endif
+
+Data structures:
+The Gamepad class has the name of the controller (except for Keyboard)
+The profile list is just a list
+The controller name index + profile index makes a unique key
+Probably the best way to deal with it is to stuff the name/profile indices
+into the key definition structure.
+
+#define CONTROLLER1 0x01
+#define CONTROLLER2 0x02
+
+struct Profile
+{
+       int device;                                     // Host device number
+       char mapName[32];                       // Human readable map name
+       int preferredController;        // CONTROLLER1 and/or CONTROLLER2
+       int map[21];                            // Keys/buttons/axes
+};
+
+NOTE that device is an int, and the list is maintained elsewhere. It is
+*not* the same as what you see in GetJoystickName(); the device names have
+to be able to persist even when not available.
+
+Where to store the master profile list? It has to be accessible to this class.
+vjs.profile[x] would be good, but it's not really a concern for the Jaguar core.
+So it shouldn't go there. There should be a separate global setting place for
+GUI stuff...
+*/