QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
FlightDisplayViewVideo.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3
4import QGroundControl
5import QGroundControl.FlyView
6import QGroundControl.FlightMap
7import QGroundControl.Controls
8
9Item {
10 id: root
11 clip: true
12
13 property bool useSmallFont: true
14
15 property double _ar: (cameraLoader.visible && cameraLoader.status === Loader.Ready)
16 ? cameraLoader.item.implicitWidth / cameraLoader.item.implicitHeight
17 : QGroundControl.videoManager.gstreamerEnabled
18 ? QGroundControl.videoManager.videoSize.width / QGroundControl.videoManager.videoSize.height
19 : QGroundControl.videoManager.aspectRatio
20 property bool _showGrid: QGroundControl.settingsManager.videoSettings.gridLines.rawValue
21 property var _dynamicCameras: globals.activeVehicle ? globals.activeVehicle.cameraManager : null
22 property bool _connected: globals.activeVehicle ? !globals.activeVehicle.communicationLost : false
23 property int _curCameraIndex: _dynamicCameras ? _dynamicCameras.currentCamera : 0
24 property bool _isCamera: _dynamicCameras ? _dynamicCameras.cameras.count > 0 : false
25 property var _camera: _isCamera ? _dynamicCameras.cameras.get(_curCameraIndex) : null
26 property bool _hasZoom: _camera && _camera.hasZoom
27 property int _fitMode: QGroundControl.settingsManager.videoSettings.videoFit.rawValue
28 property bool _showStreamLoader: QGroundControl.videoManager.decoding
29 property bool _showUvcLoader: QGroundControl.videoManager.isUvc
30
31 property bool _isMode_FIT_WIDTH: _fitMode === 0
32 property bool _isMode_FIT_HEIGHT: _fitMode === 1
33 property bool _isMode_FILL: _fitMode === 2
34 property bool _isMode_NO_CROP: _fitMode === 3
35
36 function getWidth() {
37 return videoBackground.getWidth()
38 }
39 function getHeight() {
40 return videoBackground.getHeight()
41 }
42
43 property double _thermalHeightFactor: 0.85 //-- TODO
44
45 Image {
46 id: noVideo
47 anchors.fill: parent
48 source: "/res/NoVideoBackground.jpg"
49 fillMode: Image.PreserveAspectCrop
50 visible: !_showStreamLoader && !_showUvcLoader
51
52 Rectangle {
53 anchors.centerIn: parent
54 width: noVideoLabel.contentWidth + ScreenTools.defaultFontPixelHeight
55 height: noVideoLabel.contentHeight + ScreenTools.defaultFontPixelHeight
56 radius: ScreenTools.defaultFontPixelWidth / 2
57 color: "black"
58 opacity: 0.5
59 }
60
61 QGCLabel {
62 id: noVideoLabel
63 text: QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue ? qsTr("WAITING FOR VIDEO") : qsTr("VIDEO DISABLED")
64 font.bold: true
65 color: "white"
66 font.pointSize: useSmallFont ? ScreenTools.smallFontPointSize : ScreenTools.largeFontPointSize
67 anchors.centerIn: parent
68 }
69 }
70
71 Rectangle {
72 id: videoBackground
73 anchors.fill: parent
74 color: "black"
75 visible: _showStreamLoader || _showUvcLoader
76 function getWidth() {
77 if(_ar != 0.0){
78 if(_isMode_FIT_HEIGHT
79 || (_isMode_FILL && (root.width/root.height < _ar))
80 || (_isMode_NO_CROP && (root.width/root.height > _ar))){
81 // This return value has different implications depending on the mode
82 // For FIT_HEIGHT and FILL
83 // makes so the video width will be larger than (or equal to) the screen width
84 // For NO_CROP Mode
85 // makes so the video width will be smaller than (or equal to) the screen width
86 return root.height * _ar
87 }
88 }
89 return root.width
90 }
91 function getHeight() {
92 if(_ar != 0.0){
93 if(_isMode_FIT_WIDTH
94 || (_isMode_FILL && (root.width/root.height > _ar))
95 || (_isMode_NO_CROP && (root.width/root.height < _ar))){
96 // This return value has different implications depending on the mode
97 // For FIT_WIDTH and FILL
98 // makes so the video height will be larger than (or equal to) the screen height
99 // For NO_CROP Mode
100 // makes so the video height will be smaller than (or equal to) the screen height
101 return root.width * (1 / _ar)
102 }
103 }
104 return root.height
105 }
106 Loader {
107 id: videoStreamLoader
108 anchors.fill: videoContentArea
109 visible: _showStreamLoader
110 sourceComponent: videoOutputComponent
111
112 property bool videoDisabled: QGroundControl.settingsManager.videoSettings.videoSource.rawValue === QGroundControl.settingsManager.videoSettings.disabledVideoSource
113 }
114 Component {
115 id: videoOutputComponent
116 FlightDisplayViewVideoOutput {
117 }
118 }
119 //-- UVC Video (USB Camera or Video Device)
120 Loader {
121 id: cameraLoader
122 anchors.fill: videoContentArea
123 visible: _showUvcLoader
124 source: QGroundControl.videoManager.uvcEnabled ? "qrc:/qml/QGroundControl/FlyView/FlightDisplayViewUVC.qml" : "qrc:/qml/QGroundControl/FlyView//FlightDisplayViewDummy.qml"
125 }
126
127 Item {
128 id: videoContentArea
129 height: parent.getHeight()
130 width: parent.getWidth()
131 anchors.centerIn: parent
132 visible: _showStreamLoader || _showUvcLoader
133
134 // grid lines
135 Item {
136 anchors.fill: parent
137 visible: _showGrid && !QGroundControl.videoManager.fullScreen
138
139 Rectangle {
140 color: Qt.rgba(1,1,1,0.5)
141 height: parent.height
142 width: 1
143 x: parent.width * 0.33
144 }
145 Rectangle {
146 color: Qt.rgba(1,1,1,0.5)
147 height: parent.height
148 width: 1
149 x: parent.width * 0.66
150 }
151 Rectangle {
152 color: Qt.rgba(1,1,1,0.5)
153 width: parent.width
154 height: 1
155 y: parent.height * 0.33
156 }
157 Rectangle {
158 color: Qt.rgba(1,1,1,0.5)
159 width: parent.width
160 height: 1
161 y: parent.height * 0.66
162 }
163 }
164 }
165
166 //-- Thermal Image
167 Item {
168 id: thermalItem
169 width: height * QGroundControl.videoManager.thermalAspectRatio
170 height: _camera ? (_camera.thermalMode === MavlinkCameraControlInterface.THERMAL_FULL ? parent.height : (_camera.thermalMode === MavlinkCameraControlInterface.THERMAL_PIP ? ScreenTools.defaultFontPixelHeight * 12 : parent.height * _thermalHeightFactor)) : 0
171 anchors.centerIn: parent
172 visible: QGroundControl.videoManager.hasThermal && _camera.thermalMode !== MavlinkCameraControlInterface.THERMAL_OFF
173 function pipOrNot() {
174 if(_camera) {
175 if(_camera.thermalMode === MavlinkCameraControlInterface.THERMAL_PIP) {
176 anchors.centerIn = undefined
177 anchors.top = parent.top
178 anchors.topMargin = mainWindow.header.height + (ScreenTools.defaultFontPixelHeight * 0.5)
179 anchors.left = parent.left
180 anchors.leftMargin = ScreenTools.defaultFontPixelWidth * 12
181 } else {
182 anchors.top = undefined
183 anchors.topMargin = undefined
184 anchors.left = undefined
185 anchors.leftMargin = undefined
186 anchors.centerIn = parent
187 }
188 }
189 }
190 Connections {
191 target: _camera
192 function onThermalModeChanged() { thermalItem.pipOrNot() }
193 }
194 onVisibleChanged: {
195 thermalItem.pipOrNot()
196 }
197 Loader {
198 id: thermalVideo
199 anchors.fill: parent
200 opacity: _camera ? (_camera.thermalMode === MavlinkCameraControlInterface.THERMAL_BLEND ? _camera.thermalOpacity / 100 : 1.0) : 0
201 sourceComponent: thermalOutputComponent
202 onLoaded: { if (item) item.objectName = "thermalVideo" }
203
204 Component {
205 id: thermalOutputComponent
206 FlightDisplayViewVideoOutput {}
207 }
208 }
209 }
210 //-- Zoom
211 PinchArea {
212 id: pinchZoom
213 enabled: _hasZoom
214 anchors.fill: parent
215 onPinchStarted: pinchZoom.zoom = 0
216 onPinchUpdated: {
217 if(_hasZoom) {
218 var z = 0
219 if(pinch.scale < 1) {
220 z = Math.round(pinch.scale * -10)
221 } else {
222 z = Math.round(pinch.scale)
223 }
224 if(pinchZoom.zoom != z) {
225 _camera.stepZoom(z)
226 }
227 }
228 }
229 property int zoom: 0
230 }
231 }
232}