Initial ui reimplementation. Still in its early phase.
[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 1.1
24 import com.nokia.meego 1.1
25 import QtCamera 1.0
26 import CameraPlus 1.0
27 import "data.js" as Data
28
29 Item {
30     id: overlay
31     property bool recording: false
32
33     property Camera cam
34     property bool animationRunning: false
35     property int policyMode: recording == true ? CameraResources.Recording : CameraResources.Video
36     property bool controlsVisible: !animationRunning && cam.running && dimmer.opacity == 0.0
37         && !cameraMode.busy
38 // TODO:
39     property bool pressed: overlay.recording || capture.pressed ||
40         zoomSlider.pressed || modeButton.pressed
41
42     signal previewAvailable(string uri)
43
44     anchors.fill: parent
45
46     VideoMode {
47         id: videoMode
48         camera: cam
49         onPreviewAvailable: overlay.previewAvailable(preview)
50     }
51
52     ZoomSlider {
53         id: zoomSlider
54         camera: cam
55         anchors.top: parent.top
56         anchors.topMargin: 0
57         anchors.horizontalCenter: parent.horizontalCenter
58         visible: controlsVisible
59     }
60
61     ModeButton {
62         id: modeButton
63         anchors.bottom: parent.bottom
64         anchors.right: parent.right
65         anchors.rightMargin: 20
66         anchors.bottomMargin: 20
67         visible: controlsVisible && !overlay.recording
68     }
69
70     ZoomCaptureButton {
71         id: zoomCapture
72         onReleased: overlay.toggleRecording()
73     }
74
75     ZoomCaptureCancel {
76         anchors.fill: parent
77         zoomCapture: zoomCapture
78     }
79
80     CaptureButton {
81         id: capture
82         anchors.right: parent.right
83         anchors.rightMargin: 20
84         anchors.verticalCenter: parent.verticalCenter
85         iconSource: overlay.recording ? "image://theme/icon-m-camera-video-record" : "image://theme/icon-m-camera-video-record"
86         width: 75
87         height: 75
88         opacity: 0.5
89
90         onClicked: overlay.toggleRecording()
91
92         visible: controlsVisible && (!settings.zoomAsShutter && keys.active)
93     }
94
95     CameraToolBar {
96         id: toolBar
97         anchors.bottom: parent.bottom
98         anchors.bottomMargin: 20
99         anchors.left: parent.left
100         anchors.leftMargin: 20
101         opacity: 0.5
102         targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5)
103         visible: controlsVisible
104         expanded: settings.showToolBar
105         onExpandedChanged: settings.showToolBar = expanded;
106
107         items: [
108             VideoTorchButton {
109                 camera: cam
110             },
111             VideoSceneButton {
112 // TODO: hide when recording
113                 onClicked: toolBar.push(items)
114             },
115             VideoEvCompButton {
116                 onClicked: toolBar.push(items)
117             },
118             VideoWhiteBalanceButton {
119                 onClicked: toolBar.push(items)
120             },
121             VideoColorFilterButton {
122                 onClicked: toolBar.push(items)
123             },
124             VideoMuteButton {
125             }
126         ]
127     }
128
129     Rectangle {
130         anchors.top: parent.top
131         anchors.topMargin: 20
132         anchors.left: parent.left
133         anchors.leftMargin: 20
134         width: 48
135         height: col.height
136         color: "black"
137         border.color: "gray"
138         radius: 20
139         opacity: 0.5
140         visible: controlsVisible
141
142         Column {
143             id: col
144             width: parent.width
145             spacing: 5
146
147             Indicator {
148                 id: resolutionIndicator
149                 source: "image://theme/" + Data.videoIcon(settings.videoResolution)
150             }
151
152             Indicator {
153                 id: wbIndicator
154                 source: visible ? "image://theme/" + Data.wbIcon(settings.videoWhiteBalance) + "-screen" : ""
155                 visible: settings.videoWhiteBalance != WhiteBalance.Auto
156             }
157
158             Indicator {
159                 id: cfIndicator
160                 source: "image://theme/" + Data.cfIcon(settings.videoColorFilter) + "-screen"
161                 visible: settings.videoColorFilter != ColorTone.Normal
162             }
163
164             Indicator {
165                 id: gpsIndicator
166                 visible: settings.useGps
167                 source: "image://theme/icon-m-camera-location"
168
169                 PropertyAnimation on opacity  {
170                     easing.type: Easing.OutSine
171                     loops: Animation.Infinite
172                     from: 0.2
173                     to: 1.0
174                     duration: 1000
175                     running: settings.useGps && !positionSource.position.longitudeValid
176                     alwaysRunToEnd: true
177                 }
178             }
179         }
180     }
181
182     DisplayState {
183         inhibitDim: overlay.recording
184     }
185
186     Connections {
187         target: Qt.application
188         onActiveChanged: {
189             if (!Qt.application.active && overlay.recording) {
190                 overlay.stopRecording()
191             }
192         }
193     }
194
195     Timer {
196         id: recordingDuration
197         property int duration: 0
198         running: overlay.recording
199         interval: 1000
200         repeat: true
201
202         onTriggered: {
203             duration = duration + 1
204
205             if (duration == 3600) {
206                 overlay.stopRecording()
207                 showError(qsTr("Maximum recording time reached."))
208             } else if (!checkDiskSpace()) {
209                 page.stopRecording()
210                 showError(qsTr("Not enough space to continue recording."))
211             }
212
213         }
214     }
215
216     RecordingDurationLabel {
217         visible: overlay.recording
218         duration: recordingDuration.duration
219     }
220
221     function doStartRecording() {
222         if (!overlay.recording) {
223             return
224         }
225
226         if (!pipelineManager.acquired || pipelineManager.hijacked) {
227             showError(qsTr("Failed to acquire needed resources."))
228             overlay.recording = false
229             return
230         }
231
232         metaData.setMetaData()
233
234         if (!mountProtector.lock()) {
235             showError(qsTr("Failed to lock images directory."))
236             overlay.recording = false
237             return
238         }
239
240         var file = fileNaming.videoFileName()
241         var tmpFile = fileNaming.temporaryVideoFileName()
242
243         if (!videoMode.startRecording(file, tmpFile)) {
244             showError(qsTr("Failed to record video. Please restart the camera."))
245             mountProtector.unlock()
246             overlay.recording = false
247             return
248         }
249
250         trackerStore.storeVideo(file);
251     }
252
253     function startRecording() {
254         if (!fileSystem.available) {
255             showError(qsTr("Camera cannot record videos in mass storage mode."))
256         } else if (!checkBattery()) {
257             showError(qsTr("Not enough battery to record video."))
258         } else if (!checkDiskSpace()) {
259             showError(qsTr("Not enough space to record video."))
260         } else {
261             recordingDuration.duration = 0
262             overlay.recording = true
263             doStartRecording()
264         }
265     }
266
267     function stopRecording() {
268         videoMode.stopRecording(true)
269         mountProtector.unlock()
270         overlay.recording = false
271     }
272
273     function toggleRecording() {
274         if (overlay.recording) {
275             overlay.stopRecording()
276         } else {
277             overlay.startRecording()
278         }
279     }
280
281     function cameraError() {
282         overlay.stopRecording()
283     }
284
285     function policyLost() {
286         overlay.stopRecording()
287     }
288
289     function batteryLow() {
290         if (!overlay.recording) {
291             return
292         }
293
294         if (!checkBattery()) {
295             overlay.stopRecording()
296             showError(qsTr("Not enough battery to record video."))
297         }
298     }
299
300 }