[Simulator] Asynchronous SimulatorInterface & a few new features. (#4738)
[opentx.git] / companion / src / simulation / joystickdialog.cpp
blobd2c87b2d66a6d6af58f9da43114bdc6c909f7a55
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "joystickdialog.h"
22 #include "ui_joystickdialog.h"
24 #include "boards.h"
25 #include "constants.h"
27 joystickDialog::joystickDialog(QWidget *parent, int stick) :
28 QDialog(parent),
29 ui(new Ui::joystickDialog),
30 step(0),
31 numAxes(0),
32 started(false)
34 ui->setupUi(this);
36 int jscaltmp[8][3] = {
37 {32767, 0, -32767},
38 {32767, 0, -32767},
39 {32767, 0, -32767},
40 {32767, 0, -32767},
41 {32767, 0, -32767},
42 {32767, 0, -32767},
43 {32767, 0, -32767},
44 {32767, 0, -32767}
46 memcpy(jscal, jscaltmp, sizeof (jscal));
48 foreach(QComboBox *cb, findChildren<QComboBox *>(QRegExp("jsmapCB_[0-9]+"))) {
49 populateSourceCombo(cb);
50 sticks[cb->property("channel").toUInt()] = cb;
52 foreach(QCheckBox *ib, findChildren<QCheckBox *>(QRegExp("ChInv_[0-9]+"))) {
53 invert[ib->property("channel").toUInt()] = ib;
55 foreach(QSlider *sl, findChildren<QSlider *>(QRegExp("Ch_[0-9]+"))) {
56 sliders[sl->property("channel").toUInt()] = sl;
59 for (int i = 0; i < MAX_JOYSTICKS; ++i) {
60 if (!g.joystick[i].existsOnDisk())
61 continue;
63 jscal[i][0] = g.joystick[i].stick_min();
64 jscal[i][1] = g.joystick[i].stick_med();
65 jscal[i][2] = g.joystick[i].stick_max();
66 sliders[i]->setMinimum(jscal[i][0]);
67 sliders[i]->setMaximum(jscal[i][2]);
68 invert[i]->setChecked(g.joystick[i].stick_inv());
69 sticks[i]->setCurrentIndex(sticks[i]->findData(g.joystick[i].stick_axe()));
72 ui->backButton->setEnabled(false);
74 ui->joystickChkB->setChecked(g.jsSupport() || stick > -1);
76 if (stick < 0)
77 stick = g.jsCtrl();
79 if (loadJoysticks(stick)) {
80 joystickSetEnabled(ui->joystickChkB->isChecked());
81 joystickOpen(ui->joystickCB->currentIndex());
83 else {
84 joystickSetEnabled(false);
86 loadStep();
88 connect(joystick, SIGNAL(axisValueChanged(int, int)), this, SLOT(onjoystickAxisValueChanged(int, int)));
89 connect(ui->joystickCB, SIGNAL(currentIndexChanged(int)), this, SLOT(joystickOpen(int)));
90 connect(ui->joystickChkB, SIGNAL(toggled(bool)), this, SLOT(joystickSetEnabled(bool)));
93 joystickDialog::~joystickDialog()
95 delete ui;
98 void joystickDialog::populateSourceCombo(QComboBox * cb)
100 int i;
101 cb->clear();
102 cb->addItem(tr("Not Assigned"), -1);
103 for (i=0; i < Board::STICK_AXIS_COUNT; ++i) {
104 cb->addItem(Boards::getAxisName(i) % tr(" Stick"), i);
106 for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS; ++i) {
107 cb->addItem(tr("Knob/Slider %1").arg(i - Board::STICK_AXIS_COUNT + 1), i);
111 bool joystickDialog::loadJoysticks(int stick)
113 QStringList joystickNames;
114 bool found = false;
116 ui->joystickCB->clear();
117 joystickNames << tr("No joysticks found");
118 joystick = new Joystick(0, false, 0, 0);
119 if ( joystick ) {
120 if ( joystick->joystickNames.count() > 0 ) {
121 joystickNames = joystick->joystickNames;
122 found = true;
124 joystick->close();
126 ui->joystickCB->insertItems(0, joystickNames);
127 if (found && stick < joystickNames.size()) {
128 ui->joystickCB->setCurrentIndex(stick);
130 else if (!found) {
131 joystickSetEnabled(false);
133 return found;
136 void joystickDialog::joystickOpen(int stick)
138 if (stick < 0)
139 return;
141 joystick = new Joystick(this, 1, false, 0);
142 if (joystick && joystick->open(stick)) {
143 numAxes = std::min(joystick->numAxes, MAX_JOYSTICKS);
144 for (int j=0; j<numAxes; j++) {
145 joystick->sensitivities[j] = 0;
146 joystick->deadzones[j]=20;
149 else {
150 QMessageBox::critical(this, tr("Error"), tr("Cannot open joystick."));
154 void joystickDialog::joystickSetEnabled(bool enable)
156 ui->joystickCB->setEnabled(enable);
157 ui->calibrationWidget->setEnabled(enable);
158 ui->nextButton->setEnabled(enable && step < 4);
159 ui->backButton->setEnabled(enable && step);
162 void joystickDialog::onjoystickAxisValueChanged(int axis, int value)
164 if (axis >= MAX_JOYSTICKS)
165 return;
167 if (started) {
168 if (value > jscal[axis][2])
169 jscal[axis][2] = value;
170 else if (value < jscal[axis][0])
171 jscal[axis][0] = value;
173 sliders[axis]->setMinimum(jscal[axis][0]);
174 sliders[axis]->setMaximum(jscal[axis][2]);
176 sliders[axis]->setInvertedAppearance(invert[axis]->isChecked());
177 sliders[axis]->setValue(value);
180 void joystickDialog::loadStep()
182 switch (step) {
183 case 0:
184 ui->howtoLabel->setText(tr("Press the Start button to start the stick range calibration procedure.\n" \
185 "You may change the channel assignments or inversion at any time."));
186 ui->backButton->setDisabled(true);
187 break;
188 case 1:
189 started = true;
190 ui->howtoLabel->setText(tr("Move sticks and pots in every direction making full movement\nPress Next when finished"));
191 ui->nextButton->setText(tr("Next"));
192 ui->backButton->setDisabled(true);
193 break;
194 case 2:
195 ui->howtoLabel->setText(tr("Place sticks and pots in middle position.\nPress Next when done"));
196 ui->backButton->setEnabled(true);
197 ui->nextButton->setEnabled(true);
198 break;
199 case 3:
200 for (int i=0; i < numAxes; i++) {
201 jscal[i][1]=0;
202 for (int j=0; j < 100; j++) {
203 jscal[i][1] += joystick->getAxisValue(i);
205 jscal[i][1] /= 100;
207 ui->howtoLabel->setText(tr("Map joystick channels to controls using comboboxes.\nPress Next when done."));
208 ui->nextButton->setEnabled(true);
209 break;
210 case 4:
211 ui->howtoLabel->setText(tr("Check inversion checkbox to if necessary to reverse direction.\nPress Next when done."));
212 ui->nextButton->setEnabled(true);
213 break;
214 case 5:
215 ui->howtoLabel->setText(tr("Press OK to save configuration\nPress Cancel to abort joystick calibration without saving."));
216 ui->nextButton->setDisabled(true);
220 void joystickDialog::on_backButton_clicked()
222 if (step) {
223 --step;
224 loadStep();
228 void joystickDialog::on_nextButton_clicked()
230 if (step < 5){
231 ++step;
232 loadStep();
236 void joystickDialog::on_cancelButton_clicked()
238 joystick->close();
239 this->reject();
242 void joystickDialog::on_okButton_clicked()
244 int stick;
246 g.jsSupport(ui->joystickChkB->isChecked());
247 g.jsCtrl(ui->joystickCB->currentIndex());
249 if (joystick)
250 joystick->close();
252 if (!g.jsSupport() || g.jsCtrl() < 0) {
253 this->accept();
254 return;
257 if (started && step < 4) {
258 int resp = QMessageBox::warning(this, tr("Warning"), tr("Calibration not complete, save anyway?"),
259 QDialogButtonBox::Ok | QMessageBox::Default, QDialogButtonBox::Cancel | QMessageBox::Escape, QMessageBox::NoButton);
260 if (resp == QDialogButtonBox::Cancel)
261 return;
264 for (int i = 0; i < MAX_JOYSTICKS; ++i) {
265 stick = sticks[i]->currentData().toInt();
266 if (stick < 0) {
267 g.joystick[i].stick_axe(-1);
269 else {
270 g.joystick[i].stick_axe(stick);
271 g.joystick[i].stick_max(jscal[i][2]);
272 g.joystick[i].stick_med(jscal[i][1]);
273 g.joystick[i].stick_min(jscal[i][0]);
274 g.joystick[i].stick_inv(invert[i]->isChecked() );
275 qDebug() << "joystick mapping " << sticks[i]->objectName() << "stick:" << i << "axe:" << stick;
279 this->accept();