Convert TextSwitch to a platform specific component and rename it to CameraTextSwitch
[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     }
70
71     CaptureControl {
72         id: captureControl
73         capturePressed: capture.pressed
74         zoomPressed: zoomCapture.zoomPressed
75         proximityClosed: proximitySensor.close
76         onStartCapture: overlay.toggleRecording()
77     }
78
79     CaptureCancel {
80         anchors.fill: parent
81         enabled: captureControl.showCancelBanner
82         onPressed: captureControl.canceled = true
83     }
84
85     CaptureButton {
86         id: capture
87         anchors.right: parent.right
88         anchors.rightMargin: 20
89         anchors.verticalCenter: parent.verticalCenter
90         iconSource: overlay.recording ? cameraTheme.captureButtonRecordingIconId : cameraTheme.captureButtonVideoIconId
91         width: 75
92         height: 75
93         opacity: 0.5
94
95         visible: controlsVisible
96
97         onExited: {
98             if (mouseX <= 0 || mouseY <= 0 || mouseX > width || mouseY > height) {
99                 // Release outside the button:
100                 captureControl.canceled = true
101             }
102         }
103     }
104
105     CameraToolBar {
106         id: toolBar
107         anchors.bottom: parent.bottom
108         anchors.bottomMargin: 20
109         anchors.left: parent.left
110         anchors.leftMargin: 20
111         opacity: 0.5
112         targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5)
113         visible: controlsVisible
114         expanded: settings.showToolBar
115         onExpandedChanged: settings.showToolBar = expanded;
116
117         tools: CameraToolBarTools {
118             VideoTorchButton {
119                 camera: cam
120                 visible: !overlay.cam.quirks.hasQuirk(Quirks.NoVideoTorch)
121             }
122
123             VideoSceneButton {
124                 property bool hide: (overlay.recording && overlay.cam.quirks.hasQuirk(Quirks.NoSceneModeChangeDuringRecording)) || overlay.cam.quirks.hasQuirk(Quirks.NoNightSceneMode)
125                 visible: !hide
126                 onClicked: toolBar.push(tools)
127             }
128
129             VideoEvCompButton {
130                 onClicked: toolBar.push(tools)
131             }
132
133             VideoWhiteBalanceButton {
134                 onClicked: toolBar.push(tools)
135             }
136
137             VideoColorFilterButton {
138                 onClicked: toolBar.push(tools)
139             }
140
141             VideoMuteButton {
142             }
143         }
144     }
145
146     Rectangle {
147         anchors.top: parent.top
148         anchors.topMargin: 20
149         anchors.left: parent.left
150         anchors.leftMargin: 20
151         width: 48
152         height: col.height
153         color: "black"
154         border.color: "gray"
155         radius: 20
156         opacity: 0.5
157         visible: controlsVisible
158
159         Column {
160             id: col
161             width: parent.width
162             spacing: 5
163
164             Indicator {
165                 id: resolutionIndicator
166                 source: cameraTheme.videoIcon(settings.videoAspectRatio,
167                     settings.videoResolution, settings.device)
168             }
169
170             Indicator {
171                 id: wbIndicator
172                 source: visible ? cameraTheme.whiteBalanceIcon(settings.videoWhiteBalance) : ""
173                 visible: settings.videoWhiteBalance != WhiteBalance.Auto && !toolBar.expanded
174             }
175
176             Indicator {
177                 id: cfIndicator
178                 source: visible ? cameraTheme.colorFilterIcon(settings.videoColorFilter) : ""
179                 visible: settings.videoColorFilter != ColorTone.Normal && !toolBar.expanded
180             }
181
182             Indicator {
183                 id: sceneIndicator
184                 visible: settings.videoSceneMode != Scene.Auto && (!toolBar.expanded || overlay.recording)
185                 source: visible ? cameraTheme.videoSceneModeIcon(settings.videoSceneMode) : ""
186             }
187
188             Indicator {
189                 id: gpsIndicator
190                 visible: settings.useGps
191                 source: cameraTheme.gpsIndicatorIcon
192
193                 PropertyAnimation on opacity  {
194                     easing.type: Easing.OutSine
195                     loops: Animation.Infinite
196                     from: 0.2
197                     to: 1.0
198                     duration: 1000
199                     running: settings.useGps && !positionSource.position.longitudeValid
200                     alwaysRunToEnd: true
201                 }
202             }
203         }
204     }
205
206     DisplayState {
207         inhibitDim: overlay.recording
208     }
209
210     Connections {
211         target: Qt.application
212         onActiveChanged: {
213             if (!Qt.application.active && overlay.recording) {
214                 overlay.stopRecording()
215             }
216         }
217     }
218
219     Timer {
220         id: recordingDuration
221         property int duration: 0
222         running: overlay.recording
223         interval: 1000
224         repeat: true
225
226         onTriggered: {
227             duration = duration + 1
228
229             if (duration == 3600) {
230                 overlay.stopRecording()
231                 showError(qsTr("Maximum recording time reached."))
232             } else if (!fileSystem.hasFreeSpace(fileNaming.temporaryVideoPath)) {
233                 page.stopRecording()
234                 showError(qsTr("Not enough space to continue recording."))
235             }
236
237         }
238     }
239
240     RecordingDurationLabel {
241         visible: overlay.recording
242         duration: recordingDuration.duration
243     }
244
245     function resetToolBar() {
246         if (toolBar.depth() > 1) {
247             toolBar.pop()
248         }
249     }
250
251     function doStartRecording() {
252         if (!overlay.recording) {
253             return
254         }
255
256         if (!pipelineManager.acquired || pipelineManager.hijacked) {
257             showError(qsTr("Failed to acquire needed resources."))
258             overlay.recording = false
259             return
260         }
261
262         metaData.setMetaData()
263
264         if (!mountProtector.lock(fileNaming.temporaryVideoPath)) {
265             showError(qsTr("Failed to lock temporary videos directory."))
266             overlay.recording = false
267             return
268         }
269
270         if (!mountProtector.lock(fileNaming.videoPath)) {
271             showError(qsTr("Failed to lock videos directory."))
272             overlay.recording = false
273             mountProtector.unlockAll()
274             return
275         }
276
277         var file = fileNaming.videoFileName()
278         var tmpFile = fileNaming.temporaryVideoFileName()
279
280         if (!videoMode.startRecording(file, tmpFile)) {
281             showError(qsTr("Failed to record video. Please restart the camera."))
282             mountProtector.unlockAll()
283             overlay.recording = false
284             return
285         }
286
287         trackerStore.storeVideo(file);
288
289         resetToolBar()
290     }
291
292     function startRecording() {
293         if (!fileSystem.available) {
294             showError(qsTr("Camera cannot record videos in mass storage mode."))
295         } else if (!checkBattery()) {
296             showError(qsTr("Not enough battery to record video."))
297         } else if (!fileSystem.hasFreeSpace(fileNaming.videoPath) || !fileSystem.hasFreeSpace(fileNaming.temporaryVideoPath)) {
298             showError(qsTr("Not enough space to record video."))
299         } else {
300             recordingDuration.duration = 0
301             overlay.recording = true
302             doStartRecording()
303         }
304     }
305
306     function stopRecording() {
307         videoMode.stopRecording(true)
308         mountProtector.unlockAll()
309         overlay.recording = false
310     }
311
312     function toggleRecording() {
313         if (overlay.recording) {
314             overlay.stopRecording()
315         } else {
316             overlay.startRecording()
317         }
318     }
319
320     function cameraError() {
321         overlay.stopRecording()
322     }
323
324     function policyLost() {
325         overlay.stopRecording()
326     }
327
328     function batteryLow() {
329         if (!overlay.recording) {
330             return
331         }
332
333         if (!checkBattery()) {
334             overlay.stopRecording()
335             showError(qsTr("Not enough battery to record video."))
336         }
337     }
338
339     function cameraDeviceChanged() {
340         resetToolBar()
341     }
342 }