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.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controllers 1.0
import QGroundControl.FactControls 1.0
SetupPage {
id: joystickPage
pageComponent: pageComponent
pageName: qsTr("Joystick")
pageDescription: qsTr("Joystick Setup is used to configure a calibrate joysticks.")
Connections {
target: joystickManager
onAvailableJoysticksChanged: {
summaryButton.checked = true
setupView.showSummaryPanel()
}
}
}
Component {
id: pageComponent
Item {
width: availableWidth
height: Math.max(leftColumn.height, rightColumn.height)
Gus Grubba
committed
readonly property real labelToMonitorMargin: ScreenTools.defaultFontPixelWidth * 3
property var _activeJoystick: joystickManager.activeJoystick
function setupPageCompleted() {
Gus Grubba
committed
controller.start()
}
JoystickConfigController {
id: controller
statusText: statusText
cancelButton: cancelButton
nextButton: nextButton
skipButton: skipButton
}
// Live axis monitor control component
Component {
id: axisMonitorDisplayComponent
property bool narrowIndicator: false
property color deadbandColor: "#8c161a"
// Bar
Rectangle {
id: bar
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: parent.height / 2
color: __barColor
}
// Deadband
Rectangle {
id: deadbandBar
anchors.verticalCenter: parent.verticalCenter
x: _deadbandPosition
width: _deadbandWidth
height: parent.height / 2
color: deadbandColor
visible: controller.deadbandToggle
property real _percentDeadband: ((2 * deadbandValue) / (32768.0 * 2))
property real _deadbandWidth: parent.width * _percentDeadband
property real _deadbandPosition: (parent.width - _deadbandWidth) / 2
}
// Center point
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
Gus Grubba
committed
width: ScreenTools.defaultFontPixelWidth / 2
// Indicator
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.narrowIndicator ? height/6 : height
height: parent.height * 0.75
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
}
QGCLabel {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: qsTr("Not Mapped")
visible: !mapped
}
ColorAnimation {
id: barAnimation
target: bar
property: "color"
from: "yellow"
to: __barColor
duration: 1500
}
QGCLabel {
anchors.fill: parent
text: axisValue
}
*/
// 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
// Attitude Controls
Column {
width: parent.width
spacing: 5
Item {
width: parent.width
height: defaultTextHeight * 2
Gus Grubba
committed
width: ScreenTools.defaultFontPixelWidth * 10
text: activeVehicle.sub ? qsTr("Lateral") : qsTr("Roll")
Loader {
id: rollLoader
anchors.left: rollLabel.right
anchors.right: parent.right
height: ScreenTools.defaultFontPixelHeight
width: 100
sourceComponent: axisMonitorDisplayComponent
property bool mapped: controller.rollAxisMapped
property bool reversed: controller.rollAxisReversed
nanthony21
committed
Connections {
target: _activeJoystick
onManualControl: rollLoader.item.axisValue = roll*32768.0
}
Item {
width: parent.width
height: defaultTextHeight * 2
Gus Grubba
committed
width: ScreenTools.defaultFontPixelWidth * 10
text: activeVehicle.sub ? qsTr("Forward") : qsTr("Pitch")
Loader {
id: pitchLoader
anchors.left: pitchLabel.right
anchors.right: parent.right
height: ScreenTools.defaultFontPixelHeight
width: 100
sourceComponent: axisMonitorDisplayComponent
property bool mapped: controller.pitchAxisMapped
property bool reversed: controller.pitchAxisReversed
}
nanthony21
committed
Connections {
target: _activeJoystick
onManualControl: pitchLoader.item.axisValue = pitch*32768.0
}
Item {
width: parent.width
height: defaultTextHeight * 2
Gus Grubba
committed
width: ScreenTools.defaultFontPixelWidth * 10
Loader {
id: yawLoader
anchors.left: yawLabel.right
anchors.right: parent.right
height: ScreenTools.defaultFontPixelHeight
width: 100
sourceComponent: axisMonitorDisplayComponent
property bool mapped: controller.yawAxisMapped
property bool reversed: controller.yawAxisReversed
}
nanthony21
committed
Connections {
target: _activeJoystick
onManualControl: yawLoader.item.axisValue = yaw*32768.0
}
Item {
width: parent.width
height: defaultTextHeight * 2
Gus Grubba
committed
width: ScreenTools.defaultFontPixelWidth * 10
Loader {
id: throttleLoader
anchors.left: throttleLabel.right
anchors.right: parent.right
height: ScreenTools.defaultFontPixelHeight
width: 100
sourceComponent: axisMonitorDisplayComponent
property bool mapped: controller.throttleAxisMapped
property bool reversed: controller.throttleAxisReversed
}
nanthony21
committed
Connections {
target: _activeJoystick
onManualControl: throttleLoader.item.axisValue = _activeJoystick.negativeThrust ? -throttle*32768.0 : (-2*throttle+1)*32768.0
nanthony21
committed
}
visible: _activeJoystick.requiresCalibration
QGCButton {
id: skipButton
text: qsTr("Skip")
QGCButton {
id: cancelButton
text: qsTr("Cancel")
QGCButton {
id: nextButton
primary: true
text: qsTr("Calibrate")
onClicked: controller.nextButtonClicked()
}
} // Row - Buttons
// Status Text
QGCLabel {
id: statusText
width: parent.width
wrapMode: Text.WordWrap
Rectangle {
width: parent.width
height: 1
border.color: qgcPal.text
border.width: 1
// Settings
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelHeight
QGCLabel { text: qsTr("Additional Joystick settings:") }
Column {
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight
enabled: _activeJoystick ? _activeJoystick.calibrated : false
text: _activeJoystick ? _activeJoystick.calibrated ? qsTr("Enable joystick input") : qsTr("Enable not allowed (Calibrate First)") : ""
onClicked: activeVehicle.joystickEnabled = checked
Component.onCompleted: checked = activeVehicle.joystickEnabled
Connections {
onJoystickEnabledChanged: {
enabledCheckBox.checked = activeVehicle.joystickEnabled
Nick Anthony
committed
Connections {
target: joystickManager
onActiveJoystickChanged: {
if(_activeJoystick) {
enabledCheckBox.checked = Qt.binding(function() { return _activeJoystick.calibrated && activeVehicle.joystickEnabled })
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
id: activeJoystickLabel
anchors.baseline: joystickCombo.baseline
text: qsTr("Active joystick:")
}
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)
console.warn(qsTr("Active joystick name not in combo"), joystickManager.activeJoystickName)
} else {
joystickCombo.currentIndex = index
}
Connections {
target: joystickManager
onAvailableJoysticksChanged: {
var index = joystickCombo.find(joystickManager.activeJoystickName)
joystickCombo.currentIndex = index
}
}
}
Column {
spacing: ScreenTools.defaultFontPixelHeight / 3
visible: activeVehicle.supportsThrottleModeCenterZero
QGCRadioButton {
text: qsTr("Center stick is zero throttle")
checked: _activeJoystick ? _activeJoystick.throttleMode === 0 : false
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: _activeJoystick ? _activeJoystick.throttleMode === 0 : false
QGCCheckBox {
id: accumulator
checked: _activeJoystick ? _activeJoystick.accumulator : false
onClicked: _activeJoystick.accumulator = checked
}
}
QGCRadioButton {
text: qsTr("Full down stick is zero throttle")
checked: _activeJoystick ? _activeJoystick.throttleMode === 1 : false
visible: activeVehicle.supportsNegativeThrust
id: negativeThrust
text: qsTr("Allow negative Thrust")
enabled: _activeJoystick.negativeThrust = activeVehicle.supportsNegativeThrust
checked: _activeJoystick ? _activeJoystick.negativeThrust : false
onClicked: _activeJoystick.negativeThrust = checked
Column {
spacing: ScreenTools.defaultFontPixelHeight / 3
QGCLabel {
id: expoSliderLabel
text: qsTr("Exponential:")
}
Row {
QGCSlider {
id: expoSlider
minimumValue: 0
maximumValue: 0.75
Component.onCompleted: value=-_activeJoystick.exponential
onValueChanged: _activeJoystick.exponential=-value
}
QGCLabel {
id: expoSliderIndicator
text: expoSlider.value.toFixed(2)
nanthony21
committed
}
activeVehicle.joystickMode = 0
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: advancedSettings.checked
QGCLabel {
id: joystickModeLabel
anchors.baseline: joystickModeCombo.baseline
text: qsTr("Joystick mode:")
}
currentIndex: activeVehicle.joystickMode
model: activeVehicle.joystickModes
onActivated: activeVehicle.joystickMode = index
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: advancedSettings.checked
QGCLabel {
text: qsTr("Message frequency (Hz):")
anchors.verticalCenter: parent.verticalCenter
}
QGCTextField {
text: _activeJoystick.frequency
validator: DoubleValidator { bottom: 0.25; top: 100.0; }
inputMethodHints: Qt.ImhFormattedNumbersOnly
onEditingFinished: {
_activeJoystick.frequency = parseFloat(text)
}
}
}
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: advancedSettings.checked
QGCCheckBox {
id: joystickCircleCorrection
text: qsTr("Enable circle correction")
Component.onCompleted: checked = _activeJoystick.circleCorrection
onClicked: {
_activeJoystick.circleCorrection = checked
}
}
}
Row {
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: advancedSettings.checked
QGCCheckBox {
id: deadband
checked: controller.deadbandToggle
text: qsTr("Deadbands")
onClicked: controller.deadbandToggle = checked
}
}
Row{
width: parent.width
spacing: ScreenTools.defaultFontPixelWidth
visible: advancedSettings.checked
QGCLabel{
width: parent.width * 0.85
font.pointSize: ScreenTools.smallFontPointSize
wrapMode: Text.WordWrap
text: qsTr("Deadband can be set during the first ") +
qsTr("step of calibration by gently wiggling each axis. ") +
qsTr("Deadband can also be adjusted by clicking and ") +
qsTr("dragging vertically on the corresponding axis monitor.")
visible: controller.deadbandToggle
}
}
// Right column settings
Column {
width: parent.width / 2
spacing: ScreenTools.defaultFontPixelHeight
onRawButtonPressedChanged: {
if (buttonActionRepeater.itemAt(index)) {
buttonActionRepeater.itemAt(index).pressed = pressed
}
if (jsButtonActionRepeater.itemAt(index)) {
jsButtonActionRepeater.itemAt(index).pressed = pressed
}
Column {
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight / 3
model: _activeJoystick ? Math.min(_activeJoystick.totalButtonCount, _maxButtons) : 0
visible: !activeVehicle.supportsJSButton
QGCCheckBox {
anchors.verticalCenter: parent.verticalCenter
checked: _activeJoystick ? _activeJoystick.buttonActions[modelData] !== "" : false
onClicked: _activeJoystick.setButtonAction(modelData, checked ? buttonActionCombo.textAt(buttonActionCombo.currentIndex) : "")
}
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
}
QGCComboBox {
id: buttonActionCombo
width: ScreenTools.defaultFontPixelWidth * 20
model: _activeJoystick ? _activeJoystick.actions : 0
onActivated: _activeJoystick.setButtonAction(modelData, textAt(index))
Component.onCompleted: currentIndex = find(_activeJoystick.buttonActions[modelData])
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
visible: activeVehicle.supportsJSButton
QGCLabel {
horizontalAlignment: Text.AlignHCenter
width: ScreenTools.defaultFontPixelHeight * 1.5
text: qsTr("#")
QGCLabel {
width: ScreenTools.defaultFontPixelWidth * 15
text: qsTr("Function: ")
QGCLabel {
width: ScreenTools.defaultFontPixelWidth * 15
text: qsTr("Shift Function: ")
model: _activeJoystick ? Math.min(_activeJoystick.totalButtonCount, _maxButtons) : 0
Row {
spacing: ScreenTools.defaultFontPixelWidth
visible: activeVehicle.supportsJSButton
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
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
id: rightColumn
anchors.top: parent.top
anchors.right: parent.right
Gus Grubba
committed
width: Math.min(joystickPage.ScreenTools.defaultFontPixelWidth * 35, availableWidth * 0.4)
spacing: ScreenTools.defaultFontPixelHeight / 2
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: "TX Mode:"
}
QGCRadioButton {
text: "1"
checked: controller.transmitterMode == 1
enabled: !controller.calibrating
onClicked: controller.transmitterMode = 1
}
QGCRadioButton {
text: "2"
checked: controller.transmitterMode == 2
enabled: !controller.calibrating
onClicked: controller.transmitterMode = 2
}
QGCRadioButton {
text: "3"
checked: controller.transmitterMode == 3
enabled: !controller.calibrating
onClicked: controller.transmitterMode = 3
}
QGCRadioButton {
text: "4"
checked: controller.transmitterMode == 4
enabled: !controller.calibrating
onClicked: controller.transmitterMode = 4
}
}
fillMode: Image.PreserveAspectFit
smooth: true
source: controller.imageHelp
}
// Axis monitor
Column {
width: parent.width
spacing: 5
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
}
}
model: _activeJoystick ? _activeJoystick.axisCount : 0
// Need this to get to loader from Connections above
property Item loader: theLoader
QGCLabel {
id: axisLabel
text: modelData
}
Loader {
id: theLoader
anchors.verticalCenter: axisLabel.verticalCenter
height: ScreenTools.defaultFontPixelHeight
width: 200
sourceComponent: axisMonitorDisplayComponent
Component.onCompleted: item.narrowIndicator = true
property bool mapped: true
readonly property bool reversed: false
id: deadbandMouseArea
anchors.fill: parent.item
enabled: controller.deadbandToggle
preventStealing: true
property real startX
property real direction
startX = mouseX
direction = startX > width/2 ? 1 : -1
parent.item.deadbandColor = "#3C6315"
var mouseToDeadband = 32768/(width/2) // Factor to have deadband follow the mouse movement
var newValue = parent.item.deadbandValue + direction*(mouseX - startX)*mouseToDeadband
if ((newValue > 0) && (newValue <32768)){parent.item.deadbandValue=newValue;}
startX = mouseX
}
onReleased: {
controller.setDeadbandValue(modelData,parent.item.deadbandValue)
parent.item.deadbandColor = "#8c161a"
// Button monitor
Column {
width: parent.width
spacing: ScreenTools.defaultFontPixelHeight
onRawButtonPressedChanged: {
if (buttonMonitorRepeater.itemAt(index)) {
buttonMonitorRepeater.itemAt(index).pressed = pressed
}
model: _activeJoystick ? _activeJoystick.totalButtonCount : 0
Rectangle {
width: ScreenTools.defaultFontPixelHeight * 1.2
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
}
} // Repeater
} // Row
} // Column - Axis Monitor
} // Column - Right Column
} // Item
} // Component - pageComponent
} // SetupPage