Added repeat property to DeviceKeys
[harmattan/cameraplus] / qml / main.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 com.nokia.extras 1.1
26 import QtCamera 1.0
27 import CameraPlus 1.0
28 import QtMobility.location 1.2
29
30 // TODO: flash not ready (battery low or flash not ready message)
31
32 PageStackWindow {
33         id: root
34
35         property alias dimmer: camDimmer
36
37         showStatusBar: false
38
39         Component.onCompleted: {
40                 theme.inverted = true;
41                 // TODO: hardcoding device id
42                 root.resetCamera(0, settings.mode);
43         }
44
45         function showError(msg) {
46                 error.text = msg;
47                 error.show();
48         }
49
50         function resetCamera(deviceId, mode) {
51                 if (!cam.reset(deviceId, mode)) {
52                         showError(qsTr("Failed to set camera device and mode. Please restart the application."));
53                 }
54         }
55
56         PositionSource {
57                 // NOTE: The source will not reset the position when we lose the signal.
58                 // This shouldn't be a big problem as we are course enough.
59                 // If we ever need street level updates then this will be an issue.
60                 id: positionSource
61                 active: settings.useGps
62                 // TODO: we cannot bind to cam.running because camera will stop
63                 // when the connection dialog pops up and we end up with an infinite loop
64                 // active: cam.running && settings.useGps
65                 onPositionChanged: geocode.search(position.coordinate.longitude, position.coordinate.latitude);
66         }
67
68         MetaData {
69                 id: metaData
70                 camera: cam
71                 manufacturer: deviceInfo.manufacturer
72                 model: deviceInfo.model
73                 country: geocode.country
74                 city: geocode.city
75                 suburb: geocode.suburb
76                 longitude: positionSource.position.coordinate.longitude
77                 longitudeValid: positionSource.position.longitudeValid && settings.useGps
78                 latitude: positionSource.position.coordinate.latitude
79                 latitudeValid: positionSource.position.latitudeValid && settings.useGps
80                 elevation: positionSource.position.coordinate.altitude
81                 elevationValid: positionSource.position.altitudeValid && settings.useGps
82                 orientation: orientation.orientation
83                 artist: settings.creatorName
84                 captureDirection: compass.direction
85                 captureDirectionValid: compass.directionValid
86                 horizontalError: positionSource.position.horizontalAccuracy
87                 horizontalErrorValid: positionSource.position.horizontalAccuracyValid && settings.useGps
88                 dateTimeEnabled: true
89         }
90
91         Orientation {
92                 id: orientation
93                 active: cam.running
94         }
95
96         Compass {
97                 id: compass
98                 active: cam.running
99         }
100
101         ReverseGeocode {
102                 id: geocode
103                 active: cam.running && settings.useGps && settings.useGeotags
104         }
105
106         PipelineManager {
107                 id: pipelineManager
108                 camera: cam
109         }
110
111         DeviceInfo {
112                 id: deviceInfo
113         }
114
115         FSMonitor {
116                 id: fileSystem
117         }
118
119         InfoBanner {
120                 id: error
121         }
122
123         Settings {
124                 id: settings
125         }
126
127         FileNaming {
128                 id: fileNaming
129                 imageSuffix: cam.imageSuffix
130                 videoSuffix: cam.videoSuffix
131         }
132
133         MountProtector {
134                 id: mountProtector
135                 path: fileNaming.path
136         }
137
138         BatteryInfo {
139                 id: batteryMonitor
140                 active: cam.running
141
142                 function check() {
143                         if (!checkBattery()) {
144                                 pageStack.currentPage.batteryLow();
145                         }
146                 }
147
148                 onChargingChanged: {
149                         batteryMonitor.check();
150                 }
151
152                 onCriticalChanged: {
153                         batteryMonitor.check();
154                 }
155         }
156
157         function replacePage(file) {
158                 pageStack.replace(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true);
159         }
160
161         function openFile(file) {
162                 pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer});
163         }
164
165         function openFileNow(file) {
166                 pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true);
167         }
168
169         function checkBattery() {
170                 // We are fine if we are connected to the charger:
171                 if (batteryMonitor.charging) {
172                         return true;
173                 }
174
175                 // If we have enough battery then we are fine:
176                 if (!batteryMonitor.critical) {
177                         return true;
178                 }
179
180                 return false;
181         }
182
183         platformStyle: PageStackWindowStyle {
184                 cornersVisible: false
185                 background: ""
186                 backgroundColor: "transparent"
187         }
188
189         ImageSettings {
190                 id: imageSettings
191                 camera: cam
192                 function setImageResolution() {
193                         if (!imageSettings.setResolution(settings.imageAspectRatio, settings.imageResolution)) {
194                                 showError(qsTr("Failed to set required resolution"));
195                         }
196                 }
197
198                 onReadyChanged: {
199                         if (ready) {
200                                 imageSettings.setImageResolution();
201                         }
202                 }
203         }
204
205         VideoSettings {
206                 id: videoSettings
207                 camera: cam
208
209                 function setVideoResolution() {
210                         if (!videoSettings.setResolution(settings.videoAspectRatio, settings.videoResolution)) {
211                                 showError(qsTr("Failed to set required resolution"));
212                         }
213                 }
214
215                 onReadyChanged: {
216                         if (ready) {
217                                 videoSettings.setVideoResolution();
218                         }
219                 }
220         }
221
222         Connections {
223                 target: settings
224
225                 onImageAspectRatioChanged: {
226                         imageSettings.setImageResolution();
227                 }
228
229                 onImageResolutionChanged: {
230                         imageSettings.setImageResolution();
231                 }
232
233                 onVideoResolutionChanged: {
234                         videoSettings.setVideoResolution();
235                 }
236         }
237
238         Camera {
239                 id: cam
240                 anchors.fill: parent
241
242                 onRoiChanged: roi.normalize = false;
243
244                 GridLines {
245                         x: cam.renderArea.x
246                         y: cam.renderArea.y
247                         width: cam.renderArea.width
248                         height: cam.renderArea.height
249                         visible: settings.gridEnabled
250                 }
251
252                 FocusReticle {
253                         id: focusReticle
254                         cam: cam
255                         visible: pageStack.currentPage && pageStack.currentPage.controlsVisible && pageStack.currentPage.focusReticleVisible && cam && cam.autoFocus.canFocus(cam.scene.value);
256                         cafStatus: cam ? cam.autoFocus.cafStatus : -1
257                         status: cam ? cam.autoFocus.status : -1
258                 }
259
260                 onError: {
261                         if (pipelineManager.error) {
262                                 // Ignore any subsequent errors.
263                                 // Killing pulseaudio while recording will lead to an
264                                 // infinite supply of errors which will break the UI
265                                 // if we show a banner for each.
266                                 return;
267                         }
268
269                         pipelineManager.error = true;
270                         pageStack.currentPage.cameraError();
271                         console.log("Camera error (" + code + "): " + message + " " + debug);
272                         showError(qsTr("Camera error. Please restart the application."));
273
274                         // We cannot stop camera here. Seems there is a race condition somewhere
275                         // which leads to a freeze if we do so.
276                 }
277
278                 onRunningChanged: {
279                         if (!cam.running) {
280                                 mountProtector.unlock();
281                         }
282                 }
283
284                 Component.onDestruction: cam.stop();
285
286                 // We need to show viewfinder below pages.
287                 z: -1
288
289                 Rectangle {
290                         property bool dimmed: false
291                         id: camDimmer
292                         z: 1
293                         anchors.fill: parent
294                         opacity: dimmed ? 1.0 : 0.0
295                         color: "black"
296                         Behavior on opacity {
297                                 PropertyAnimation { duration: 150 }
298                         }
299                 }
300
301                 notifications: Sounds {
302                         id: sounds
303                         mute: !settings.soundEnabled
304                 }
305
306         }
307
308         Binding {
309                 target: cam.flash
310                 property: "value"
311                 when: cam.mode == Camera.ImageMode
312                 value: settings.imageFlashMode
313         }
314
315         Binding {
316                 target: settings
317                 property: "imageFlashMode"
318                 when: cam.mode == Camera.ImageMode
319                 value: cam.flash.value
320         }
321
322         Binding {
323                 target: cam.scene
324                 property: "value"
325                 when: cam.mode == Camera.VideoMode
326                 value: settings.videoSceneMode
327         }
328
329         Binding {
330                 target: cam.scene
331                 property: "value"
332                 when: cam.mode == Camera.ImageMode
333                 value: settings.imageSceneMode
334         }
335
336         Binding {
337                 target: cam.evComp
338                 property: "value"
339                 when: cam.mode == Camera.ImageMode
340                 value: settings.imageEvComp
341         }
342
343         Binding {
344                 target: cam.evComp
345                 property: "value"
346                 when: cam.mode == Camera.VideoMode
347                 value: settings.videoEvComp
348         }
349
350         Binding {
351                 target: settings
352                 property: "imageEvComp"
353                 when: cam.mode == Camera.ImageMode
354                 value: cam.evComp.value
355         }
356
357         Binding {
358                 target: settings
359                 property: "videoEvComp"
360                 when: cam.mode == Camera.VideoMode
361                 value: cam.evComp.value
362         }
363
364         Binding {
365                 target: cam.whiteBalance
366                 property: "value"
367                 when: cam.mode == Camera.ImageMode
368                 value: settings.imageWhiteBalance
369         }
370
371         Binding {
372                 target: cam.whiteBalance
373                 property: "value"
374                 when: cam.mode == Camera.VideoMode
375                 value: settings.videoWhiteBalance
376         }
377
378         Binding {
379                 target: cam.colorTone
380                 property: "value"
381                 when: cam.mode == Camera.ImageMode
382                 value: settings.imageColorFilter
383         }
384
385         Binding {
386                 target: cam.colorTone
387                 property: "value"
388                 when: cam.mode == Camera.VideoMode
389                 value: settings.videoColorFilter
390         }
391
392         Binding {
393                 target: cam.iso
394                 property: "value"
395                 when: cam.mode == Camera.ImageMode
396                 value: settings.imageIso
397         }
398
399         Binding {
400                 target: settings
401                 property: "imageIso"
402                 when: cam.mode == Camera.ImageMode
403                 value: cam.iso.value
404         }
405
406         Binding {
407                 target: cam.videoMute
408                 property: "enabled"
409                 value: settings.videoMuted
410         }
411
412         Binding {
413                 target: cam.roi
414                 property: "enabled"
415                 value: settings.faceDetectionEnabled && !focusReticle.pressed && !focusReticle.touchMode && cam.mode == Camera.ImageMode
416         }
417
418
419         TrackerStore {
420                 id: trackerStore
421                 active: cam.running
422                 manufacturer: deviceInfo.manufacturer
423                 model: deviceInfo.model
424         }
425
426         ModeController {
427                 id: cameraMode
428                 cam: cam
429                 dimmer: root.dimmer
430         }
431
432         Connections {
433                 target: cam
434                 onModeChanged: {
435                         if (cam.mode == Camera.VideoMode) {
436                                 replacePage("VideoPage.qml");
437                         }
438                         else {
439                                 replacePage("ImagePage.qml");
440                         }
441                 }
442         }
443
444         Standby {
445                 policyLost: pipelineManager.state == "policyLost"
446                 show: !pageStack.currentPage || (pageStack.currentPage.standbyVisible && pageStack.currentPage.status == PageStatus.Active && pipelineManager.showStandBy)
447         }
448
449         DeviceKeys {
450                 id: keys
451                 active: Qt.application.active && pipelineManager.scaleAcquired
452                 repeat: !settings.zoomAsShutter
453         }
454 }