Create a QDeclarativeItem Viewfinder subclass
[harmattan/cameraplus] / qml / CameraView.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 // TODO: reset reticle and roi when we stop camera or change mode
28 Camera {
29     id: cam
30
31     property bool pressed: focusReticle.locked || (loader.item ? loader.item.pressed : false)
32     property int policyMode: loader.item ? loader.item.policyMode : CameraResources.None
33
34     Viewfinder {
35         id: viewfinder
36         width: cam.width
37         height: cam.height
38         x: 0
39         y: 0
40
41         camera: cam
42         cameraConfig: cam.cameraConfig
43
44         renderingEnabled: mainView.currentItem == cam
45
46         GridLines {
47             x: viewfinder.renderArea.x
48             y: viewfinder.renderArea.y
49             width: viewfinder.renderArea.width
50             height: viewfinder.renderArea.height
51             visible: settings.gridEnabled
52         }
53     }
54
55     function policyLost() {
56         if (loader.item) {
57             loader.item.policyLost()
58         }
59     }
60
61     function checkBattery() {
62         // We are fine if we are connected to the charger:
63         if (batteryMonitor.charging) {
64             return true
65         }
66
67         // If we have enough battery then we are fine:
68         if (!batteryMonitor.critical) {
69             return true
70         }
71
72         return false
73     }
74
75     Component.onDestruction: cam.stop()
76
77     onRunningChanged: {
78         if (!cam.running) {
79             mountProtector.unlock()
80         }
81     }
82
83     SoundVolumeControl {
84         id: volumeControl
85     }
86
87     sounds: Sounds {
88         id: sounds
89         mute: !settings.soundEnabled
90         volume: volumeControl.fullVolume ? Sounds.VolumeHigh : Sounds.VolumeLow
91         imageCaptureStart: platformSettings.imageCaptureStartedSound
92         imageCaptureEnd: platformSettings.imageCaptureEndedSound
93         videoRecordingStart: platformSettings.videoRecordingStartedSound
94         videoRecordingEnd: platformSettings.videoRecordingEndedSound
95         autoFocusAcquired: platformSettings.autoFocusAcquiredSound
96     }
97
98     BatteryInfo {
99         id: batteryMonitor
100         active: cam.running
101
102         function check() {
103             if (!checkBattery()) {
104                 loader.item.batteryLow()
105             }
106         }
107
108         onChargingChanged: {
109             batteryMonitor.check()
110         }
111
112         onCriticalChanged: {
113             batteryMonitor.check()
114         }
115     }
116
117     PreviewImage {
118         id: preview
119     }
120
121     Connections {
122         target: loader.item
123         onPreviewAvailable: preview.setPreview(uri)
124     }
125
126     Binding {
127         target: loader.item
128         property: "cam"
129         value: cam
130         when: loader.item != null
131     }
132
133     Binding {
134         target: loader.item
135         property: "animationRunning"
136         value: preview.animationRunning
137         when: loader.item != null
138     }
139
140     onRoiChanged: roi.normalize = false
141
142     FocusReticle {
143         id: focusReticle
144         cam: cam
145         videoResolution: viewfinder.videoResolution
146         renderArea: viewfinder.renderArea
147
148         visible: loader.item != null && loader.item.controlsVisible &&
149             cam.autoFocus.canFocus(cam.scene.value)
150         cafStatus: cam ? cam.autoFocus.cafStatus : -1
151         status: cam ? cam.autoFocus.status : -1
152     }
153
154     Loader {
155         id: loader
156         property string src: mode == Camera.VideoMode ? "VideoOverlay.qml" : "ImageOverlay.qml"
157         anchors.fill: parent
158         source: Qt.resolvedUrl(src)
159     }
160
161     Binding {
162         target: cam.flash
163         property: "value"
164         when: cam.mode == Camera.ImageMode
165         value: settings.imageFlashMode
166     }
167
168     Binding {
169         target: settings
170         property: "imageFlashMode"
171         when: cam.mode == Camera.ImageMode
172         value: cam.flash.value
173     }
174
175     Binding {
176         target: cam.scene
177         property: "value"
178         when: cam.mode == Camera.VideoMode
179         value: settings.videoSceneMode
180     }
181
182     Binding {
183         target: cam.scene
184         property: "value"
185         when: cam.mode == Camera.ImageMode
186         value: settings.imageSceneMode
187     }
188
189     Binding {
190         target: cam.evComp
191         property: "value"
192         when: cam.mode == Camera.ImageMode
193         value: settings.imageEvComp
194     }
195
196     Binding {
197         target: cam.evComp
198         property: "value"
199         when: cam.mode == Camera.VideoMode
200         value: settings.videoEvComp
201     }
202
203     Binding {
204         target: settings
205         property: "imageEvComp"
206         when: cam.mode == Camera.ImageMode
207         value: cam.evComp.value
208     }
209
210     Binding {
211         target: settings
212         property: "videoEvComp"
213         when: cam.mode == Camera.VideoMode
214         value: cam.evComp.value
215     }
216
217     Binding {
218         target: cam.whiteBalance
219         property: "value"
220         when: cam.mode == Camera.ImageMode
221         value: settings.imageWhiteBalance
222     }
223
224     Binding {
225         target: cam.whiteBalance
226         property: "value"
227         when: cam.mode == Camera.VideoMode
228         value: settings.videoWhiteBalance
229     }
230
231     Binding {
232         target: cam.colorTone
233         property: "value"
234         when: cam.mode == Camera.ImageMode
235         value: settings.imageColorFilter
236     }
237
238     Binding {
239         target: cam.colorTone
240         property: "value"
241         when: cam.mode == Camera.VideoMode
242         value: settings.videoColorFilter
243     }
244
245     Binding {
246         target: cam.iso
247         property: "value"
248         when: cam.mode == Camera.ImageMode
249         value: settings.imageIso
250     }
251
252     Binding {
253         target: settings
254         property: "imageIso"
255         when: cam.mode == Camera.ImageMode
256         value: cam.iso.value
257     }
258
259     Binding {
260         target: cam.videoMute
261         property: "enabled"
262         value: settings.videoMuted
263     }
264
265     Binding {
266         target: cam.roi
267         property: "enabled"
268         value: settings.faceDetectionEnabled && !focusReticle.pressed && !focusReticle.touchMode && cam.mode == Camera.ImageMode
269     }
270
271     onError: {
272         if (pipelineManager.error) {
273             // Ignore any subsequent errors.
274             // Killing pulseaudio while recording will lead to an
275             // infinite supply of errors which will break the UI
276             // if we show a banner for each.
277             return
278         }
279
280         pipelineManager.error = true
281         if (loader.item) {
282             loader.item.cameraError()
283         }
284
285         console.log("Camera error (" + code + "): " + message + " " + debug)
286         showError(qsTr("Camera error. Please restart the application."))
287         // We cannot stop camera here. Seems there is a race condition somewhere
288         // which leads to a freeze if we do so.
289     }
290
291 }