diff --git a/plugins/feature/gs232controller/CMakeLists.txt b/plugins/feature/gs232controller/CMakeLists.txt index c849be982..c35195adb 100644 --- a/plugins/feature/gs232controller/CMakeLists.txt +++ b/plugins/feature/gs232controller/CMakeLists.txt @@ -45,6 +45,7 @@ if(NOT SERVER_MODE) gs232controllergui.h dfmstatusdialog.h inputcontroller.h + inputcontrollersettings.h ) set(TARGET_NAME featuregs232controller) diff --git a/plugins/feature/gs232controller/gamepadconfigurationdialog.cpp b/plugins/feature/gs232controller/gamepadconfigurationdialog.cpp index b4b0c886e..200c37487 100644 --- a/plugins/feature/gs232controller/gamepadconfigurationdialog.cpp +++ b/plugins/feature/gs232controller/gamepadconfigurationdialog.cpp @@ -19,17 +19,32 @@ #include #include "gamepadconfigurationdialog.h" +#include "inputcontrollersettings.h" -GamepadConfigurationDialog::GamepadConfigurationDialog(QGamepad *gamepad, QWidget* parent) : +GamepadConfigurationDialog::GamepadConfigurationDialog(QGamepad *gamepad, InputControllerSettings *settings, bool supportsConfiguraiton, QWidget* parent) : QDialog(parent), ui(new Ui::GamepadConfigurationDialog), - m_gamepad(gamepad) + m_gamepad(gamepad), + m_settings(settings) { ui->setupUi(this); connect(m_gamepad, &QGamepad::axisRightXChanged, this, &GamepadConfigurationDialog::axisRightXChanged); connect(m_gamepad, &QGamepad::axisRightYChanged, this, &GamepadConfigurationDialog::axisRightYChanged); connect(m_gamepad, &QGamepad::axisLeftXChanged, this, &GamepadConfigurationDialog::axisLeftXChanged); connect(m_gamepad, &QGamepad::axisLeftYChanged, this, &GamepadConfigurationDialog::axisLeftYChanged); + ui->deadzone0->setValue(settings->m_deadzone[0]); + ui->deadzone1->setValue(settings->m_deadzone[1]); + ui->deadzone2->setValue(settings->m_deadzone[2]); + ui->deadzone3->setValue(settings->m_deadzone[3]); + ui->lowSensitivity->blockSignals(true); + ui->lowSensitivity->setRange(0.01, 100); + ui->lowSensitivity->blockSignals(false); + ui->lowSensitivity->setValue((double)settings->m_lowSensitivity); + ui->highSensitivity->blockSignals(true); + ui->highSensitivity->setRange(0.01, 100); + ui->highSensitivity->blockSignals(false); + ui->highSensitivity->setValue((double)settings->m_highSensitivity); + ui->configurationGroup->setEnabled(supportsConfiguraiton); } GamepadConfigurationDialog::~GamepadConfigurationDialog() @@ -42,6 +57,11 @@ void GamepadConfigurationDialog::accept() QDialog::accept(); } +void GamepadConfigurationDialog::on_configReset_clicked() +{ + QGamepadManager::instance()->resetConfiguration(m_gamepad->deviceId()); +} + void GamepadConfigurationDialog::on_config0_clicked() { ui->config0->setText("Configuring"); @@ -121,3 +141,52 @@ void GamepadConfigurationDialog::axisLeftYChanged(double value) ui->config2->setEnabled(true); ui->config3->setEnabled(true); } + +// Convert double to string and remove trailing zeros +static QString toSimpleFloat(double v, int prec) +{ + QString s = QString::number(v, 'f', prec); + while (s.back() == '0') { + s.chop(1); + } + if (s.back() == '.') { + s.chop(1); + } + return s; +} + +void GamepadConfigurationDialog::on_lowSensitivity_logValueChanged(double value) +{ + m_settings->m_lowSensitivity = value; + ui->lowSensitivityText->setText(QString("%1%").arg(toSimpleFloat(m_settings->m_lowSensitivity, 4))); +} + +void GamepadConfigurationDialog::on_highSensitivity_logValueChanged(double value) +{ + m_settings->m_highSensitivity = value; + ui->highSensitivityText->setText(QString("%1%").arg(toSimpleFloat(m_settings->m_highSensitivity, 4))); +} + +void GamepadConfigurationDialog::on_deadzone0_valueChanged(int value) +{ + m_settings->m_deadzone[0] = value; + ui->deadzone0Text->setText(QString("%1%").arg(m_settings->m_deadzone[0])); +} + +void GamepadConfigurationDialog::on_deadzone1_valueChanged(int value) +{ + m_settings->m_deadzone[1] = value; + ui->deadzone1Text->setText(QString("%1%").arg(m_settings->m_deadzone[1])); +} + +void GamepadConfigurationDialog::on_deadzone2_valueChanged(int value) +{ + m_settings->m_deadzone[2] = value; + ui->deadzone2Text->setText(QString("%1%").arg(m_settings->m_deadzone[2])); +} + +void GamepadConfigurationDialog::on_deadzone3_valueChanged(int value) +{ + m_settings->m_deadzone[3] = value; + ui->deadzone3Text->setText(QString("%1%").arg(m_settings->m_deadzone[3])); +} diff --git a/plugins/feature/gs232controller/gamepadconfigurationdialog.h b/plugins/feature/gs232controller/gamepadconfigurationdialog.h index 4f0db8551..cdfeb664e 100644 --- a/plugins/feature/gs232controller/gamepadconfigurationdialog.h +++ b/plugins/feature/gs232controller/gamepadconfigurationdialog.h @@ -21,16 +21,18 @@ #include "ui_gamepadconfigurationdialog.h" class QGamepad; +struct InputControllerSettings; class GamepadConfigurationDialog : public QDialog { Q_OBJECT public: - explicit GamepadConfigurationDialog(QGamepad *gamepad, QWidget* parent = 0); + explicit GamepadConfigurationDialog(QGamepad *gamepad, InputControllerSettings *settings, bool supportsConfiguraiton, QWidget* parent = 0); ~GamepadConfigurationDialog(); private slots: void accept(); + void on_configReset_clicked(); void on_config0_clicked(); void on_config1_clicked(); void on_config2_clicked(); @@ -39,10 +41,17 @@ private slots: void axisRightYChanged(double value); void axisLeftXChanged(double value); void axisLeftYChanged(double value); + void on_lowSensitivity_logValueChanged(double value); + void on_highSensitivity_logValueChanged(double value); + void on_deadzone0_valueChanged(int value); + void on_deadzone1_valueChanged(int value); + void on_deadzone2_valueChanged(int value); + void on_deadzone3_valueChanged(int value); private: Ui::GamepadConfigurationDialog* ui; QGamepad *m_gamepad; + InputControllerSettings *m_settings; }; #endif // INCLUDE_GAMEPADCONFIGURATIONDIALOG_H diff --git a/plugins/feature/gs232controller/gamepadconfigurationdialog.ui b/plugins/feature/gs232controller/gamepadconfigurationdialog.ui index 9c9ddcf65..4830ee9dd 100644 --- a/plugins/feature/gs232controller/gamepadconfigurationdialog.ui +++ b/plugins/feature/gs232controller/gamepadconfigurationdialog.ui @@ -6,8 +6,8 @@ 0 0 - 380 - 309 + 383 + 568 @@ -21,10 +21,37 @@ - + + + Configuration + - - + + + + Reset configuration + + + Reset + + + + + + + 0 + + + + + + + Elevation Offset Axis + + + + + 0 @@ -37,48 +64,6 @@ - - - - 0 - - - - - - - Configure - - - - - - - Elevation Offset Axis - - - - - - - 0 - - - - - - - Configure - - - - - - - Azimuth Offset Axis - - - @@ -86,40 +71,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Target Aziumth/X Axis - - - - - - - 0 - - - - - - - Configure - - - @@ -136,9 +87,264 @@ + + + + Configure + + + + + + + Target Aziumth/X Axis + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Configure + + + + + + + + 60 + 0 + + + + 0 + + + + + + + Configure + + + + + + + 0 + + + + + + + Azimuth Offset Axis + + + + + + + Deadzones + + + + + + Target Azimuth/X Axis + + + + + + + 100 + + + 1 + + + Qt::Horizontal + + + + + + + + 35 + 0 + + + + 0% + + + + + + + Target Elevation/Y Axis + + + + + + + 100 + + + 1 + + + Qt::Horizontal + + + + + + + 0% + + + + + + + Azimuth Offset Axis + + + + + + + 100 + + + 1 + + + Qt::Horizontal + + + + + + + 0% + + + + + + + Elevation Offset Axis + + + + + + + 100 + + + 1 + + + Qt::Horizontal + + + + + + + 0% + + + + + + + + + + Sensitivity + + + + + + + + + 100% + + + + + + + + 65 + 0 + + + + + 0 + 0 + + + + Low + + + + + + + + 65 + 0 + + + + 100% + + + + + + + High + + + + + + + + + + + + @@ -151,6 +357,13 @@ + + + LogLabelSlider + QSlider +
gui/loglabelslider.h
+
+
config0 config1 @@ -166,8 +379,8 @@ accept() - 248 - 254 + 257 + 519 157 @@ -182,8 +395,8 @@ reject() - 316 - 260 + 325 + 519 286 diff --git a/plugins/feature/gs232controller/gamepadinputcontroller.cpp b/plugins/feature/gs232controller/gamepadinputcontroller.cpp index eacffab9d..2096e5ed4 100644 --- a/plugins/feature/gs232controller/gamepadinputcontroller.cpp +++ b/plugins/feature/gs232controller/gamepadinputcontroller.cpp @@ -26,12 +26,25 @@ GamepadInputController::GamepadInputController(int deviceId) : m_rightX(0.0), m_rightY(0.0), m_leftX(0.0), - m_leftY(0.0) + m_leftY(0.0), + m_configurationDialog(nullptr) { connect(&m_gamepad, &QGamepad::axisRightXChanged, this, &GamepadInputController::axisRightXChanged); connect(&m_gamepad, &QGamepad::axisRightYChanged, this, &GamepadInputController::axisRightYChanged); connect(&m_gamepad, &QGamepad::axisLeftXChanged, this, &GamepadInputController::axisLeftXChanged); connect(&m_gamepad, &QGamepad::axisLeftYChanged, this, &GamepadInputController::axisLeftYChanged); + connect(&m_gamepad, &QGamepad::buttonAChanged, this, &GamepadInputController::buttonAChanged); + connect(&m_gamepad, &QGamepad::buttonBChanged, this, &GamepadInputController::buttonBChanged); + connect(&m_gamepad, &QGamepad::buttonXChanged, this, &GamepadInputController::buttonXChanged); + connect(&m_gamepad, &QGamepad::buttonYChanged, this, &GamepadInputController::buttonYChanged); + connect(&m_gamepad, &QGamepad::buttonUpChanged, this, &GamepadInputController::buttonUpChanged); + connect(&m_gamepad, &QGamepad::buttonDownChanged, this, &GamepadInputController::buttonDownChanged); + connect(&m_gamepad, &QGamepad::buttonLeftChanged, this, &GamepadInputController::buttonLeftChanged); + connect(&m_gamepad, &QGamepad::buttonRightChanged, this, &GamepadInputController::buttonRightChanged); + connect(&m_gamepad, &QGamepad::buttonR1Changed, this, &GamepadInputController::buttonR1Changed); + connect(&m_gamepad, &QGamepad::buttonL1Changed, this, &GamepadInputController::buttonL1Changed); + connect(&m_gamepad, &QGamepad::buttonR3Changed, this, &GamepadInputController::buttonR3Changed); + connect(&m_gamepad, &QGamepad::buttonL3Changed, this, &GamepadInputController::buttonL3Changed); } double GamepadInputController::getAxisValue(int axis) @@ -65,20 +78,27 @@ bool GamepadInputController::supportsConfiguration() const #endif } -void GamepadInputController::configure() +void GamepadInputController::configure(InputControllerSettings *settings) { - disconnect(&m_gamepad, &QGamepad::axisRightXChanged, this, &GamepadInputController::axisRightXChanged); - disconnect(&m_gamepad, &QGamepad::axisRightYChanged, this, &GamepadInputController::axisRightYChanged); - disconnect(&m_gamepad, &QGamepad::axisLeftXChanged, this, &GamepadInputController::axisLeftXChanged); - disconnect(&m_gamepad, &QGamepad::axisLeftYChanged, this, &GamepadInputController::axisLeftYChanged); + if (!m_configurationDialog) + { + m_configurationDialog = new GamepadConfigurationDialog(&m_gamepad, settings, supportsConfiguration()); + connect(m_configurationDialog, &QDialog::finished, this, &GamepadInputController::configurationDialogClosed); + m_configurationDialog->setAttribute(Qt::WA_DeleteOnClose, true); + m_configurationDialog->setModal(false); + m_configurationDialog->show(); + } + else + { + m_configurationDialog->raise(); + m_configurationDialog->activateWindow(); + } +} - GamepadConfigurationDialog dialog(&m_gamepad); - dialog.exec(); - - connect(&m_gamepad, &QGamepad::axisRightXChanged, this, &GamepadInputController::axisRightXChanged); - connect(&m_gamepad, &QGamepad::axisRightYChanged, this, &GamepadInputController::axisRightYChanged); - connect(&m_gamepad, &QGamepad::axisLeftXChanged, this, &GamepadInputController::axisLeftXChanged); - connect(&m_gamepad, &QGamepad::axisLeftYChanged, this, &GamepadInputController::axisLeftYChanged); +void GamepadInputController::configurationDialogClosed() +{ + m_configurationDialog = false; + emit configurationComplete(); } void GamepadInputController::axisRightXChanged(double value) @@ -101,6 +121,66 @@ void GamepadInputController::axisLeftYChanged(double value) m_leftY = value; } +void GamepadInputController::buttonAChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_RIGHT_BOTTOM, !value); +} + +void GamepadInputController::buttonBChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_RIGHT_RIGHT, !value); +} + +void GamepadInputController::buttonXChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_RIGHT_LEFT, !value); +} + +void GamepadInputController::buttonYChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_RIGHT_TOP, !value); +} + +void GamepadInputController::buttonUpChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_LEFT_UP, !value); +} + +void GamepadInputController::buttonDownChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_LEFT_DOWN, !value); +} + +void GamepadInputController::buttonLeftChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_LEFT_LEFT, !value); +} + +void GamepadInputController::buttonRightChanged(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_LEFT_RIGHT, !value); +} + +void GamepadInputController::buttonL1Changed(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_L1, !value); +} + +void GamepadInputController::buttonR1Changed(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_R1, !value); +} + +void GamepadInputController::buttonL3Changed(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_L3, !value); +} + +void GamepadInputController::buttonR3Changed(bool value) +{ + emit buttonChanged(INPUTCONTROLLER_BUTTON_R3, !value); +} + QStringList GamepadInputController::getAllControllers() { QStringList names; diff --git a/plugins/feature/gs232controller/gamepadinputcontroller.h b/plugins/feature/gs232controller/gamepadinputcontroller.h index 996d12f94..340c6f178 100644 --- a/plugins/feature/gs232controller/gamepadinputcontroller.h +++ b/plugins/feature/gs232controller/gamepadinputcontroller.h @@ -22,6 +22,8 @@ #include +class GamepadConfigurationDialog; + class GamepadInputController : public InputController { public: @@ -30,17 +32,30 @@ public: double getAxisValue(int axis) override; int getNumberOfAxes() const override; bool supportsConfiguration() const override; - void configure() override; + void configure(InputControllerSettings *settings) override; static QStringList getAllControllers(); static GamepadInputController* open(const QString& name); private slots: + void configurationDialogClosed(); void axisRightXChanged(double value); void axisRightYChanged(double value); void axisLeftXChanged(double value); void axisLeftYChanged(double value); + void buttonAChanged(bool value); + void buttonBChanged(bool value); + void buttonXChanged(bool value); + void buttonYChanged(bool value); + void buttonUpChanged(bool value); + void buttonDownChanged(bool value); + void buttonLeftChanged(bool value); + void buttonRightChanged(bool value); + void buttonL1Changed(bool value); + void buttonR1Changed(bool value); + void buttonL3Changed(bool value); + void buttonR3Changed(bool value); private: @@ -49,6 +64,8 @@ private: double m_rightY; double m_leftX; double m_leftY; + GamepadConfigurationDialog *m_configurationDialog; + }; #endif // INCLUDE_FEATURE_GAMEPADINPUTCONTROLLER_H_ diff --git a/plugins/feature/gs232controller/gs232controller.cpp b/plugins/feature/gs232controller/gs232controller.cpp index ba8fda383..f12496ff4 100644 --- a/plugins/feature/gs232controller/gs232controller.cpp +++ b/plugins/feature/gs232controller/gs232controller.cpp @@ -492,7 +492,7 @@ void GS232Controller::webapiFormatFeatureSettings( response.getGs232ControllerSettings()->setPrecision(settings.m_precision); response.getGs232ControllerSettings()->setCoordinates((int)settings.m_coordinates); response.getGs232ControllerSettings()->setInputController(new QString(settings.m_inputController)); - response.getGs232ControllerSettings()->setInputSensitivity(settings.m_inputSensitivity); + response.getGs232ControllerSettings()->setInputSensitivity(settings.m_inputControllerSettings.m_lowSensitivity); if (response.getGs232ControllerSettings()->getTitle()) { *response.getGs232ControllerSettings()->getTitle() = settings.m_title; @@ -591,7 +591,7 @@ void GS232Controller::webapiUpdateFeatureSettings( settings.m_inputController = *response.getGs232ControllerSettings()->getInputController(); } if (featureSettingsKeys.contains("inputSensitivity")) { - settings.m_inputSensitivity = response.getGs232ControllerSettings()->getInputSensitivity(); + settings.m_inputControllerSettings.m_lowSensitivity = response.getGs232ControllerSettings()->getInputSensitivity(); } if (featureSettingsKeys.contains("title")) { settings.m_title = *response.getGs232ControllerSettings()->getTitle(); @@ -688,7 +688,7 @@ void GS232Controller::webapiReverseSendSettings(const QList& featureSet swgGS232ControllerSettings->setInputController(new QString(settings.m_inputController)); } if (featureSettingsKeys.contains("inputSensitivity") || force) { - swgGS232ControllerSettings->setInputSensitivity(settings.m_inputSensitivity); + swgGS232ControllerSettings->setInputSensitivity(settings.m_inputControllerSettings.m_lowSensitivity); } if (featureSettingsKeys.contains("title") || force) { swgGS232ControllerSettings->setTitle(new QString(settings.m_title)); diff --git a/plugins/feature/gs232controller/gs232controllergui.cpp b/plugins/feature/gs232controller/gs232controllergui.cpp index eea0a2b4b..4579dfa47 100644 --- a/plugins/feature/gs232controller/gs232controllergui.cpp +++ b/plugins/feature/gs232controller/gs232controllergui.cpp @@ -252,7 +252,8 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu m_settings.setRollupState(&m_rollupState); - ui->inputConfigure->setVisible(false); + //ui->inputConfigure->setVisible(false); + ui->inputConfigure->setEnabled(false); updateInputControllerList(); connect(InputControllerManager::instance(), &InputControllerManager::controllersChanged, this, &GS232ControllerGUI::updateInputControllerList); connect(&m_inputTimer, &QTimer::timeout, this, &GS232ControllerGUI::checkInputController); @@ -293,6 +294,8 @@ void GS232ControllerGUI::updateInputController() m_inputController = InputControllerManager::open(m_settings.m_inputController); if (m_inputController) { + connect(m_inputController, &InputController::buttonChanged, this, &GS232ControllerGUI::buttonChanged); + connect(m_inputController, &InputController::configurationComplete, this, &GS232ControllerGUI::inputConfigurationComplete); m_inputTimer.start(20); enabled = true; } @@ -301,12 +304,32 @@ void GS232ControllerGUI::updateInputController() { m_inputTimer.stop(); } - - ui->inputSensitivityLabel->setEnabled(enabled); - ui->inputSensitivity->setEnabled(enabled); - ui->inputSensitivityText->setEnabled(enabled); ui->inputConfigure->setEnabled(enabled); - ui->inputConfigure->setVisible(enabled && m_inputController->supportsConfiguration()); +} + +void GS232ControllerGUI::buttonChanged(int button, bool released) +{ + if (!released) + { + switch (button) + { + case INPUTCONTROLLER_BUTTON_RIGHT_TOP: + ui->startStop->doToggle(!ui->startStop->isChecked()); + break; + case INPUTCONTROLLER_BUTTON_RIGHT_BOTTOM: + ui->track->click(); + break; + case INPUTCONTROLLER_BUTTON_RIGHT_RIGHT: + ui->enableTargetControl->click(); + break; + case INPUTCONTROLLER_BUTTON_RIGHT_LEFT: + ui->enableOffsetControl->click(); + break; + case INPUTCONTROLLER_BUTTON_R1: + ui->highSensitivity->click(); + break; + } + } } void GS232ControllerGUI::checkInputController() @@ -319,8 +342,11 @@ void GS232ControllerGUI::checkInputController() if (!m_settings.m_track) { - m_inputCoord1 += m_settings.m_inputSensitivity * m_inputController->getAxisValue(0); - m_inputCoord2 += m_settings.m_inputSensitivity * -m_inputController->getAxisValue(1); + if (m_settings.m_targetControlEnabled) + { + m_inputCoord1 += m_extraSensitivity * m_inputController->getAxisCalibratedValue(0, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + m_inputCoord2 += m_extraSensitivity * -m_inputController->getAxisCalibratedValue(1, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + } if (m_settings.m_coordinates == GS232ControllerSettings::AZ_EL) { @@ -340,13 +366,19 @@ void GS232ControllerGUI::checkInputController() if ((m_inputController->getNumberOfAxes() < 4) && m_settings.m_track) { - m_inputAzOffset += m_settings.m_inputSensitivity * m_inputController->getAxisValue(0); - m_inputElOffset += m_settings.m_inputSensitivity * -m_inputController->getAxisValue(1); + if (m_settings.m_offsetControlEnabled) + { + m_inputAzOffset += m_extraSensitivity * m_inputController->getAxisCalibratedValue(0, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + m_inputElOffset += m_extraSensitivity * -m_inputController->getAxisCalibratedValue(1, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + } } else if (m_inputController->getNumberOfAxes() >= 4) { - m_inputAzOffset += m_settings.m_inputSensitivity * m_inputController->getAxisValue(2); - m_inputElOffset += m_settings.m_inputSensitivity * -m_inputController->getAxisValue(3); + if (m_settings.m_offsetControlEnabled) + { + m_inputAzOffset += m_extraSensitivity * m_inputController->getAxisCalibratedValue(2, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + m_inputElOffset += m_extraSensitivity * -m_inputController->getAxisCalibratedValue(3, &m_settings.m_inputControllerSettings, m_settings.m_highSensitivity); + } } m_inputAzOffset = std::max(m_inputAzOffset, -360.0); m_inputAzOffset = std::min(m_inputAzOffset, 360.0); @@ -374,25 +406,47 @@ void GS232ControllerGUI::on_inputController_currentIndexChanged(int index) if (index >= 0) { m_settings.m_inputController = ui->inputController->currentText(); + m_settingsKeys.append("inputController"); applySettings(); updateInputController(); } } -void GS232ControllerGUI::on_inputSensitivty_valueChanged(int value) -{ - m_settings.m_inputSensitivity = value / 1000.0; - ui->inputSensitivityText->setText(QString("%1%").arg(m_settings.m_inputSensitivity * 100.0)); - applySettings(); -} - void GS232ControllerGUI::on_inputConfigure_clicked() { if (m_inputController) { - m_inputController->configure(); + m_inputController->configure(&m_settings.m_inputControllerSettings); } } +void GS232ControllerGUI::on_highSensitivity_clicked(bool checked) +{ + m_settings.m_highSensitivity = checked; + ui->highSensitivity->setText(checked ? "H" : "L"); + m_settingsKeys.append("highSensitivity"); + applySettings(); +} + +void GS232ControllerGUI::on_enableTargetControl_clicked(bool checked) +{ + m_settings.m_targetControlEnabled = checked; + m_settingsKeys.append("targetControlEnabled"); + applySettings(); +} + +void GS232ControllerGUI::on_enableOffsetControl_clicked(bool checked) +{ + m_settings.m_offsetControlEnabled = checked; + m_settingsKeys.append("offsetControlEnabled"); + applySettings(); +} + +void GS232ControllerGUI::inputConfigurationComplete() +{ + m_settingsKeys.append("inputControllerSettings"); + applySettings(); +} + GS232ControllerGUI::~GS232ControllerGUI() { m_dfmStatusDialog.close(); @@ -440,8 +494,9 @@ void GS232ControllerGUI::displaySettings() ui->elevationMax->setValue(m_settings.m_elevationMax); ui->tolerance->setValue(m_settings.m_tolerance); ui->inputController->setCurrentText(m_settings.m_inputController); - ui->inputSensitivity->setValue((int) (m_settings.m_inputSensitivity * 1000.0)); - ui->inputSensitivityText->setText(QString("%1%").arg(m_settings.m_inputSensitivity * 100.0)); + ui->highSensitivity->setChecked(m_settings.m_highSensitivity); + ui->enableTargetControl->setChecked(m_settings.m_targetControlEnabled); + ui->enableOffsetControl->setChecked(m_settings.m_offsetControlEnabled); ui->dfmTrack->setChecked(m_settings.m_dfmTrackOn); ui->dfmLubePumps->setChecked(m_settings.m_dfmLubePumpsOn); ui->dfmBrakes->setChecked(m_settings.m_dfmBrakesOn); @@ -960,8 +1015,10 @@ void GS232ControllerGUI::makeUIConnections() QObject::connect(ui->precision, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_precision_valueChanged); QObject::connect(ui->coordinates, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_coordinates_currentIndexChanged); QObject::connect(ui->inputController, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_inputController_currentIndexChanged); - QObject::connect(ui->inputSensitivity, qOverload(&QSlider::valueChanged), this, &GS232ControllerGUI::on_inputSensitivty_valueChanged); QObject::connect(ui->inputConfigure, &QToolButton::clicked, this, &GS232ControllerGUI::on_inputConfigure_clicked); + QObject::connect(ui->highSensitivity, &QToolButton::clicked, this, &GS232ControllerGUI::on_highSensitivity_clicked); + QObject::connect(ui->enableTargetControl, &QToolButton::clicked, this, &GS232ControllerGUI::on_enableTargetControl_clicked); + QObject::connect(ui->enableOffsetControl, &QToolButton::clicked, this, &GS232ControllerGUI::on_enableOffsetControl_clicked); QObject::connect(ui->dfmTrack, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmTrack_clicked); QObject::connect(ui->dfmLubePumps, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmLubePumps_clicked); QObject::connect(ui->dfmBrakes, &QToolButton::toggled, this, &GS232ControllerGUI::on_dfmBrakes_clicked); diff --git a/plugins/feature/gs232controller/gs232controllergui.h b/plugins/feature/gs232controller/gs232controllergui.h index 6ab1a6d9d..f351a7e99 100644 --- a/plugins/feature/gs232controller/gs232controllergui.h +++ b/plugins/feature/gs232controller/gs232controllergui.h @@ -76,6 +76,7 @@ private: double m_inputAzOffset; double m_inputElOffset; bool m_inputUpdate; + static const int m_extraSensitivity = 4.0f; // Otherwise 100% isn't quite fast enough explicit GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~GS232ControllerGUI(); @@ -126,10 +127,14 @@ private slots: void on_dfmShowStatus_clicked(); void updateStatus(); void on_inputController_currentIndexChanged(int index); - void on_inputSensitivty_valueChanged(int value); void on_inputConfigure_clicked(); + void on_highSensitivity_clicked(bool checked); + void on_enableTargetControl_clicked(bool checked); + void on_enableOffsetControl_clicked(bool checked); void updateInputControllerList(); void checkInputController(); + void buttonChanged(int button, bool released); + void inputConfigurationComplete(); }; #endif // INCLUDE_FEATURE_GS232CONTROLLERGUI_H_ diff --git a/plugins/feature/gs232controller/gs232controllergui.ui b/plugins/feature/gs232controller/gs232controllergui.ui index 35a1e1958..2cf086935 100644 --- a/plugins/feature/gs232controller/gs232controllergui.ui +++ b/plugins/feature/gs232controller/gs232controllergui.ui @@ -382,16 +382,6 @@ - - - - false - - - Sensitivity - - - @@ -667,64 +657,13 @@ - - - - false - - - Input controller sensitivity - - - 1 - - - 2000 - - - 10 - - - 25 - - - Qt::Horizontal - - - - - - - false - - - 100% - - - - - - - - - - - Gamepad / joystick to use - - - - None - - - - Configure input - C + Config... @@ -762,6 +701,70 @@ + + + + + + Gamepad / joystick to use + + + + None + + + + + + + + Input controller sensitvitiy (High / low) + + + H + + + true + + + true + + + + + + + Enable offset control + + + O + + + true + + + true + + + + + + + Enable target control + + + T + + + true + + + true + + + + + @@ -800,6 +803,17 @@ elevationMin elevationMax tolerance + precision + coordinates + inputController + highSensitivity + enableTargetControl + inputConfigure + dfmTrack + dfmLubePumps + dfmBrakes + dfmDrives + dfmShowStatus diff --git a/plugins/feature/gs232controller/gs232controllerplugin.cpp b/plugins/feature/gs232controller/gs232controllerplugin.cpp index 0a46180d8..92d45d84f 100644 --- a/plugins/feature/gs232controller/gs232controllerplugin.cpp +++ b/plugins/feature/gs232controller/gs232controllerplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = { GS232Controller::m_featureId, QStringLiteral("Rotator Controller"), - QStringLiteral("7.15.2"), + QStringLiteral("7.15.3"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/feature/gs232controller/gs232controllersettings.cpp b/plugins/feature/gs232controller/gs232controllersettings.cpp index 59af88346..136526c42 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.cpp +++ b/plugins/feature/gs232controller/gs232controllersettings.cpp @@ -22,6 +22,7 @@ #include "settings/serializable.h" #include "gs232controllersettings.h" +#include "inputcontrollersettings.h" const QStringList GS232ControllerSettings::m_pipeTypes = { QStringLiteral("ADSBDemod"), @@ -65,7 +66,14 @@ void GS232ControllerSettings::resetToDefaults() m_precision = 0; m_coordinates = AZ_EL; m_inputController = "None"; - m_inputSensitivity = 0.25; + m_targetControlEnabled = true; + m_offsetControlEnabled = true; + m_highSensitivity = true; + m_inputControllerSettings.m_lowSensitivity = 5.0f; + m_inputControllerSettings.m_highSensitivity = 50.0f; + for (int i = 0; i < INPUTCONTROLLER_MAX_AXES; i++) { + m_inputControllerSettings.m_deadzone[i] = 10.0f; + } m_dfmTrackOn = false; m_dfmLubePumpsOn = false; m_dfmBrakesOn = false; @@ -122,7 +130,15 @@ QByteArray GS232ControllerSettings::serialize() const s.writeBool(33, m_dfmBrakesOn); s.writeBool(34, m_dfmDrivesOn); s.writeString(35, m_inputController); - s.writeFloat(36, m_inputSensitivity); + s.writeBool(37, m_targetControlEnabled); + s.writeBool(38, m_offsetControlEnabled); + s.writeBool(39, m_highSensitivity); + + s.writeFloat(50, m_inputControllerSettings.m_lowSensitivity); + s.writeFloat(51, m_inputControllerSettings.m_highSensitivity); + for (int i = 0; i < INPUTCONTROLLER_MAX_AXES; i++) { + s.writeFloat(60+i, m_inputControllerSettings.m_deadzone[i]); + } return s.final(); } @@ -192,7 +208,15 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) d.readBool(33, &m_dfmBrakesOn); d.readBool(34, &m_dfmDrivesOn); d.readString(35, &m_inputController, "None"); - d.readFloat(36, &m_inputSensitivity, 0.25); + d.readBool(37, &m_targetControlEnabled, true); + d.readBool(38, &m_offsetControlEnabled, true); + d.readBool(39, &m_highSensitivity, true); + + d.readFloat(50, &m_inputControllerSettings.m_lowSensitivity, 5.0f); + d.readFloat(51, &m_inputControllerSettings.m_highSensitivity, 50.0f); + for (int i = 0; i < INPUTCONTROLLER_MAX_AXES; i++) { + d.readFloat(60+i, &m_inputControllerSettings.m_deadzone[i], 10.0f); + } return true; } @@ -280,8 +304,17 @@ void GS232ControllerSettings::applySettings(const QStringList& settingsKeys, con if (settingsKeys.contains("inputController")) { m_inputController = settings.m_inputController; } - if (settingsKeys.contains("inputSensitivity")) { - m_inputSensitivity = settings.m_inputSensitivity; + if (settingsKeys.contains("inputControllerSettings")) { + m_inputControllerSettings = settings.m_inputControllerSettings; + } + if (settingsKeys.contains("targetControlEnabled")) { + m_targetControlEnabled = settings.m_targetControlEnabled; + } + if (settingsKeys.contains("offsetControlEnabled")) { + m_offsetControlEnabled = settings.m_offsetControlEnabled; + } + if (settingsKeys.contains("highSensitivity")) { + m_highSensitivity = settings.m_highSensitivity; } if (settingsKeys.contains("dfmTrackOn")) { m_dfmTrackOn = settings.m_dfmTrackOn; @@ -385,8 +418,21 @@ QString GS232ControllerSettings::getDebugString(const QStringList& settingsKeys, if (settingsKeys.contains("inputController") || force) { ostr << " m_inputController: " << m_inputController.toStdString(); } - if (settingsKeys.contains("inputSensitivity") || force) { - ostr << " m_inputSensitivity: " << m_inputSensitivity; + if (settingsKeys.contains("inputControllerSettings") || force) { + ostr << " m_inputControllerSettings.m_lowSensitivity: " << m_inputControllerSettings.m_lowSensitivity; + ostr << " m_inputControllerSettings.m_highSensitivity: " << m_inputControllerSettings.m_highSensitivity; + for (int i = 0; i < INPUTCONTROLLER_MAX_AXES; i++) { + ostr << " m_inputControllerSettings.m_deadzone: " << m_inputControllerSettings.m_deadzone[i]; + } + } + if (settingsKeys.contains("targetControlEnabled") || force) { + ostr << " m_targetControlEnabled: " << m_targetControlEnabled; + } + if (settingsKeys.contains("offsetControlEnabled") || force) { + ostr << " m_offsetControlEnabled: " << m_offsetControlEnabled; + } + if (settingsKeys.contains("highSensitivity") || force) { + ostr << " m_highSensitivity: " << m_highSensitivity; } if (settingsKeys.contains("title") || force) { ostr << " m_title: " << m_title.toStdString(); diff --git a/plugins/feature/gs232controller/gs232controllersettings.h b/plugins/feature/gs232controller/gs232controllersettings.h index c97f0b958..b600bc049 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.h +++ b/plugins/feature/gs232controller/gs232controllersettings.h @@ -23,6 +23,7 @@ #include #include "util/message.h" +#include "inputcontrollersettings.h" class Serializable; @@ -63,7 +64,10 @@ struct GS232ControllerSettings int m_precision; enum Coordinates { AZ_EL, X_Y_85, X_Y_30 } m_coordinates; QString m_inputController; - float m_inputSensitivity; + InputControllerSettings m_inputControllerSettings; + bool m_targetControlEnabled; + bool m_offsetControlEnabled; + bool m_highSensitivity; bool m_dfmTrackOn; bool m_dfmLubePumpsOn; diff --git a/plugins/feature/gs232controller/inputcontroller.cpp b/plugins/feature/gs232controller/inputcontroller.cpp index e7f8f8df4..d9b8cf891 100644 --- a/plugins/feature/gs232controller/inputcontroller.cpp +++ b/plugins/feature/gs232controller/inputcontroller.cpp @@ -22,6 +22,23 @@ #include "inputcontroller.h" +double InputController::getAxisCalibratedValue(int axis, InputControllerSettings *settings, bool highSensitvity) +{ + double value = getAxisValue(axis); + double absValue = abs(value); + double l = settings->m_deadzone[axis] / 100.0; + if (absValue < l) { + // Set to 0 if in deadzone + value = 0.0; + } else { + // Rescale to [0,1] if outside of deadzone + absValue = (absValue - l) / (1.0 - l); + // Negate if original value was negative + value = (value < 0.0) ? -absValue : absValue; + } + return value * (highSensitvity ? settings->m_highSensitivity : settings->m_lowSensitivity) / 100.0; +} + InputControllerManager* InputControllerManager::m_instance = nullptr; QStringList InputControllerManager::getAllControllers() diff --git a/plugins/feature/gs232controller/inputcontroller.h b/plugins/feature/gs232controller/inputcontroller.h index 56a0d66a5..8a85fb91f 100644 --- a/plugins/feature/gs232controller/inputcontroller.h +++ b/plugins/feature/gs232controller/inputcontroller.h @@ -20,6 +20,23 @@ #include +#include "inputcontrollersettings.h" + +#define INPUTCONTROLLER_BUTTON_RIGHT_TOP 0 // Y / triangle +#define INPUTCONTROLLER_BUTTON_RIGHT_BOTTOM 1 // A / X +#define INPUTCONTROLLER_BUTTON_RIGHT_LEFT 2 // X / Square +#define INPUTCONTROLLER_BUTTON_RIGHT_RIGHT 3 // B / Circle + +#define INPUTCONTROLLER_BUTTON_LEFT_UP 4 // D-Pad +#define INPUTCONTROLLER_BUTTON_LEFT_DOWN 5 +#define INPUTCONTROLLER_BUTTON_LEFT_LEFT 6 +#define INPUTCONTROLLER_BUTTON_LEFT_RIGHT 7 + +#define INPUTCONTROLLER_BUTTON_R1 8 // On top of controller +#define INPUTCONTROLLER_BUTTON_L1 9 +#define INPUTCONTROLLER_BUTTON_R3 10 // Sticks pushed +#define INPUTCONTROLLER_BUTTON_L3 11 + class InputController : public QObject { Q_OBJECT public: @@ -28,9 +45,15 @@ public: // axis 0-3. 0=Az/X, 1=El/Y, 2=Az Offset, 3=El Offset // value returned should be current axis position in range [-1,1] virtual double getAxisValue(int axis) = 0; + // Gets axis value applying deadzone and sensitivity + double getAxisCalibratedValue(int axis, InputControllerSettings *settings, bool highSensitivity); virtual int getNumberOfAxes() const = 0; virtual bool supportsConfiguration() const { return false; } - virtual void configure() {}; + virtual void configure(InputControllerSettings *settings) {}; + +signals: + void buttonChanged(int button, bool released); + void configurationComplete(); }; diff --git a/plugins/feature/gs232controller/inputcontrollersettings.h b/plugins/feature/gs232controller/inputcontrollersettings.h new file mode 100644 index 000000000..2682a809f --- /dev/null +++ b/plugins/feature/gs232controller/inputcontrollersettings.h @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_INPUTCONTROLLERSETTINGS_H_ +#define INCLUDE_FEATURE_INPUTCONTROLLERSETTINGS_H_ + +#define INPUTCONTROLLER_MAX_AXES 4 + +struct InputControllerSettings { + float m_lowSensitivity; + float m_highSensitivity; + float m_deadzone[INPUTCONTROLLER_MAX_AXES]; +}; + +#endif // INCLUDE_FEATURE_INPUTCONTROLLERSETTINGS_H_ diff --git a/plugins/feature/gs232controller/readme.md b/plugins/feature/gs232controller/readme.md index ce688b42d..f5106599d 100644 --- a/plugins/feature/gs232controller/readme.md +++ b/plugins/feature/gs232controller/readme.md @@ -115,14 +115,52 @@ When a gamepad with 2 sticks (4 axes) such as the XBox Wireless Controller is us while the left stick is for controlling azimuth and elevation offset. If a controller only has 2 axes, target coordinates will be controlled when not tracking (6) and offset will be controlled when tracking. +Buttons on a controller are assigned to the following functions: + +| Button | XBox Controller | Function | +|---------|------------------|------------------------------------------| +| 0 | Y | Start/stop plugin | +| 1 | A | Enable/disabling tracking | +| 3 | B | Enable/disable target control | +| 2 | X | Enable/disable offset control | +| 8 | R1 | Switch between low and high sensitivity | + The [Qt Gamepad](https://doc.qt.io/qt-5/qtgamepad-index.html) library is used to implement gamepad support. On Linux, using Qt Gamepad with the evdev backend, all joysticks & gamepads appear as though they have 4 axes (a limitation of Qt Gamepad). -If using a joystick which only has 2 axes, whether it corresponds to the left or right stick can be configured by pressing the 'C' button. +If using a joystick which only has 2 axes, whether it corresponds to the left or right stick can be configured by pressing the 'Config...' button. On Linux, the [xone driver](https://github.com/medusalix/xone) has support for the Xbox Wireless Controller, that isn't supported by the older xpad driver that is included with Ubuntu. -

23: Sensitivity

+

23: High or Low Sensitivity

-Specifies the sensitivity on the input controls (22). The higher the value, the faster coordinates will change for a given control stick movement. +Specifies High (H) or Low (L) Sensitivity mode. This is how fast coordinates will change for a given control stick movement. +High Sensitivity is used for coarse target/offset adjustment, whereas Low sensitivity is used for fine target/offset adjustment. +The sensitivity in each mode can be set in the Input Configuration Dialog (22). + +

24: (T) Enable Target Control

+ +When checked, the target coordinates can be set with the input controller. When unchecked, the axes controlling the target will be ignored. + +

25: (O) Enable Offset Control

+ +When checked, the offset coordinates can be set with the input controller. When unchecked, the axes controlling the offset will be ignored. + +

26: Input Control Configuration

+ +Pressing the Config... button will display the Input Configuration Dialog: + +

1: Configuration

+ +The Configure buttons allow setting which axis is assigned to target or offset control. To assign an axis, press the corresponding Configure button, then move the controller axis. + +

2: Deadzones

+ +Deadzones can be set individually for each for the 4 axes. A deadzone specifies the amount a controller axis can be moved without a response. +This can be used to prevent very small movements around the center position on a stick from adjusting the target, or eliminate target adjustments +when a stick is centered, but is reporting a non-zero position on the axis. + +

3: Sensitivity

+ +Specifies the sensitivity of the input in Low and High Sensitivity mode (23). The higher the value, the faster coordinates will change for a given control stick movement.

Protocol Implementations

diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index ebaa856d6..4d4155196 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -62,6 +62,8 @@ set(sdrgui_SOURCES gui/indicator.cpp gui/levelmeter.cpp gui/loggingdialog.cpp + gui/logslider.cpp + gui/loglabelslider.cpp gui/mypositiondialog.cpp gui/pluginsdialog.cpp gui/presetitem.cpp @@ -176,6 +178,8 @@ set(sdrgui_HEADERS gui/indicator.h gui/levelmeter.h gui/loggingdialog.h + gui/logslider.h + gui/loglabelslider.h gui/mypositiondialog.h gui/physicalunit.h gui/pluginsdialog.h diff --git a/sdrgui/gui/loglabelslider.cpp b/sdrgui/gui/loglabelslider.cpp new file mode 100644 index 000000000..064e4eba2 --- /dev/null +++ b/sdrgui/gui/loglabelslider.cpp @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "loglabelslider.h" + +LogLabelSlider::LogLabelSlider(QWidget *parent) : + QWidget(parent) +{ + m_vLayout = new QVBoxLayout(this); + m_hLayout = new QHBoxLayout(); + m_slider = new LogSlider(); + connect(m_slider, &LogSlider::logValueChanged, this, &LogLabelSlider::handleLogValueChanged); + + m_vLayout->addLayout(m_hLayout); + m_vLayout->addWidget(m_slider); +} + +void LogLabelSlider::setRange(double min, double max) +{ + m_slider->setRange(min, max); + double start = floor(log10(min)); + double stop = ceil(log10(max)); + double steps = stop - start; + + qDeleteAll(m_labels); + m_labels.clear(); + + double v = pow(10.0, start); + for (int i = 0; i <= steps; i++) + { + QString t = QString("%1").arg(v); + + QLabel *label = new QLabel(t); + + if (i == 0) { + label->setAlignment(Qt::AlignLeft); + } else if (i == steps) { + label->setAlignment(Qt::AlignRight); + } else { + label->setAlignment(Qt::AlignCenter); + } + + + m_labels.append(label); + m_hLayout->addWidget(label); + + v *= 10.0; + } +} + +void LogLabelSlider::handleLogValueChanged(double value) +{ + emit logValueChanged(value); +} diff --git a/sdrgui/gui/loglabelslider.h b/sdrgui/gui/loglabelslider.h new file mode 100644 index 000000000..1e2c8a30d --- /dev/null +++ b/sdrgui/gui/loglabelslider.h @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRGUI_GUI_LOGLABELSLIDER_H +#define SDRGUI_GUI_LOGLABELSLIDER_H + +#include +#include +#include +#include + +#include "logslider.h" + +#include "export.h" + +// Logarithmic Slider with labels above +class SDRGUI_API LogLabelSlider : public QWidget { + Q_OBJECT + +public: + + explicit LogLabelSlider(QWidget *parent = nullptr); + void setRange(double min, double max); + void setValue(double value) { m_slider->setValue(value); } + +signals: + + void logValueChanged(double value); + +private slots: + void handleLogValueChanged(double value); + +private: + + QList m_labels; + LogSlider *m_slider; + QVBoxLayout *m_vLayout; + QHBoxLayout *m_hLayout; + +}; + +#endif // SDRGUI_GUI_LOGLABELSLIDER_H diff --git a/sdrgui/gui/logslider.cpp b/sdrgui/gui/logslider.cpp new file mode 100644 index 000000000..5a4c13be3 --- /dev/null +++ b/sdrgui/gui/logslider.cpp @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "logslider.h" + +LogSlider::LogSlider(QWidget *parent) : + QSlider(Qt::Horizontal, parent) +{ + setRange(0, 1000); + connect(this, &QSlider::valueChanged, this, &LogSlider::handleValueChanged); + setPageStep(1); + setTickPosition(QSlider::TicksAbove); + setTickInterval(m_stepsPerPower); +} + +void LogSlider::setRange(double min, double max) +{ + m_start = floor(log10(min)); + m_stop = ceil(log10(max)); + m_steps = m_stop - m_start; + setMinimum(0); + setMaximum(m_steps * m_stepsPerPower); +} + +void LogSlider::handleValueChanged(int value) +{ + double v = pow(10.0, value/(double)m_stepsPerPower + m_start); + emit logValueChanged(v); +} + +void LogSlider::setValue(double value) +{ + int v = (int)((log10(value) - m_start) * 100); + QSlider::setValue(v); +} diff --git a/sdrgui/gui/logslider.h b/sdrgui/gui/logslider.h new file mode 100644 index 000000000..eba69a1af --- /dev/null +++ b/sdrgui/gui/logslider.h @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRGUI_GUI_LOGSLIDER_H +#define SDRGUI_GUI_LOGSLIDER_H + +#include + +#include "export.h" + +// Logarithmic Slider (hozizontal only) +class SDRGUI_API LogSlider : public QSlider { + Q_OBJECT + +public: + + explicit LogSlider(QWidget *parent = nullptr); + + void setRange(double min, double max); + void setValue(double value); + + +signals: + + void logValueChanged(double value); + +private slots: + void handleValueChanged(int value); + +private: + + double m_start; + double m_stop; + double m_steps; + + static const int m_stepsPerPower = 100; + +}; + +#endif // SDRGUI_GUI_LOGSLIDER_H