185d0791d8086e1992ab720b63710d050cd2d246
[harmattan/cameraplus] / qml / VideoOverlay.qml
1 // -*- qml -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 import QtQuick 2.0
24 import QtCamera 1.0
25 import CameraPlus 1.0
26
27 Item {
28     id: overlay
29     property bool recording: false
30
31     property Camera cam
32     property bool animationRunning: false
33     property int policyMode: recording == true ? CameraResources.Recording : CameraResources.Video
34     property bool controlsVisible: !animationRunning && cam != null && cam.running
35         && dimmer.opacity == 0.0 && !cameraMode.busy
36     property bool pressed: overlay.recording || capture.pressed ||
37         zoomSlider.pressed || modeButton.pressed
38
39     signal previewAvailable(string uri)
40
41     anchors.fill: parent
42
43     VideoMode {
44         id: videoMode
45         camera: cam
46         onPreviewAvailable: overlay.previewAvailable(preview)
47     }
48
49     ZoomSlider {
50         id: zoomSlider
51         camera: cam
52         anchors.top: parent.top
53         anchors.topMargin: 0
54         anchors.horizontalCenter: parent.horizontalCenter
55         visible: controlsVisible
56     }
57
58     ModeButton {
59         id: modeButton
60         anchors.bottom: parent.bottom
61         anchors.right: parent.right
62         anchors.rightMargin: 20
63         anchors.bottomMargin: 20
64         visible: controlsVisible && !overlay.recording
65     }
66
67     ZoomCaptureButton {
68         id: zoomCapture
69         onReleased: overlay.toggleRecording()
70     }
71
72     ZoomCaptureCancel {
73         anchors.fill: parent
74         zoomCapture: zoomCapture
75     }
76
77     CaptureButton {
78         id: capture
79         anchors.right: parent.right
80         anchors.rightMargin: 20
81         anchors.verticalCenter: parent.verticalCenter
82         iconSource: overlay.recording ? cameraTheme.captureButtonRecordingIconId : cameraTheme.captureButtonVideoIconId
83         width: 75
84         height: 75
85         opacity: 0.5
86
87         onClicked: overlay.toggleRecording()
88
89         visible: controlsVisible && (!settings.zoomAsShutter && keys.active)
90     }
91
92     CameraToolBar {
93         id: toolBar
94         anchors.bottom: parent.bottom
95         anchors.bottomMargin: 20
96         anchors.left: parent.left
97         anchors.leftMargin: 20
98         opacity: 0.5
99         targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5)
100         visible: controlsVisible
101         expanded: settings.showToolBar
102         onExpandedChanged: settings.showToolBar = expanded;
103
104         tools: CameraToolBarTools {
105             VideoTorchButton {
106                 camera: cam
107             }
108
109             VideoSceneButton {
110                 visible: !overlay.recording
111                 onClicked: toolBar.push(tools)
112             }
113
114             VideoEvCompButton {
115                 onClicked: toolBar.push(tools)
116             }
117
118             VideoWhiteBalanceButton {
119                 onClicked: toolBar.push(tools)
120             }
121
122             VideoColorFilterButton {
123                 onClicked: toolBar.push(tools)
124             }
125
126             VideoMuteButton {
127             }
128         }
129     }
130
131     Rectangle {
132         anchors.top: parent.top
133         anchors.topMargin: 20
134         anchors.left: parent.left
135         anchors.leftMargin: 20
136         width: 48
137         height: col.height
138         color: "black"
139         border.color: "gray"
140         radius: 20
141         opacity: 0.5
142         visible: controlsVisible
143
144         Column {
145             id: col
146             width: parent.width
147             spacing: 5
148
149             Indicator {
150                 id: resolutionIndicator
151                 property string videoResolution: settings.device == 1 ? settings.secondaryVideoResolution : settings.primaryVideoResolution
152                 property string videoRatio: settings.device == 1 ? settings.secondaryVideoAspectRatio : settings.primaryVideoAspectRatio
153                 source: cameraTheme.videoIcon(videoRatio, videoResolution, settings.device)
154             }
155
156             Indicator {
157                 id: wbIndicator
158                 source: visible ? cameraTheme.whiteBalanceIcon(settings.videoWhiteBalance) : ""
159                 visible: settings.videoWhiteBalance != WhiteBalance.Auto && !toolBar.expanded
160             }
161
162             Indicator {
163                 id: cfIndicator
164                 source: visible ? cameraTheme.colorFilterIcon(settings.videoColorFilter) : ""
165                 visible: settings.videoColorFilter != ColorTone.Normal && !toolBar.expanded
166             }
167
168             Indicator {
169                 id: sceneIndicator
170                 visible: settings.videoSceneMode != Scene.Auto && (!toolBar.expanded || overlay.recording)
171                 source: visible ? cameraTheme.videoSceneModeIcon(settings.videoSceneMode) : ""
172             }
173
174             Indicator {
175                 id: gpsIndicator
176                 visible: settings.useGps
177                 source: cameraTheme.gpsIndicatorIcon
178
179                 PropertyAnimation on opacity  {
180                     easing.type: Easing.OutSine
181                     loops: Animation.Infinite
182                     from: 0.2
183                     to: 1.0
184                     duration: 1000
185                     running: settings.useGps && !positionSource.position.longitudeValid
186                     alwaysRunToEnd: true
187                 }
188             }
189         }
190     }
191
192     DisplayState {
193         inhibitDim: overlay.recording
194     }
195
196     Connections {
197         target: Qt.application
198         onActiveChanged: {
199             if (!Qt.application.active && overlay.recording) {
200                 overlay.stopRecording()
201             }
202         }
203     }
204
205     Timer {
206         id: recordingDuration
207         property int duration: 0
208         running: overlay.recording
209         interval: 1000
210         repeat: true
211
212         onTriggered: {
213             duration = duration + 1
214
215             if (duration == 3600) {
216                 overlay.stopRecording()
217                 showError(qsTr("Maximum recording time reached."))
218             } else if (!fileSystem.hasFreeSpace(fileNaming.temporaryVideoPath)) {
219                 page.stopRecording()
220                 showError(qsTr("Not enough space to continue recording."))
221             }
222
223         }
224     }
225
226     RecordingDurationLabel {
227         visible: overlay.recording
228         duration: recordingDuration.duration
229     }
230
231     function doStartRecording() {
232         if (!overlay.recording) {
233             return
234         }
235
236         if (!pipelineManager.acquired || pipelineManager.hijacked) {
237             showError(qsTr("Failed to acquire needed resources."))
238             overlay.recording = false
239             return
240         }
241
242         metaData.setMetaData()
243
244         if (!mountProtector.lock(fileNaming.temporaryVideoPath)) {
245             showError(qsTr("Failed to lock temporary videos directory."))
246             overlay.recording = false
247             return
248         }
249
250         if (!mountProtector.lock(fileNaming.videoPath)) {
251             showError(qsTr("Failed to lock videos directory."))
252             overlay.recording = false
253             mountProtector.unlockAll()
254             return
255         }
256
257         var file = fileNaming.videoFileName()
258         var tmpFile = fileNaming.temporaryVideoFileName()
259
260         if (!videoMode.startRecording(file, tmpFile)) {
261             showError(qsTr("Failed to record video. Please restart the camera."))
262             mountProtector.unlockAll()
263             overlay.recording = false
264             return
265         }
266
267         trackerStore.storeVideo(file);
268
269         if (toolBar.depth() > 1) {
270             toolBar.pop()
271         }
272     }
273
274     function startRecording() {
275         if (!fileSystem.available) {
276             showError(qsTr("Camera cannot record videos in mass storage mode."))
277         } else if (!checkBattery()) {
278             showError(qsTr("Not enough battery to record video."))
279         } else if (!fileSystem.hasFreeSpace(fileNaming.videoPath) || !fileSystem.hasFreeSpace(fileNaming.temporaryVideoPath)) {
280             showError(qsTr("Not enough space to record video."))
281         } else {
282             recordingDuration.duration = 0
283             overlay.recording = true
284             doStartRecording()
285         }
286     }
287
288     function stopRecording() {
289         videoMode.stopRecording(true)
290         mountProtector.unlockAll()
291         overlay.recording = false
292     }
293
294     function toggleRecording() {
295         if (overlay.recording) {
296             overlay.stopRecording()
297         } else {
298             overlay.startRecording()
299         }
300     }
301
302     function cameraError() {
303         overlay.stopRecording()
304     }
305
306     function policyLost() {
307         overlay.stopRecording()
308     }
309
310     function batteryLow() {
311         if (!overlay.recording) {
312             return
313         }
314
315         if (!checkBattery()) {
316             overlay.stopRecording()
317             showError(qsTr("Not enough battery to record video."))
318         }
319     }
320
321 }