8import QGroundControl.Controls
9import QGroundControl.FactControls
13 width: mainLayout.width + (_smallMargins * 2)
14 height: mainLayout.height + (_smallMargins * 2)
15 color: Qt.rgba(qgcPal.window.r, qgcPal.window.g, qgcPal.window.b, 0.5)
17 visible: _camera.capturesVideo || _camera.capturesPhotos || _camera.hasTracking || _camera.hasVideoStream
19 property real _margins: ScreenTools.defaultFontPixelHeight / 2
20 property real _smallMargins: ScreenTools.defaultFontPixelWidth / 2
21 property var _activeVehicle: globals.activeVehicle
22 property var _cameraManager: _activeVehicle.cameraManager
23 property var _camera: _cameraManager.currentCameraInstance
24 property bool _cameraInPhotoMode: _camera.cameraMode === MavlinkCameraControl.CAM_MODE_PHOTO || _camera.cameraMode === MavlinkCameraControl.CAM_MODE_SURVEY
25 property bool _cameraInVideoMode: !_cameraInPhotoMode
26 property bool _videoCaptureIdle: _camera.captureVideoState === MavlinkCameraControl.CaptureVideoStateIdle
27 property bool _photoCaptureIdle: _camera.capturePhotosState === MavlinkCameraControl.CapturePhotosStateIdle
29 QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
31 DeadMouseArea { anchors.fill: parent }
35 anchors.margins: _smallMargins
36 anchors.top: parent.top
37 anchors.left: parent.left
41 Layout.fillHeight: true
43 visible: _camera.hasZoom
46 Layout.alignment: Qt.AlignHCenter
48 font.pointSize: ScreenTools.smallFontPointSize
52 Layout.alignment: Qt.AlignHCenter
53 Layout.fillHeight: true
54 orientation: Qt.Vertical
57 value: _camera.zoomLevel
59 onValueChanged: _camera.zoomLevel = value
68 Layout.alignment: Qt.AlignHCenter
69 text: _camera.modelName
70 visible: _cameraManager.cameras.length > 1
73 // Photo/Video Mode Selector
75 Layout.alignment: Qt.AlignHCenter
76 width: ScreenTools.defaultFontPixelWidth * 10
78 color: qgcPal.windowShadeLight
80 visible: _camera.hasModes
84 anchors.verticalCenter: parent.verticalCenter
87 color: _cameraInVideoMode ? qgcPal.window : qgcPal.windowShadeLight
89 anchors.left: parent.left
90 border.color: qgcPal.text
91 border.width: _cameraInPhotoMode ? 0 : 1
94 height: parent.height * 0.5
96 anchors.centerIn: parent
97 source: "/qmlimages/camera_video.svg"
98 fillMode: Image.PreserveAspectFit
99 sourceSize.height: height
100 color: _cameraInVideoMode ? qgcPal.colorGreen : qgcPal.text
104 enabled: _cameraInPhotoMode ? _photoCaptureIdle : true
105 onClicked: _camera.setCameraModeVideo()
112 anchors.verticalCenter: parent.verticalCenter
114 height: parent.height
115 color: _cameraInPhotoMode ? qgcPal.window : qgcPal.windowShadeLight
117 anchors.right: parent.right
118 border.color: qgcPal.text
119 border.width: _cameraInPhotoMode ? 1 : 0
122 height: parent.height * 0.5
124 anchors.centerIn: parent
125 source: "/qmlimages/camera_photo.svg"
126 fillMode: Image.PreserveAspectFit
127 sourceSize.height: height
128 color: _cameraInPhotoMode ? qgcPal.colorGreen : qgcPal.text
132 enabled: _cameraInVideoMode ? _videoCaptureIdle : true
133 onClicked: _camera.setCameraModePhoto()
140 Layout.alignment: Qt.AlignHCenter
141 spacing: _smallMargins
143 // Start/Stop Video button
145 id: videoCaptureButton
146 Layout.alignment: Qt.AlignHCenter
147 color: videoCaptureButtonPalette.button
148 width: ScreenTools.defaultFontPixelWidth * 6
152 border.color: videoCaptureButtonPalette.buttonBorder
153 visible: (_camera.hasModes && _cameraInVideoMode) || (!_camera.hasModes && _camera.capturesVideo)
154 enabled: _camera.captureVideoState !== MavlinkCameraControl.CaptureVideoStateDisabled
156 QGCPalette { id: videoCaptureButtonPalette; colorGroupEnabled: videoCaptureButton.enabled }
159 anchors.centerIn: parent
160 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
161 color: videoCaptureButtonPalette.buttonBorder
162 width: parent.width * 0.75
168 anchors.centerIn: parent
169 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
170 width: parent.width * (_isCapturing ? 0.5 : 0.75)
172 radius: _isCapturing ? ScreenTools.defaultFontPixelWidth * 0.5 : width * 0.5
173 color: videoCaptureButtonPalette.videoCaptureButtonColor
175 border.color: videoCaptureButtonPalette.buttonBorder
177 property bool _isCapturing: _camera.captureVideoState === MavlinkCameraControl.CaptureVideoStateCapturing
182 onClicked: _camera.toggleVideoRecording()
187 Layout.alignment: Qt.AlignHCenter
189 font.pointSize: ScreenTools.smallFontPointSize
190 visible: videoCaptureButton.visible && photoCaptureButton.visible
195 Layout.alignment: Qt.AlignHCenter
196 color: _videoCaptureIdle ? "transparent" : videoCaptureButtonPalette.videoCaptureButtonColor
197 Layout.preferredWidth: videoRecordTime.width + (_smallMargins * 2)
198 Layout.preferredHeight: videoRecordTime.height
199 radius: _smallMargins
200 visible: videoCaptureButton.visible
205 anchors.leftMargin: _smallMargins
206 anchors.left: parent.left
207 anchors.top: parent.top
208 text: _videoCaptureIdle ? "00:00:00" : _camera.recordTimeStr
213 Layout.alignment: Qt.AlignHCenter
216 visible: videoCaptureButton.visible && photoCaptureButton.visible
221 id: photoCaptureButton
222 Layout.alignment: Qt.AlignHCenter
223 color: photoCaptureButtonPalette.button
224 width: ScreenTools.defaultFontPixelWidth * 6
228 border.color: photoCaptureButtonPalette.buttonBorder
229 visible: (_camera.hasModes && _cameraInPhotoMode) || (!_camera.hasModes && (_camera.hasVideoStream || _camera.capturesPhotos))
230 enabled: _camera.capturePhotosState !== MavlinkCameraControl.CapturePhotosStateDisabled
232 QGCPalette { id: photoCaptureButtonPalette; colorGroupEnabled: photoCaptureButton.enabled }
235 anchors.centerIn: parent
236 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
237 color: photoCaptureButtonPalette.buttonBorder
238 width: parent.width * 0.75
244 anchors.centerIn: parent
245 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
246 width: parent.width * (_isCapturing ? 0.5 : 0.75)
248 radius: _isCapturing ? ScreenTools.defaultFontPixelWidth * 0.5 : width * 0.5
249 color: photoCaptureButtonPalette.photoCaptureButtonColor
251 border.color: photoCaptureButtonPalette.buttonBorder
253 property bool _isCapturing: _camera.capturePhotosState === MavlinkCameraControl.CapturePhotosStateCapturingSinglePhoto ||
254 _camera.capturePhotosState === MavlinkCameraControl.CapturePhotosStateCapturingMultiplePhotos
260 if (_camera.capturePhotosState === MavlinkCameraControl.CapturePhotosStateCapturingMultiplePhotos) {
261 _camera.stopTakePhoto()
262 } else if (_camera.capturePhotosState === MavlinkCameraControl.CapturePhotosStateIdle) {
270 Layout.alignment: Qt.AlignHCenter
272 font.pointSize: ScreenTools.smallFontPointSize
273 visible: videoCaptureButton.visible && photoCaptureButton.visible
278 Layout.alignment: Qt.AlignHCenter
279 color: _photoCaptureIdle ? "transparent" : photoCaptureButtonPalette.photoCaptureButtonColor
280 Layout.preferredWidth: photoCaptureCount.width + (_smallMargins * 2)
281 Layout.preferredHeight: photoCaptureCount.height
282 radius: _smallMargins
283 visible: photoCaptureButton.visible
285 // Photo capture count
287 id: photoCaptureCount
288 anchors.leftMargin: _smallMargins
289 anchors.left: parent.left
290 anchors.top: parent.top
291 text: _activeVehicle ? ('00000' + _activeVehicle.cameraTriggerPoints.count).slice(-5) : "00000"
296 //-- Status Information
298 Layout.alignment: Qt.AlignHCenter
300 visible: storageStatus.visible || batteryStatus.visible
304 Layout.alignment: Qt.AlignHCenter
305 text: qsTr("Free: ") + _camera.storageFreeStr
306 font.pointSize: ScreenTools.defaultFontPointSize
307 visible: _camera.storageStatus === MavlinkCameraControl.STORAGE_READY
312 Layout.alignment: Qt.AlignHCenter
313 text: qsTr("Battery: ") + _camera.batteryRemainingStr
314 font.pointSize: ScreenTools.defaultFontPointSize
315 visible: _camera.batteryRemaining >= 0
321 Layout.alignment: Qt.AlignHCenter
323 visible: _camera.hasTracking
326 Layout.alignment: Qt.AlignHCenter
327 color: _camera.trackingEnabled ? qgcPal.colorRed : qgcPal.windowShadeLight
328 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 6
329 Layout.preferredHeight: Layout.preferredWidth
330 border.color: qgcPal.buttonText
334 height: parent.height * 0.5
336 anchors.centerIn: parent
337 source: "/qmlimages/TrackingIcon.svg"
338 fillMode: Image.PreserveAspectFit
339 sourceSize.height: height
345 _camera.trackingEnabled = !_camera.trackingEnabled;
346 if (!_camera.trackingEnabled) {
347 _camera.stopTracking()
355 Layout.alignment: Qt.AlignHCenter
356 text: qsTr("Camera Tracking")
357 font.pointSize: ScreenTools.smallFontPointSize
362 Layout.alignment: Qt.AlignHCenter
363 source: "/res/gear-black.svg"
365 Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
366 Layout.preferredWidth: Layout.preferredHeight
367 sourceSize.height: Layout.preferredHeight
369 fillMode: Image.PreserveAspectFit
373 onClicked: settingsDialogFactory.open()
378 QGCPopupDialogFactory {
379 id: settingsDialogFactory
381 dialogComponent: settingsDialogComponent
385 id: settingsDialogComponent
388 title: qsTr("Settings")
389 buttons: Dialog.Close
391 property bool _multipleMavlinkCameras: _cameraManager.cameras.count > 1
392 property bool _multipleMavlinkCameraStreams: _camera.streamLabels.length > 1
393 property bool _cameraStorageSupported: _camera.storageStatus !== MavlinkCameraControl.STORAGE_NOT_SUPPORTED
394 property var _videoSettings: QGroundControl.settingsManager.videoSettings
401 flow: GridLayout.TopToBottom
402 rows: dynamicRows + _camera.activeSettings.length
404 property int dynamicRows: 10
409 visible: _multipleMavlinkCameras
410 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
414 text: qsTr("Video Stream")
415 visible: _multipleMavlinkCameraStreams
416 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
420 text: qsTr("Thermal View Mode")
421 visible: _camera.thermalStreamInstance
422 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
426 text: qsTr("Blend Opacity")
427 visible: _camera.thermalStreamInstance && _camera.thermalMode === MavlinkCameraControl.THERMAL_BLEND
428 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
431 // Mavlink Camera Protocol active settings
433 model: _camera.activeSettings
436 text: _camera.getFact(modelData).shortDescription
441 text: qsTr("Photo Mode")
442 visible: _camera.capturesPhotos
443 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
447 text: qsTr("Photo Interval (seconds)")
448 visible: _camera.capturesPhotos && _camera.photoCaptureMode === MavlinkCameraControl.PHOTO_CAPTURE_TIMELAPSE
449 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
453 text: qsTr("Video Grid Lines")
454 visible: _camera.hasVideoStream
455 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
459 text: qsTr("Video Screen Fit")
460 visible: _camera.hasVideoStream
461 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
465 text: qsTr("Reset Camera Defaults")
466 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
470 text: qsTr("Storage")
471 visible: _cameraStorageSupported
472 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
477 Layout.fillWidth: true
479 model: _cameraManager.cameraLabels
480 currentIndex: _cameraManager.currentCamera
481 visible: _multipleMavlinkCameras
482 onActivated: (index) => { _cameraManager.currentCamera = index }
486 Layout.fillWidth: true
488 model: _camera.streamLabels
489 currentIndex: _camera.currentStream
490 visible: _multipleMavlinkCameraStreams
491 onActivated: (index) => { _camera.currentStream = index }
495 Layout.fillWidth: true
497 model: [ qsTr("Off"), qsTr("Blend"), qsTr("Full"), qsTr("Picture In Picture") ]
498 currentIndex: _camera.thermalMode
499 visible: _camera.thermalStreamInstance
500 onActivated: (index) => { _camera.thermalMode = index }
504 Layout.fillWidth: true
507 value: _camera.thermalOpacity
509 visible: _camera.thermalStreamInstance && _camera.thermalMode === MavlinkCameraControl.THERMAL_BLEND
510 onValueChanged: _camera.thermalOpacity = value
513 // Mavlink Camera Protocol active settings
515 model: _camera.activeSettings
518 Layout.fillWidth: true
519 spacing: ScreenTools.defaultFontPixelWidth
521 property var _fact: _camera.getFact(modelData)
522 property bool _isBool: _fact.typeIsBool
523 property bool _isCombo: !_isBool && _fact.enumStrings.length > 0
524 property bool _isSlider: _fact && !isNaN(_fact.increment)
525 property bool _isEdit: !_isBool && !_isSlider && _fact.enumStrings.length < 1
528 Layout.fillWidth: true
532 visible: parent._isCombo
535 Layout.fillWidth: true
537 visible: parent._isEdit
540 Layout.fillWidth: true
542 from: parent._fact.min
543 stepSize: parent._fact.increment
544 visible: parent._isSlider
546 property bool initialized: false
552 parent._fact.value = value
555 Component.onCompleted: {
556 value = parent._fact.value
561 checked: parent._fact ? parent._fact.value : false
562 visible: parent._isBool
563 onClicked: parent._fact.value = checked ? 1 : 0
569 Layout.fillWidth: true
571 model: [ qsTr("Single"), qsTr("Time Lapse") ]
572 currentIndex: _camera.photoCaptureMode
573 visible: _camera.capturesPhotos
574 onActivated: (index) => { _camera.photoCaptureMode = index }
578 Layout.fillWidth: true
582 value: _camera.photoLapse
585 visible: _camera.capturesPhotos && _camera.photoCaptureMode === MavlinkCameraControl.PHOTO_CAPTURE_TIMELAPSE
586 onValueChanged: _camera.photoLapse = value
590 checked: _videoSettings.gridLines.rawValue
591 visible: _camera.hasVideoStream
592 onClicked: _videoSettings.gridLines.rawValue = checked ? 1 : 0
596 Layout.fillWidth: true
598 fact: _videoSettings.videoFit
600 visible: _camera.hasVideoStream
604 Layout.fillWidth: true
606 onClicked: resetPrompt.open()
609 title: qsTr("Reset Camera to Factory Settings")
610 text: qsTr("Confirm resetting all settings?")
611 buttons: MessageDialog.Yes | MessageDialog.No
613 onButtonClicked: function (button, role) {
615 case MessageDialog.Yes:
616 _camera.resetSettings()
619 case MessageDialog.No:
628 Layout.fillWidth: true
630 visible: _cameraStorageSupported
631 onClicked: formatPrompt.open()
634 title: qsTr("Format Camera Storage")
635 text: qsTr("Confirm erasing all files?")
636 buttons: MessageDialog.Yes | MessageDialog.No
638 onButtonClicked: function (button, role) {
640 case MessageDialog.Yes:
644 case MessageDialog.No: