[Companion] Fixes
[opentx.git] / companion / src / modeledit / setup.cpp
blobd0cc378b91f50c831a2c0ebeea2228cf356ac88b
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 "setup.h"
22 #include "ui_setup.h"
23 #include "ui_setup_timer.h"
24 #include "ui_setup_module.h"
25 #include "helpers.h"
26 #include "appdata.h"
27 #include "modelprinter.h"
29 TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget * prevFocus):
30 ModelPanel(parent, model, generalSettings, firmware),
31 timer(timer),
32 ui(new Ui::Timer)
34 BoardEnum board = firmware->getBoard();
36 ui->setupUi(this);
38 lock = true;
40 // Name
41 int length = firmware->getCapability(TimersName);
42 if (length == 0) {
43 ui->name->hide();
45 else {
46 ui->name->setMaxLength(length);
47 ui->name->setText(timer.name);
50 // Mode
51 populateSwitchCB(ui->mode, timer.mode, generalSettings, TimersContext);
53 if (!firmware->getCapability(PermTimers)) {
54 ui->persistent->hide();
55 ui->persistentValue->hide();
58 ui->countdownBeep->setField(timer.countdownBeep, this);
59 ui->countdownBeep->addItem(tr("Silent"), TimerData::COUNTDOWN_SILENT);
60 ui->countdownBeep->addItem(tr("Beeps"), TimerData::COUNTDOWN_BEEPS);
61 if (IS_ARM(board) || IS_2560(board)) {
62 ui->countdownBeep->addItem(tr("Voice"), TimerData::COUNTDOWN_VOICE);
63 ui->countdownBeep->addItem(tr("Haptic"), TimerData::COUNTDOWN_HAPTIC);
66 ui->value->setMaximumTime(firmware->getMaxTimerStart());
68 ui->persistent->setField(timer.persistent, this);
69 ui->persistent->addItem(tr("Not persistent"), 0);
70 ui->persistent->addItem(tr("Persistent (flight)"), 1);
71 ui->persistent->addItem(tr("Persistent (manual reset)"), 2);
73 disableMouseScrolling();
74 QWidget::setTabOrder(prevFocus, ui->name);
75 QWidget::setTabOrder(ui->name, ui->value);
76 QWidget::setTabOrder(ui->value, ui->mode);
77 QWidget::setTabOrder(ui->mode, ui->countdownBeep);
78 QWidget::setTabOrder(ui->countdownBeep, ui->minuteBeep);
79 QWidget::setTabOrder(ui->minuteBeep, ui->persistent);
81 lock = false;
84 TimerPanel::~TimerPanel()
86 delete ui;
89 void TimerPanel::update()
91 int hour = timer.val / 3600;
92 int min = (timer.val - (hour * 3600)) / 60;
93 int sec = (timer.val - (hour * 3600)) % 60;
95 ui->value->setTime(QTime(hour, min, sec));
97 if (firmware->getCapability(PermTimers)) {
98 int sign = 1;
99 int pvalue = timer.pvalue;
100 if (pvalue < 0) {
101 pvalue = -pvalue;
102 sign = -1;
104 int hours = pvalue / 3600;
105 pvalue -= hours * 3600;
106 int minutes = pvalue / 60;
107 int seconds = pvalue % 60;
108 ui->persistentValue->setText(QString(" %1(%2:%3:%4)").arg(sign<0 ? "-" :" ").arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
111 ui->minuteBeep->setChecked(timer.minuteBeep);
114 QWidget * TimerPanel::getLastFocus()
116 return ui->persistent;
119 void TimerPanel::on_value_editingFinished()
121 timer.val = ui->value->time().hour()*3600 + ui->value->time().minute()*60 + ui->value->time().second();
122 emit modified();
125 void TimerPanel::on_mode_currentIndexChanged(int index)
127 if (!lock) {
128 timer.mode = RawSwitch(ui->mode->itemData(index).toInt());
129 emit modified();
133 void TimerPanel::on_minuteBeep_toggled(bool checked)
135 timer.minuteBeep = checked;
136 emit modified();
139 void TimerPanel::on_name_editingFinished()
141 int length = ui->name->maxLength();
142 strncpy(timer.name, ui->name->text().toLatin1(), length);
143 emit modified();
146 /******************************************************************************/
148 #define FAILSAFE_CHANNEL_HOLD 2000
149 #define FAILSAFE_CHANNEL_NOPULSE 2001
151 ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & module, GeneralSettings & generalSettings, Firmware * firmware, int moduleIdx):
152 ModelPanel(parent, model, generalSettings, firmware),
153 module(module),
154 moduleIdx(moduleIdx),
155 ui(new Ui::Module)
157 lock = true;
159 ui->setupUi(this);
161 QString label;
162 if (moduleIdx < 0) {
163 label = tr("Trainer Port");
164 if (generalSettings.hw_uartMode != UART_MODE_SBUS_TRAINER) {
165 ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1);
167 ui->trainerMode->setCurrentIndex(model.trainerMode);
168 if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
169 ui->label_trainerMode->hide();
170 ui->trainerMode->hide();
173 else {
174 ui->label_trainerMode->hide();
175 ui->trainerMode->hide();
176 if (firmware->getCapability(NumModules) > 1) {
177 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
178 if (moduleIdx == 0)
179 label = tr("Internal Radio System");
180 else
181 label = tr("External Radio Module");
183 else {
184 if (moduleIdx == 0)
185 label = tr("Radio System");
186 else
187 label = tr("Extra Radio System");
190 else {
191 label = tr("Radio System");
194 ui->label_module->setText(label);
196 // The protocols available on this board
197 for (int i=0; i<PULSES_PROTOCOL_LAST; i++) {
198 if (firmware->isAvailable((PulsesProtocol)i, moduleIdx)) {
199 ui->protocol->addItem(ModelPrinter::printModuleProtocol(i), (QVariant)i);
200 if (i == module.protocol) ui->protocol->setCurrentIndex(ui->protocol->count()-1);
204 for (int i=0; i<=MM_RF_PROTO_LAST; i++) {
205 ui->multiProtocol->addItem(ModelPrinter::printMultiRfProtocol(i, false), (QVariant) i);
208 if (firmware->getCapability(HasFailsafe)) {
209 for (int i=0; i<maxChannels; i++) {
210 QLabel * label = new QLabel(this);
211 label->setText(QString::number(i+1));
212 QComboBox * combo = new QComboBox(this);
213 combo->setProperty("index", i);
214 combo->addItem(tr("Value"), 0);
215 combo->addItem(tr("Hold"), FAILSAFE_CHANNEL_HOLD);
216 combo->addItem(tr("No Pulse"), FAILSAFE_CHANNEL_NOPULSE);
217 QDoubleSpinBox * spinbox = new QDoubleSpinBox(this);
218 spinbox->setMinimumSize(QSize(20, 0));
219 spinbox->setRange(-150, 150);
220 spinbox->setSingleStep(0.1);
221 spinbox->setDecimals(1);
222 label->setProperty("index", i);
223 spinbox->setProperty("index", i);
224 ui->failsafesLayout->addWidget(label, 3*(i/8), i%8, Qt::AlignHCenter);
225 ui->failsafesLayout->addWidget(combo, 1+3*(i/8), i%8, Qt::AlignHCenter);
226 ui->failsafesLayout->addWidget(spinbox, 2+3*(i/8), i%8, Qt::AlignHCenter);
227 failsafeGroups[i].combo = combo;
228 failsafeGroups[i].spinbox = spinbox;
229 failsafeGroups[i].label = label;
230 updateFailsafe(i);
231 connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(onFailsafeComboIndexChanged(int)));
232 connect(spinbox, SIGNAL(valueChanged(double)), this, SLOT(onFailsafeSpinChanged(double)));
236 disableMouseScrolling();
238 lock = false;
241 ModulePanel::~ModulePanel()
243 delete ui;
246 #define MASK_PROTOCOL 1
247 #define MASK_CHANNELS_COUNT 2
248 #define MASK_RX_NUMBER 4
249 #define MASK_CHANNELS_RANGE 8
250 #define MASK_PPM_FIELDS 16
251 #define MASK_FAILSAFES 32
252 #define MASK_OPEN_DRAIN 64
253 #define MASK_MULTIMODULE 128
255 void ModulePanel::update()
257 unsigned int mask = 0;
258 PulsesProtocol protocol = (PulsesProtocol)module.protocol;
259 unsigned int max_rx_num = 63;
261 if (moduleIdx >= 0) {
262 mask |= MASK_PROTOCOL;
263 switch (protocol) {
264 case PULSES_PXX_XJT_X16:
265 case PULSES_PXX_XJT_D8:
266 case PULSES_PXX_XJT_LR12:
267 case PULSES_PXX_DJT:
268 mask |= MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
269 if (protocol==PULSES_PXX_XJT_X16) mask |= MASK_FAILSAFES | MASK_RX_NUMBER;
270 if (protocol==PULSES_PXX_XJT_LR12) mask |= MASK_RX_NUMBER;
271 break;
272 case PULSES_LP45:
273 case PULSES_DSM2:
274 case PULSES_DSMX:
275 mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER;
276 module.channelsCount = 6;
277 max_rx_num = 20;
278 break;
279 case PULSES_CROSSFIRE:
280 mask |= MASK_CHANNELS_RANGE;
281 module.channelsCount = 16;
282 break;
283 case PULSES_PPM:
284 mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT;
285 if (IS_9XRPRO(firmware->getBoard())) {
286 mask |= MASK_OPEN_DRAIN;
288 break;
289 case PULSES_MULTIMODULE:
290 mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER | MASK_MULTIMODULE;
291 break;
292 case PULSES_OFF:
293 default:
294 break;
297 else if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
298 if (model->trainerMode == TRAINER_SLAVE_JACK) {
299 mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
302 else if (model->trainerMode != TRAINER_MASTER_JACK) {
303 mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
306 ui->label_protocol->setVisible(mask & MASK_PROTOCOL);
307 ui->protocol->setVisible(mask & MASK_PROTOCOL);
308 ui->label_rxNumber->setVisible(mask & MASK_RX_NUMBER);
309 ui->rxNumber->setVisible(mask & MASK_RX_NUMBER);
310 ui->rxNumber->setMaximum(max_rx_num);
311 ui->rxNumber->setValue(module.modelId);
312 ui->label_channelsStart->setVisible(mask & MASK_CHANNELS_RANGE);
313 ui->channelsStart->setVisible(mask & MASK_CHANNELS_RANGE);
314 ui->channelsStart->setValue(module.channelsStart+1);
315 ui->label_channelsCount->setVisible(mask & MASK_CHANNELS_RANGE);
316 ui->channelsCount->setVisible(mask & MASK_CHANNELS_RANGE);
317 ui->channelsCount->setEnabled(mask & MASK_CHANNELS_COUNT);
318 ui->channelsCount->setValue(module.channelsCount);
319 ui->channelsCount->setSingleStep(firmware->getCapability(HasPPMStart) ? 1 : 2);
321 // PPM settings fields
322 ui->label_ppmPolarity->setVisible(mask & MASK_PPM_FIELDS);
323 ui->ppmPolarity->setVisible(mask & MASK_PPM_FIELDS);
324 ui->ppmPolarity->setCurrentIndex(module.ppm.pulsePol);
325 ui->label_ppmOutputType->setVisible(mask & MASK_OPEN_DRAIN);
326 ui->ppmOutputType->setVisible(mask & MASK_OPEN_DRAIN);
327 ui->ppmOutputType->setCurrentIndex(module.ppm.outputType);
328 ui->label_ppmDelay->setVisible(mask & MASK_PPM_FIELDS);
329 ui->ppmDelay->setVisible(mask & MASK_PPM_FIELDS);
330 ui->ppmDelay->setValue(module.ppm.delay);
331 ui->label_ppmFrameLength->setVisible(mask & MASK_PPM_FIELDS);
332 ui->ppmFrameLength->setVisible(mask & MASK_PPM_FIELDS);
333 ui->ppmFrameLength->setMinimum(module.channelsCount*(model->extendedLimits ? 2.250 : 2)+3.5);
334 ui->ppmFrameLength->setMaximum(firmware->getCapability(PPMFrameLength));
335 ui->ppmFrameLength->setValue(22.5+((double)module.ppm.frameLength)*0.5);
337 // Multi settings fields
338 ui->label_multiProtocol->setVisible(mask & MASK_MULTIMODULE);
339 ui->multiProtocol->setVisible(mask & MASK_MULTIMODULE);
340 ui->multiProtocol->setCurrentIndex(module.multi.rfProtocol);
341 ui->label_multiSubType->setVisible(mask & MASK_MULTIMODULE);
342 ui->multiSubType->setVisible(mask & MASK_MULTIMODULE);
344 if (mask & MASK_MULTIMODULE) {
345 int numEntries = getNumSubtypes(static_cast<MultiModuleRFProtocols>(module.multi.rfProtocol));
346 if (module.multi.customProto)
347 numEntries=8;
348 // Removes extra items
349 ui->multiSubType->setMaxCount(numEntries);
350 for (int i=0; i < numEntries; i++) {
351 if (i < ui->multiSubType->count())
352 ui->multiSubType->setItemText(i, ModelPrinter::printMultiSubType(module.multi.rfProtocol, module.multi.customProto, i));
353 else
354 ui->multiSubType->addItem(ModelPrinter::printMultiSubType(module.multi.rfProtocol, module.multi.customProto, i), (QVariant) i);
357 ui->multiSubType->setCurrentIndex(module.subType);
359 ui->autoBind->setVisible(mask & MASK_MULTIMODULE);
360 ui->autoBind->setChecked(module.multi.autoBindMode ? Qt::Checked : Qt::Unchecked);
361 ui->lowPower->setVisible(mask & MASK_MULTIMODULE);
362 ui->lowPower->setChecked(module.multi.lowPowerMode ? Qt::Checked : Qt::Unchecked);
365 if (firmware->getCapability(HasFailsafe)) {
366 ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES);
367 ui->failsafeMode->setVisible(mask & MASK_FAILSAFES);
368 ui->failsafeMode->setCurrentIndex(module.failsafeMode);
369 ui->failsafesFrame->setEnabled(module.failsafeMode == FAILSAFE_CUSTOM);
370 if (firmware->getCapability(ChannelsName) > 0) {
371 for(int i=0; i<maxChannels;i++) {
372 QString name = QString(model->limitData[i+module.channelsStart].name).trimmed();
373 if (!name.isEmpty()) {
374 failsafeGroups[i].label->setText(name);
376 else {
377 failsafeGroups[i].label->setText(QString::number(i+1));
382 else {
383 mask = 0;
386 ui->failsafesLayoutLabel->setVisible(mask & MASK_FAILSAFES);
387 ui->failsafesFrame->setVisible(mask & MASK_FAILSAFES);
389 if (mask & MASK_CHANNELS_RANGE) {
390 ui->channelsStart->setMaximum(33 - ui->channelsCount->value());
391 ui->channelsCount->setMaximum(qMin(16, 33-ui->channelsStart->value()));
395 void ModulePanel::on_trainerMode_currentIndexChanged(int index)
397 if (!lock) {
398 model->trainerMode = index;
399 update();
400 emit modified();
404 void ModulePanel::on_protocol_currentIndexChanged(int index)
406 if (!lock) {
407 module.protocol = ui->protocol->itemData(index).toInt();
408 update();
409 emit modified();
413 void ModulePanel::on_ppmPolarity_currentIndexChanged(int index)
415 module.ppm.pulsePol = index;
416 emit modified();
419 void ModulePanel::on_ppmOutputType_currentIndexChanged(int index)
421 module.ppm.outputType = index;
422 emit modified();
425 void ModulePanel::on_channelsCount_editingFinished()
427 if (!lock) {
428 module.channelsCount = ui->channelsCount->value();
429 update();
430 emit modified();
434 void ModulePanel::on_channelsStart_editingFinished()
436 if (!lock) {
437 module.channelsStart = ui->channelsStart->value() - 1;
438 update();
439 emit modified();
443 void ModulePanel::on_ppmDelay_editingFinished()
445 if (!lock) {
446 // TODO only accept valid values
447 module.ppm.delay = ui->ppmDelay->value();
448 emit modified();
452 void ModulePanel::on_rxNumber_editingFinished()
454 module.modelId = ui->rxNumber->value();
455 emit modified();
458 void ModulePanel::on_ppmFrameLength_editingFinished()
460 module.ppm.frameLength = (ui->ppmFrameLength->value()-22.5) / 0.5;
461 emit modified();
464 void ModulePanel::on_failsafeMode_currentIndexChanged(int value)
466 if (!lock) {
467 module.failsafeMode = value;
468 update();
469 emit modified();
473 void ModulePanel::onFailsafeSpinChanged(double value)
475 if (!lock) {
476 int channel = sender()->property("index").toInt();
477 module.failsafeChannels[channel] = (value*1024)/100;
478 emit modified();
482 void ModulePanel::onFailsafeComboIndexChanged(int index)
484 if (!lock) {
485 lock = true;
486 int channel = sender()->property("index").toInt();
487 module.failsafeChannels[channel] = ((QComboBox *)sender())->itemData(index).toInt();
488 updateFailsafe(channel);
489 emit modified();
490 lock = false;
494 void ModulePanel::on_multiProtocol_currentIndexChanged(int index)
496 if (!lock) {
497 lock=true;
498 module.multi.rfProtocol = index;
499 unsigned int maxSubTypes = getNumSubtypes(static_cast<MultiModuleRFProtocols>(index));
500 if (module.multi.customProto)
501 maxSubTypes=8;
502 module.subType = std::min(module.subType, maxSubTypes -1);
503 update();
504 emit modified();
505 lock = false;
509 void ModulePanel::on_multiSubType_currentIndexChanged(int index)
511 if (!lock) {
512 lock=true;
513 module.subType = index;
514 update();
515 emit modified();
516 lock = false;
520 void ModulePanel::on_autoBind_stateChanged(int state)
522 module.multi.autoBindMode = (state == Qt::Checked);
524 void ModulePanel::on_lowPower_stateChanged(int state)
526 module.multi.lowPowerMode = (state == Qt::Checked);
529 void ModulePanel::updateFailsafe(int channel)
531 int failsafeValue = module.failsafeChannels[channel];
532 QComboBox * combo = failsafeGroups[channel].combo;
533 QDoubleSpinBox * spinbox = failsafeGroups[channel].spinbox;
534 if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
535 combo->setCurrentIndex(1);
536 spinbox->setEnabled(false);
537 spinbox->setValue(0);
539 else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
540 combo->setCurrentIndex(2);
541 spinbox->setEnabled(false);
542 spinbox->setValue(0);
544 else {
545 combo->setCurrentIndex(0);
546 spinbox->setEnabled(true);
547 spinbox->setValue(((double)failsafeValue*100)/1024);
551 /******************************************************************************/
553 SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
554 ModelPanel(parent, model, generalSettings, firmware),
555 ui(new Ui::Setup)
557 BoardEnum board = firmware->getBoard();
559 lock = true;
561 memset(modules, 0, sizeof(modules));
563 ui->setupUi(this);
565 QRegExp rx(CHAR_FOR_NAMES_REGEX);
566 ui->name->setValidator(new QRegExpValidator(rx, this));
567 ui->name->setMaxLength(firmware->getCapability(ModelName));
569 if (firmware->getCapability(ModelImage)) {
570 QStringList items;
571 items.append("");
572 QString path = g.profile[g.id()].sdPath();
573 path.append("/IMAGES/");
574 QDir qd(path);
575 if (qd.exists()) {
576 QStringList filters;
577 filters << "*.bmp" << "*.bmp";
578 foreach ( QString file, qd.entryList(filters, QDir::Files) ) {
579 QFileInfo fi(file);
580 QString temp = fi.completeBaseName();
581 if (!items.contains(temp) && temp.length() <= 10+4) {
582 items.append(temp);
586 if (!items.contains(model.bitmap)) {
587 items.append(model.bitmap);
589 items.sort();
590 foreach ( QString file, items ) {
591 ui->image->addItem(file);
592 if (file == model.bitmap) {
593 ui->image->setCurrentIndex(ui->image->count()-1);
594 QString fileName = path;
595 fileName.append(model.bitmap);
596 fileName.append(".bmp");
597 QImage image(fileName);
598 if (image.isNull()) {
599 fileName = path;
600 fileName.append(model.bitmap);
601 fileName.append(".BMP");
602 image.load(fileName);
604 if (!image.isNull()) {
605 ui->imagePreview->setPixmap(QPixmap::fromImage(image.scaled( 64,32)));;
610 else {
611 ui->image->hide();
612 ui->modelImage_label->hide();
613 ui->imagePreview->hide();
616 QWidget * prevFocus = ui->image;
617 for (int i=0; i<CPN_MAX_TIMERS; i++) {
618 if (i<firmware->getCapability(Timers)) {
619 timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus);
620 ui->gridLayout->addWidget(timers[i], 1+i, 1);
621 connect(timers[i], SIGNAL(modified()), this, SLOT(onChildModified()));
622 prevFocus = timers[i]->getLastFocus();
624 else {
625 foreach(QLabel *label, findChildren<QLabel *>(QRegExp(QString("label_timer%1").arg(i+1)))) {
626 label->hide();
631 if (firmware->getCapability(HasTopLcd)) {
632 ui->toplcdTimer->setField(model.toplcdTimer, this);
633 for (int i=0; i<CPN_MAX_TIMERS; i++) {
634 if (i<firmware->getCapability(Timers)) {
635 ui->toplcdTimer->addItem(tr("Timer %1").arg(i+1), i);
639 else {
640 ui->toplcdTimerLabel->hide();
641 ui->toplcdTimer->hide();
644 if (!firmware->getCapability(HasDisplayText)) {
645 ui->displayText->hide();
648 if (!firmware->getCapability(GlobalFunctions)) {
649 ui->gfEnabled->hide();
652 // Beep Center checkboxes
653 prevFocus = ui->trimsDisplay;
654 int analogs = CPN_MAX_STICKS + firmware->getCapability(Pots) + firmware->getCapability(Sliders);
655 for (int i=0; i<analogs+firmware->getCapability(RotaryEncoders); i++) {
656 QCheckBox * checkbox = new QCheckBox(this);
657 checkbox->setProperty("index", i);
658 checkbox->setText(i<analogs ? firmware->getAnalogInputName(i) : RotaryEncoderString(i-analogs));
659 ui->centerBeepLayout->addWidget(checkbox, 0, i+1);
660 connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool)));
661 centerBeepCheckboxes << checkbox;
662 if (IS_HORUS_OR_TARANIS(board)) {
663 RawSource src(SOURCE_TYPE_STICK, i);
664 if (src.isPot() && !generalSettings.isPotAvailable(i-CPN_MAX_STICKS)) {
665 checkbox->hide();
667 else if (src.isSlider() && !generalSettings.isSliderAvailable(i-CPN_MAX_STICKS-firmware->getCapability(Pots))) {
668 checkbox->hide();
671 QWidget::setTabOrder(prevFocus, checkbox);
672 prevFocus = checkbox;
675 // Startup switches warnings
676 for (int i=0; i<firmware->getCapability(Switches); i++) {
677 Firmware::Switch sw = firmware->getSwitch(i);
678 if (IS_HORUS_OR_TARANIS(board)) {
679 sw.type = GeneralSettings::SwitchConfig(generalSettings.switchConfig[i]);
681 if (sw.type == GeneralSettings::SWITCH_NONE || sw.type == GeneralSettings::SWITCH_TOGGLE) {
682 continue;
684 QLabel * label = new QLabel(this);
685 QSlider * slider = new QSlider(this);
686 QCheckBox * cb = new QCheckBox(this);
687 slider->setProperty("index", i);
688 slider->setOrientation(Qt::Vertical);
689 slider->setMinimum(0);
690 slider->setInvertedAppearance(true);
691 slider->setTickPosition(QSlider::TicksBothSides);
692 slider->setMinimumSize(QSize(30, 50));
693 slider->setMaximumSize(QSize(50, 50));
694 slider->setSingleStep(1);
695 slider->setPageStep(1);
696 slider->setTickInterval(1);
697 label->setText(sw.name);
698 slider->setMaximum(sw.type == GeneralSettings::SWITCH_3POS ? 2 : 1);
699 cb->setProperty("index", i);
700 ui->switchesStartupLayout->addWidget(label, 0, i+1);
701 ui->switchesStartupLayout->setAlignment(label, Qt::AlignCenter);
702 ui->switchesStartupLayout->addWidget(slider, 1, i+1);
703 ui->switchesStartupLayout->setAlignment(slider, Qt::AlignCenter);
704 ui->switchesStartupLayout->addWidget(cb, 2, i+1);
705 ui->switchesStartupLayout->setAlignment(cb, Qt::AlignCenter);
706 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(startupSwitchEdited(int)));
707 connect(cb, SIGNAL(toggled(bool)), this, SLOT(startupSwitchToggled(bool)));
708 startupSwitchesSliders << slider;
709 startupSwitchesCheckboxes << cb;
710 QWidget::setTabOrder(prevFocus, slider);
711 QWidget::setTabOrder(slider, cb);
712 prevFocus = cb;
715 // Pot warnings
716 prevFocus = ui->potWarningMode;
717 if (IS_HORUS_OR_TARANIS(board)) {
718 for (int i=0; i<firmware->getCapability(Pots)+firmware->getCapability(Sliders); i++) {
719 QCheckBox * cb = new QCheckBox(this);
720 cb->setProperty("index", i);
721 cb->setText(firmware->getAnalogInputName(i+4));
722 ui->potWarningLayout->addWidget(cb, 0, i+1);
723 connect(cb, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool)));
724 potWarningCheckboxes << cb;
725 if (RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+i).isPot()) {
726 if (!generalSettings.isPotAvailable(i)) {
727 cb->hide();
730 else {
731 if (!generalSettings.isSliderAvailable(i-firmware->getCapability(Pots))) {
732 cb->hide();
735 QWidget::setTabOrder(prevFocus, cb);
736 prevFocus = cb;
739 else {
740 ui->label_potWarning->hide();
741 ui->potWarningMode->hide();
744 if (IS_ARM(board)) {
745 ui->trimsDisplay->setField(model.trimsDisplay, this);
747 else {
748 ui->labelTrimsDisplay->hide();
749 ui->trimsDisplay->hide();
752 for (int i=0; i<firmware->getCapability(NumModules); i++) {
753 modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i);
754 ui->modulesLayout->addWidget(modules[i]);
755 connect(modules[i], SIGNAL(modified()), this, SLOT(onChildModified()));
758 if (firmware->getCapability(ModelTrainerEnable)) {
759 modules[CPN_MAX_MODULES] = new ModulePanel(this, model, model.moduleData[CPN_MAX_MODULES], generalSettings, firmware, -1);
760 ui->modulesLayout->addWidget(modules[CPN_MAX_MODULES]);
761 connect(modules[CPN_MAX_MODULES], SIGNAL(modified()), this, SLOT(onChildModified()));
764 disableMouseScrolling();
766 lock = false;
769 SetupPanel::~SetupPanel()
771 delete ui;
774 void SetupPanel::on_extendedLimits_toggled(bool checked)
776 model->extendedLimits = checked;
777 emit extendedLimitsToggled();
778 emit modified();
781 void SetupPanel::on_throttleWarning_toggled(bool checked)
783 model->disableThrottleWarning = !checked;
784 emit modified();
787 void SetupPanel::on_throttleReverse_toggled(bool checked)
789 model->throttleReversed = checked;
790 emit modified();
793 void SetupPanel::on_extendedTrims_toggled(bool checked)
795 model->extendedTrims = checked;
796 emit modified();
799 void SetupPanel::on_trimIncrement_currentIndexChanged(int index)
801 model->trimInc = index-2;
802 emit modified();
805 void SetupPanel::on_throttleSource_currentIndexChanged(int index)
807 if (!lock) {
808 model->thrTraceSrc = index;
809 emit modified();
813 void SetupPanel::on_name_editingFinished()
815 int length = ui->name->maxLength();
816 strncpy(model->name, ui->name->text().toLatin1(), length);
817 emit modified();
820 void SetupPanel::on_image_currentIndexChanged(int index)
822 if (!lock) {
823 strncpy(model->bitmap, ui->image->currentText().toLatin1(), 10);
824 QString path = g.profile[g.id()].sdPath();
825 path.append("/IMAGES/");
826 QDir qd(path);
827 if (qd.exists()) {
828 QString fileName=path;
829 fileName.append(model->bitmap);
830 fileName.append(".bmp");
831 QImage image(fileName);
832 if (image.isNull()) {
833 fileName=path;
834 fileName.append(model->bitmap);
835 fileName.append(".BMP");
836 image.load(fileName);
838 if (!image.isNull()) {
839 ui->imagePreview->setPixmap(QPixmap::fromImage(image.scaled(64, 32)));;
841 else {
842 ui->imagePreview->clear();
845 else {
846 ui->imagePreview->clear();
848 emit modified();
852 void SetupPanel::populateThrottleSourceCB()
854 lock = true;
855 ui->throttleSource->clear();
856 ui->throttleSource->addItem(QObject::tr("THR"));
857 for (int i=0; i<firmware->getCapability(Pots)+firmware->getCapability(Sliders); i++) {
858 ui->throttleSource->addItem(firmware->getAnalogInputName(4+i), i);
860 for (int i=0; i<firmware->getCapability(Outputs); i++) {
861 ui->throttleSource->addItem(ModelPrinter::printChannelName(i));
863 ui->throttleSource->setCurrentIndex(model->thrTraceSrc);
864 lock = false;
867 void SetupPanel::update()
869 ui->name->setText(model->name);
870 ui->throttleReverse->setChecked(model->throttleReversed);
871 populateThrottleSourceCB();
872 ui->throttleWarning->setChecked(!model->disableThrottleWarning);
873 ui->trimIncrement->setCurrentIndex(model->trimInc+2);
874 ui->throttleTrim->setChecked(model->thrTrim);
875 ui->extendedLimits->setChecked(model->extendedLimits);
876 ui->extendedTrims->setChecked(model->extendedTrims);
877 ui->displayText->setChecked(model->displayChecklist);
878 ui->gfEnabled->setChecked(!model->noGlobalFunctions);
880 updateBeepCenter();
881 updateStartupSwitches();
883 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
884 updatePotWarnings();
887 for (int i=0; i<firmware->getCapability(Timers); i++) {
888 timers[i]->update();
891 for (int i=0; i<CPN_MAX_MODULES+1; i++) {
892 if (modules[i]) {
893 modules[i]->update();
898 void SetupPanel::updateBeepCenter()
900 for (int i=0; i<centerBeepCheckboxes.size(); i++) {
901 centerBeepCheckboxes[i]->setChecked(model->beepANACenter & (0x01 << i));
905 void SetupPanel::updateStartupSwitches()
907 lock = true;
909 uint64_t switchStates = model->switchWarningStates;
910 uint64_t value;
912 for (int i=0; i<startupSwitchesSliders.size(); i++) {
913 QSlider * slider = startupSwitchesSliders[i];
914 QCheckBox * cb = startupSwitchesCheckboxes[i];
915 int index = slider->property("index").toInt();
916 bool enabled = !(model->switchWarningEnable & (1 << index));
917 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
918 value = (switchStates >> 2*index) & 0x03;
919 if (generalSettings.switchConfig[index] != GeneralSettings::SWITCH_3POS && value == 2) {
920 value = 1;
923 else {
924 value = (i==0 ? switchStates & 0x3 : switchStates & 0x1);
925 switchStates >>= (i==0 ? 2 : 1);
927 slider->setValue(value);
928 slider->setEnabled(enabled);
929 cb->setChecked(enabled);
932 lock = false;
935 void SetupPanel::startupSwitchEdited(int value)
937 if (!lock) {
938 int shift = 0;
939 uint64_t mask;
940 int index = sender()->property("index").toInt();
942 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
943 shift = index * 2;
944 mask = 0x03ul << shift;
946 else {
947 if (index == 0) {
948 mask = 0x03;
950 else {
951 shift = index+1;
952 mask = 0x01ull << shift;
956 model->switchWarningStates &= ~mask;
958 if (IS_HORUS_OR_TARANIS(firmware->getBoard()) && generalSettings.switchConfig[index] != GeneralSettings::SWITCH_3POS) {
959 if (value == 1) {
960 value = 2;
964 if (value) {
965 model->switchWarningStates |= ((uint64_t)value << shift);
968 updateStartupSwitches();
969 emit modified();
973 void SetupPanel::startupSwitchToggled(bool checked)
975 if (!lock) {
976 int index = sender()->property("index").toInt();
978 if (checked)
979 model->switchWarningEnable &= ~(1 << index);
980 else
981 model->switchWarningEnable |= (1 << index);
983 updateStartupSwitches();
984 emit modified();
988 void SetupPanel::updatePotWarnings()
990 lock = true;
991 ui->potWarningMode->setCurrentIndex(model->potsWarningMode);
992 for (int i=0; i<potWarningCheckboxes.size(); i++) {
993 QCheckBox *checkbox = potWarningCheckboxes[i];
994 int index = checkbox->property("index").toInt();
995 checkbox->setChecked(!model->potsWarningEnabled[index]);
996 checkbox->setDisabled(model->potsWarningMode == 0);
998 lock = false;
1001 void SetupPanel::potWarningToggled(bool checked)
1003 if (!lock) {
1004 int index = sender()->property("index").toInt();
1005 model->potsWarningEnabled[index] = !checked;
1006 updatePotWarnings();
1007 emit modified();
1011 void SetupPanel::on_potWarningMode_currentIndexChanged(int index)
1013 if (!lock) {
1014 model->potsWarningMode = index;
1015 updatePotWarnings();
1016 emit modified();
1020 void SetupPanel::on_displayText_toggled(bool checked)
1022 model->displayChecklist = checked;
1023 emit modified();
1026 void SetupPanel::on_gfEnabled_toggled(bool checked)
1028 model->noGlobalFunctions = !checked;
1029 emit modified();
1032 void SetupPanel::on_throttleTrim_toggled(bool checked)
1034 model->thrTrim = checked;
1035 emit modified();
1038 void SetupPanel::onBeepCenterToggled(bool checked)
1040 if (!lock) {
1041 int index = sender()->property("index").toInt();
1042 unsigned int mask = (0x01 << index);
1043 if (checked)
1044 model->beepANACenter |= mask;
1045 else
1046 model->beepANACenter &= ~mask;
1047 emit modified();
1051 void SetupPanel::onChildModified()
1053 emit modified();