5import QGroundControl.Controls
10 property alias lightColors: mapPal.lightColors ///< true: use light colors from QGCMapPalette for drawing
11 property real xAxis: 0 ///< Value range [-1,1], negative values left stick, positive values right stick
12 property real yAxis: 0 ///< Value range [-1,1], negative values down stick, positive values up stick
13 property bool yAxisPositiveRangeOnly: false ///< true: value range [0,1], false: value range [-1,1]
14 property bool yAxisReCenter: false ///< true: snaps back to center on release, false: stays at current position on release
15 property real xPositionDelta: 0 ///< Amount to move the control on x axis
16 property real yPositionDelta: 0 ///< Amount to move the control on y axis
18 property real _centerXY: width / 2
19 property bool _processTouchPoints: false
20 property color _fgColor: QGroundControl.globalPalette.text
21 property color _bgColor: QGroundControl.globalPalette.window
22 property real _hatWidth: ScreenTools.defaultFontPixelHeight
23 property real _hatWidthHalf: _hatWidth / 2
24 property bool calculateYAxisMutex: true
25 property real stickPositionX: _centerXY
26 property real stickPositionY: !yAxisReCenter ? height : height / 2
27 property bool alreadyCreated: false
29 QGCMapPalette { id: mapPal }
31 onStickPositionXChanged: calculateXAxis()
32 onStickPositionYChanged: calculateYAxis()
33 onYAxisPositiveRangeOnlyChanged: calculateYAxis()
34 onYAxisReCenterChanged: yAxisReCentered()
36 function yAxisReCentered() {
38 yAxis = yAxisPositiveRangeOnly ? 0.5 : 0
39 stickPositionY = _joyRoot.height / 2
41 if( !alreadyCreated && !yAxisReCenter ) {
42 yAxis = yAxisPositiveRangeOnly ? 0 : -1
43 stickPositionY = _joyRoot.height
45 if ( alreadyCreated && !yAxisReCenter ){
46 yAxis = yAxisPositiveRangeOnly ? 0.5 : 0
47 stickPositionY = _joyRoot.height / 2
53 //We prevent Joystick to move while the screen is resizing
54 function resize( yPositionAfterResize ) {
55 if(_joyRoot.height <= 0) {
58 calculateYAxisMutex = false
59 stickPositionY = ( 1 - ( ( yPositionAfterResize + ( !yAxisPositiveRangeOnly ? 1 : 0) ) / ( yAxisPositiveRangeOnly ? 1 : 2 ) )) * _joyRoot.height // Reverse the CalculateYAxis Procedure
60 stickPositionX = _joyRoot.width / 2 // Manual recenter
61 calculateYAxisMutex = true
64 function calculateXAxis() {
65 if(!_joyRoot.visible) {
68 var xAxisTemp = stickPositionX / width
74 function calculateYAxis() {
75 if(!_joyRoot.visible) {
78 if(!calculateYAxisMutex) {
81 var fullRange = yAxisPositiveRangeOnly ? 1 : 2
82 var pctUp = 1.0 - (stickPositionY / height)
83 var rangeUp = pctUp * fullRange
84 if (!yAxisPositiveRangeOnly) {
91 _processTouchPoints = false
92 _centerXY = _joyRoot.width / 2 // Reload before using it to make sure of using the right value
93 // Move control back to original position
97 // Re-Center sticks as needed
98 stickPositionX = _centerXY
100 stickPositionY = _centerXY
104 function thumbDown(touchPoints) {
105 // Position the control around the initial thumb position
106 _centerXY = _joyRoot.width / 2 // make sure to know the correct center of the item
108 var limitOffset = uiRealX >= _joyRoot.width / 2 ? true : false // as the joystick become small the UI too so we limit the maxOffset for reCentering joystick to prevent misclicks
109 var maxDelta = _joyRoot.x > uiTotalWidth / 2 ? uiTotalWidth - uiRealX - _joyRoot.x - _centerXY : uiRealX
110 var isRightJoystick = _joyRoot.x > uiTotalWidth / 2 ? true : false
112 // Check if new xDelta will make joystick to be beyond screen boundaries or can cause a misclick
113 if (!limitOffset && isRightJoystick && touchPoints[0].x <= maxDelta || !limitOffset && !isRightJoystick && touchPoints[0].x >= maxDelta) {
114 xPositionDelta = touchPoints[0].x - _centerXY
115 } else if (limitOffset && !isRightJoystick && touchPoints[0].x >= _centerXY * 0.25 && touchPoints[0].x <= _centerXY * 2) { // more offset at the side near to the center
116 xPositionDelta = touchPoints[0].x - _centerXY
117 } else if (limitOffset && isRightJoystick && touchPoints[0].x >= 0 && touchPoints[0].x <= _centerXY * 1.75) {
118 xPositionDelta = touchPoints[0].x - _centerXY
123 if (yAxisPositiveRangeOnly) {
124 yPositionDelta = touchPoints[0].y - stickPositionY
126 yPositionDelta = touchPoints[0].y - _centerXY
128 // We need to wait until we move the control to the right position before we process touch points
129 _processTouchPoints = true
133 // Keep in for debugging
135 QGCLabel { text: xAxis }
136 QGCLabel { text: yAxis }
142 source: "/res/JoystickBezelLight.png"
154 anchors.margins: parent.width / 4
157 border.color: _fgColor
165 border.color: _fgColor
173 visible: yAxisPositiveRangeOnly
174 height: ScreenTools.defaultFontPixelHeight
176 sourceSize.height: height
178 fillMode: Image.PreserveAspectFit
179 source: "/res/clockwise-arrow.svg"
180 anchors.right: parent.right
181 anchors.rightMargin: ScreenTools.defaultFontPixelWidth
182 anchors.verticalCenter: parent.verticalCenter
187 visible: yAxisPositiveRangeOnly
188 height: ScreenTools.defaultFontPixelHeight
190 sourceSize.height: height
192 fillMode: Image.PreserveAspectFit
193 source: "/res/counter-clockwise-arrow.svg"
194 anchors.left: parent.left
195 anchors.leftMargin: ScreenTools.defaultFontPixelWidth
196 anchors.verticalCenter: parent.verticalCenter
201 visible: yAxisPositiveRangeOnly
202 height: ScreenTools.defaultFontPixelHeight
204 sourceSize.height: height
206 fillMode: Image.PreserveAspectFit
207 source: "/res/chevron-up.svg"
208 anchors.top: parent.top
209 anchors.topMargin: ScreenTools.defaultFontPixelWidth
210 anchors.horizontalCenter: parent.horizontalCenter
215 visible: yAxisPositiveRangeOnly
216 height: ScreenTools.defaultFontPixelHeight
218 sourceSize.height: height
220 fillMode: Image.PreserveAspectFit
221 source: "/res/chevron-down.svg"
222 anchors.bottom: parent.bottom
223 anchors.bottomMargin: ScreenTools.defaultFontPixelWidth
224 anchors.horizontalCenter: parent.horizontalCenter
230 radius: _hatWidthHalf
231 border.color: _fgColor
233 color: Qt.rgba(_fgColor.r, _fgColor.g, _fgColor.b, 0.5)
234 x: stickPositionX - _hatWidthHalf
235 y: stickPositionY - _hatWidthHalf
242 if (_processTouchPoints) {
243 _joyRoot.stickPositionX = Math.max(Math.min(touchPoint.x, _joyRoot.width), 0)
247 if (_processTouchPoints) {
248 _joyRoot.stickPositionY = Math.max(Math.min(touchPoint.y, _joyRoot.height), 0)
253 MultiPointTouchArea {
255 anchors.bottomMargin: yAxisReCenter ? 0 : -_hatWidthHalf
256 minimumTouchPoints: 1
257 maximumTouchPoints: 1
258 touchPoints: [ TouchPoint { id: touchPoint } ]
259 onPressed: touchPoints => _joyRoot.thumbDown(touchPoints)
260 onReleased: _joyRoot.reCenter()