JoystickWidget.cc 9.68 KB
Newer Older
pixhawk's avatar
pixhawk committed
1
#include "JoystickWidget.h"
2
#include "QGCApplication.h"
pixhawk's avatar
pixhawk committed
3
#include "ui_JoystickWidget.h"
4 5
#include "JoystickButton.h"
#include "JoystickAxis.h"
6

7
#include <QDesktopWidget>
pixhawk's avatar
pixhawk committed
8 9

JoystickWidget::JoystickWidget(JoystickInput* joystick, QWidget *parent) :
10
    QWidget(parent),
11
    joystick(joystick),
12
    m_ui(new Ui::JoystickWidget)
pixhawk's avatar
pixhawk committed
13 14
{
    m_ui->setupUi(this);
15 16 17 18 19 20

    // Center the window on the screen.
    QRect position = frameGeometry();
    position.moveCenter(QDesktopWidget().availableGeometry().center());
    move(position.topLeft());

21 22
    // Initialize the UI based on the current joystick
    initUI();
Lorenz Meier's avatar
Lorenz Meier committed
23

24
    // Watch for button, axis, and hat input events from the joystick.
25 26
    connect(this->joystick, SIGNAL(buttonPressed(int)), this, SLOT(joystickButtonPressed(int)));
    connect(this->joystick, SIGNAL(buttonReleased(int)), this, SLOT(joystickButtonReleased(int)));
27
    connect(this->joystick, SIGNAL(axisValueChanged(int,float)), this, SLOT(updateAxisValue(int,float)));
28
    connect(this->joystick, SIGNAL(hatDirectionChanged(qint8,qint8)), this, SLOT(setHat(qint8,qint8)));
pixhawk's avatar
pixhawk committed
29

30 31
    // Also watch for when new settings were loaded for the current joystick to do a mass UI refresh.
    connect(this->joystick, SIGNAL(joystickSettingsChanged()), this, SLOT(updateUI()));
32

33
    // If the selected joystick is changed, update the JoystickInput.
34
    connect(m_ui->joystickNameComboBox, SIGNAL(currentIndexChanged(int)), this->joystick, SLOT(setActiveJoystick(int)));
35 36
    // Also wait for the JoystickInput to switch, then update our UI.
    connect(this->joystick, SIGNAL(newJoystickSelected()), this, SLOT(createUIForJoystick()));
37 38 39

    // Initialize the UI to the current JoystickInput state. Also make sure to listen for future changes
    // so that the UI can be updated.
40
    connect(m_ui->enableCheckBox, SIGNAL(toggled(bool)), m_ui->joystickFrame, SLOT(setEnabled(bool)));
41 42
    m_ui->enableCheckBox->setChecked(this->joystick->enabled()); // Needs to be after connecting to the joystick frame and before watching for enabled events from JoystickInput.
    connect(m_ui->enableCheckBox, SIGNAL(toggled(bool)), this->joystick, SLOT(setEnabled(bool)));
43

44
    // Update the button label colors based on the current theme and watch for future theme changes.
45 46
    styleChanged(qgcApp()->styleIsDark());
    connect(qgcApp(), &QGCApplication::styleChanged, this, &JoystickWidget::styleChanged);
47

48 49 50
    // change mode when mode combobox is changed
    connect(m_ui->joystickModeComboBox, SIGNAL(currentIndexChanged(int)), this->joystick, SLOT(setMode(int)));

51 52
    // Display the widget above all other windows.
    this->raise();
pixhawk's avatar
pixhawk committed
53 54 55
    this->show();
}

56 57 58 59 60 61 62 63 64 65 66 67
void JoystickWidget::initUI()
{
    // Add the joysticks to the top combobox. They're indexed by their item number.
    // And set the currently-selected combobox item to the current joystick.
    int joysticks = joystick->getNumJoysticks();
    if (joysticks)
    {
        for (int i = 0; i < joysticks; i++)
        {
            m_ui->joystickNameComboBox->addItem(joystick->getJoystickNameById(i));
        }
        m_ui->joystickNameComboBox->setCurrentIndex(joystick->getJoystickID());
68 69 70 71 72
        // And if joystick support is enabled, show the UI.
        if (m_ui->enableCheckBox->isChecked())
        {
            m_ui->joystickFrame->setEnabled(true);
        }
73

74 75 76 77 78 79 80 81
        // mode combo box
        m_ui->joystickModeComboBox->addItem("Attitude");
        m_ui->joystickModeComboBox->addItem("Position");
        m_ui->joystickModeComboBox->addItem("Force");
        m_ui->joystickModeComboBox->addItem("Velocity");
        m_ui->joystickModeComboBox->addItem("Manual");
        m_ui->joystickModeComboBox->setCurrentIndex(joystick->getMode());

82 83
        // Create the initial UI.
        createUIForJoystick();
84
    }
85
    // But if there're no joysticks, disable everything and hide empty UI.
86 87
    else
    {
88
        m_ui->enableCheckBox->setEnabled(false);
89
        m_ui->joystickNameComboBox->addItem(tr("No joysticks found. Connect and restart QGC to add one."));
90
        m_ui->joystickNameComboBox->setEnabled(false);
91
        m_ui->joystickFrame->hide();
92 93 94
    }
}

95
void JoystickWidget::styleChanged(bool styleIsDark)
96
{
97
    if (styleIsDark)
98
    {
99
        buttonLabelColor = QColor(0x14, 0xC6, 0x14);
100 101 102
    }
    else
    {
103
        buttonLabelColor = QColor(0x73, 0xD9, 0x5D);
104 105 106
    }
}

pixhawk's avatar
pixhawk committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
JoystickWidget::~JoystickWidget()
{
    delete m_ui;
}

void JoystickWidget::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

123 124
void JoystickWidget::updateUI()
{
125
    // Update the actions for all of the buttons
126 127 128 129
    for (int i = 0; i < buttons.size(); i++)
    {
        JoystickButton* button = buttons[i];
        int action = joystick->getActionForButton(i);
130
        button->setAction(action);
131
    }
132 133

    // Update the axis mappings
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    int rollAxis = joystick->getMappingRollAxis();
    int pitchAxis = joystick->getMappingPitchAxis();
    int yawAxis = joystick->getMappingYawAxis();
    int throttleAxis = joystick->getMappingThrottleAxis();
    for (int i = 0; i < axes.size(); i++)
    {
        JoystickAxis* axis = axes[i];
        JoystickInput::JOYSTICK_INPUT_MAPPING mapping = JoystickInput::JOYSTICK_INPUT_MAPPING_NONE;
        if (i == rollAxis)
        {
            mapping = JoystickInput::JOYSTICK_INPUT_MAPPING_ROLL;
        }
        else if (i == pitchAxis)
        {
            mapping = JoystickInput::JOYSTICK_INPUT_MAPPING_PITCH;
        }
        else if (i == yawAxis)
        {
            mapping = JoystickInput::JOYSTICK_INPUT_MAPPING_YAW;
        }
        else if (i == throttleAxis)
        {
            mapping = JoystickInput::JOYSTICK_INPUT_MAPPING_THROTTLE;
        }
        axis->setMapping(mapping);
        bool inverted = joystick->getInvertedForAxis(i);
        axis->setInverted(inverted);
        bool limited = joystick->getRangeLimitForAxis(i);
        axis->setRangeLimit(limited);
    }
}

void JoystickWidget::createUIForJoystick()
167
{
168 169
    // Delete all the old UI elements
    foreach (JoystickButton* b, buttons)
170
    {
171
        delete b;
172
    }
173 174 175 176 177 178
    buttons.clear();
    foreach (JoystickAxis* a, axes)
    {
        delete a;
    }
    axes.clear();
179

180 181
    // And add the necessary button displays for this joystick.
    int newButtons = joystick->getJoystickNumButtons();
182
    if (newButtons)
183
    {
184 185 186 187
        m_ui->buttonBox->show();
        for (int i = 0; i < newButtons; i++)
        {
            JoystickButton* button = new JoystickButton(i, m_ui->buttonBox);
188 189
            button->setAction(joystick->getActionForButton(i));
            connect(button, SIGNAL(actionChanged(int,int)), this->joystick, SLOT(setButtonAction(int,int)));
190
            connect(this->joystick, &JoystickInput::activeVehicleChanged, button, &JoystickButton::activeVehicleChanged);
191
            m_ui->buttonLayout->addWidget(button);
192 193 194 195 196 197
            buttons.append(button);
        }
    }
    else
    {
        m_ui->buttonBox->hide();
198 199
    }

200
    // Do the same for the axes supported by this joystick.
201 202 203 204
    int rollAxis = joystick->getMappingRollAxis();
    int pitchAxis = joystick->getMappingPitchAxis();
    int yawAxis = joystick->getMappingYawAxis();
    int throttleAxis = joystick->getMappingThrottleAxis();
205 206 207 208 209 210 211
    int newAxes = joystick->getJoystickNumAxes();
    if (newAxes)
    {
        for (int i = 0; i < newAxes; i++)
        {
            JoystickAxis* axis = new JoystickAxis(i, m_ui->axesBox);
            axis->setValue(joystick->getCurrentValueForAxis(i));
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
            if (i == rollAxis)
            {
                axis->setMapping(JoystickInput::JOYSTICK_INPUT_MAPPING_ROLL);
            }
            else if (i == pitchAxis)
            {
                axis->setMapping(JoystickInput::JOYSTICK_INPUT_MAPPING_PITCH);
            }
            else if (i == yawAxis)
            {
                axis->setMapping(JoystickInput::JOYSTICK_INPUT_MAPPING_YAW);
            }
            else if (i == throttleAxis)
            {
                axis->setMapping(JoystickInput::JOYSTICK_INPUT_MAPPING_THROTTLE);
            }
            axis->setInverted(joystick->getInvertedForAxis(i));
            axis->setRangeLimit(joystick->getRangeLimitForAxis(i));
230 231
            connect(axis, SIGNAL(mappingChanged(int,JoystickInput::JOYSTICK_INPUT_MAPPING)), this->joystick, SLOT(setAxisMapping(int,JoystickInput::JOYSTICK_INPUT_MAPPING)));
            connect(axis, SIGNAL(inversionChanged(int,bool)), this->joystick, SLOT(setAxisInversion(int,bool)));
232
            connect(axis, SIGNAL(rangeChanged(int,bool)), this->joystick, SLOT(setAxisRangeLimit(int,bool)));
233
            connect(this->joystick, &JoystickInput::activeVehicleChanged, axis, &JoystickAxis::activeVehicleChanged);
234
            m_ui->axesLayout->addWidget(axis);
235 236 237 238
            axes.append(axis);
        }
    }
    else
239
    {
240
        m_ui->axesBox->hide();
241
    }
242 243

    connect(m_ui->calibrationButton, SIGNAL(clicked()), this, SLOT(cycleCalibrationButton()));
pixhawk's avatar
pixhawk committed
244
}
pixhawk's avatar
pixhawk committed
245

246
void JoystickWidget::updateAxisValue(int axis, float value)
pixhawk's avatar
pixhawk committed
247
{
248
    if (axis < axes.size())
249
    {
250
        axes.at(axis)->setValue(value);
251
    }
pixhawk's avatar
pixhawk committed
252
}
pixhawk's avatar
pixhawk committed
253

254
void JoystickWidget::setHat(qint8 x, qint8 y)
pixhawk's avatar
pixhawk committed
255
{
256
    m_ui->statusLabel->setText(tr("Hat position: x: %1, y: %2").arg(x).arg(y));
257 258
}

259 260 261
void JoystickWidget::joystickButtonPressed(int key)
{
    QString colorStyle = QString("QLabel { background-color: %1;}").arg(buttonLabelColor.name());
262
    buttons.at(key)->setStyleSheet(colorStyle);
263 264 265
}

void JoystickWidget::joystickButtonReleased(int key)
pixhawk's avatar
pixhawk committed
266
{
267
    buttons.at(key)->setStyleSheet("");
268
}
269 270 271 272 273 274 275 276 277 278 279

void JoystickWidget::cycleCalibrationButton()
{
    if (this->joystick->calibrating()) {
        this->joystick->setCalibrating(false);
        m_ui->calibrationButton->setText("Calibrate range");
    } else {
        this->joystick->setCalibrating(true);
        m_ui->calibrationButton->setText("End calibration");
    }
}