2 // controllertab.cpp: "Controller" tab on the config dialog
4 // Part of the Virtual Jaguar Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
11 // --- ---------- ------------------------------------------------------------
12 // JLH 06/23/2011 Created this file
13 // JLH 07/20/2011 Fixed a bunch of stuff
14 // JLH 10/02/2014 Fixed even more stuff, related to the profile system
18 To really fix this shit, we have to straighten out some stuff. So here goes:
20 We have a database of profiles consisting of a device list (devices that have
21 been seen already) and map list (consisting of a key into the device list, a
22 human readable name, a preferred slot #, and a key/button mapping). This is a
23 list that can hold up to 64 different profiles.
25 We have a a list of attached gamepads in Gamepad::. There can be 8 at most
26 attached any one time.
28 There are two game port slots that a controller can be hooked into.
30 So, what we need to do when configuring and/or using this system is this.
32 - Populate the device combobox with the list of attached devices from the
34 - Populate the map to combobox with the profiles associated with that profile
36 - Save stuff when the user changes stuff (this happens already)
39 #include "controllertab.h"
41 #include "controllerwidget.h"
44 #include "keygrabber.h"
48 ControllerTab::ControllerTab(QWidget
* parent
/*= 0*/): QWidget(parent
),
49 label1(new QLabel(tr("Host Device:"))),
50 label2(new QLabel(tr("Map Name:"))),
51 label3(new QLabel(tr("Maps to:"))),
52 deviceList(new QComboBox(this)),
53 mapNameList(new QComboBox(this)),
54 mapToList(new QComboBox(this)),
55 addMapName(new QPushButton(tr("+"))),
56 deleteMapName(new QPushButton(tr("-"))),
57 redefineAll(new QPushButton(tr("Define All Inputs"))),
58 controllerWidget(new ControllerWidget(this))
60 QVBoxLayout
* layout
= new QVBoxLayout
;
61 QHBoxLayout
* top
= new QHBoxLayout
;
62 QVBoxLayout
* left
= new QVBoxLayout
;
63 QVBoxLayout
* right
= new QVBoxLayout
;
64 QHBoxLayout
* middle
= new QHBoxLayout
;
65 top
->addLayout(left
, 0);
66 top
->addLayout(right
, 1);
67 layout
->addLayout(top
);
68 left
->addWidget(label1
, 0, Qt::AlignRight
);
69 left
->addWidget(label2
, 0, Qt::AlignRight
);
70 left
->addWidget(label3
, 0, Qt::AlignRight
);
71 right
->addWidget(deviceList
);
73 right
->addLayout(middle
);
74 middle
->addWidget(mapNameList
, 1);
75 middle
->addWidget(addMapName
, 0);
76 middle
->addWidget(deleteMapName
, 0);
78 right
->addWidget(mapToList
);
79 layout
->addWidget(controllerWidget
);
80 layout
->addWidget(redefineAll
, 0, Qt::AlignHCenter
);
82 // At least by doing this, it keeps the QComboBox from resizing itself too
83 // large and breaking the layout. :-P
84 setFixedWidth(sizeHint().width());
86 connect(redefineAll
, SIGNAL(clicked()), this, SLOT(DefineAllKeys()));
87 connect(deviceList
, SIGNAL(activated(int)), this, SLOT(ChangeDevice(int)));
88 connect(mapNameList
, SIGNAL(activated(int)), this, SLOT(ChangeMapName(int)));
89 connect(addMapName
, SIGNAL(clicked()), this, SLOT(AddMapName()));
90 connect(deleteMapName
, SIGNAL(clicked()), this, SLOT(DeleteMapName()));
91 connect(controllerWidget
, SIGNAL(KeyDefined(int, uint32_t)), this, SLOT(UpdateProfileKeys(int, uint32_t)));
92 connect(mapToList
, SIGNAL(activated(int)), this, SLOT(UpdateProfileConnections(int)));
94 // Set up the device combobox (Keyboard is the default, and always
96 deviceList
->addItem(tr("Keyboard"), 0);
98 for(int i
=0; i
<Gamepad::numJoysticks
; i
++)
100 int deviceNum
= FindDeviceNumberForName(Gamepad::GetJoystickName(i
));
101 deviceList
->addItem(Gamepad::GetJoystickName(i
), deviceNum
);
104 // Set up "Map To" combobox
105 mapToList
->addItem(tr("None"), 0);
106 mapToList
->addItem(tr("Controller #1"), CONTROLLER1
);
107 mapToList
->addItem(tr("Controller #2"), CONTROLLER2
);
108 mapToList
->addItem(tr("Either one that's free"), CONTROLLER1
| CONTROLLER2
);
112 ControllerTab::~ControllerTab()
117 void ControllerTab::SetupLastUsedProfile(void)
119 int deviceNumIndex
= deviceList
->findData(profile
[profileNum
].device
);
120 int mapNumIndex
= mapNameList
->findText(profile
[profileNum
].mapName
);
122 if (deviceNumIndex
== -1 || mapNumIndex
== -1)
124 // We're doing the default, so set it up...
130 deviceList
->setCurrentIndex(deviceNumIndex
);
131 mapNameList
->setCurrentIndex(mapNumIndex
);
133 int controllerIndex
= mapToList
->findData(profile
[profileNum
].preferredSlot
);
134 mapToList
->setCurrentIndex(controllerIndex
);
136 // We have to do this manually, since it's no longer done automagically...
137 ChangeDevice(deviceNumIndex
);
138 ChangeMapName(mapNumIndex
);
142 void ControllerTab::DefineAllKeys(void)
144 // char jagButtonName[21][10] = { "Up", "Down", "Left", "Right",
145 // "*", "7", "4", "1", "0", "8", "5", "2", "#", "9", "6", "3",
146 // "A", "B", "C", "Option", "Pause" };
147 int orderToDefine
[21] = { 0, 1, 2, 3, 18, 17, 16, 20, 19, 7, 11, 15, 6, 10, 14, 5, 9, 13, 8, 4, 12 };
148 KeyGrabber
keyGrab(this);
150 for(int i
=BUTTON_FIRST
; i
<=BUTTON_LAST
; i
++)
152 keyGrab
.SetKeyText(orderToDefine
[i
]);
154 int key
= keyGrab
.key
;
156 if (key
== Qt::Key_Escape
)
159 // Otherwise, populate the appropriate spot in the settings & update
161 controllerWidget
->keys
[orderToDefine
[i
]] = key
;
162 controllerWidget
->update();
163 profile
[profileNum
].map
[orderToDefine
[i
]] = key
;
168 void ControllerTab::UpdateProfileKeys(int mapPosition
, uint32_t key
)
170 profile
[profileNum
].map
[mapPosition
] = key
;
174 void ControllerTab::UpdateProfileConnections(int selection
)
176 profile
[profileNum
].preferredSlot
= mapToList
->itemData(selection
).toInt();
180 void ControllerTab::ChangeDevice(int selection
)
182 int deviceNum
= deviceList
->itemData(selection
).toInt();
183 mapNameList
->clear();
184 int numberOfMappings
= FindMappingsForDevice(deviceNum
, mapNameList
);
185 // Make sure to disable the "-" button is there's only one mapping for this
187 deleteMapName
->setDisabled(numberOfMappings
== 1 ? true : false);
188 // Set up new profile #...
193 void ControllerTab::ChangeMapName(int selection
)
195 profileNum
= mapNameList
->itemData(selection
).toInt();
197 for(int i
=BUTTON_FIRST
; i
<=BUTTON_LAST
; i
++)
198 controllerWidget
->keys
[i
] = profile
[profileNum
].map
[i
];
200 controllerWidget
->update();
201 mapToList
->setCurrentIndex(mapToList
->findData(profile
[profileNum
].preferredSlot
));
205 void ControllerTab::AddMapName(void)
207 int freeProfile
= GetFreeProfile();
209 if (freeProfile
== -1)
211 // Oh crap, we're out of room! Alert the media!
212 QMessageBox::warning(this, tr("Houston, we have a problem..."), tr("Can't create any more profiles!"));
217 QString text
= QInputDialog::getText(this, tr("Add Map Name"), tr("Map name:"), QLineEdit::Normal
);
223 profileNum
= freeProfile
;
224 profile
[profileNum
].device
= deviceList
->itemData(deviceList
->currentIndex()).toInt();
225 strncpy(profile
[profileNum
].mapName
, text
.toUtf8().data(), 31);
226 profile
[profileNum
].mapName
[31] = 0;
227 profile
[profileNum
].preferredSlot
= CONTROLLER1
;
229 for(int i
=BUTTON_FIRST
; i
<=BUTTON_LAST
; i
++)
230 profile
[profileNum
].map
[i
] = '*';
232 mapNameList
->addItem(text
, profileNum
);
234 mapNameList
->setCurrentIndex(mapNameList
->count() - 1);
236 int selection
= mapNameList
->count() - 1;
237 mapNameList
->setCurrentIndex(selection
);
238 ChangeMapName(selection
);
239 // We just added a new mapping, so enable the delete button!
240 deleteMapName
->setDisabled(false);
245 void ControllerTab::DeleteMapName(void)
247 QString msg
= QString("Map name: %1\n\nAre you sure you want to remove this mapping?").arg(profile
[profileNum
].mapName
);
249 // 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);
250 QMessageBox::StandardButton retVal
= QMessageBox::question(this, tr("Remove Mapping"), msg
, QMessageBox::No
| QMessageBox::Yes
, QMessageBox::No
);
252 if (retVal
== QMessageBox::No
)
255 int index
= mapNameList
->currentIndex();
256 int profileToRemove
= profileNum
;
257 mapNameList
->removeItem(index
);
258 DeleteProfile(profileToRemove
);
259 // We need to reload the profile that we move to after deleting the current
261 ChangeMapName(mapNameList
->currentIndex());
262 // If we get down to one profile left for the device, we need to make sure
263 // that the user can't delete it!
264 deleteMapName
->setDisabled(mapNameList
->count() == 1 ? true : false);