diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 36cdcd951..41ddf0b3d 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -203,6 +203,15 @@ void ConfigOutputWidget::runChannelTests(bool state) if (state) { sendAllChannelTests(); } + + // Add info at end + if (!state && isDirty()) { + QMessageBox mbox; + mbox.setText(QString(tr("You may want to save your neutral settings."))); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.setIcon(QMessageBox::Information); + mbox.exec(); + } } OutputChannelForm *ConfigOutputWidget::getOutputChannelForm(const int index) const diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp index 06d0f443b..a57a7126e 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp @@ -56,6 +56,15 @@ OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) : ui.actuatorMax->setMinimum(MINOUTPUT_VALUE); ui.actuatorValue->setMinimum(MINOUTPUT_VALUE); + // Remove keyboard focus + ui.actuatorMin->setFocusPolicy(Qt::ClickFocus); + ui.actuatorMax->setFocusPolicy(Qt::ClickFocus); + ui.actuatorRev->setFocusPolicy(Qt::ClickFocus); + ui.actuatorLink->setFocusPolicy(Qt::ClickFocus); + ui.actuatorValue->setFocusPolicy(Qt::NoFocus); + + setChannelRange(); + disableMouseWheelEvents(); } @@ -120,11 +129,12 @@ void OutputChannelForm::enableChannelTest(bool state) } else { ui.actuatorMin->setEnabled(true); ui.actuatorMax->setEnabled(true); - ui.actuatorRev->setEnabled(true); + if (m_mixerType != "Motor") { + ui.actuatorRev->setEnabled(true); + } } } - /** * Toggles the channel linked state for use in testing mode */ @@ -139,7 +149,7 @@ void OutputChannelForm::linkToggled(bool state) if (!parent()) { return; } - int min = 10000; + int min = MAXOUTPUT_VALUE; int linked_count = 0; QList outputChannelForms = parent()->findChildren(); // set the linked channels of the parent widget to the same value @@ -179,7 +189,7 @@ int OutputChannelForm::max() const */ void OutputChannelForm::setMax(int maximum) { - setRange(ui.actuatorMin->value(), maximum); + setRange(ui.actuatorMax->value(), maximum); } int OutputChannelForm::min() const @@ -192,7 +202,7 @@ int OutputChannelForm::min() const */ void OutputChannelForm::setMin(int minimum) { - setRange(minimum, ui.actuatorMax->value()); + setRange(minimum, ui.actuatorMin->value()); } int OutputChannelForm::neutral() const @@ -216,11 +226,6 @@ void OutputChannelForm::setRange(int minimum, int maximum) ui.actuatorMin->setValue(minimum); ui.actuatorMax->setValue(maximum); setChannelRange(); - if (ui.actuatorMin->value() > ui.actuatorMax->value()) { - ui.actuatorRev->setChecked(true); - } else { - ui.actuatorRev->setChecked(false); - } } /** @@ -232,39 +237,59 @@ void OutputChannelForm::setRange(int minimum, int maximum) */ void OutputChannelForm::setChannelRange() { - int oldMini = ui.actuatorNeutral->minimum(); int minValue = ui.actuatorMin->value(); int maxValue = ui.actuatorMax->value(); - // int oldMaxi = ui.actuatorNeutral->maximum(); + int oldMini = ui.actuatorNeutral->minimum(); + int oldMaxi = ui.actuatorNeutral->maximum(); - if (minValue <= maxValue) { - ui.actuatorNeutral->setRange(ui.actuatorMin->value(), ui.actuatorMax->value()); - ui.actuatorRev->setChecked(false); + m_mixerType = outputMixerType(); + + // Red handle for Motors + if ((m_mixerType == "Motor") || (m_mixerType == "ReversableMotor")) { + ui.actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(255, 100, 100); width: 18px; height: 28px;" + "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }"); } else { - ui.actuatorNeutral->setRange(ui.actuatorMax->value(), ui.actuatorMin->value()); - ui.actuatorRev->setChecked(true); + ui.actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(196, 196, 196); width: 18px; height: 28px;" + "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }"); } + // Normal motor will be *** never *** reversed : without arming a "Min" value (like 1900) can be applied ! + if (m_mixerType == "Motor") { + if (minValue >= maxValue) { + // Keep old values + ui.actuatorMin->setValue(oldMini); + ui.actuatorMax->setValue(oldMaxi); + } + ui.actuatorRev->setChecked(false); + ui.actuatorRev->setEnabled(false); + ui.actuatorNeutral->setInvertedAppearance(false); + ui.actuatorNeutral->setRange(ui.actuatorMin->value(), ui.actuatorMax->value()); + } else { + // Others output (!Motor) + // Auto check reverse checkbox SpinBox Min/Max changes + ui.actuatorRev->setEnabled(true); + if (minValue <= maxValue) { + ui.actuatorRev->setChecked(false); + ui.actuatorNeutral->setInvertedAppearance(false); + ui.actuatorNeutral->setRange(minValue, maxValue); + } else { + ui.actuatorRev->setChecked(true); + ui.actuatorNeutral->setInvertedAppearance(true); + ui.actuatorNeutral->setRange(maxValue, minValue); + } + } + // If old neutral was Min, stay Min if (ui.actuatorNeutral->value() == oldMini) { ui.actuatorNeutral->setValue(ui.actuatorNeutral->minimum()); } // Enable only outputs already set in mixer - if (name() != "-") { + if (m_mixerType != "Disabled") { ui.actuatorMin->setEnabled(true); ui.actuatorMax->setEnabled(true); ui.actuatorNeutral->setEnabled(true); ui.actuatorValue->setEnabled(true); - - // Enable checkboxes Rev and Link if some range - if (minValue != maxValue) { - ui.actuatorRev->setEnabled(true); - ui.actuatorLink->setEnabled(true); - } else { - ui.actuatorRev->setEnabled(false); - ui.actuatorLink->setEnabled(false); - } } else { ui.actuatorMin->setEnabled(false); ui.actuatorMax->setEnabled(false); @@ -273,13 +298,9 @@ void OutputChannelForm::setChannelRange() ui.actuatorMin->setValue(1000); ui.actuatorMax->setValue(1000); ui.actuatorNeutral->setRange(minValue, maxValue); - ui.actuatorNeutral->setEnabled(false); + ui.actuatorNeutral->setValue(minValue); ui.actuatorValue->setEnabled(false); } - - // if (ui.actuatorNeutral->value() == oldMaxi) - // this can be dangerous if it happens to be controlling a motor at the time! - // ui.actuatorNeutral->setValue(ui.actuatorNeutral->maximum()); } /** @@ -287,30 +308,17 @@ void OutputChannelForm::setChannelRange() */ void OutputChannelForm::reverseChannel(bool state) { - // Sanity check: if state became true, make sure the Maxvalue was higher than Minvalue - // the situations below can happen! - if (state && (ui.actuatorMax->value() < ui.actuatorMin->value())) { - return; - } - if (!state && (ui.actuatorMax->value() > ui.actuatorMin->value())) { - return; - } + // if 'state' (reverse channel requested) apply only if not already reversed + if ((state && (ui.actuatorMax->value() > ui.actuatorMin->value())) + || (!state && (ui.actuatorMax->value() < ui.actuatorMin->value()))) { + // Now, swap the min & max values (spin boxes) + int temp = ui.actuatorMax->value(); + ui.actuatorMax->setValue(ui.actuatorMin->value()); + ui.actuatorMin->setValue(temp); + ui.actuatorNeutral->setInvertedAppearance(state); - // Now, swap the min & max values (only on the spinboxes, the slider does not change!) - int temp = ui.actuatorMax->value(); - ui.actuatorMax->setValue(ui.actuatorMin->value()); - ui.actuatorMin->setValue(temp); - - // Also update the channel value - // This is a trick to force the slider to update its value and - // emit the right signal itself, because our sendChannelTest(int) method - // relies on the object sender's identity. - if (ui.actuatorNeutral->value() < ui.actuatorNeutral->maximum()) { - ui.actuatorNeutral->setValue(ui.actuatorNeutral->value() + 1); - ui.actuatorNeutral->setValue(ui.actuatorNeutral->value() - 1); - } else { - ui.actuatorNeutral->setValue(ui.actuatorNeutral->value() - 1); - ui.actuatorNeutral->setValue(ui.actuatorNeutral->value() + 1); + setChannelRange(); + return; } } @@ -328,10 +336,6 @@ void OutputChannelForm::sendChannelTest(int value) return; } - if (ui.actuatorRev->isChecked()) { - // the channel is reversed - value = ui.actuatorMin->value() - value + ui.actuatorMax->value(); - } // update the label ui.actuatorValue->setValue(value); @@ -370,3 +374,21 @@ void OutputChannelForm::sendChannelTest(int value) } emit channelChanged(index(), value); } + +/** + * + * Returns MixerType + */ +QString OutputChannelForm::outputMixerType() +{ + UAVDataObject *mixer = dynamic_cast(getObjectManager()->getObject(QString("MixerSettings"))); + + Q_ASSERT(mixer); + + QString mixerNumType = QString("Mixer%1Type").arg(index() + 1); + UAVObjectField *field = mixer->getField(mixerNumType); + Q_ASSERT(field); + QString mixerType = field->getValue().toString(); + + return mixerType; +} diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.h b/ground/openpilotgcs/src/plugins/config/outputchannelform.h index e17155f41..e10891c2a 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.h +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.h @@ -58,6 +58,7 @@ public slots: void setNeutral(int value); void setRange(int minimum, int maximum); void enableChannelTest(bool state); + QString outputMixerType(); signals: void channelChanged(int index, int value); @@ -65,6 +66,7 @@ signals: private: Ui::outputChannelForm ui; bool m_inChannelTest; + QString m_mixerType; private slots: void linkToggled(bool state);