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 === MavlinkCameraControlInterface.CAM_MODE_PHOTO || _camera.cameraMode === MavlinkCameraControlInterface.CAM_MODE_SURVEY
25 property bool _cameraInVideoMode: !_cameraInPhotoMode
26 property bool _videoCaptureIdle: _camera.captureVideoState === MavlinkCameraControlInterface.CaptureVideoStateIdle
27 property bool _photoCaptureIdle: _camera.capturePhotosState === MavlinkCameraControlInterface.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 objectName: "photoVideoControl_zoomSlider"
53 Layout.alignment: Qt.AlignHCenter
54 Layout.fillHeight: true
55 orientation: Qt.Vertical
58 value: _camera.zoomLevel
60 onMoved: _camera.zoomLevel = value
69 Layout.alignment: Qt.AlignHCenter
70 text: _camera.modelName
71 visible: _cameraManager.cameras.length > 1
74 // Photo/Video Mode Selector
76 Layout.alignment: Qt.AlignHCenter
77 width: ScreenTools.defaultFontPixelWidth * 10
79 color: qgcPal.windowShadeLight
81 visible: _camera.hasModes
85 anchors.verticalCenter: parent.verticalCenter
88 color: _cameraInVideoMode ? qgcPal.window : qgcPal.windowShadeLight
90 anchors.left: parent.left
91 border.color: qgcPal.text
92 border.width: _cameraInPhotoMode ? 0 : 1
95 height: parent.height * 0.5
97 anchors.centerIn: parent
98 source: "/qmlimages/camera_video.svg"
99 fillMode: Image.PreserveAspectFit
100 sourceSize.height: height
101 color: _cameraInVideoMode ? qgcPal.colorGreen : qgcPal.text
105 enabled: _cameraInPhotoMode ? _photoCaptureIdle : true
106 onClicked: _camera.setCameraModeVideo()
113 anchors.verticalCenter: parent.verticalCenter
115 height: parent.height
116 color: _cameraInPhotoMode ? qgcPal.window : qgcPal.windowShadeLight
118 anchors.right: parent.right
119 border.color: qgcPal.text
120 border.width: _cameraInPhotoMode ? 1 : 0
123 height: parent.height * 0.5
125 anchors.centerIn: parent
126 source: "/qmlimages/camera_photo.svg"
127 fillMode: Image.PreserveAspectFit
128 sourceSize.height: height
129 color: _cameraInPhotoMode ? qgcPal.colorGreen : qgcPal.text
133 enabled: _cameraInVideoMode ? _videoCaptureIdle : true
134 onClicked: _camera.setCameraModePhoto()
141 Layout.alignment: Qt.AlignHCenter
142 spacing: _smallMargins
144 // Start/Stop Video button
146 id: videoCaptureButton
147 Layout.alignment: Qt.AlignHCenter
148 color: videoCaptureButtonPalette.button
149 width: ScreenTools.defaultFontPixelWidth * 6
153 border.color: videoCaptureButtonPalette.buttonBorder
154 visible: (_camera.hasModes && _cameraInVideoMode) || (!_camera.hasModes && _camera.capturesVideo)
155 enabled: _camera.captureVideoState !== MavlinkCameraControlInterface.CaptureVideoStateDisabled
157 QGCPalette { id: videoCaptureButtonPalette; colorGroupEnabled: videoCaptureButton.enabled }
160 anchors.centerIn: parent
161 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
162 color: videoCaptureButtonPalette.buttonBorder
163 width: parent.width * 0.75
169 anchors.centerIn: parent
170 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
171 width: parent.width * (_isCapturing ? 0.5 : 0.75)
173 radius: _isCapturing ? ScreenTools.defaultFontPixelWidth * 0.5 : width * 0.5
174 color: videoCaptureButtonPalette.videoCaptureButtonColor
176 border.color: videoCaptureButtonPalette.buttonBorder
178 property bool _isCapturing: _camera.captureVideoState === MavlinkCameraControlInterface.CaptureVideoStateCapturing
183 onClicked: _camera.toggleVideoRecording()
188 Layout.alignment: Qt.AlignHCenter
190 font.pointSize: ScreenTools.smallFontPointSize
191 visible: videoCaptureButton.visible && photoCaptureButton.visible
196 Layout.alignment: Qt.AlignHCenter
197 color: _videoCaptureIdle ? "transparent" : videoCaptureButtonPalette.videoCaptureButtonColor
198 Layout.preferredWidth: videoRecordTime.width + (_smallMargins * 2)
199 Layout.preferredHeight: videoRecordTime.height
200 radius: _smallMargins
201 visible: videoCaptureButton.visible
206 anchors.leftMargin: _smallMargins
207 anchors.left: parent.left
208 anchors.top: parent.top
209 text: _videoCaptureIdle ? "00:00:00" : _camera.recordTimeStr
214 Layout.alignment: Qt.AlignHCenter
217 visible: videoCaptureButton.visible && photoCaptureButton.visible
222 id: photoCaptureButton
223 objectName: "photoVideoControl_photoCaptureButton"
224 Layout.alignment: Qt.AlignHCenter
225 color: photoCaptureButtonPalette.button
226 width: ScreenTools.defaultFontPixelWidth * 6
230 border.color: photoCaptureButtonPalette.buttonBorder
231 visible: (_camera.hasModes && _cameraInPhotoMode) || (!_camera.hasModes && (_camera.hasVideoStream || _camera.capturesPhotos))
232 enabled: _camera.capturePhotosState !== MavlinkCameraControlInterface.CapturePhotosStateDisabled
234 QGCPalette { id: photoCaptureButtonPalette; colorGroupEnabled: photoCaptureButton.enabled }
237 anchors.centerIn: parent
238 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
239 color: photoCaptureButtonPalette.buttonBorder
240 width: parent.width * 0.75
246 anchors.centerIn: parent
247 anchors.alignWhenCentered: false // Prevents anchors.centerIn from snapping to integer coordinates, which can throw off centering.
248 width: parent.width * (_isCapturing ? 0.5 : 0.75)
250 radius: _isCapturing ? ScreenTools.defaultFontPixelWidth * 0.5 : width * 0.5
251 color: photoCaptureButtonPalette.photoCaptureButtonColor
253 border.color: photoCaptureButtonPalette.buttonBorder
255 property bool _isCapturing: _camera.capturePhotosState === MavlinkCameraControlInterface.CapturePhotosStateCapturingSinglePhoto ||
256 _camera.capturePhotosState === MavlinkCameraControlInterface.CapturePhotosStateCapturingMultiplePhotos
262 if (_camera.capturePhotosState === MavlinkCameraControlInterface.CapturePhotosStateCapturingMultiplePhotos) {
263 _camera.stopTakePhoto()
264 } else if (_camera.capturePhotosState === MavlinkCameraControlInterface.CapturePhotosStateIdle) {
272 Layout.alignment: Qt.AlignHCenter
274 font.pointSize: ScreenTools.smallFontPointSize
275 visible: videoCaptureButton.visible && photoCaptureButton.visible
280 Layout.alignment: Qt.AlignHCenter
281 color: _photoCaptureIdle ? "transparent" : photoCaptureButtonPalette.photoCaptureButtonColor
282 Layout.preferredWidth: photoCaptureCount.width + (_smallMargins * 2)
283 Layout.preferredHeight: photoCaptureCount.height
284 radius: _smallMargins
285 visible: photoCaptureButton.visible
287 // Photo capture count
289 id: photoCaptureCount
290 anchors.leftMargin: _smallMargins
291 anchors.left: parent.left
292 anchors.top: parent.top
293 text: _activeVehicle ? ('00000' + _activeVehicle.cameraTriggerPoints.count).slice(-5) : "00000"
298 //-- Status Information
300 Layout.alignment: Qt.AlignHCenter
302 visible: storageStatus.visible || batteryStatus.visible
306 Layout.alignment: Qt.AlignHCenter
307 text: qsTr("Free: ") + _camera.storageFreeStr
308 font.pointSize: ScreenTools.defaultFontPointSize
309 visible: _camera.storageStatus === MavlinkCameraControlInterface.STORAGE_READY
314 Layout.alignment: Qt.AlignHCenter
315 text: qsTr("Battery: ") + _camera.batteryRemainingStr
316 font.pointSize: ScreenTools.defaultFontPointSize
317 visible: _camera.batteryRemaining >= 0
323 Layout.alignment: Qt.AlignHCenter
325 visible: _camera.hasTracking
328 Layout.alignment: Qt.AlignHCenter
329 color: _camera.trackingEnabled ? qgcPal.colorRed : qgcPal.windowShadeLight
330 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 6
331 Layout.preferredHeight: Layout.preferredWidth
332 border.color: qgcPal.buttonText
336 height: parent.height * 0.5
338 anchors.centerIn: parent
339 source: "/qmlimages/TrackingIcon.svg"
340 fillMode: Image.PreserveAspectFit
341 sourceSize.height: height
347 _camera.trackingEnabled = !_camera.trackingEnabled;
348 if (!_camera.trackingEnabled) {
349 _camera.stopTracking()
357 Layout.alignment: Qt.AlignHCenter
358 text: qsTr("Camera Tracking")
359 font.pointSize: ScreenTools.smallFontPointSize
364 Layout.alignment: Qt.AlignHCenter
365 source: "/res/gear-black.svg"
367 Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
368 Layout.preferredWidth: Layout.preferredHeight
369 sourceSize.height: Layout.preferredHeight
371 fillMode: Image.PreserveAspectFit
375 onClicked: settingsDialogFactory.open()
380 QGCPopupDialogFactory {
381 id: settingsDialogFactory
383 dialogComponent: settingsDialogComponent
387 id: settingsDialogComponent
390 title: qsTr("Settings")
391 buttons: Dialog.Close
393 property bool _multipleMavlinkCameras: _cameraManager.cameras.count > 1
394 property bool _multipleMavlinkCameraStreams: _camera.streamLabels.length > 1
395 property bool _cameraStorageSupported: _camera.storageStatus !== MavlinkCameraControlInterface.STORAGE_NOT_SUPPORTED
396 property var _videoSettings: QGroundControl.settingsManager.videoSettings
403 flow: GridLayout.TopToBottom
404 rows: dynamicRows + _camera.activeSettings.length
406 property int dynamicRows: 10
411 visible: _multipleMavlinkCameras
412 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
416 text: qsTr("Video Stream")
417 visible: _multipleMavlinkCameraStreams
418 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
422 text: qsTr("Thermal View Mode")
423 visible: _camera.thermalStreamInstance
424 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
428 text: qsTr("Blend Opacity")
429 visible: _camera.thermalStreamInstance && _camera.thermalMode === MavlinkCameraControlInterface.THERMAL_BLEND
430 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
433 // Mavlink Camera Protocol active settings
435 model: _camera.activeSettings
438 text: _camera.getFact(modelData).shortDescription
443 text: qsTr("Photo Mode")
444 visible: _camera.capturesPhotos
445 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
449 text: qsTr("Photo Interval (seconds)")
450 visible: _camera.capturesPhotos && _camera.photoCaptureMode === MavlinkCameraControlInterface.PHOTO_CAPTURE_TIMELAPSE
451 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
455 text: qsTr("Video Grid Lines")
456 visible: _camera.hasVideoStream
457 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
461 text: qsTr("Video Screen Fit")
462 visible: _camera.hasVideoStream
463 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
467 text: qsTr("Reset Camera Defaults")
468 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
472 text: qsTr("Storage")
473 visible: _cameraStorageSupported
474 onVisibleChanged: gridLayout.dynamicRows += visible ? 1 : -1
479 Layout.fillWidth: true
481 model: _cameraManager.cameraLabels
482 currentIndex: _cameraManager.currentCamera
483 visible: _multipleMavlinkCameras
484 onActivated: (index) => { _cameraManager.currentCamera = index }
488 Layout.fillWidth: true
490 model: _camera.streamLabels
491 currentIndex: _camera.currentStream
492 visible: _multipleMavlinkCameraStreams
493 onActivated: (index) => { _camera.currentStream = index }
497 Layout.fillWidth: true
499 model: [ qsTr("Off"), qsTr("Blend"), qsTr("Full"), qsTr("Picture In Picture") ]
500 currentIndex: _camera.thermalMode
501 visible: _camera.thermalStreamInstance
502 onActivated: (index) => { _camera.thermalMode = index }
506 Layout.fillWidth: true
509 value: _camera.thermalOpacity
511 visible: _camera.thermalStreamInstance && _camera.thermalMode === MavlinkCameraControlInterface.THERMAL_BLEND
512 onValueChanged: _camera.thermalOpacity = value
515 // Mavlink Camera Protocol active settings
517 model: _camera.activeSettings
520 Layout.fillWidth: true
521 spacing: ScreenTools.defaultFontPixelWidth
523 property var _fact: _camera.getFact(modelData)
524 property bool _isBool: _fact.typeIsBool
525 property bool _isCombo: !_isBool && _fact.enumStrings.length > 0
526 property bool _isSlider: _fact && !isNaN(_fact.increment)
527 property bool _isEdit: !_isBool && !_isSlider && _fact.enumStrings.length < 1
528 property bool _isReadOnly: _fact && _fact.readOnly
531 Layout.fillWidth: true
535 visible: parent._isCombo
536 enabled: !parent._isReadOnly
539 Layout.fillWidth: true
541 visible: parent._isEdit
542 enabled: !parent._isReadOnly
545 Layout.fillWidth: true
547 from: parent._fact.min
548 stepSize: parent._fact.increment
549 visible: parent._isSlider
550 enabled: !parent._isReadOnly
552 property bool initialized: false
558 parent._fact.value = value
561 Component.onCompleted: {
562 value = parent._fact.value
567 checked: parent._fact ? parent._fact.value : false
568 visible: parent._isBool
569 enabled: !parent._isReadOnly
570 onClicked: parent._fact.value = checked ? 1 : 0
576 Layout.fillWidth: true
578 model: [ qsTr("Single"), qsTr("Time Lapse") ]
579 currentIndex: _camera.photoCaptureMode
580 visible: _camera.capturesPhotos
581 onActivated: (index) => { _camera.photoCaptureMode = index }
585 Layout.fillWidth: true
589 value: _camera.photoLapse
592 visible: _camera.capturesPhotos && _camera.photoCaptureMode === MavlinkCameraControlInterface.PHOTO_CAPTURE_TIMELAPSE
593 onValueChanged: _camera.photoLapse = value
597 checked: _videoSettings.gridLines.rawValue
598 visible: _camera.hasVideoStream
599 onClicked: _videoSettings.gridLines.rawValue = checked ? 1 : 0
603 Layout.fillWidth: true
605 fact: _videoSettings.videoFit
607 visible: _camera.hasVideoStream
611 Layout.fillWidth: true
613 onClicked: resetPrompt.open()
616 title: qsTr("Reset Camera to Factory Settings")
617 text: qsTr("Confirm resetting all settings?")
618 buttons: MessageDialog.Yes | MessageDialog.No
620 onButtonClicked: function (button, role) {
622 case MessageDialog.Yes:
623 _camera.resetSettings()
626 case MessageDialog.No:
635 Layout.fillWidth: true
637 visible: _cameraStorageSupported
638 onClicked: formatPrompt.open()
641 title: qsTr("Format Camera Storage")
642 text: qsTr("Confirm erasing all files?")
643 buttons: MessageDialog.Yes | MessageDialog.No
645 onButtonClicked: function (button, role) {
647 case MessageDialog.Yes:
651 case MessageDialog.No: