Skip to content
JoystickConfig.qml 36.8 KiB
Newer Older
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
import QtQuick          2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs  1.2

import QGroundControl               1.0
import QGroundControl.Palette       1.0
import QGroundControl.Controls      1.0
import QGroundControl.ScreenTools   1.0
import QGroundControl.Controllers   1.0
import QGroundControl.FactSystem    1.0
import QGroundControl.FactControls  1.0

/// Joystick Config
Don Gagne's avatar
Don Gagne committed
SetupPage {
    id:                 joystickPage
    pageComponent:      pageComponent
    pageName:           qsTr("Joystick")
    pageDescription:    qsTr("Joystick Setup is used to configure a calibrate joysticks.")

Jacob Walser's avatar
Jacob Walser committed
    Connections {
        target: joystickManager
        onAvailableJoysticksChanged: {
            if( joystickManager.joysticks.length == 0 ) {
                summaryButton.checked = true
                setupView.showSummaryPanel()
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
    Component {
        id: pageComponent

        Item {
            width:  availableWidth
            height: Math.max(leftColumn.height, rightColumn.height)

            property bool controllerCompleted:      false
            property bool controllerAndViewReady:   false

            readonly property real labelToMonitorMargin: defaultTextWidth * 3

            property var _activeVehicle:    QGroundControl.multiVehicleManager.activeVehicle
            property var _activeJoystick:   joystickManager.activeJoystick

            JoystickConfigController {
                id:             controller
                factPanel:      joystickPage.viewPanel
                statusText:     statusText
                cancelButton:   cancelButton
                nextButton:     nextButton
                skipButton:     skipButton

                Component.onCompleted: {
                    controllerCompleted = true
                    if (joystickPage.completedSignalled) {
                        controllerAndViewReady = true
                        controller.start()
                    }
                }
Don Gagne's avatar
Don Gagne committed
            Component.onCompleted: {
                if (controllerCompleted) {
                    controllerAndViewReady = true
                    controller.start()
                }
            }
Don Gagne's avatar
Don Gagne committed
            // Live axis monitor control component
            Component {
                id: axisMonitorDisplayComponent
Don Gagne's avatar
Don Gagne committed
                Item {
                    property int axisValue: 0
Gregory Dymarek's avatar
Gregory Dymarek committed
                    property int deadbandValue: 0
Don Gagne's avatar
Don Gagne committed
                    property color          __barColor:             qgcPal.windowShade
Don Gagne's avatar
Don Gagne committed
                    // Bar
                    Rectangle {
                        id:                     bar
                        anchors.verticalCenter: parent.verticalCenter
                        width:                  parent.width
                        height:                 parent.height / 2
                        color:                  __barColor
                    }
Gregory Dymarek's avatar
Gregory Dymarek committed
                    // Deadband
                    Rectangle {
                        id:                     deadbandBar
                        anchors.verticalCenter: parent.verticalCenter
                        x:                      _deadbandPosition
                        width:                  _deadbandWidth
                        height:                 parent.height / 2
                        color:                  "#8c161a"
                        visible:                controller.deadbandToggle
Gregory Dymarek's avatar
Gregory Dymarek committed

                        property real _percentDeadband:    ((2 * deadbandValue) / (32768.0 * 2))
                        property real _deadbandWidth:   parent.width * _percentDeadband
                        property real _deadbandPosition:   (parent.width - _deadbandWidth) / 2
                    }

Don Gagne's avatar
Don Gagne committed
                    // Center point
                    Rectangle {
                        anchors.horizontalCenter:   parent.horizontalCenter
                        width:                      defaultTextWidth / 2
                        height:                     parent.height
                        color:                      qgcPal.window
                    }
Don Gagne's avatar
Don Gagne committed
                    // Indicator
                    Rectangle {
                        anchors.verticalCenter: parent.verticalCenter
                        width:                  parent.height * 0.75
                        height:                 width
                        x:                      (reversed ? (parent.width - _indicatorPosition) : _indicatorPosition) - (width / 2)
                        radius:                 width / 2
                        color:                  qgcPal.text
                        visible:                mapped

                        property real _percentAxisValue:    ((axisValue + 32768.0) / (32768.0 * 2))
                        property real _indicatorPosition:   parent.width * _percentAxisValue
                    }
Don Gagne's avatar
Don Gagne committed
                    QGCLabel {
                        anchors.fill:           parent
                        horizontalAlignment:    Text.AlignHCenter
                        verticalAlignment:      Text.AlignVCenter
                        text:                   qsTr("Not Mapped")
                        visible:                !mapped
                    }
Don Gagne's avatar
Don Gagne committed
                    ColorAnimation {
                        id:         barAnimation
                        target:     bar
                        property:   "color"
                        from:       "yellow"
                        to:         __barColor
                        duration:   1500
                    }
Gregory Dymarek's avatar
Gregory Dymarek committed

Don Gagne's avatar
Don Gagne committed
                    // Axis value debugger
Gregory Dymarek's avatar
Gregory Dymarek committed
                    /*
Don Gagne's avatar
Don Gagne committed
                    QGCLabel {
                        anchors.fill: parent
                        text: axisValue
                    }
                    */
Gregory Dymarek's avatar
Gregory Dymarek committed

Don Gagne's avatar
Don Gagne committed
            } // Component - axisMonitorDisplayComponent
Don Gagne's avatar
Don Gagne committed
            // Main view Qml starts here

            // Left side column
            Column {
                id:                     leftColumn
                anchors.rightMargin:    ScreenTools.defaultFontPixelWidth
                anchors.left:           parent.left
                anchors.right:          rightColumn.left
                spacing:                10
Don Gagne's avatar
Don Gagne committed
                // Attitude Controls
                Column {
                    width:      parent.width
                    spacing:    5
Don Gagne's avatar
Don Gagne committed
                    QGCLabel { text: qsTr("Attitude Controls") }
Don Gagne's avatar
Don Gagne committed
                    Item {
                        width:  parent.width
                        height: defaultTextHeight * 2
Don Gagne's avatar
Don Gagne committed
                        QGCLabel {
                            id:     rollLabel
                            width:  defaultTextWidth * 10
                            text:   _activeVehicle.sub ? qsTr("Lateral") : qsTr("Roll")
Don Gagne's avatar
Don Gagne committed
                        }
Don Gagne's avatar
Don Gagne committed
                        Loader {
                            id:                 rollLoader
                            anchors.left:       rollLabel.right
                            anchors.right:      parent.right
                            height:             ScreenTools.defaultFontPixelHeight
                            width:              100
                            sourceComponent:    axisMonitorDisplayComponent

                            property real defaultTextWidth: ScreenTools.defaultFontPixelWidth
                            property bool mapped:           controller.rollAxisMapped
                            property bool reversed:         controller.rollAxisReversed
                        }
                        Connections {
                            target: _activeJoystick

                            onManualControl: rollLoader.item.axisValue = roll*32768.0
                        }
Don Gagne's avatar
Don Gagne committed
                    Item {
                        width:  parent.width
                        height: defaultTextHeight * 2
Don Gagne's avatar
Don Gagne committed
                        QGCLabel {
                            id:     pitchLabel
                            width:  defaultTextWidth * 10
                            text:   _activeVehicle.sub ? qsTr("Forward") : qsTr("Pitch")
Don Gagne's avatar
Don Gagne committed
                        }
Don Gagne's avatar
Don Gagne committed
                        Loader {
                            id:                 pitchLoader
                            anchors.left:       pitchLabel.right
                            anchors.right:      parent.right
                            height:             ScreenTools.defaultFontPixelHeight
                            width:              100
                            sourceComponent:    axisMonitorDisplayComponent

                            property real defaultTextWidth: ScreenTools.defaultFontPixelWidth
                            property bool mapped:           controller.pitchAxisMapped
                            property bool reversed:         controller.pitchAxisReversed
                        }
                        Connections {
                            target: _activeJoystick

                            onManualControl: pitchLoader.item.axisValue = pitch*32768.0
                        }
Don Gagne's avatar
Don Gagne committed
                    Item {
                        width:  parent.width
                        height: defaultTextHeight * 2
Don Gagne's avatar
Don Gagne committed
                        QGCLabel {
                            id:     yawLabel
                            width:  defaultTextWidth * 10
                            text:   qsTr("Yaw")
                        }
Don Gagne's avatar
Don Gagne committed
                        Loader {
                            id:                 yawLoader
                            anchors.left:       yawLabel.right
                            anchors.right:      parent.right
                            height:             ScreenTools.defaultFontPixelHeight
                            width:              100
                            sourceComponent:    axisMonitorDisplayComponent

                            property real defaultTextWidth: ScreenTools.defaultFontPixelWidth
                            property bool mapped:           controller.yawAxisMapped
                            property bool reversed:         controller.yawAxisReversed
                        }
                        Connections {
                            target: _activeJoystick

                            onManualControl: yawLoader.item.axisValue = yaw*32768.0
                        }
Don Gagne's avatar
Don Gagne committed
                    Item {
                        width:  parent.width
                        height: defaultTextHeight * 2
Don Gagne's avatar
Don Gagne committed
                        QGCLabel {
                            id:     throttleLabel
                            width:  defaultTextWidth * 10
                            text:   qsTr("Throttle")
                        }
Don Gagne's avatar
Don Gagne committed
                        Loader {
                            id:                 throttleLoader
                            anchors.left:       throttleLabel.right
                            anchors.right:      parent.right
                            height:             ScreenTools.defaultFontPixelHeight
                            width:              100
                            sourceComponent:    axisMonitorDisplayComponent

                            property real defaultTextWidth: ScreenTools.defaultFontPixelWidth
                            property bool mapped:           controller.throttleAxisMapped
                            property bool reversed:         controller.throttleAxisReversed
                        }
                        Connections {
                            target: _activeJoystick

                            onManualControl: throttleLoader.item.axisValue = (-2*throttle+1)*32768.0
                        }
Don Gagne's avatar
Don Gagne committed
                } // Column - Attitude Control labels
Don Gagne's avatar
Don Gagne committed
                // Command Buttons
                Row {
                    spacing: 10
                    visible: _activeJoystick.requiresCalibration
Don Gagne's avatar
Don Gagne committed

                    QGCButton {
                        id:     skipButton
                        text:   qsTr("Skip")
Don Gagne's avatar
Don Gagne committed
                        onClicked: controller.skipButtonClicked()
Don Gagne's avatar
Don Gagne committed
                    QGCButton {
                        id:     cancelButton
                        text:   qsTr("Cancel")
Don Gagne's avatar
Don Gagne committed
                        onClicked: controller.cancelButtonClicked()
                    }
Don Gagne's avatar
Don Gagne committed
                    QGCButton {
                        id:         nextButton
                        primary:    true
                        text:       qsTr("Calibrate")
Don Gagne's avatar
Don Gagne committed
                        onClicked: controller.nextButtonClicked()
                    }
                } // Row - Buttons
Don Gagne's avatar
Don Gagne committed
                // Status Text
                QGCLabel {
                    id:         statusText
                    width:      parent.width
                    wrapMode:   Text.WordWrap
Don Gagne's avatar
Don Gagne committed
                Rectangle {
                    width:          parent.width
                    height:         1
                    border.color:   qgcPal.text
                    border.width:   1
Don Gagne's avatar
Don Gagne committed
                // Settings
                Row {
                    width:      parent.width
                    spacing:    ScreenTools.defaultFontPixelWidth
Don Gagne's avatar
Don Gagne committed
                    // Left column settings
Don Gagne's avatar
Don Gagne committed
                        width:      parent.width / 2
                        spacing:    ScreenTools.defaultFontPixelHeight

Don Gagne's avatar
Don Gagne committed
                        QGCLabel { text: qsTr("Additional Joystick settings:") }
Don Gagne's avatar
Don Gagne committed
                        Column {
                            width:      parent.width
                            spacing:    ScreenTools.defaultFontPixelHeight
Don Gagne's avatar
Don Gagne committed
                            QGCCheckBox {
Jacob Walser's avatar
Jacob Walser committed
                                id:         enabledCheckBox
                                enabled:    _activeJoystick ? _activeJoystick.calibrated : false
                                text:       _activeJoystick ? _activeJoystick.calibrated ? qsTr("Enable joystick input") : qsTr("Enable not allowed (Calibrate First)") : ""
Don Gagne's avatar
Don Gagne committed
                                checked:    _activeVehicle.joystickEnabled
Don Gagne's avatar
Don Gagne committed
                                onClicked:  _activeVehicle.joystickEnabled = checked
Jacob Walser's avatar
Jacob Walser committed

                                Connections {
                                    target: joystickManager

                                    onActiveJoystickChanged: {
Jacob Walser's avatar
Jacob Walser committed
                                            enabledCheckBox.checked = Qt.binding(function() { return _activeJoystick.calibrated && _activeVehicle.joystickEnabled })
Don Gagne's avatar
Don Gagne committed
                            Row {
                                width:      parent.width
                                spacing:    ScreenTools.defaultFontPixelWidth
Don Gagne's avatar
Don Gagne committed
                                QGCLabel {
                                    id:                 activeJoystickLabel
                                    anchors.baseline:   joystickCombo.baseline
                                    text:               qsTr("Active joystick:")
                                }
Don Gagne's avatar
Don Gagne committed
                                QGCComboBox {
                                    id:                 joystickCombo
                                    width:              parent.width - activeJoystickLabel.width - parent.spacing
                                    model:              joystickManager.joystickNames

                                    onActivated: joystickManager.activeJoystickName = textAt(index)

                                    Component.onCompleted: {
                                        var index = joystickCombo.find(joystickManager.activeJoystickName)
                                        if (index == -1) {
                                            console.warn(qsTr("Active joystick name not in combo"), joystickManager.activeJoystickName)
                                        } else {
                                            joystickCombo.currentIndex = index
                                        }
Jacob Walser's avatar
Jacob Walser committed

                                    Connections {
                                        target: joystickManager
                                        onAvailableJoysticksChanged: {
                                            var index = joystickCombo.find(joystickManager.activeJoystickName)
Jacob Walser's avatar
Jacob Walser committed
                                                joystickCombo.currentIndex = index
                                            }
                                        }
                                    }
Don Gagne's avatar
Don Gagne committed
                            Column {
                                spacing: ScreenTools.defaultFontPixelHeight / 3
                                visible: _activeVehicle.supportsThrottleModeCenterZero
Don Gagne's avatar
Don Gagne committed
                                ExclusiveGroup { id: throttleModeExclusiveGroup }
Don Gagne's avatar
Don Gagne committed
                                QGCRadioButton {
                                    exclusiveGroup: throttleModeExclusiveGroup
                                    text:           qsTr("Center stick is zero throttle")
                                    checked:        _activeJoystick ? _activeJoystick.throttleMode == 0 : false
Don Gagne's avatar
Don Gagne committed
                                    onClicked: _activeJoystick.throttleMode = 0
                                }
Gregory Dymarek's avatar
Gregory Dymarek committed
                                    x:          20
                                    width:      parent.width
                                    spacing:    ScreenTools.defaultFontPixelWidth
                                    visible:    _activeJoystick ? _activeJoystick.throttleMode == 0 : false
                                        checked:    _activeJoystick ? _activeJoystick.accumulator : false
Gregory Dymarek's avatar
Gregory Dymarek committed
                                        text:       qsTr("Spring loaded throttle smoothing")

                                        onClicked:  _activeJoystick.accumulator = checked
                                    }
                                }

Don Gagne's avatar
Don Gagne committed
                                QGCRadioButton {
                                    exclusiveGroup: throttleModeExclusiveGroup
                                    text:           qsTr("Full down stick is zero throttle")
                                    checked:        _activeJoystick ? _activeJoystick.throttleMode == 1 : false
Don Gagne's avatar
Don Gagne committed
                                    onClicked: _activeJoystick.throttleMode = 1
                                }
Don Gagne's avatar
Don Gagne committed
                            Column {
                                spacing: ScreenTools.defaultFontPixelHeight / 3
                                QGCLabel {
                                    id:                 expoSliderLabel
                                    text:               qsTr("Exponential:")
                                }

                                Row {
                                    QGCSlider {
                                        id: expoSlider
                                        minimumValue: 0
                                        maximumValue: 0.75

nanthony21's avatar
nanthony21 committed
                                        Component.onCompleted: value=-_activeJoystick.exponential
                                        onValueChanged: _activeJoystick.exponential=-value
                                     }

                                    QGCLabel {
                                        id:     expoSliderIndicator
                                        text:   expoSlider.value.toFixed(2)
Don Gagne's avatar
Don Gagne committed
                                }
Don Gagne's avatar
Don Gagne committed
                            QGCCheckBox {
                                id:         advancedSettings
                                checked:    _activeVehicle.joystickMode != 0
                                text:       qsTr("Advanced settings (careful!)")
Don Gagne's avatar
Don Gagne committed
                                onClicked: {
                                    if (!checked) {
                                        _activeVehicle.joystickMode = 0
                                    }
Don Gagne's avatar
Don Gagne committed
                            Row {
                                width:      parent.width
                                spacing:    ScreenTools.defaultFontPixelWidth
                                visible:    advancedSettings.checked

                                QGCLabel {
                                    id:                 joystickModeLabel
                                    anchors.baseline:   joystickModeCombo.baseline
                                    text:               qsTr("Joystick mode:")
                                }
Don Gagne's avatar
Don Gagne committed
                                QGCComboBox {
                                    id:             joystickModeCombo
                                    currentIndex:   _activeVehicle.joystickMode
                                    width:          ScreenTools.defaultFontPixelWidth * 20
                                    model:          _activeVehicle.joystickModes
Don Gagne's avatar
Don Gagne committed
                                    onActivated: _activeVehicle.joystickMode = index
                                }

                            Row {
                                width:      parent.width
                                spacing:    ScreenTools.defaultFontPixelWidth
                                visible:    advancedSettings.checked

                                QGCCheckBox {
                                    id:         deadband
                                    checked:    controller.deadbandToggle
                                    text:       qsTr("Deadbands")

                                    onClicked:  controller.deadbandToggle = checked
                                }
                            }
Don Gagne's avatar
Don Gagne committed
                    } // Column - left column
Don Gagne's avatar
Don Gagne committed
                    // Right column settings
                    Column {
                        width:      parent.width / 2
                        spacing:    ScreenTools.defaultFontPixelHeight
Don Gagne's avatar
Don Gagne committed
                        Connections {
                            target: _activeJoystick
Don Gagne's avatar
Don Gagne committed
                            onRawButtonPressedChanged: {
                                if (buttonActionRepeater.itemAt(index)) {
                                    buttonActionRepeater.itemAt(index).pressed = pressed
                                }
                                if (jsButtonActionRepeater.itemAt(index)) {
                                    jsButtonActionRepeater.itemAt(index).pressed = pressed
                                }
Don Gagne's avatar
Don Gagne committed
                        QGCLabel { text: qsTr("Button actions:") }
Don Gagne's avatar
Don Gagne committed
                        Column {
                            width:      parent.width
                            spacing:    ScreenTools.defaultFontPixelHeight / 3
Don Gagne's avatar
Don Gagne committed
                            QGCLabel {
                                visible: _activeVehicle.manualControlReservedButtonCount != 0
                                text: qsTr("Buttons 0-%1 reserved for firmware use").arg(reservedButtonCount)
Don Gagne's avatar
Don Gagne committed
                                property int reservedButtonCount: _activeVehicle.manualControlReservedButtonCount == -1 ? _activeJoystick.totalButtonCount : _activeVehicle.manualControlReservedButtonCount
                            }
Don Gagne's avatar
Don Gagne committed
                            Repeater {
                                id:     buttonActionRepeater
                                model:  _activeJoystick ? _activeJoystick.totalButtonCount : 0
Don Gagne's avatar
Don Gagne committed
                                Row {
                                    spacing: ScreenTools.defaultFontPixelWidth
                                    visible: (_activeVehicle.manualControlReservedButtonCount == -1 ? false : modelData >= _activeVehicle.manualControlReservedButtonCount) && !_activeVehicle.supportsJSButton
Don Gagne's avatar
Don Gagne committed
                                    property bool pressed
Don Gagne's avatar
Don Gagne committed
                                    QGCCheckBox {
                                        anchors.verticalCenter:     parent.verticalCenter
                                        checked:                    _activeJoystick ? _activeJoystick.buttonActions[modelData] != "" : false
Don Gagne's avatar
Don Gagne committed
                                        onClicked: _activeJoystick.setButtonAction(modelData, checked ? buttonActionCombo.textAt(buttonActionCombo.currentIndex) : "")
                                    }
Don Gagne's avatar
Don Gagne committed
                                    Rectangle {
                                        anchors.verticalCenter:     parent.verticalCenter
                                        width:                      ScreenTools.defaultFontPixelHeight * 1.5
                                        height:                     width
                                        border.width:               1
                                        border.color:               qgcPal.text
                                        color:                      pressed ? qgcPal.buttonHighlight : qgcPal.button


                                        QGCLabel {
                                            anchors.fill:           parent
                                            color:                  pressed ? qgcPal.buttonHighlightText : qgcPal.buttonText
                                            horizontalAlignment:    Text.AlignHCenter
                                            verticalAlignment:      Text.AlignVCenter
                                            text:                   modelData
                                        }
Don Gagne's avatar
Don Gagne committed
                                    QGCComboBox {
                                        id:             buttonActionCombo
                                        width:          ScreenTools.defaultFontPixelWidth * 20
                                        model:          _activeJoystick ? _activeJoystick.actions : 0
Don Gagne's avatar
Don Gagne committed
                                        onActivated:            _activeJoystick.setButtonAction(modelData, textAt(index))
                                        Component.onCompleted:  currentIndex = find(_activeJoystick.buttonActions[modelData])
                                    }
Don Gagne's avatar
Don Gagne committed
                            } // Repeater

                            Row {
                                spacing: ScreenTools.defaultFontPixelWidth
                                visible: _activeVehicle.supportsJSButton
Don Gagne's avatar
Don Gagne committed
                                QGCLabel {
                                    horizontalAlignment:    Text.AlignHCenter
                                    width:                  ScreenTools.defaultFontPixelHeight * 1.5
                                    text:                   qsTr("#")
Don Gagne's avatar
Don Gagne committed
                                QGCLabel {
                                    width:                  ScreenTools.defaultFontPixelWidth * 15
                                    text:                   qsTr("Function: ")
Don Gagne's avatar
Don Gagne committed
                                QGCLabel {
                                    width:                  ScreenTools.defaultFontPixelWidth * 15
                                    text:                   qsTr("Shift Function: ")
Don Gagne's avatar
Don Gagne committed
                            Repeater {
                                id:     jsButtonActionRepeater
                                model:  _activeJoystick ? _activeJoystick.totalButtonCount : 0
Don Gagne's avatar
Don Gagne committed

                                Row {
                                    spacing: ScreenTools.defaultFontPixelWidth
                                    visible: _activeVehicle.supportsJSButton

                                    property bool pressed

                                    Rectangle {
                                        anchors.verticalCenter:     parent.verticalCenter
                                        width:                      ScreenTools.defaultFontPixelHeight * 1.5
                                        height:                     width
                                        border.width:               1
                                        border.color:               qgcPal.text
                                        color:                      pressed ? qgcPal.buttonHighlight : qgcPal.button


                                        QGCLabel {
                                            anchors.fill:           parent
                                            color:                  pressed ? qgcPal.buttonHighlightText : qgcPal.buttonText
                                            horizontalAlignment:    Text.AlignHCenter
                                            verticalAlignment:      Text.AlignVCenter
                                            text:                   modelData
                                        }
                                    }

                                    FactComboBox {
                                        id:         mainJSButtonActionCombo
                                        width:      ScreenTools.defaultFontPixelWidth * 15
                                        fact:       controller.parameterExists(-1, "BTN"+index+"_FUNCTION") ? controller.getParameterFact(-1, "BTN" + index + "_FUNCTION") : null;
                                        indexModel: false
                                    }

                                    FactComboBox {
                                        id:         shiftJSButtonActionCombo
                                        width:      ScreenTools.defaultFontPixelWidth * 15
                                        fact:       controller.parameterExists(-1, "BTN"+index+"_SFUNCTION") ? controller.getParameterFact(-1, "BTN" + index + "_SFUNCTION") : null;
                                        indexModel: false
                                    }
                                } // Row
                            } // Repeater
                        } // Column
                    } // Column - right setting column
                } // Row - Settings
            } // Column - Left Main Column

            // Right side column
Don Gagne's avatar
Don Gagne committed
                id:             rightColumn
                anchors.top:    parent.top
                anchors.right:  parent.right
                width:          Math.min(joystickPage.defaultTextWidth * 35, availableWidth * 0.4)
                spacing:        ScreenTools.defaultFontPixelHeight / 2

                Row {
                    spacing: ScreenTools.defaultFontPixelWidth

                    ExclusiveGroup { id: modeGroup }

                    QGCLabel {
                        text: "TX Mode:"
                    }

                    QGCRadioButton {
                        exclusiveGroup: modeGroup
                        text:           "1"
                        checked:        controller.transmitterMode == 1
                        enabled:        !controller.calibrating

                        onClicked: controller.transmitterMode = 1
                    }

                    QGCRadioButton {
                        exclusiveGroup: modeGroup
                        text:           "2"
                        checked:        controller.transmitterMode == 2
                        enabled:        !controller.calibrating

                        onClicked: controller.transmitterMode = 2
                    }

                    QGCRadioButton {
                        exclusiveGroup: modeGroup
                        text:           "3"
                        checked:        controller.transmitterMode == 3
                        enabled:        !controller.calibrating

                        onClicked: controller.transmitterMode = 3
                    }

                    QGCRadioButton {
                        exclusiveGroup: modeGroup
                        text:           "4"
                        checked:        controller.transmitterMode == 4
                        enabled:        !controller.calibrating

                        onClicked: controller.transmitterMode = 4
                    }
                }
Don Gagne's avatar
Don Gagne committed

                Image {
                    width:      parent.width
Don Gagne's avatar
Don Gagne committed
                    fillMode:   Image.PreserveAspectFit
                    smooth:     true
                    source:     controller.imageHelp
                }
Don Gagne's avatar
Don Gagne committed
                // Axis monitor
                Column {
                    width:      parent.width
                    spacing:    5
Don Gagne's avatar
Don Gagne committed
                    QGCLabel { text: qsTr("Axis Monitor") }
Don Gagne's avatar
Don Gagne committed
                    Connections {
                        target: controller

                        onAxisValueChanged: {
                            if (axisMonitorRepeater.itemAt(axis)) {
                                axisMonitorRepeater.itemAt(axis).loader.item.axisValue = value
                            }

                        onAxisDeadbandChanged: {
                            if (axisMonitorRepeater.itemAt(axis)) {
                                axisMonitorRepeater.itemAt(axis).loader.item.deadbandValue = value
                            }
                        }
Don Gagne's avatar
Don Gagne committed
                    Repeater {
                        id:     axisMonitorRepeater
                        model:  _activeJoystick ? _activeJoystick.axisCount : 0
Don Gagne's avatar
Don Gagne committed
                        width:  parent.width
Don Gagne's avatar
Don Gagne committed
                        Row {
                            spacing:    5
Don Gagne's avatar
Don Gagne committed
                            // Need this to get to loader from Connections above
                            property Item loader: theLoader
Don Gagne's avatar
Don Gagne committed
                            QGCLabel {
                                id:     axisLabel
                                text:   modelData
                            }
Don Gagne's avatar
Don Gagne committed
                            Loader {
                                id:                     theLoader
                                anchors.verticalCenter: axisLabel.verticalCenter
                                height:                 ScreenTools.defaultFontPixelHeight
                                width:                  200
                                sourceComponent:        axisMonitorDisplayComponent

                                property real defaultTextWidth:     ScreenTools.defaultFontPixelWidth
                                property bool mapped:               true
                                readonly property bool reversed:    false
                            }
Don Gagne's avatar
Don Gagne committed
                } // Column - Axis Monitor
Don Gagne's avatar
Don Gagne committed
                // Button monitor
                Column {
                    width:      parent.width
                    spacing:    ScreenTools.defaultFontPixelHeight
Don Gagne's avatar
Don Gagne committed
                    QGCLabel { text: qsTr("Button Monitor") }
Don Gagne's avatar
Don Gagne committed
                    Connections {
                        target: _activeJoystick
Don Gagne's avatar
Don Gagne committed
                        onRawButtonPressedChanged: {
                            if (buttonMonitorRepeater.itemAt(index)) {
                                buttonMonitorRepeater.itemAt(index).pressed = pressed
                            }
Don Gagne's avatar
Don Gagne committed
                    Flow {
                        width:      parent.width
                        spacing:    -1
Don Gagne's avatar
Don Gagne committed
                        Repeater {
                            id:     buttonMonitorRepeater
                            model:  _activeJoystick ? _activeJoystick.totalButtonCount : 0
Don Gagne's avatar
Don Gagne committed
                            Rectangle {
                                width:          ScreenTools.defaultFontPixelHeight * 1.2
                                height:         width
                                border.width:   1
                                border.color:   qgcPal.text
                                color:          pressed ? qgcPal.buttonHighlight : qgcPal.button
Don Gagne's avatar
Don Gagne committed
                                property bool pressed
Don Gagne's avatar
Don Gagne committed
                                QGCLabel {
                                    anchors.fill:           parent
                                    color:                  pressed ? qgcPal.buttonHighlightText : qgcPal.buttonText
                                    horizontalAlignment:    Text.AlignHCenter
                                    verticalAlignment:      Text.AlignVCenter
                                    text:                   modelData
                                }
Don Gagne's avatar
Don Gagne committed
                        } // Repeater
                    } // Row
                } // Column - Axis Monitor
            } // Column - Right Column
        } // Item
    } // Component - pageComponent
} // SetupPage