]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/controllertab.cpp
89a678f380ddff453bce1b412735ba527813c5a2
[virtualjaguar] / src / gui / controllertab.cpp
1 //
2 // controllertab.cpp: "Controller" tab on the config dialog
3 //
4 // Part of the Virtual Jaguar Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // WHO  WHEN        WHAT
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
15 //
16
17 /*
18 To really fix this shit, we have to straighten out some stuff. So here goes:
19
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.
24
25 We have a a list of attached gamepads in Gamepad::. There can be 8 at most
26 attached any one time.
27
28 There are two game port slots that a controller can be hooked into.
29
30 So, what we need to do when configuring and/or using this system is this.
31
32  - Populate the device combobox with the list of attached devices from the
33    profile database.
34  - Populate the map to combobox with the profiles associated with that profile
35    device number.
36  - Save stuff when the user changes stuff (this happens already)
37 */
38
39 #include "controllertab.h"
40
41 #include "controllerwidget.h"
42 #include "gamepad.h"
43 #include "joystick.h"
44 #include "keygrabber.h"
45 #include "profile.h"
46
47
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))
59 {
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);
72
73         right->addLayout(middle);
74         middle->addWidget(mapNameList, 1);
75         middle->addWidget(addMapName, 0);
76         middle->addWidget(deleteMapName, 0);
77
78         right->addWidget(mapToList);
79         layout->addWidget(controllerWidget);
80         layout->addWidget(redefineAll, 0, Qt::AlignHCenter);
81         setLayout(layout);
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());
85
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)));
93
94         // Set up the device combobox (Keyboard is the default, and always
95         // present)
96         deviceList->addItem(tr("Keyboard"), 0);
97
98         for(int i=0; i<Gamepad::numJoysticks; i++)
99         {
100                 int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
101                 deviceList->addItem(Gamepad::GetJoystickName(i), deviceNum);
102         }
103
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);
109 }
110
111
112 ControllerTab::~ControllerTab()
113 {
114 }
115
116
117 void ControllerTab::SetupLastUsedProfile(void)
118 {
119         int deviceNumIndex = deviceList->findData(profile[profileNum].device);
120         int mapNumIndex = mapNameList->findText(profile[profileNum].mapName);
121
122         if (deviceNumIndex == -1 || mapNumIndex == -1)
123         {
124                 // We're doing the default, so set it up...
125                 deviceNumIndex = 0;
126                 mapNumIndex = 0;
127                 profileNum = 0;
128         }
129
130         deviceList->setCurrentIndex(deviceNumIndex);
131         mapNameList->setCurrentIndex(mapNumIndex);
132
133         int controllerIndex = mapToList->findData(profile[profileNum].preferredSlot);
134         mapToList->setCurrentIndex(controllerIndex);
135
136         // We have to do this manually, since it's no longer done automagically...
137         ChangeDevice(deviceNumIndex);
138         ChangeMapName(mapNumIndex);
139 }
140
141
142 void ControllerTab::DefineAllKeys(void)
143 {
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);
149
150         for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
151         {
152                 keyGrab.SetKeyText(orderToDefine[i]);
153                 keyGrab.exec();
154                 int key = keyGrab.key;
155
156                 if (key == Qt::Key_Escape)
157                         break;
158
159                 // Otherwise, populate the appropriate spot in the settings & update
160                 // the screen...
161                 controllerWidget->keys[orderToDefine[i]] = key;
162                 controllerWidget->update();
163                 profile[profileNum].map[orderToDefine[i]] = key;
164         }
165 }
166
167
168 void ControllerTab::UpdateProfileKeys(int mapPosition, uint32_t key)
169 {
170         profile[profileNum].map[mapPosition] = key;
171 }
172
173
174 void ControllerTab::UpdateProfileConnections(int selection)
175 {
176         profile[profileNum].preferredSlot = mapToList->itemData(selection).toInt();
177 }
178
179
180 void ControllerTab::ChangeDevice(int selection)
181 {
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
186         // device...
187         deleteMapName->setDisabled(numberOfMappings == 1 ? true : false);
188         // Set up new profile #...
189         ChangeMapName(0);
190 }
191
192
193 void ControllerTab::ChangeMapName(int selection)
194 {
195         profileNum = mapNameList->itemData(selection).toInt();
196
197         for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
198                 controllerWidget->keys[i] = profile[profileNum].map[i];
199
200         controllerWidget->update();
201         mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredSlot));
202 }
203
204
205 void ControllerTab::AddMapName(void)
206 {
207         int freeProfile = GetFreeProfile();
208
209         if (freeProfile == -1)
210         {
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!"));
213
214                 return;
215         }
216
217         QString text = QInputDialog::getText(this, tr("Add Map Name"), tr("Map name:"), QLineEdit::Normal);
218
219         if (text.isEmpty())
220                 return;
221
222         // Add mapping...
223         profileNum = freeProfile;
224         profile[profileNum].device = deviceList->itemData(deviceList->currentIndex()).toInt();
225         strncpy(profile[profileNum].mapName, text.toAscii().data(), 31);
226         profile[profileNum].mapName[31] = 0;
227         profile[profileNum].preferredSlot = CONTROLLER1;
228
229         for(int i=BUTTON_FIRST; i<BUTTON_LAST; i++)
230                 profile[profileNum].map[i] = '*';
231
232         mapNameList->addItem(text, profileNum);
233         mapNameList->setCurrentIndex(mapNameList->count() - 1);
234 }
235
236
237 void ControllerTab::DeleteMapName(void)
238 {
239         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);
240
241         if (retVal == QMessageBox::No)
242                 return;
243
244         int index = mapNameList->currentIndex();
245         int profileToRemove = profileNum;
246         mapNameList->removeItem(index);
247         DeleteProfile(profileToRemove);
248 }
249