Also play model name on model changes (#5416)
[opentx.git] / companion / src / wizarddialog.cpp
blobe681cfc6ea506f13417ad8f34eda328a7791902c
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 "wizarddialog.h"
22 #include "wizarddata.h"
23 #include "helpers.h"
25 WizardDialog::WizardDialog(const GeneralSettings & settings, unsigned int modelId, const ModelData & modelData, QWidget *parent):
26 QWizard(parent),
27 mix(settings, modelId, modelData),
28 settings(settings)
30 setWindowIcon(CompanionIcon("wizard.png"));
31 setWindowTitle(tr("Model Wizard"));
33 setPage(Page_Models, new ModelSelectionPage(this, "models", tr("Model Type"), tr("Enter model name and model type.")));
34 setPage(Page_Throttle, new ThrottlePage(this, "throttle", tr("Throttle"), tr("Has your model got a motor or an engine?"), Page_Wingtypes));
35 setPage(Page_Wingtypes, new WingtypeSelectionPage(this, "wingtype", tr("Wing Type"), tr("Is your model a flying wing/deltawing or has it a standard wing configuration?")));
36 setPage(Page_Ailerons, new AileronsPage(this, "ailerons", tr("Ailerons"), tr("Has your model got ailerons?"), Page_Flaps));
37 setPage(Page_Flaps, new FlapsPage(this, "flaps", tr("Flaps"), tr("Has your model got flaps?"), Page_Airbrakes));
38 setPage(Page_Airbrakes, new AirbrakesPage(this, "airbrakes", tr("Airbrakes"), tr("Has your model got airbrakes?"), Page_Tails));
39 setPage(Page_Elevons, new ElevonsPage(this, "elevons", tr("Flying-wing / Delta-wing"), tr("Select the elevons channels"), Page_Rudder));
40 setPage(Page_Rudder, new RudderPage(this, "rudder", tr("Rudder"), tr("Does your model have a rudder?"), Page_Options));
41 setPage(Page_Tails, new TailSelectionPage(this, "tails", tr("Tail Type"), tr("Select which type of tail your model is equiped with.")));
42 setPage(Page_Tail, new TailPage(this, "tail", tr("Tail"), tr("Select channels for tail control."), Page_Options));
43 setPage(Page_Vtail, new VTailPage(this, "vtail", tr("V-Tail"), tr("Select channels for tail control."), Page_Options));
44 setPage(Page_Simpletail, new SimpleTailPage(this, "simpletail", tr("Tail"), tr("Select elevator channel."), Page_Options));
45 setPage(Page_Cyclic, new CyclicPage(this, "cyclic", tr("Cyclic"), tr("Which type of swash control is installed in your helicopter?"), Page_Gyro));
46 setPage(Page_Gyro, new GyroPage(this, "gyro", tr("Tail Gyro"), tr("Has your helicopter got an adjustable gyro for the tail?"), Page_Flybar));
47 setPage(Page_Flybar, new FlybarSelectionPage(this, "flybar", tr("Rotor Type"), tr("Has your helicopter got a flybar?")));
48 setPage(Page_Fblheli, new FblPage(this, "fblheli", tr("Helicopter"), tr("Select the controls for your helicopter"), Page_Options));
49 setPage(Page_Helictrl, new HeliPage(this, "helictrl", tr("Helicopter"), tr("Select the controls for your helicopter"), Page_Options));
50 setPage(Page_Multirotor, new MultirotorPage(this, "multirotor", tr("Multirotor"), tr("Select the control channels for your multirotor"), Page_Options));
51 setPage(Page_Options, new OptionsPage(this, "options", tr("Model Options"), tr("Select additional options"), Page_Conclusion));
52 setPage(Page_Conclusion, new ConclusionPage(this, "conclusion", tr("Save Changes"), tr(
53 "Manually check the direction of each control surface and reverse any channels that make controls move in the wrong direction. "
54 "Remove the propeller/propellers before you try to control your model for the first time.<br>"
55 "Please note that continuing removes all old model settings!"), -1));
56 setStartId(Page_Models);
58 // Workaround for Qt radio button rendering issue on Mac
59 Q_FOREACH(QAbstractButton * rb, findChildren<QAbstractButton *>()) {
60 rb->setAttribute(Qt::WA_LayoutUsesWidgetRect);
63 setWizardStyle(ModernStyle);
64 setOption(QWizard::NoCancelButton, false);
65 setOption(HaveHelpButton, true);
66 connect(this, SIGNAL(helpRequested()), this, SLOT(showHelp()));
69 void WizardDialog::showHelp()
71 QString message;
73 switch (currentId()) {
74 case Page_Models:
75 message = tr("Enter a name for your model and select model type.");
76 break;
77 case Page_Throttle:
78 message = tr("Select the receiver channel that is connected to your ESC or throttle servo.<br><br>"
79 "Throttle - Spektrum: CH1, Futaba: CH3");
80 break;
81 case Page_Wingtypes:
82 message = tr("Most aircraft have a main wing and a tail with control surfaces. Flying wings and delta winged aircraft only have a single wing. "
83 "The main control surface on a standard wing controls the roll of the aircraft. This surface is called an aileron.<br>"
84 "The control surface of a delta wing controls both roll and pitch. This surface is called an elevon. ");
85 break;
86 case Page_Ailerons:
87 message = tr("Models use one or two channels to control the ailerons.<br>"
88 "A so called Y-cable can be used to connect a single receiver channel to two separate aileron servos. "
89 "If your servos are connected by a Y-cable you should select the single-servo option.<br><br>"
90 "Aileron - Spektrum: CH2, Futaba: CH1");
91 break;
92 case Page_Flaps:
93 message = tr("This wizard assumes that your flaps are controlled by a switch. "
94 "If your flaps are controlled by a potentiometer you can change that manually later.");
95 break;
96 case Page_Airbrakes:
97 message = tr("Air brakes are used to reduce the speed of advanced sail planes.<br>"
98 "They are very uncommon on other types of planes.");
99 break;
100 case Page_Elevons:
101 message = tr("Models use two channels to control the elevons.<br>"
102 "Select these two channels");
103 break;
104 case Page_Rudder:
105 message = tr("Select the receiver channel that is connected to your rudder.<br><br>"
106 "Rudder - Spektrum: CH4, Futaba: CH4");
107 break;
108 case Page_Tails:
109 message = tr("Select the tail type of your plane.");
110 break;
111 case Page_Tail:
112 message = tr("Select the Rudder and Elevator channels.<br><br>"
113 "Rudder - Spektrum: CH4, Futaba: CH4<br>"
114 "Elevator - Spektrum: CH3, Futaba: CH2");
115 break;
116 case Page_Vtail:
117 message = tr("Select the Rudder and Elevator channels.<br><br>"
118 "Rudder - Spektrum: CH4, Futaba: CH4<br>"
119 "Elevator - Spektrum: CH3, Futaba: CH2");
120 break;
121 case Page_Simpletail:
122 message = tr("Select the Elevator channel.<br><br>"
123 "Elevator - Spektrum: CH3, Futaba: CH2");
124 break;
125 case Page_Flybar:
126 message = tr("TBD.");
127 break;
128 case Page_Cyclic:
129 message = tr("TBD.");
130 break;
131 case Page_Gyro:
132 message = tr("TBD.");
133 break;
134 case Page_Fblheli:
135 message = tr("TBD.");
136 break;
137 case Page_Helictrl:
138 message = tr("TBD.");
139 break;
140 case Page_Multirotor:
141 message = tr("Select the control channels for your multirotor.<br><br>"
142 "Throttle - Spektrum: CH1, Futaba: CH3<br>"
143 "Yaw - Spektrum: CH4, Futaba: CH4<br>"
144 "Pitch - Spektrum: CH3, Futaba: CH2<br>"
145 "Roll - Spektrum: CH2, Futaba: CH1");
146 break;
147 case Page_Options:
148 message = tr("TBD.");
149 break;
150 case Page_Conclusion:
151 message = tr("TBD.");
152 break;
153 default:
154 message = tr("There is no help available for the current page.");
157 QMessageBox::information(this, tr("Model Wizard Help"), message);
160 StandardPage::StandardPage(WizardPage currentPage, WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
161 QWizardPage(),
162 wizDlg(dlg),
163 pageCurrent(currentPage),
164 pageFollower(nextPage)
166 setTitle(title);
167 setPixmap(QWizard::WatermarkPixmap, QPixmap(QString(":/images/wizard/%1.png").arg(image)));
168 topLabel = new QLabel(text+"<br>");
169 topLabel->setWordWrap(true);
171 QVBoxLayout *layout = new QVBoxLayout;
172 layout->addWidget(topLabel);
173 setLayout(layout);
176 int StandardPage::getDefaultChannel(const Input input)
178 return wizDlg->settings.getDefaultChannel(input-1);
181 int StandardPage::nextFreeChannel(int channel)
183 for(int i=channel;i<8; i++)
184 if (wizDlg->mix.channel[i].page == Page_None)
185 return i;
186 return -1;
189 int StandardPage::totalChannelsAvailable()
191 int c = 0;
192 for(int i=0; i<WIZ_MAX_CHANNELS; i++)
193 if (wizDlg->mix.channel[i].page == Page_None)
194 c++;
196 return c;
199 void StandardPage::populateCB(QComboBox *cb, int preferred)
201 cb->clear();
203 // Add all unbooked channels and select the preferred one
204 for (int i=0; i<WIZ_MAX_CHANNELS; i++) {
205 if (wizDlg->mix.channel[i].page == Page_None) {
206 cb->addItem(tr("Channel %1").arg(i+1), i);
207 if (preferred == i) {
208 cb->setCurrentIndex(cb->count()-1);
212 // Avoid selecting prebooked channels
213 int channel = cb->itemData(cb->currentIndex()).toInt();
214 if (wizDlg->mix.channel[channel].prebooked) {
215 for (int i=cb->count()-1; i>=0; i--){
216 channel = cb->itemData(i).toInt();
217 if (!wizDlg->mix.channel[channel].prebooked) {
218 cb->setCurrentIndex(i);
219 break;
223 // Prebook the selected channel
224 channel = cb->itemData(cb->currentIndex()).toInt();
225 wizDlg->mix.channel[channel].prebooked = true;
228 bool StandardPage::bookChannel(QComboBox * cb, Input input1, int weight1, Input input2, int weight2 )
230 int channel = cb->itemData(cb->currentIndex()).toInt();
231 if (channel<0 || channel>=WIZ_MAX_CHANNELS)
232 return false;
233 if (wizDlg->mix.channel[channel].page != Page_None)
234 return false;
236 wizDlg->mix.channel[channel].page = pageCurrent;
237 wizDlg->mix.channel[channel].input1 = input1;
238 wizDlg->mix.channel[channel].input2 = input2;
239 wizDlg->mix.channel[channel].weight1 = weight1;
240 wizDlg->mix.channel[channel].weight2 = weight2;
242 return true;
245 void StandardPage::releaseBookings()
247 for (int i=0; i<WIZ_MAX_CHANNELS; i++) {
248 if (wizDlg->mix.channel[i].page == pageCurrent) {
249 wizDlg->mix.channel[i].clear();
254 void StandardPage::releasePreBookings()
256 for (int i=0; i<WIZ_MAX_CHANNELS; i++) {
257 wizDlg->mix.channel[i].prebooked = false;
261 void StandardPage::initializePage()
263 releasePreBookings(); // All prebookings are void after page has initialized
266 void StandardPage::cleanupPage()
268 releaseBookings();
271 int StandardPage::nextId() const
273 return pageFollower;
276 ModelSelectionPage::ModelSelectionPage(WizardDialog *dlg, QString image, QString title, QString text)
277 : StandardPage(Page_Models, dlg, image, title, text)
279 nameLineEdit = new QLineEdit;
280 planeRB = new QRadioButton(tr("Plane"));
281 planeRB->setChecked(true);
282 multirotorRB = new QRadioButton(tr("Multirotor"));
283 helicopterRB = new QRadioButton(tr("Helicopter"));
284 helicopterRB->setDisabled(true); //TODO REMOVE TO ENABLE HELICOPTERS
286 registerField("evaluate.name*", nameLineEdit);
288 QLayout *l = layout();
289 l->addWidget(new QLabel(tr("Model Name:")));
290 l->addWidget(nameLineEdit);
291 l->addWidget(new QLabel(""));
292 l->addWidget(new QLabel(tr("Model Type:")));
293 l->addWidget(planeRB);
294 l->addWidget(multirotorRB);
295 l->addWidget(helicopterRB);
298 void ModelSelectionPage::initializePage()
300 nameLineEdit->setText(wizDlg->mix.name);
303 bool ModelSelectionPage::validatePage()
305 //Filter and insert model name in mix data
306 QString newName(nameLineEdit->text());
307 newName = (newName.normalized(QString::NormalizationForm_D));
308 newName = newName.replace(QRegExp("[^ A-Za-z0-9_.-,\\s]"), "");
309 strncpy( wizDlg->mix.name, newName.toLatin1(), WIZ_MODEL_NAME_LENGTH);
310 wizDlg->mix.name[WIZ_MODEL_NAME_LENGTH] = 0;
312 if (multirotorRB->isChecked())
313 wizDlg->mix.vehicle = MULTICOPTER;
314 else if (helicopterRB->isChecked())
315 wizDlg->mix.vehicle = HELICOPTER;
316 else
317 wizDlg->mix.vehicle = PLANE;
318 return true;
321 int ModelSelectionPage::nextId() const
323 if (helicopterRB->isChecked())
324 return Page_Cyclic;
325 else if (multirotorRB->isChecked())
326 return Page_Multirotor;
327 else
328 return Page_Throttle;
331 WingtypeSelectionPage::WingtypeSelectionPage(WizardDialog *dlg, QString image, QString title, QString text)
332 : StandardPage(Page_Wingtypes, dlg, image, title, text)
334 standardWingRB = new QRadioButton(tr("Standard Wing"));
335 standardWingRB->setChecked(true);
336 deltaWingRB = new QRadioButton(tr("Flying Wing / Deltawing"));
338 QLayout *l = layout();
339 l->addWidget(standardWingRB);
340 l->addWidget(deltaWingRB);
343 int WingtypeSelectionPage::nextId() const
345 if (deltaWingRB->isChecked())
346 return Page_Elevons;
347 else
348 return Page_Ailerons;
351 TailSelectionPage::TailSelectionPage(WizardDialog *dlg, QString image, QString title, QString text)
352 : StandardPage(Page_Tails, dlg, image, title, text)
354 standardTailRB = new QRadioButton(tr("Elevator and Rudder"));
355 standardTailRB->setChecked(true);
356 simpleTailRB = new QRadioButton(tr("Only Elevator"));
357 vTailRB = new QRadioButton(tr("V-tail"));
359 QLayout *l = layout();
360 l->addWidget(new QLabel(tr("Tail Type:")));
361 l->addWidget(standardTailRB);
362 l->addWidget(simpleTailRB);
363 l->addWidget(vTailRB);
366 int TailSelectionPage::nextId() const
368 if (simpleTailRB->isChecked())
369 return Page_Simpletail;
370 else if (vTailRB->isChecked())
371 return Page_Vtail;
372 else
373 return Page_Tail;
376 FlybarSelectionPage::FlybarSelectionPage(WizardDialog *dlg, QString image, QString title, QString text)
377 : StandardPage(Page_Flybar, dlg, image, title, text)
379 flybarRB = new QRadioButton(tr("Has Flybar"));
380 flybarRB->setChecked(true);
381 noFlybarRB = new QRadioButton(tr("Flybarless"));
383 QLayout *l = layout();
384 l->addWidget(new QLabel(tr("Flybar:")));
385 l->addWidget(flybarRB);
386 l->addWidget(noFlybarRB);
389 int FlybarSelectionPage::nextId() const
391 if (flybarRB->isChecked())
392 return Page_Helictrl;
393 else
394 return Page_Fblheli;
397 ThrottlePage::ThrottlePage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage)
398 : StandardPage(Page_Throttle, dlg, image, title, text, nextPage)
400 motorRB = new QRadioButton(tr("Yes"));
401 noMotorRB = new QRadioButton(tr("No"));
402 motorRB->setChecked(true);
403 throttleCB = new QComboBox();
405 QLayout *l = layout();
406 l->addWidget(motorRB);
407 l->addWidget(noMotorRB);
408 l->addWidget(new QLabel(tr("<br>Throttle Channel:")));
409 l->addWidget(throttleCB);
411 connect(motorRB, SIGNAL(toggled(bool)), this, SLOT(onMotorStateChanged(bool)));
414 void ThrottlePage::initializePage()
416 populateCB(throttleCB, getDefaultChannel(THROTTLE_INPUT));
417 StandardPage::initializePage();
420 bool ThrottlePage::validatePage()
422 releaseBookings();
423 if (motorRB->isChecked())
424 return bookChannel(throttleCB, THROTTLE_INPUT, 100);
425 else
426 return true;
429 void ThrottlePage::onMotorStateChanged(bool toggled)
431 throttleCB->setEnabled(toggled);
434 AileronsPage::AileronsPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage)
435 : StandardPage(Page_Ailerons, dlg, image, title, text, nextPage)
437 noAileronsRB = new QRadioButton(tr("No"));
438 oneAileronRB = new QRadioButton(tr("Yes, controlled by a single channel"));
439 twoAileronsRB = new QRadioButton(tr("Yes, controlled by two channels"));
440 noAileronsRB->setChecked(true);
442 aileron1CB = new QComboBox();
443 aileron2CB = new QComboBox();
444 aileron1CB->setEnabled(false);
445 aileron2CB->setEnabled(false);
447 QLayout *l = layout();
448 l->addWidget(noAileronsRB);
449 l->addWidget(oneAileronRB);
450 l->addWidget(twoAileronsRB);
451 l->addWidget(new QLabel(tr("<br>First Aileron Channel:")));
452 l->addWidget(aileron1CB);
453 l->addWidget(new QLabel(tr("Second Aileron Channel:")));
454 l->addWidget(aileron2CB);
456 connect(noAileronsRB, SIGNAL(toggled(bool)), this, SLOT(noAileronChannel()));
457 connect(oneAileronRB, SIGNAL(toggled(bool)), this, SLOT(oneAileronChannel()));
458 connect(twoAileronsRB, SIGNAL(toggled(bool)), this, SLOT(twoAileronChannels()));
461 void AileronsPage::initializePage()
463 populateCB(aileron1CB, getDefaultChannel(AILERONS_INPUT));
464 populateCB(aileron2CB, nextFreeChannel(4));
465 StandardPage::initializePage();
468 bool AileronsPage::validatePage()
470 releaseBookings();
471 if (noAileronsRB->isChecked()) {
472 return true;
474 if (oneAileronRB->isChecked()) {
475 return (bookChannel(aileron1CB, AILERONS_INPUT, 100 ));
477 return( bookChannel(aileron1CB, AILERONS_INPUT, 100 ) &&
478 bookChannel(aileron2CB, AILERONS_INPUT, -100 ));
481 void AileronsPage::noAileronChannel()
483 aileron1CB->setEnabled(false);
484 aileron2CB->setEnabled(false);
487 void AileronsPage::oneAileronChannel()
489 aileron1CB->setEnabled(true);
490 aileron2CB->setEnabled(false);
493 void AileronsPage::twoAileronChannels()
495 aileron1CB->setEnabled(true);
496 aileron2CB->setEnabled(true);
499 FlapsPage::FlapsPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
500 StandardPage(Page_Flaps, dlg, image, title, text, nextPage)
502 noFlapsRB = new QRadioButton(tr("No"));
503 oneFlapRB = new QRadioButton(tr("Yes, controlled by a single channel"));
504 twoFlapsRB = new QRadioButton(tr("Yes, controlled by two channels"));
505 noFlapsRB->setChecked(true);
507 flap1CB = new QComboBox();
508 flap2CB = new QComboBox();
509 flap1CB->setEnabled(false);
510 flap2CB->setEnabled(false);
512 QLayout *l = layout();
513 l->addWidget(noFlapsRB);
514 l->addWidget(oneFlapRB);
515 l->addWidget(twoFlapsRB);
516 l->addWidget(new QLabel(tr("<br>First Flap Channel:")));
517 l->addWidget(flap1CB);
518 l->addWidget(new QLabel(tr("Second Flap Channel:")));
519 l->addWidget(flap2CB);
521 connect(noFlapsRB, SIGNAL(toggled(bool)), this, SLOT(noFlapChannel()));
522 connect(oneFlapRB, SIGNAL(toggled(bool)), this, SLOT(oneFlapChannel()));
523 connect(twoFlapsRB, SIGNAL(toggled(bool)), this, SLOT(twoFlapChannels()));
526 void FlapsPage::initializePage()
528 populateCB(flap1CB, nextFreeChannel(4));
529 populateCB(flap2CB, nextFreeChannel(4));
530 StandardPage::initializePage();
533 bool FlapsPage::validatePage() {
534 releaseBookings();
535 if (noFlapsRB->isChecked()) {
536 return true;
538 if (oneFlapRB->isChecked()) {
539 return (bookChannel(flap1CB, FLAPS_INPUT, 100 ));
541 return( bookChannel(flap1CB, FLAPS_INPUT, 100 ) &&
542 bookChannel(flap2CB, FLAPS_INPUT, 100 ));
545 void FlapsPage::noFlapChannel()
547 flap1CB->setEnabled(false);
548 flap2CB->setEnabled(false);
551 void FlapsPage::oneFlapChannel()
553 flap1CB->setEnabled(true);
554 flap2CB->setEnabled(false);
557 void FlapsPage::twoFlapChannels()
559 flap1CB->setEnabled(true);
560 flap2CB->setEnabled(true);
563 AirbrakesPage::AirbrakesPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
564 StandardPage(Page_Airbrakes, dlg, image, title, text, nextPage)
566 noAirbrakesRB = new QRadioButton(tr("No"));
567 oneAirbrakeRB = new QRadioButton(tr("Yes, controlled by a single channel"));
568 twoAirbrakesRB = new QRadioButton(tr("Yes, controlled by two channels"));
569 noAirbrakesRB->setChecked(true);
571 airbrake1CB = new QComboBox();
572 airbrake2CB = new QComboBox();
573 airbrake1CB->setEnabled(false);
574 airbrake2CB->setEnabled(false);
576 QLayout *l = layout();
577 l->addWidget(noAirbrakesRB);
578 l->addWidget(oneAirbrakeRB);
579 l->addWidget(twoAirbrakesRB);
580 l->addWidget(new QLabel(tr("<br>First Airbrake Channel:")));
581 l->addWidget(airbrake1CB);
582 l->addWidget(new QLabel(tr("Second Airbrake Channel:")));
583 l->addWidget(airbrake2CB);
585 connect(noAirbrakesRB, SIGNAL(toggled(bool)), this, SLOT(noAirbrakeChannel()));
586 connect(oneAirbrakeRB, SIGNAL(toggled(bool)), this, SLOT(oneAirbrakeChannel()));
587 connect(twoAirbrakesRB, SIGNAL(toggled(bool)), this, SLOT(twoAirbrakeChannels()));
590 void AirbrakesPage::initializePage()
592 populateCB(airbrake1CB, nextFreeChannel(4));
593 populateCB(airbrake2CB, nextFreeChannel(4));
594 StandardPage::initializePage();
597 bool AirbrakesPage::validatePage()
599 releaseBookings();
600 if (noAirbrakesRB->isChecked()) {
601 return true;
603 if (oneAirbrakeRB->isChecked()) {
604 return (bookChannel(airbrake1CB, AIRBRAKES_INPUT, 100 ));
606 return( bookChannel(airbrake1CB, AIRBRAKES_INPUT, 100 ) &&
607 bookChannel(airbrake2CB, AIRBRAKES_INPUT, 100 ));
610 void AirbrakesPage::noAirbrakeChannel()
612 airbrake1CB->setEnabled(false);
613 airbrake2CB->setEnabled(false);
616 void AirbrakesPage::oneAirbrakeChannel()
618 airbrake1CB->setEnabled(true);
619 airbrake2CB->setEnabled(false);
622 void AirbrakesPage::twoAirbrakeChannels()
624 airbrake1CB->setEnabled(true);
625 airbrake2CB->setEnabled(true);
628 ElevonsPage::ElevonsPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
629 StandardPage(Page_Elevons, dlg, image, title, text, nextPage)
631 elevon1CB = new QComboBox();
632 elevon2CB = new QComboBox();
634 QLayout *l = layout();
635 l->addWidget(new QLabel(tr("<br>First Elevon Channel:")));
636 l->addWidget(elevon1CB);
637 l->addWidget(new QLabel(tr("Second Elevon Channel:")));
638 l->addWidget(elevon2CB);
641 void ElevonsPage::initializePage()
643 populateCB(elevon1CB, getDefaultChannel(ELEVATOR_INPUT));
644 populateCB(elevon2CB, getDefaultChannel(AILERONS_INPUT));
645 StandardPage::initializePage();
648 bool ElevonsPage::validatePage()
650 releaseBookings();
651 return (bookChannel(elevon1CB, AILERONS_INPUT, 50, ELEVATOR_INPUT, 50) &&
652 bookChannel(elevon2CB, AILERONS_INPUT, -50, ELEVATOR_INPUT, 50));
655 RudderPage::RudderPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
656 StandardPage(Page_Rudder, dlg, image, title, text, nextPage)
658 noRudderRB = new QRadioButton(tr("No"));
659 hasRudderRB = new QRadioButton(tr("Yes"));
660 noRudderRB->setChecked(true);
662 rudderCB = new QComboBox();
663 rudderCB->setEnabled(false);
665 QLayout *l = layout();
666 l->addWidget(noRudderRB);
667 l->addWidget(hasRudderRB);
668 l->addWidget(new QLabel(tr("<br>Rudder Channel:")));
669 l->addWidget(rudderCB);
670 connect(noRudderRB, SIGNAL(toggled(bool)), this, SLOT(noRudder()));
671 connect(hasRudderRB, SIGNAL(toggled(bool)), this, SLOT(hasRudder()));
674 void RudderPage::initializePage()
676 populateCB(rudderCB, getDefaultChannel(RUDDER_INPUT));
677 StandardPage::initializePage();
680 bool RudderPage::validatePage() {
681 releaseBookings();
682 if (noRudderRB->isChecked())
683 return true;
685 return (bookChannel(rudderCB, RUDDER_INPUT, 100));
688 void RudderPage::noRudder()
690 rudderCB->setEnabled(false);
693 void RudderPage::hasRudder()
695 rudderCB->setEnabled(true);
698 VTailPage::VTailPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage)
699 : StandardPage(Page_Tail, dlg, image, title, text, nextPage)
701 tail1CB = new QComboBox();
702 tail2CB = new QComboBox();
704 QLayout *l = layout();
705 l->addWidget(new QLabel(tr("First Tail Channel:")));
706 l->addWidget(tail1CB);
707 l->addWidget(new QLabel(tr("Second Tail Channel:")));
708 l->addWidget(tail2CB);
711 void VTailPage::initializePage()
713 populateCB(tail1CB, getDefaultChannel(ELEVATOR_INPUT));
714 populateCB(tail2CB, getDefaultChannel(AILERONS_INPUT));
715 StandardPage::initializePage();
718 bool VTailPage::validatePage()
720 releaseBookings();
721 return (bookChannel(tail1CB, ELEVATOR_INPUT, 50, RUDDER_INPUT, 50) &&
722 bookChannel(tail2CB, ELEVATOR_INPUT, 50, RUDDER_INPUT, -50 ));
725 TailPage::TailPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
726 StandardPage(Page_Tail, dlg, image, title, text, nextPage)
728 elevatorCB = new QComboBox();
729 rudderCB = new QComboBox();
731 l = layout();
732 l->addWidget(new QLabel(tr("Rudder Channel:")));
733 l->addWidget(rudderCB);
734 l->addWidget(new QLabel(tr("Elevator Channel:")));
735 l->addWidget(elevatorCB);
737 errorMessage = NULL;
740 void TailPage::initializePage()
742 populateCB(elevatorCB, getDefaultChannel(ELEVATOR_INPUT));
743 populateCB(rudderCB, getDefaultChannel(RUDDER_INPUT));
744 StandardPage::initializePage();
746 if (totalChannelsAvailable() < 2) {
747 errorMessage = new QLabel(tr("Only one channel still available!<br>"
748 "You probably should configure your model without using the wizard."));
749 errorMessage->setStyleSheet("QLabel { color : red; }");
750 l->addWidget(errorMessage);
754 bool TailPage::validatePage()
756 releaseBookings();
757 return( bookChannel(elevatorCB, ELEVATOR_INPUT, 100) &&
758 bookChannel(rudderCB, RUDDER_INPUT, 100));
761 void TailPage::cleanupPage()
763 if (errorMessage)
765 l->removeWidget(errorMessage);
766 delete errorMessage;
767 errorMessage = NULL;
769 StandardPage::cleanupPage();
772 SimpleTailPage::SimpleTailPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage)
773 : StandardPage(Page_Simpletail, dlg, image, title, text, nextPage)
775 elevatorCB = new QComboBox();
777 QLayout *l = layout();
778 l->addWidget(new QLabel(tr("Elevator Channel:")));
779 l->addWidget(elevatorCB);
782 void SimpleTailPage::initializePage()
784 populateCB(elevatorCB, getDefaultChannel(ELEVATOR_INPUT));
785 StandardPage::initializePage();
788 bool SimpleTailPage::validatePage()
790 releaseBookings();
791 return( bookChannel(elevatorCB, ELEVATOR_INPUT, 100 ));
794 CyclicPage::CyclicPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
795 StandardPage(Page_Cyclic, dlg, image, title, text, nextPage)
797 cyclic90RB = new QRadioButton(tr("90"));
798 cyclic90RB->setChecked(true);
799 cyclic120RB = new QRadioButton(tr("120"));
800 cyclic120XRB = new QRadioButton(tr("120x"));
801 cyclic140RB = new QRadioButton(tr("140"));
803 QLayout *l = layout();
804 l->addWidget(cyclic90RB);
805 l->addWidget(cyclic120RB);
806 l->addWidget(cyclic120XRB);
807 l->addWidget(cyclic140RB);
810 void CyclicPage::initializePage()
812 StandardPage::initializePage();
815 bool CyclicPage::validatePage()
817 releaseBookings();
818 return true;
821 GyroPage::GyroPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
822 StandardPage(Page_Gyro, dlg, image, title, text, nextPage)
824 noGyroRB = new QRadioButton(tr("No"));
825 noGyroRB->setChecked(true);
826 switchGyroRB = new QRadioButton(tr("Yes, controled by a switch"));
827 potGyroRB = new QRadioButton(tr("Yes, controlled by a pot"));
829 QLayout *l = layout();
830 l->addWidget(noGyroRB);
831 l->addWidget(switchGyroRB);
832 l->addWidget(potGyroRB);
835 void GyroPage::initializePage()
837 StandardPage::initializePage();
840 bool GyroPage::validatePage() {
841 releaseBookings();
842 return true;
845 FblPage::FblPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
846 StandardPage(Page_Fblheli, dlg, image, title, text, nextPage)
848 throttleCB = new QComboBox();
849 yawCB = new QComboBox();
850 pitchCB = new QComboBox();
851 rollCB = new QComboBox();
853 QLayout *l = layout();
854 l->addWidget(new QLabel(tr("Throttle Channel:")));
855 l->addWidget(throttleCB);
856 l->addWidget(new QLabel(tr("Yaw Channel:")));
857 l->addWidget(yawCB);
858 l->addWidget(new QLabel(tr("Pitch Channel:")));
859 l->addWidget(pitchCB);
860 l->addWidget(new QLabel(tr("Roll Channel:")));
861 l->addWidget(rollCB);
864 void FblPage::initializePage()
866 populateCB(throttleCB, getDefaultChannel(THROTTLE_INPUT));
867 populateCB(yawCB, getDefaultChannel(RUDDER_INPUT));
868 populateCB(pitchCB, getDefaultChannel(ELEVATOR_INPUT));
869 populateCB(rollCB, getDefaultChannel(AILERONS_INPUT));
870 StandardPage::initializePage();
873 bool FblPage::validatePage()
875 releaseBookings();
876 return( bookChannel(throttleCB, THROTTLE_INPUT, 100 ) &&
877 bookChannel( yawCB, RUDDER_INPUT, 100 ) &&
878 bookChannel( pitchCB, ELEVATOR_INPUT, 100 ) &&
879 bookChannel( rollCB, AILERONS_INPUT, 100 ));
882 HeliPage::HeliPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
883 StandardPage(Page_Helictrl, dlg, image, title, text, nextPage)
885 throttleCB = new QComboBox();
886 yawCB = new QComboBox();
887 pitchCB = new QComboBox();
888 rollCB = new QComboBox();
890 QLayout *l = layout();
891 l->addWidget(new QLabel(tr("Throttle Channel:")));
892 l->addWidget(throttleCB);
893 l->addWidget(new QLabel(tr("Yaw Channel:")));
894 l->addWidget(yawCB);
895 l->addWidget(new QLabel(tr("Pitch Channel:")));
896 l->addWidget(pitchCB);
897 l->addWidget(new QLabel(tr("Roll Channel:")));
898 l->addWidget(rollCB);
901 void HeliPage::initializePage()
903 populateCB(throttleCB, getDefaultChannel(THROTTLE_INPUT));
904 populateCB(yawCB, getDefaultChannel(RUDDER_INPUT));
905 populateCB(pitchCB, getDefaultChannel(ELEVATOR_INPUT));
906 populateCB(rollCB, getDefaultChannel(AILERONS_INPUT));
907 StandardPage::initializePage();
910 bool HeliPage::validatePage()
912 releaseBookings();
913 return( bookChannel(throttleCB, THROTTLE_INPUT, 100 ) &&
914 bookChannel( yawCB, RUDDER_INPUT, 100 ) &&
915 bookChannel( pitchCB, ELEVATOR_INPUT, 100 ) &&
916 bookChannel( rollCB, AILERONS_INPUT, 100 ));
919 MultirotorPage::MultirotorPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
920 StandardPage(Page_Multirotor, dlg, image, title, text, nextPage)
922 throttleCB = new QComboBox();
923 yawCB = new QComboBox();
924 pitchCB = new QComboBox();
925 rollCB = new QComboBox();
927 QLayout *l = layout();
928 l->addWidget(new QLabel(tr("Throttle Channel:")));
929 l->addWidget(throttleCB);
930 l->addWidget(new QLabel(tr("Yaw Channel:")));
931 l->addWidget(yawCB);
932 l->addWidget(new QLabel(tr("Pitch Channel:")));
933 l->addWidget(pitchCB);
934 l->addWidget(new QLabel(tr("Roll Channel:")));
935 l->addWidget(rollCB);
938 void MultirotorPage::initializePage()
940 populateCB(throttleCB, getDefaultChannel(THROTTLE_INPUT));
941 populateCB(yawCB, getDefaultChannel(RUDDER_INPUT));
942 populateCB(pitchCB, getDefaultChannel(ELEVATOR_INPUT));
943 populateCB(rollCB, getDefaultChannel(AILERONS_INPUT));
944 StandardPage::initializePage();
947 bool MultirotorPage::validatePage()
949 releaseBookings();
950 return( bookChannel(throttleCB, THROTTLE_INPUT, 100 ) &&
951 bookChannel(yawCB, RUDDER_INPUT, 100 ) &&
952 bookChannel(pitchCB, ELEVATOR_INPUT, 100 ) &&
953 bookChannel(rollCB, AILERONS_INPUT, 100 ));
956 OptionsPage::OptionsPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage):
957 StandardPage(Page_Options, dlg, image, title, text, nextPage)
959 throttleCutRB = new QCheckBox(tr("Throttle Cut"));
960 throttleTimerRB = new QCheckBox(tr("Throttle Timer"));
961 flightTimerRB = new QCheckBox(tr("Flight Timer"));
963 QLayout *l = layout();
964 l->addWidget(throttleCutRB);
965 l->addWidget(throttleTimerRB);
966 l->addWidget(flightTimerRB);
969 void OptionsPage::initializePage(){
970 StandardPage::initializePage();
973 bool OptionsPage::validatePage(){
974 wizDlg->mix.options[THROTTLE_CUT_OPTION] = throttleCutRB->isChecked();
975 wizDlg->mix.options[THROTTLE_TIMER_OPTION] = throttleTimerRB->isChecked();
976 wizDlg->mix.options[FLIGHT_TIMER_OPTION] = flightTimerRB->isChecked();
977 return true;
980 ConclusionPage::ConclusionPage(WizardDialog *dlg, QString image, QString title, QString text, int nextPage)
981 : StandardPage(Page_Conclusion, dlg, image, title, text, nextPage)
983 textLabel = new QLabel();
984 proceedCB = new QCheckBox(tr("OK, I understand."));
985 registerField("evaluate.proceed*", proceedCB);
987 QLayout *l = layout();
988 l->addWidget(textLabel);
989 l->addWidget(proceedCB);
992 void ConclusionPage::initializePage()
994 WizardPrinter p(&wizDlg->mix);
995 textLabel->setText(p.print());
996 StandardPage::initializePage();
999 bool ConclusionPage::validatePage()
1001 wizDlg->mix.complete = true;
1002 return true;
1006 QString WizardPrinter::inputName(Input input)
1008 switch (input) {
1009 case THROTTLE_INPUT:
1010 return "THR";
1011 case RUDDER_INPUT:
1012 return "RUD";
1013 case ELEVATOR_INPUT:
1014 return "ELE";
1015 case AILERONS_INPUT:
1016 return "AIL";
1017 case FLAPS_INPUT:
1018 return "FLP";
1019 case AIRBRAKES_INPUT:
1020 return "AIR";
1021 default:
1022 return "---";
1026 QString WizardPrinter::vehicleName(Vehicle vehicle)
1028 switch (vehicle) {
1029 case PLANE:
1030 return tr("Plane");
1031 case MULTICOPTER:
1032 return tr("Multicopter");
1033 case HELICOPTER:
1034 return tr("Helicopter");
1035 default:
1036 return "---";
1040 WizardPrinter::WizardPrinter(WizMix *wizMix)
1042 mix = wizMix;
1045 QString WizardPrinter::printChannel( Input input1, int weight1, Input input2, int weight2 )
1047 QString str;
1048 str = QString("[%1, %2]").arg(inputName(input1)).arg(weight1);
1049 if ( input2 != NO_INPUT )
1050 str += QString("[%1, %2]").arg(inputName(input2)).arg(weight2);
1051 return str;
1054 QString WizardPrinter::print()
1056 QString str = tr("Model Name: ") + mix->name + "\n";
1057 str += tr("Model Type: ") + vehicleName(mix->vehicle) + "\n";
1059 str += tr("Options: ") + "[";
1060 for (int i=0; i<WIZ_MAX_OPTIONS; i++) {
1061 if (mix->options[i])
1062 str += "X";
1063 else
1064 str += "-";
1066 str += QString("]") + "\n";
1068 for (int i=0; i<WIZ_MAX_CHANNELS; i++) {
1069 if (mix->channel[i].page != Page_None) {
1070 Channel ch = mix->channel[i];
1071 str += tr("Channel %1: ").arg(i+1);
1072 str += printChannel(ch.input1, ch.weight1, ch.input2, ch.weight2 );
1073 str += QString("\n");
1076 return str;